From 54ab1c114eb245f39722f56b28dd4f3262e7d9b0 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Fri, 10 Nov 2017 19:46:15 +0100 Subject: [PATCH 001/647] first version of UnifPlus for MA --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 298 +++++++++++++++++- .../helper/SparseMarkovAutomatonCslHelper.h | 62 +++- 2 files changed, 357 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 0bdc633f7..8fdfb3054 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -133,10 +133,304 @@ namespace storm { void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } + + template ::SupportsExponential, int>::type=0> + void SparseMarkovAutomatonCslHelper::printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ + std::ofstream logfile("U+logfile.txt", std::ios::app); + + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); + + logfile << "number of states = num of row group count " << numberOfStates << "\n"; + for (int i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + logfile << " from node " << i << " "; + auto from = rowGroupIndices[i]; + auto to = rowGroupIndices[i+1]; + for (auto j = from ; j< to; j++){ + for (auto &v : fullTransitionMatrix.getRow(j)) { + if (markovianStates[i]){ + logfile << v.getValue() *exitRateVector[i] << " -> "<< v.getColumn() << "\t"; + } else { + logfile << v.getValue() << " -> "<< v.getColumn() << "\t"; + } + } + logfile << "\n"; + } + } + logfile << "\n"; + + logfile << "vd: \n"; + for (int i =0 ; i + ValueType SparseMarkovAutomatonCslHelper::poisson(ValueType lambda, uint64_t i) { + ValueType res = pow(lambda, i); + ValueType fac = 1; + for (long j = i ; j>0 ; j--){ + fac = fac *j; + } + res = res / fac ; + res = res * exp(-lambda); + return res; + } + + template ::SupportsExponential, int>::type=0> + void SparseMarkovAutomatonCslHelper::calculateVu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. + uint64_t N = vu.size()-1; + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + ValueType res =0; + for (long i = k ; i < N ; i++ ){ + if (wu[N-1-(i-k)][node]==-1){ + calculateWu((N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + } + res+=poisson(lambda, i)*wu[N-1-(i-k)][node]; + } + vu[k][node]=res; + } + + template ::SupportsExponential, int>::type=0> + void SparseMarkovAutomatonCslHelper::calculateWu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. + uint64_t N = wu.size()-1; + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + ValueType res; + if (k==N){ + wu[k][node]=0; + return; + } + + if (psiStates[node]){ + wu[k][node]=1; + return; + } + + if (markovianStates[node]){ + res = 0; + auto line = fullTransitionMatrix.getRow(rowGroupIndices[node]); + for (auto &element : line){ + uint64_t to = element.getColumn(); + if (wu[k+1][to]==-1){ + calculateWu(k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + } + res+=element.getValue()*wu[k+1][to]; + } + } else { + res = 0; + uint64_t rowStart = rowGroupIndices[node]; + uint64_t rowEnd = rowGroupIndices[node+1]; + for (uint64_t i = rowStart; i< rowEnd; i++){ + auto line = fullTransitionMatrix.getRow(i); + ValueType between = 0; + for (auto& element: line){ + uint64_t to = element.getColumn(); + if (to==node){ + continue; + } + if (wu[k][to]==-1){ + calculateWu(k,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + } + between+=element.getValue()*wu[k][to]; + } + if (between > res){ + res = between; + } + } + } // end no goal-prob state + wu[k][node]=res; + } + + template ::SupportsExponential, int>::type=0> + void SparseMarkovAutomatonCslHelper::calculateVd(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + + std::ofstream logfile("U+logfile.txt", std::ios::app); + + if (vd[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. + logfile << "calculating vd for k = " << k << " node "<< node << " \t"; + uint64_t N = vd.size()-1; + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + ValueType res; + if (k==N){ + logfile << "k == N! res = 0\n"; + vd[k][node]=0; + return; + } + + //goal state + if (psiStates[node]){ + res = 0; + for (uint64_t i = k ; i res){ + res = between; + } + } + } + vd[k][node]=res; + logfile << " res = " << res << "\n"; + } + template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + std::ofstream logfile("U+logfile.txt", std::ios::app); + ValueType maxNorm = 0; + + //bitvectors to identify different kind of states + storm::storage::BitVector const &markovianNonGoalStates = markovianStates & ~psiStates; + storm::storage::BitVector const &probabilisticNonGoalStates = ~markovianStates & ~psiStates; + storm::storage::BitVector const &allStates = markovianStates | ~markovianStates; + + //vectors to save calculation + std::vector> vd,vu,wu; + + //transition matrix with diagonal entries. The values can be changed during uniformisation + typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + std::vector exitRate{exitRateVector}; + + //(1) define horizon, epsilon, kappa , N, lambda, + double T = boundsPair.second; + ValueType kappa = storm::utility::one() /10; // would be better as option-parameter + uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); + ValueType epsilon = storm::settings::getModule().getPrecision(); + ValueType lambda = exitRateVector[0]; + for (ValueType act: exitRateVector) { + lambda = std::max(act, lambda); + } + uint64_t N; + + // while not close enough to precision: + do { + // (2) update parameter + N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); + + // (3) uniform - just applied to markovian states + for (int i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + if (!markovianStates[i]) { + continue; + } + uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row + + if (exitRate[i] == lambda) { + continue; //already unified + } + + auto line = fullTransitionMatrix.getRow(from); + ValueType exitOld = exitRate[i]; + ValueType exitNew = lambda; + for (auto &v : line) { + if (v.getColumn() == i) { //diagonal element + ValueType newSelfLoop = exitNew - exitOld + v.getValue(); + ValueType newRate = newSelfLoop / exitNew; + v.setValue(newRate); + } else { //modify probability + ValueType propOld = v.getValue(); + ValueType propNew = propOld * exitOld / exitNew; + v.setValue(propNew); + } + } + exitRate[i] = exitNew; + } + + // (4) define vectors/matrices + std::vector init(numberOfStates, -1); + vd = std::vector> (N + 1, init); + vu = std::vector> (N + 1, init); + wu = std::vector> (N + 1, init); + + printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when develepmont is finished + + // (5) calculate vectors and maxNorm + for (uint64_t i = 0; i < numberOfStates; i++) { + for (uint64_t k = N; k <= N; k--) { + calculateVd(k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates); + calculateWu(k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates); + calculateVu(k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates); + //also use iteration to keep maxNorm of vd and vu up to date, so the loop-condition is easy to prove + ValueType diff = std::abs(vd[k][i]-vu[k][i]); + maxNorm = std::max(maxNorm, diff); + } + } + printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when development is finished + + + // (6) double lambda + lambda=2*lambda; + + } while (maxNorm>epsilon*(1-kappa)); + return vd[0]; + } + + template ::SupportsExponential, int>::type> + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + return unifPlus(boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); + /* uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); // 'Unpack' the bounds to make them more easily accessible. @@ -195,7 +489,7 @@ namespace storm { storm::utility::vector::setVectorValues(result, probabilisticNonGoalStates, vProbabilistic); storm::utility::vector::setVectorValues(result, markovianNonGoalStates, vMarkovian); return result; - } + }*/ } template ::SupportsExponential, int>::type> diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index a90c3a0cf..1dc6dcec5 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -14,7 +14,22 @@ namespace storm { class SparseMarkovAutomatonCslHelper { public: - + + /*! + * Computes TBU according to the UnifPlus algorithm + * + * @param boundsPair With precondition that the first component is 0, the second one gives the time bound + * @param exitRateVector the exit-rates of the given MA + * @param transitionMatrix the transitions of the given MA + * @param markovianStates bitvector refering to the markovian states + * @param psiStates bitvector refering to the goal states + * + * @return the probability vector + * + */ + template ::SupportsExponential, int>::type=0> + static std::vector unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); @@ -38,6 +53,51 @@ namespace storm { static std::vector computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + + /*! + * Computes the poission-distribution + * + * + * @param parameter lambda to use + * @param point i + * TODO: replace with Fox-Lynn + * @return the probability + */ + template + static ValueType poisson(ValueType lambda, uint64_t i); + + + /*! + * Computes vd vector according to UnifPlus + * + */ + template ::SupportsExponential, int>::type=0> + static void calculateVd(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + +/*! + * Computes vu vector according to UnifPlus + * + */ + template ::SupportsExponential, int>::type=0> + static void calculateVu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + + + /*! + * Computes wu vector according to UnifPlus + * + */ + template ::SupportsExponential, int>::type=0> + static void calculateWu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + + /*! + * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile + * TODO: delete when development is finished + * + */ + + template ::SupportsExponential, int>::type=0> + static void printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,std::vector>& vd, std::vector>& vu, std::vector>& wu); + template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From a6046ab0b31c12d571b003f764afb0ab2cbad5fd Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 11 Nov 2017 12:51:51 +0100 Subject: [PATCH 002/647] fixed some warnings and issues and introduce cli switch to select IMCA or UnifPlus --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 69 ++++++++++++------- .../helper/SparseMarkovAutomatonCslHelper.h | 3 + src/storm/settings/SettingsManager.cpp | 2 + .../modules/MarkovAutomatonSettings.cpp | 32 +++++++++ .../modules/MarkovAutomatonSettings.h | 38 ++++++++++ src/storm/settings/modules/SylvanSettings.h | 2 +- 6 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 src/storm/settings/modules/MarkovAutomatonSettings.cpp create mode 100644 src/storm/settings/modules/MarkovAutomatonSettings.h diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8fdfb3054..20f15344b 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -10,6 +10,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" +#include "storm/settings/modules/MarkovAutomatonSettings.h" #include "storm/utility/macros.h" #include "storm/utility/vector.h" @@ -134,19 +135,19 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ std::ofstream logfile("U+logfile.txt", std::ios::app); - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); logfile << "number of states = num of row group count " << numberOfStates << "\n"; - for (int i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { logfile << " from node " << i << " "; auto from = rowGroupIndices[i]; auto to = rowGroupIndices[i+1]; - for (auto j = from ; j< to; j++){ + for (auto j = from ; j < to; j++){ for (auto &v : fullTransitionMatrix.getRow(j)) { if (markovianStates[i]){ logfile << v.getValue() *exitRateVector[i] << " -> "<< v.getColumn() << "\t"; @@ -160,24 +161,24 @@ namespace storm { logfile << "\n"; logfile << "vd: \n"; - for (int i =0 ; i::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::calculateVu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = vu.size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res =0; - for (long i = k ; i < N ; i++ ){ + for (uint_fast64_t i = k ; i < N ; i++ ){ if (wu[N-1-(i-k)][node]==-1){ calculateWu((N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); } @@ -214,11 +215,11 @@ namespace storm { vu[k][node]=res; } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::calculateWu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = wu.size()-1; - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res; if (k==N){ @@ -267,7 +268,7 @@ namespace storm { wu[k][node]=res; } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::calculateVd(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -275,7 +276,7 @@ namespace storm { if (vd[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. logfile << "calculating vd for k = " << k << " node "<< node << " \t"; uint64_t N = vd.size()-1; - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res; if (k==N){ @@ -337,13 +338,15 @@ namespace storm { template ::SupportsExponential, int>::type> std::vector SparseMarkovAutomatonCslHelper::unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = 0; //bitvectors to identify different kind of states - storm::storage::BitVector const &markovianNonGoalStates = markovianStates & ~psiStates; - storm::storage::BitVector const &probabilisticNonGoalStates = ~markovianStates & ~psiStates; - storm::storage::BitVector const &allStates = markovianStates | ~markovianStates; +// storm::storage::BitVector const &markovianNonGoalStates = markovianStates & ~psiStates; +// storm::storage::BitVector const &probabilisticNonGoalStates = ~markovianStates & ~psiStates; + storm::storage::BitVector allStates(markovianStates.size(), true); //vectors to save calculation std::vector> vd,vu,wu; @@ -371,7 +374,7 @@ namespace storm { N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); // (3) uniform - just applied to markovian states - for (int i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { if (!markovianStates[i]) { continue; } @@ -428,15 +431,15 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { - return unifPlus(boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); - /* + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilitiesImca(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + STORM_LOG_TRACE("Using IMCA's technique to compute bounded until probabilities."); + uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); - + // 'Unpack' the bounds to make them more easily accessible. double lowerBound = boundsPair.first; double upperBound = boundsPair.second; - + // (1) Compute the accuracy we need to achieve the required error bound. ValueType maxExitRate = 0; for (auto value : exitRateVector) { @@ -489,7 +492,21 @@ namespace storm { storm::utility::vector::setVectorValues(result, probabilisticNonGoalStates, vProbabilistic); storm::utility::vector::setVectorValues(result, markovianNonGoalStates, vMarkovian); return result; - }*/ + } + } + + template ::SupportsExponential, int>::type> + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + + auto const& markovAutomatonSettings = storm::settings::getModule(); + if (markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::Imca) { + return computeBoundedUntilProbabilitiesImca(dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair, minMaxLinearEquationSolverFactory); + } else { + STORM_LOG_ASSERT(markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus, "Unknown solution technique."); + + // Why is optimization direction not passed? + return unifPlus(boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); + } } template ::SupportsExponential, int>::type> diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 1dc6dcec5..ff27180bd 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -33,6 +33,9 @@ namespace storm { template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template ::SupportsExponential, int>::type = 0> + static std::vector computeBoundedUntilProbabilitiesImca(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 188d1cba2..38e5ff10a 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -37,6 +37,7 @@ #include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/settings/modules/MarkovAutomatonSettings.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" #include "storm/settings/Option.h" @@ -534,6 +535,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } diff --git a/src/storm/settings/modules/MarkovAutomatonSettings.cpp b/src/storm/settings/modules/MarkovAutomatonSettings.cpp new file mode 100644 index 000000000..470de708f --- /dev/null +++ b/src/storm/settings/modules/MarkovAutomatonSettings.cpp @@ -0,0 +1,32 @@ +#include "storm/settings/modules/MarkovAutomatonSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/settings/SettingsManager.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string MarkovAutomatonSettings::moduleName = "ma"; + const std::string MarkovAutomatonSettings::techniqueOptionName = "technique"; + + MarkovAutomatonSettings::MarkovAutomatonSettings() : ModuleSettings(moduleName) { + std::vector techniques = {"imca", "unifplus"}; + this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The technique to use to solve bounded reachability queries.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the technique to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(techniques)).setDefaultValueString("imca").build()).build()); + } + + MarkovAutomatonSettings::BoundedReachabilityTechnique MarkovAutomatonSettings::getTechnique() const { + std::string techniqueAsString = this->getOption(techniqueOptionName).getArgumentByName("name").getValueAsString(); + if (techniqueAsString == "imca") { + return MarkovAutomatonSettings::BoundedReachabilityTechnique::Imca; + } + return MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus; + } + + } + } +} diff --git a/src/storm/settings/modules/MarkovAutomatonSettings.h b/src/storm/settings/modules/MarkovAutomatonSettings.h new file mode 100644 index 000000000..60cdaa1b4 --- /dev/null +++ b/src/storm/settings/modules/MarkovAutomatonSettings.h @@ -0,0 +1,38 @@ +#pragma once + +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for Sylvan. + */ + class MarkovAutomatonSettings : public ModuleSettings { + public: + enum class BoundedReachabilityTechnique { Imca, UnifPlus }; + + /*! + * Creates a new set of Markov automaton settings. + */ + MarkovAutomatonSettings(); + + /*! + * Retrieves the technique to use to solve bounded reachability properties. + * + * @return The selected technique. + */ + BoundedReachabilityTechnique getTechnique() const; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string techniqueOptionName; + }; + + } + } +} diff --git a/src/storm/settings/modules/SylvanSettings.h b/src/storm/settings/modules/SylvanSettings.h index b4eed806b..b218cbdfc 100644 --- a/src/storm/settings/modules/SylvanSettings.h +++ b/src/storm/settings/modules/SylvanSettings.h @@ -13,7 +13,7 @@ namespace storm { class SylvanSettings : public ModuleSettings { public: /*! - * Creates a new set of CUDD settings. + * Creates a new set of Sylvan settings. */ SylvanSettings(); From fc28fd16d3f755c44333a9d45a01183fb6cd65c6 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 13 Nov 2017 23:25:02 +0100 Subject: [PATCH 003/647] delete self loops for probabilistic states --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8fdfb3054..85906f8bc 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -190,7 +190,7 @@ namespace storm { ValueType SparseMarkovAutomatonCslHelper::poisson(ValueType lambda, uint64_t i) { ValueType res = pow(lambda, i); ValueType fac = 1; - for (long j = i ; j>0 ; j--){ + for (uint64_t j = i ; j>0 ; j--){ fac = fac *j; } res = res / fac ; @@ -205,7 +205,7 @@ namespace storm { auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res =0; - for (long i = k ; i < N ; i++ ){ + for (uint64_t i = k ; i < N ; i++ ){ if (wu[N-1-(i-k)][node]==-1){ calculateWu((N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); } @@ -286,9 +286,10 @@ namespace storm { //goal state if (psiStates[node]){ - res = 0; + res = storm::utility::zero(); for (uint64_t i = k ; i> vd,vu,wu; //transition matrix with diagonal entries. The values can be changed during uniformisation + std::vector exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - std::vector exitRate{exitRateVector}; + + //delete prob-diagonal entries + for (uint64_t i =0; i() /10; // would be better as option-parameter - uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); ValueType epsilon = storm::settings::getModule().getPrecision(); ValueType lambda = exitRateVector[0]; for (ValueType act: exitRateVector) { From 25a7b6c71a652b067af212cd2cecde7e1748e1ee Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 19 Nov 2017 12:20:54 +0100 Subject: [PATCH 004/647] implemented trajans alg to identify prob Cycles --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 74 ++++++++++++++++++- .../helper/SparseMarkovAutomatonCslHelper.h | 15 ++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8c3d33fc2..88d470dce 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -337,10 +337,82 @@ namespace storm { logfile << " res = " << res << "\n"; } + template ::SupportsExponential, int>::type=0> + int SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { + auto const &rowGroupIndice = transitionMatrix.getRowGroupIndices(); + + disc[node] = *counter; + finish[node] = *counter; + (*counter)+=1; + + auto from = rowGroupIndice[node]; + auto to = rowGroupIndice[node+1]; + + for(uint64_t i =from; i::SupportsExponential, int>::type=0> + storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCycles(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + + storm::storage::BitVector const& probabilisticStates = ~markovianStates; + storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates; + + storm::storage::SparseMatrix const& probMatrix = transitionMatrix.getSubmatrix(true, probabilisticNonGoalStates, probabilisticNonGoalStates); + uint64_t probSize = probMatrix.getRowGroupCount(); + std::vector disc(probSize, 0), finish(probSize, 0); + + uint64_t counter =1; + + for (uint64_t i =0; i::SupportsExponential, int>::type> std::vector SparseMarkovAutomatonCslHelper::unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - + + storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates; + auto cycleStates = identifyProbCycles(transitionMatrix, markovianStates, psiStates); + + for (int i=0 ; i < cycleStates.size() ; i++ ){ + std::cout << cycleStates[i] << "\t" << probabilisticNonGoalStates[i] <<"\n"; + } std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = 0; diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index ff27180bd..559912c2e 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -56,7 +56,20 @@ namespace storm { static std::vector computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + static uint64_t transformIndice(storm::storage::BitVector const& subset, uint64_t fakeId){ + uint64_t id =0; + uint64_t counter =0; + while(counter<=fakeId){ + if(subset[id]){ + counter++; + } + id++; + } + return id-1; + } + template ::SupportsExponential, int>::type=0> + static storm::storage::BitVector identifyProbCycles(storm::storage::SparseMatrix const& TransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); /*! * Computes the poission-distribution * @@ -69,6 +82,8 @@ namespace storm { template static ValueType poisson(ValueType lambda, uint64_t i); + template ::SupportsExponential, int>::type=0> + static int trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); /*! * Computes vd vector according to UnifPlus From 250fc89bc67b6d8f742e1b516fc84bfdb136793b Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 19 Nov 2017 14:01:54 +0100 Subject: [PATCH 005/647] new also supporting Pmin --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 52 ++++++++++++------- .../helper/SparseMarkovAutomatonCslHelper.h | 8 +-- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8c3d33fc2..b03b8cb39 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -200,15 +200,15 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateVu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = vu.size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - + ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (wu[N-1-(i-k)][node]==-1){ - calculateWu((N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + calculateWu(dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); } res+=poisson(lambda, i)*wu[N-1-(i-k)][node]; } @@ -216,10 +216,10 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateWu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateWu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = wu.size()-1; - auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices( ); ValueType res; if (k==N){ @@ -238,12 +238,12 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (wu[k+1][to]==-1){ - calculateWu(k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + calculateWu(dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); } res+=element.getValue()*wu[k+1][to]; } } else { - res = 0; + res = -1; uint64_t rowStart = rowGroupIndices[node]; uint64_t rowEnd = rowGroupIndices[node+1]; for (uint64_t i = rowStart; i< rowEnd; i++){ @@ -255,12 +255,18 @@ namespace storm { continue; } if (wu[k][to]==-1){ - calculateWu(k,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + calculateWu(dir, k,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); } between+=element.getValue()*wu[k][to]; } - if (between > res){ - res = between; + if (maximize(dir)){ + res = std::max(res,between); + } else { + if (res!=-1){ + res = std::min(res,between); + } else { + res = between; + } } } } // end no goal-prob state @@ -269,7 +275,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVd(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateVd(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -305,13 +311,13 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (vd[k+1][to]==-1){ - calculateVd(k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates); + calculateVd(dir,k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates); } res+=element.getValue()*vd[k+1][to]; } } else { //no-goal prob state logfile << "prob state: "; - res = 0; + res = -1; uint64_t rowStart = rowGroupIndices[node]; uint64_t rowEnd = rowGroupIndices[node+1]; for (uint64_t i = rowStart; i< rowEnd; i++){ @@ -324,12 +330,18 @@ namespace storm { continue; } if (vd[k][to]==-1){ - calculateVd(k,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates); + calculateVd(dir, k,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates); } between+=element.getValue()*vd[k][to]; } - if (between > res){ + if (maximize(dir)){ + res = std::max(res, between); + } else { + if (res!=-1){ + res =std::min(res,between); + } else { res = between; + } } } } @@ -338,7 +350,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -441,9 +453,9 @@ namespace storm { // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateVd(k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates); - calculateWu(k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates); - calculateVu(k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates); + calculateVd(dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates); + calculateWu(dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates); + calculateVu(dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates); //also use iteration to keep maxNorm of vd and vu up to date, so the loop-condition is easy to prove ValueType diff = std::abs(vd[k][i]-vu[k][i]); maxNorm = std::max(maxNorm, diff); @@ -534,7 +546,7 @@ namespace storm { STORM_LOG_ASSERT(markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus, "Unknown solution technique."); // Why is optimization direction not passed? - return unifPlus(boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); + return unifPlus(dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index ff27180bd..3346ea93d 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -28,7 +28,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static std::vector unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static std::vector unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); @@ -75,14 +75,14 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVd(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateVd(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); /*! * Computes vu vector according to UnifPlus * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateVu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); /*! @@ -90,7 +90,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateWu(uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateWu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile From fe863679bfae91277c45e09b947027508b086882 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 19 Nov 2017 15:26:30 +0100 Subject: [PATCH 006/647] identify probCycles outgoing states --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 47 +++++++++++++++---- .../helper/SparseMarkovAutomatonCslHelper.h | 6 ++- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 88d470dce..54abee155 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -136,7 +136,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ + void SparseMarkovAutomatonCslHelper::printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ std::ofstream logfile("U+logfile.txt", std::ios::app); auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -160,6 +160,13 @@ namespace storm { } logfile << "\n"; + logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; + for (int i =0 ; i< markovianStates.size() ; i++){ + logfile << (~markovianStates)[i] << "\t" << markovianStates[i] << "\t" << psiStates[i] << "\t" << cycleStates[i] << "\t" << cycleGoalStates[i] << "\n"; + } + + + logfile << "vd: \n"; for (uint_fast64_t i =0 ; i::SupportsExponential, int>::type=0> int SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { - auto const &rowGroupIndice = transitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndice = transitionMatrix.getRowGroupIndices(); disc[node] = *counter; finish[node] = *counter; @@ -362,8 +369,31 @@ namespace storm { return finish[node]; } - template ::SupportsExponential, int>::type=0> + storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates) { + + storm::storage::BitVector goalStates(cycleStates.size(), false); + auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); + + for (uint64_t i = 0 ; i < transitionMatrix.getRowGroupCount() ; i++){ + if (!cycleStates[i]){ + continue; + } + auto from = rowGroupIndices[i]; + auto to = rowGroupIndices[i+1]; + for (auto j = from ; j::SupportsExponential, int>::type=0> storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCycles(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ storm::storage::BitVector const& probabilisticStates = ~markovianStates; @@ -392,7 +422,6 @@ namespace storm { auto f = finish[i]; for (int j =i; j SparseMarkovAutomatonCslHelper::unifPlus( std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates; auto cycleStates = identifyProbCycles(transitionMatrix, markovianStates, psiStates); + auto cycleGoals = identifyProbCyclesGoalStates(transitionMatrix, cycleStates); + - for (int i=0 ; i < cycleStates.size() ; i++ ){ - std::cout << cycleStates[i] << "\t" << probabilisticNonGoalStates[i] <<"\n"; - } std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = 0; @@ -423,6 +452,7 @@ namespace storm { //vectors to save calculation std::vector> vd,vu,wu; + printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished //transition matrix with diagonal entries. The values can be changed during uniformisation std::vector exitRate{exitRateVector}; @@ -508,7 +538,6 @@ namespace storm { vu = std::vector> (N + 1, init); wu = std::vector> (N + 1, init); - printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when develepmont is finished // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { @@ -521,7 +550,7 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when development is finished + //printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when development is finished // (6) double lambda diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 559912c2e..421a1e21a 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -69,6 +69,10 @@ namespace storm { } template ::SupportsExponential, int>::type=0> + static storm::storage::BitVector identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates); + + + template ::SupportsExponential, int>::type=0> static storm::storage::BitVector identifyProbCycles(storm::storage::SparseMatrix const& TransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); /*! * Computes the poission-distribution @@ -114,7 +118,7 @@ namespace storm { */ template ::SupportsExponential, int>::type=0> - static void printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,std::vector>& vd, std::vector>& vu, std::vector>& wu); + static void printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu); template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From 253b34ce094404cc1ddccd23f762c4a285e9cbe3 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 20 Nov 2017 08:51:55 +0100 Subject: [PATCH 007/647] modularised diagonal-prob entrie delete and skipped zero loops in cycle identification --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 81 ++++++++++--------- .../helper/SparseMarkovAutomatonCslHelper.h | 6 +- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 725594d5b..b9aaa221e 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -162,7 +162,7 @@ namespace storm { logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; for (int i =0 ; i< markovianStates.size() ; i++){ - logfile << (~markovianStates)[i] << "\t" << markovianStates[i] << "\t" << psiStates[i] << "\t" << cycleStates[i] << "\t" << cycleGoalStates[i] << "\n"; + logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; } @@ -369,6 +369,9 @@ namespace storm { for(uint64_t i =from; i + std::vector SparseMarkovAutomatonCslHelper::deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ - template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ - STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - - - storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates; - auto cycleStates = identifyProbCycles(transitionMatrix, markovianStates, psiStates); - auto cycleGoals = identifyProbCyclesGoalStates(transitionMatrix, cycleStates); - - - std::ofstream logfile("U+logfile.txt", std::ios::app); - ValueType maxNorm = 0; - - //bitvectors to identify different kind of states -// storm::storage::BitVector const &markovianNonGoalStates = markovianStates & ~psiStates; -// storm::storage::BitVector const &probabilisticNonGoalStates = ~markovianStates & ~psiStates; - storm::storage::BitVector allStates(markovianStates.size(), true); - - //vectors to save calculation - std::vector> vd,vu,wu; - printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished - - //transition matrix with diagonal entries. The values can be changed during uniformisation - std::vector exitRate{exitRateVector}; - typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); - //delete prob-diagonal entries - for (uint64_t i =0; i::SupportsExponential, int>::type> + std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + + std::ofstream logfile("U+logfile.txt", std::ios::app); + ValueType maxNorm = 0; + + //bitvectors to identify different kind of states + storm::storage::BitVector allStates(markovianStates.size(), true); + + //vectors to save calculation + std::vector> vd,vu,wu; + + + //transition matrix with diagonal entries. The values can be changed during uniformisation + std::vector exitRate{exitRateVector}; + typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + + //delete prob-diagonal entries + deleteProbDiagonalEntries(fullTransitionMatrix, markovianStates); + + //identify cycles and cycleGoals + auto cycleStates = identifyProbCycles(transitionMatrix, markovianStates, psiStates); + auto cycleGoals = identifyProbCyclesGoalStates(transitionMatrix, cycleStates); //(1) define horizon, epsilon, kappa , N, lambda, @@ -543,13 +545,14 @@ namespace storm { } exitRate[i] = exitNew; } - + // (4) define vectors/matrices std::vector init(numberOfStates, -1); vd = std::vector> (N + 1, init); vu = std::vector> (N + 1, init); wu = std::vector> (N + 1, init); - + + printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { @@ -562,7 +565,7 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - //printTransitions(exitRate, fullTransitionMatrix, markovianStates,vd,vu,wu); // TODO: delete when development is finished + printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished // (6) double lambda diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 908668d2b..363de0867 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -68,7 +68,11 @@ namespace storm { return id-1; } - template ::SupportsExponential, int>::type=0> + template + static std::vector deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); + + + template ::SupportsExponential, int>::type=0> static storm::storage::BitVector identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates); From 286fc8aec7d87ebb891c43b719685b2218315e68 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 20 Nov 2017 16:02:18 +0100 Subject: [PATCH 008/647] fixed bugs, runnig now --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 27 ++++++++++++------- .../helper/SparseMarkovAutomatonCslHelper.h | 8 ++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index b9aaa221e..f654405a4 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -357,7 +357,7 @@ namespace storm { } template ::SupportsExponential, int>::type=0> - int SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { + uint64_t SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { auto const& rowGroupIndice = transitionMatrix.getRowGroupIndices(); disc[node] = *counter; @@ -430,7 +430,7 @@ namespace storm { storm::storage::BitVector cycleStates(markovianStates.size(), false); for (int i = 0 ; i< finish.size() ; i++){ auto f = finish[i]; - for (int j =i; j - std::vector SparseMarkovAutomatonCslHelper::deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ + template ::SupportsExponential, int>::type=0> + void SparseMarkovAutomatonCslHelper::deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); for (uint64_t i =0; i + std::vector SparseMarkovAutomatonCslHelper::deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ + + } template ::SupportsExponential, int>::type> @@ -494,11 +502,14 @@ namespace storm { //delete prob-diagonal entries - deleteProbDiagonalEntries(fullTransitionMatrix, markovianStates); + //deleteProbDiagonalEntries(fullTransitionMatrix, markovianStates); + deleteProbDiagonals(fullTransitionMatrix, markovianStates); //identify cycles and cycleGoals - auto cycleStates = identifyProbCycles(transitionMatrix, markovianStates, psiStates); - auto cycleGoals = identifyProbCyclesGoalStates(transitionMatrix, cycleStates); + auto cycleStates = identifyProbCycles(fullTransitionMatrix, markovianStates, psiStates); + auto cycleGoals = identifyProbCyclesGoalStates(fullTransitionMatrix, cycleStates); + + printTransitions(exitRateVector, fullTransitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished //(1) define horizon, epsilon, kappa , N, lambda, @@ -552,7 +563,6 @@ namespace storm { vu = std::vector> (N + 1, init); wu = std::vector> (N + 1, init); - printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { @@ -565,7 +575,6 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - printTransitions(exitRateVector, transitionMatrix, markovianStates, psiStates, cycleStates, cycleGoals, vd,vu,wu); // TODO: delete when develepmont is finished // (6) double lambda diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 363de0867..015b71e67 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -56,6 +56,10 @@ namespace storm { static std::vector computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + + template ::SupportsExponential, int>::type=0> + static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); + static uint64_t transformIndice(storm::storage::BitVector const& subset, uint64_t fakeId){ uint64_t id =0; uint64_t counter =0; @@ -84,14 +88,14 @@ namespace storm { * * @param parameter lambda to use * @param point i - * TODO: replace with Fox-Lynn + * TODO: replace with Fox-glynn * @return the probability */ template static ValueType poisson(ValueType lambda, uint64_t i); template ::SupportsExponential, int>::type=0> - static int trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); + static uint64_t trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); /*! * Computes vd vector according to UnifPlus From dfda3a154488ae852d5020664a7607a98b8130ff Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 20 Nov 2017 17:51:23 +0100 Subject: [PATCH 009/647] cleaned up --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 6 ------ .../csl/helper/SparseMarkovAutomatonCslHelper.h | 4 ---- 2 files changed, 10 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index f654405a4..fd1ae1161 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -473,12 +473,6 @@ namespace storm { } } } - } - - template - std::vector SparseMarkovAutomatonCslHelper::deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ - - } template ::SupportsExponential, int>::type> diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 015b71e67..1cee6364d 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -72,10 +72,6 @@ namespace storm { return id-1; } - template - static std::vector deleteProbDiagonalEntries(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); - - template ::SupportsExponential, int>::type=0> static storm::storage::BitVector identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates); From 8421ff5c654b7eedbcbc2610964ecd57e68ecb23 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 21 Nov 2017 09:55:04 +0100 Subject: [PATCH 010/647] first try, cmake not building --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 36 +++++++++++++------ .../helper/SparseMarkovAutomatonCslHelper.h | 2 +- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index fd1ae1161..67eec89ee 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -136,7 +136,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ + void SparseMarkovAutomatonCslHelper::printTransitions(std::vector> relReachability, std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ std::ofstream logfile("U+logfile.txt", std::ios::app); auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -165,6 +165,12 @@ namespace storm { logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; } + for (int i =0; i in(fullTransitionMatrix.getRowCount(), 0); + std::vector> relReachability(numberOfStates,in); + + printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished + for(int i=0 ; i& act = relReachability[j]; + for(auto element: fullTransitionMatrix.getRow(j)){ + if (markovianStates[element.getColumn()]){ + act[element.getColumn]=element.getValue(); + } + } + + } + } - // while not close enough to precision: + // while not close enough to precision: do { // (2) update parameter N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 1cee6364d..376b4e88a 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -122,7 +122,7 @@ namespace storm { */ template ::SupportsExponential, int>::type=0> - static void printTransitions(std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu); + static void printTransitions(std::vector> relReachability, std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu); template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From 5ba296404a2826d92e516b7ad07b8ad5d399e49f Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Thu, 23 Nov 2017 12:41:10 +0100 Subject: [PATCH 011/647] not finished version of MDP approach --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 186 +++++++++++++++--- .../helper/SparseMarkovAutomatonCslHelper.h | 8 +- 2 files changed, 167 insertions(+), 27 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 67eec89ee..3ef29e743 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -213,7 +213,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = vu.size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -221,7 +221,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (wu[N-1-(i-k)][node]==-1){ - calculateWu(dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + calculateWu(relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, minMaxLinearEquationSolverFactory); } res+=poisson(lambda, i)*wu[N-1-(i-k)][node]; } @@ -229,7 +229,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateWu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = wu.size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices( ); @@ -251,11 +251,72 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (wu[k+1][to]==-1){ - calculateWu(dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates); + calculateWu(relativeReachability, dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, minMaxLinearEquationSolverFactory); } res+=element.getValue()*wu[k+1][to]; } } else { + + // applying simpleMDP stuff + auto numberOfStates=relativeReachability[0].size(); + typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); + auto probSize = probMatrix.getRowGroupCount(); + std::vector b(probSize, 0), x(probSize,0); + + //calculate b + for (uint64_t i =0 ; i> solver = minMaxLinearEquationSolverFactory.create(probMatrix); + + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + + + solver->solveEquations(dir, x, b); + + for (uint64_t i =0 ; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVd(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + void SparseMarkovAutomatonCslHelper::calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -324,11 +384,83 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (vd[k+1][to]==-1){ - calculateVd(dir,k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates); + calculateVd(relativeReachability, dir,k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates, minMaxLinearEquationSolverFactory); } res+=element.getValue()*vd[k+1][to]; } + + vd[k][node]=res; + logfile << " res = " << res << "\n"; } else { //no-goal prob state + // applying simpleMDP stuff + logfile << "probState, applying MDP stuff "; + auto numberOfStates=relativeReachability[0].size(); + typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); + auto probSize = probMatrix.getRowGroupCount(); + std::vector b(probSize, 0), x(probSize,0); + + //calculate b + for (uint64_t i =0 ; i> solver = minMaxLinearEquationSolverFactory.create(probMatrix); + + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + + + solver->solveEquations(dir, x, b); + logfile << "goal vector x is \n"; + for (int i =0 ; i::SupportsExponential, int>::type=0> @@ -482,7 +613,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ + std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -516,24 +647,32 @@ namespace storm { uint64_t N; //calculate relative ReachabilityVectors - std::vector in(fullTransitionMatrix.getRowCount(), 0); - std::vector> relReachability(numberOfStates,in); + std::vector in(numberOfStates, 0); + std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished - for(int i=0 ; i& act = relReachability[j]; for(auto element: fullTransitionMatrix.getRow(j)){ if (markovianStates[element.getColumn()]){ - act[element.getColumn]=element.getValue(); + act[element.getColumn()]=element.getValue(); } } - } } + + + printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished // while not close enough to precision: do { // (2) update parameter @@ -577,15 +716,17 @@ namespace storm { // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateVd(dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates); - calculateWu(dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates); - calculateVu(dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates); + calculateVd(relReachability, dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + calculateWu(relReachability, dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + calculateVu(relReachability, dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); //also use iteration to keep maxNorm of vd and vu up to date, so the loop-condition is easy to prove ValueType diff = std::abs(vd[k][i]-vu[k][i]); maxNorm = std::max(maxNorm, diff); } } + printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished + // (6) double lambda lambda=2*lambda; @@ -668,8 +809,7 @@ namespace storm { } else { STORM_LOG_ASSERT(markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus, "Unknown solution technique."); - // Why is optimization direction not passed? - return unifPlus(dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); + return unifPlus(dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 376b4e88a..7dac4cf6f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -28,7 +28,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static std::vector unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static std::vector unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); @@ -98,14 +98,14 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVd(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); /*! * Computes vu vector according to UnifPlus * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); /*! @@ -113,7 +113,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateWu(OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + static void calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile From b90e88c365e794e0505105e2e32fd53d468514c7 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Fri, 24 Nov 2017 12:48:14 +0100 Subject: [PATCH 012/647] first version, seems to be working, need to check more --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 104 +++++++++--------- 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 3ef29e743..c84e48477 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -231,6 +231,11 @@ namespace storm { template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. + + std::ofstream logfile("U+logfile.txt", std::ios::app); + + auto probabilisticStates = ~markovianStates; + uint64_t N = wu.size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices( ); @@ -255,46 +260,42 @@ namespace storm { } res+=element.getValue()*wu[k+1][to]; } + wu[k][node]=res; } else { - // applying simpleMDP stuff auto numberOfStates=relativeReachability[0].size(); typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); auto probSize = probMatrix.getRowGroupCount(); - std::vector b(probSize, 0), x(probSize,0); + std::vector b(probMatrix.getRowCount(), 0), x(probSize,0); //calculate b - for (uint64_t i =0 ; i::SupportsExponential, int>::type> @@ -352,6 +352,8 @@ namespace storm { std::ofstream logfile("U+logfile.txt", std::ios::app); + auto probabilisticStates = ~markovianStates; + if (vd[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. logfile << "calculating vd for k = " << k << " node "<< node << " \t"; uint64_t N = vd.size()-1; @@ -397,41 +399,35 @@ namespace storm { auto numberOfStates=relativeReachability[0].size(); typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); auto probSize = probMatrix.getRowGroupCount(); - std::vector b(probSize, 0), x(probSize,0); + std::vector b(probMatrix.getRowCount(), 0), x(probSize,0); //calculate b - for (uint64_t i =0 ; isolveEquations(dir, x, b); - logfile << "goal vector x is \n"; - for (int i =0 ; i Date: Fri, 24 Nov 2017 14:56:03 +0100 Subject: [PATCH 013/647] creating solver only once --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 70 ++++++++----------- .../helper/SparseMarkovAutomatonCslHelper.h | 6 +- 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index c84e48477..bd2c99760 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -213,7 +213,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = vu.size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -221,7 +221,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (wu[N-1-(i-k)][node]==-1){ - calculateWu(relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, minMaxLinearEquationSolverFactory); + calculateWu(relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } res+=poisson(lambda, i)*wu[N-1-(i-k)][node]; } @@ -229,7 +229,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ + void SparseMarkovAutomatonCslHelper::calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -256,7 +256,7 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (wu[k+1][to]==-1){ - calculateWu(relativeReachability, dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, minMaxLinearEquationSolverFactory); + calculateWu(relativeReachability, dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } res+=element.getValue()*wu[k+1][to]; } @@ -284,7 +284,7 @@ namespace storm { continue; } if (wu[k][to]==-1){ - calculateWu(relativeReachability, dir, k, to, lambda, wu, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + calculateWu(relativeReachability, dir, k, to, lambda, wu, fullTransitionMatrix, markovianStates, psiStates, solver); } res = res + relativeReachability[j][to]*wu[k][to]; } @@ -297,19 +297,6 @@ namespace storm { logfile << b[i] << "\n"; } - - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); - requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - - std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(probMatrix); - - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - - solver->solveEquations(dir, x, b); for (uint64_t i =0 ; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ + void SparseMarkovAutomatonCslHelper::calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ std::ofstream logfile("U+logfile.txt", std::ios::app); @@ -386,7 +373,7 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (vd[k+1][to]==-1){ - calculateVd(relativeReachability, dir,k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates, minMaxLinearEquationSolverFactory); + calculateVd(relativeReachability, dir,k+1,to,lambda,vd, fullTransitionMatrix, markovianStates,psiStates, solver); } res+=element.getValue()*vd[k+1][to]; } @@ -417,7 +404,7 @@ namespace storm { continue; } if (vd[k][to]==-1){ - calculateVd(relativeReachability, dir, k, to, lambda, vd, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + calculateVd(relativeReachability, dir, k, to, lambda, vd, fullTransitionMatrix, markovianStates, psiStates, solver); } res = res + relativeReachability[j][to]*vd[k][to]; } @@ -431,20 +418,6 @@ namespace storm { logfile << b[i] << "\n"; } - - - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); - requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - - std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(probMatrix); - - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - - solver->solveEquations(dir, x, b); logfile << "vd goal vector x is \n"; for (int i =0 ; i> vd,vu,wu; @@ -625,10 +600,9 @@ namespace storm { //transition matrix with diagonal entries. The values can be changed during uniformisation std::vector exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - - + typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); + auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); //(1) define horizon, epsilon, kappa , N, lambda, @@ -666,9 +640,20 @@ namespace storm { } } + //create equitation solver + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); + requirements.clearBounds(); + STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(probMatrix); - printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + + + printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished // while not close enough to precision: do { // (2) update parameter @@ -707,14 +692,15 @@ namespace storm { vd = std::vector> (N + 1, init); vu = std::vector> (N + 1, init); wu = std::vector> (N + 1, init); + // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateVd(relReachability, dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); - calculateWu(relReachability, dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); - calculateVu(relReachability, dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + calculateVd(relReachability, dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates, solver); + calculateWu(relReachability, dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates, solver); + calculateVu(relReachability, dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates, solver); //also use iteration to keep maxNorm of vd and vu up to date, so the loop-condition is easy to prove ValueType diff = std::abs(vd[k][i]-vu[k][i]); maxNorm = std::max(maxNorm, diff); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 7dac4cf6f..d378ded43 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -98,14 +98,14 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static void calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); /*! * Computes vu vector according to UnifPlus * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); /*! @@ -113,7 +113,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static void calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile From ec41a5e661d8ebf816d3818b97b765b5306fb3db Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 25 Nov 2017 14:39:55 +0100 Subject: [PATCH 014/647] reorganised and modulised storm --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 367 +++++++----------- .../helper/SparseMarkovAutomatonCslHelper.h | 24 +- 2 files changed, 143 insertions(+), 248 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index bd2c99760..de2459647 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -134,14 +134,23 @@ namespace storm { void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } - - template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::printTransitions(std::vector> relReachability, std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu){ + + template::SupportsExponential, int>::type= 0> + void SparseMarkovAutomatonCslHelper::printTransitions( + storm::storage::SparseMatrix const &fullTransitionMatrix, + std::vector const &exitRateVector, storm::storage::BitVector const &markovianStates, + storm::storage::BitVector const &psiStates, std::vector> relReachability, + const storage::BitVector &cycleStates, const storage::BitVector &cycleGoalStates, + std::vector>> &unifVectors) { + + + std::ofstream logfile("U+logfile.txt", std::ios::app); - + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); + //Transition Matrix logfile << "number of states = num of row group count " << numberOfStates << "\n"; for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { logfile << " from node " << i << " "; @@ -161,8 +170,8 @@ namespace storm { logfile << "\n"; logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; - for (int i =0 ; i< markovianStates.size() ; i++){ - logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; + for (int i =0 ; i< markovianStates.size() ; i++){ + logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; } for (int i =0; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ - if (vu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. - uint64_t N = vu.size()-1; + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ + if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. + uint64_t N = unifVectors[1].size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ - if (wu[N-1-(i-k)][node]==-1){ - calculateWu(relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); + if (unifVectors[2][N-1-(i-k)][node]==-1){ + calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver); + //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } - res+=poisson(lambda, i)*wu[N-1-(i-k)][node]; + res+=poisson(lambda, i)*unifVectors[2][N-1-(i-k)][node]; } - vu[k][node]=res; + unifVectors[1][k][node]=res; } - template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ - if (wu[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. - - std::ofstream logfile("U+logfile.txt", std::ios::app); - - auto probabilisticStates = ~markovianStates; - uint64_t N = wu.size()-1; - auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices( ); - ValueType res; - if (k==N){ - wu[k][node]=0; - return; - } - if (psiStates[node]){ - wu[k][node]=1; - return; - } + template::SupportsExponential, int>::type= 0> + void SparseMarkovAutomatonCslHelper::calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, + std::vector> const &relativeReachability, + OptimizationDirection dir, + std::vector>> &unifVectors, + storm::storage::SparseMatrix const &fullTransitionMatrix, + storm::storage::BitVector const &markovianStates, + storm::storage::BitVector const &psiStates, + std::unique_ptr> const &solver) { - if (markovianStates[node]){ - res = 0; - auto line = fullTransitionMatrix.getRow(rowGroupIndices[node]); - for (auto &element : line){ - uint64_t to = element.getColumn(); - if (wu[k+1][to]==-1){ - calculateWu(relativeReachability, dir, k+1,to,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); - } - res+=element.getValue()*wu[k+1][to]; - } - wu[k][node]=res; - } else { - // applying simpleMDP stuff - auto numberOfStates=relativeReachability[0].size(); - typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); - auto probSize = probMatrix.getRowGroupCount(); - std::vector b(probMatrix.getRowCount(), 0), x(probSize,0); - - //calculate b - uint64_t lineCounter=0; - for (int i =0; isolveEquations(dir, x, b); - - for (uint64_t i =0 ; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ - + if (unifVectors[kind][k][node]!=-1){return;} std::ofstream logfile("U+logfile.txt", std::ios::app); + logfile << "calculating vector " << kind << " for k = " << k << " node "<< node << " \t"; auto probabilisticStates = ~markovianStates; - - if (vd[k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. - logfile << "calculating vd for k = " << k << " node "<< node << " \t"; - uint64_t N = vd.size()-1; + auto numberOfStates=fullTransitionMatrix.getRowGroupCount(); + uint64_t N = unifVectors[kind].size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - ValueType res; + + // First Case, k==N, independent from kind of state if (k==N){ logfile << "k == N! res = 0\n"; - vd[k][node]=0; + unifVectors[kind][k][node]=0; return; } - + //goal state if (psiStates[node]){ - res = storm::utility::zero(); - for (uint64_t i = k ; i(); + for (uint64_t i = k ; i probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); - auto probSize = probMatrix.getRowGroupCount(); - std::vector b(probMatrix.getRowCount(), 0), x(probSize,0); + return; + } + //probabilistic non-goal State + if (probabilisticStates[node]){ + logfile << "probabilistic state: "; + std::vector b(probSize, 0), x(probabilisticStates.getNumberOfSetBits(),0); //calculate b uint64_t lineCounter=0; - for (int i =0; isolveEquations(dir, x, b); - logfile << "vd goal vector x is \n"; - for (int i =0 ; i::SupportsExponential, int>::type=0> uint64_t SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { auto const& rowGroupIndice = transitionMatrix.getRowGroupIndices(); @@ -585,24 +475,29 @@ namespace storm { std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - std::ofstream logfile("U+logfile.txt", std::ios::app); - ValueType maxNorm = 0; + ValueType maxNorm = storm::utility::zero(); //bitvectors to identify different kind of states storm::storage::BitVector allStates(markovianStates.size(), true); - auto probabilisticStates = ~markovianStates; + storm::storage::BitVector probabilisticStates = ~markovianStates; //vectors to save calculation std::vector> vd,vu,wu; + std::vector>> unifVectors{}; //transition matrix with diagonal entries. The values can be changed during uniformisation std::vector exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); - typename storm::storage::SparseMatrix probMatrix = fullTransitionMatrix.getSubmatrix(true, ~markovianStates , ~markovianStates, true); + typename storm::storage::SparseMatrix probMatrix{}; + uint64_t probSize =0; + if (probabilisticStates.getNumberOfSetBits()!=0){ //work around in case there are no prob states + probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates , probabilisticStates, true); + probSize = probMatrix.getRowCount(); + } - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); //(1) define horizon, epsilon, kappa , N, lambda, @@ -616,13 +511,14 @@ namespace storm { } uint64_t N; + + //calculate relative ReachabilityVectors std::vector in(numberOfStates, 0); std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); - printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished - //calculate relative reachability + //calculate relative reachability for(uint64_t i=0 ; i> solver = minMaxLinearEquationSolverFactory.create(probMatrix); - - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - - - printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished + std::unique_ptr> solver; + if (probSize!=0){ + solver = minMaxLinearEquationSolverFactory.create(probMatrix); + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + } // while not close enough to precision: do { // (2) update parameter @@ -692,29 +587,37 @@ namespace storm { vd = std::vector> (N + 1, init); vu = std::vector> (N + 1, init); wu = std::vector> (N + 1, init); - + unifVectors.clear(); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + + printTransitions(fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors); //TODO remove + + //define 0=vd 1=vu 2=wu // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateVd(relReachability, dir, k, i, T*lambda, vd, fullTransitionMatrix, markovianStates, psiStates, solver); - calculateWu(relReachability, dir, k, i, T*lambda, wu, fullTransitionMatrix, markovianStates, psiStates, solver); - calculateVu(relReachability, dir, k, i, T*lambda, vu, wu, fullTransitionMatrix, markovianStates, psiStates, solver); - //also use iteration to keep maxNorm of vd and vu up to date, so the loop-condition is easy to prove - ValueType diff = std::abs(vd[k][i]-vu[k][i]); + calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); + calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); + calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); + //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove + ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); } } - - printTransitions(relReachability, exitRateVector, fullTransitionMatrix, markovianStates, psiStates, psiStates, psiStates, vd,vu,wu); // TODO: delete when develepmont is finished + std::cout << "\nTBU was " << unifVectors[0][0][0] << "\n"; + printTransitions(fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors); //TODO remove - // (6) double lambda + // (6) double lambda lambda=2*lambda; } while (maxNorm>epsilon*(1-kappa)); - return vd[0]; + + return unifVectors[0][0]; } template ::SupportsExponential, int>::type> @@ -1234,7 +1137,7 @@ namespace storm { return v.front() * uniformizationRate; } - + template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index d378ded43..3d5b8d049 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -56,6 +56,8 @@ namespace storm { static std::vector computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + template ::SupportsExponential, int>::type=0> + static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -93,27 +95,15 @@ namespace storm { template ::SupportsExponential, int>::type=0> static uint64_t trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); - /*! - * Computes vd vector according to UnifPlus - * - */ - template ::SupportsExponential, int>::type=0> - static void calculateVd(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vd, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); - -/*! + /* * Computes vu vector according to UnifPlus * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& vu, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); + - /*! - * Computes wu vector according to UnifPlus - * - */ - template ::SupportsExponential, int>::type=0> - static void calculateWu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, ValueType lambda, std::vector>& wu, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile @@ -122,7 +112,9 @@ namespace storm { */ template ::SupportsExponential, int>::type=0> - static void printTransitions(std::vector> relReachability, std::vector const& exitRateVector, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::storage::BitVector const& cycleStates, storm::storage::BitVector const& cycleGoalStates, std::vector>& vd, std::vector>& vu, std::vector>& wu); + static void printTransitions(storm::storage::SparseMatrix const& fullTransitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, + storm::storage::BitVector const& psiStates, std::vector> relReachability, + storm::storage::BitVector const& cycleStates , storm::storage::BitVector const& cycleGoalStates ,std::vector>>& unifVectors); template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From 42e650362b623ff568a02ebb4b8b9d3463182a0e Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 25 Nov 2017 15:44:25 +0100 Subject: [PATCH 015/647] fixed the sife of result vector MDP approach, add selfLoop deletion --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index de2459647..609a03e94 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -258,6 +258,7 @@ namespace storm { logfile << "calculating vector " << kind << " for k = " << k << " node "<< node << " \t"; auto probabilisticStates = ~markovianStates; + auto numberOfProbStates = probabilisticStates.getNumberOfSetBits(); auto numberOfStates=fullTransitionMatrix.getRowGroupCount(); uint64_t N = unifVectors[kind].size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -309,7 +310,7 @@ namespace storm { //probabilistic non-goal State if (probabilisticStates[node]){ logfile << "probabilistic state: "; - std::vector b(probSize, 0), x(probabilisticStates.getNumberOfSetBits(),0); + std::vector b(probSize, 0), x(numberOfProbStates,0); //calculate b uint64_t lineCounter=0; for (int i =0; i exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); + // delete diagonals + deleteProbDiagonals(fullTransitionMatrix, markovianStates); typename storm::storage::SparseMatrix probMatrix{}; uint64_t probSize =0; if (probabilisticStates.getNumberOfSetBits()!=0){ //work around in case there are no prob states @@ -518,6 +522,7 @@ namespace storm { std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); + //calculate relative reachability for(uint64_t i=0 ; i Date: Sun, 26 Nov 2017 15:06:39 +0100 Subject: [PATCH 016/647] leaving some Log prints" --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 33 ++++++++----------- .../helper/SparseMarkovAutomatonCslHelper.h | 2 +- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 609a03e94..8bd2ba44c 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -136,7 +136,7 @@ namespace storm { } template::SupportsExponential, int>::type= 0> - void SparseMarkovAutomatonCslHelper::printTransitions( + void SparseMarkovAutomatonCslHelper::printTransitions(const uint64_t N, ValueType const diff, storm::storage::SparseMatrix const &fullTransitionMatrix, std::vector const &exitRateVector, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, std::vector> relReachability, @@ -169,19 +169,12 @@ namespace storm { } logfile << "\n"; - logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; + /*logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; for (int i =0 ; i< markovianStates.size() ; i++){ logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; - } - - for (int i =0; i> const &solver) { if (unifVectors[kind][k][node]!=-1){return;} - std::ofstream logfile("U+logfile.txt", std::ios::app); - logfile << "calculating vector " << kind << " for k = " << k << " node "<< node << " \t"; + //std::ofstream logfile("U+logfile.txt", std::ios::app); + //logfile << "calculating vector " << kind << " for k = " << k << " node "<< node << " \t"; auto probabilisticStates = ~markovianStates; auto numberOfProbStates = probabilisticStates.getNumberOfSetBits(); @@ -266,7 +259,7 @@ namespace storm { // First Case, k==N, independent from kind of state if (k==N){ - logfile << "k == N! res = 0\n"; + //logfile << "k == N! res = 0\n"; unifVectors[kind][k][node]=0; return; } @@ -285,14 +278,14 @@ namespace storm { // WU unifVectors[kind][k][node]=1; } - logfile << "goal state node " << node << " res = " << res << "\n"; + //logfile << "goal state node " << node << " res = " << res << "\n"; return; } //markovian non-goal State if (markovianStates[node]){ - logfile << "markovian state: "; + //logfile << "markovian state: "; res = 0; auto line = fullTransitionMatrix.getRow(rowGroupIndices[node]); for (auto &element : line){ @@ -303,13 +296,13 @@ namespace storm { res+=element.getValue()*unifVectors[kind][k+1][to]; } unifVectors[kind][k][node]=res; - logfile << " res = " << res << "\n"; + //logfile << " res = " << res << "\n"; return; } //probabilistic non-goal State if (probabilisticStates[node]){ - logfile << "probabilistic state: "; + //logfile << "probabilistic state: "; std::vector b(probSize, 0), x(numberOfProbStates,0); //calculate b uint64_t lineCounter=0; @@ -347,7 +340,7 @@ namespace storm { unifVectors[kind][k][trueI]=x[i]; } - logfile << " res = " << unifVectors[kind][k][node] << " but calculated more \n"; + //logfile << " res = " << unifVectors[kind][k][node] << " but calculated more \n"; } //end probabilistic states } @@ -610,7 +603,7 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - printTransitions(fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors); //TODO remove + printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors); //TODO remove // (6) double lambda diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 3d5b8d049..49970334b 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -112,7 +112,7 @@ namespace storm { */ template ::SupportsExponential, int>::type=0> - static void printTransitions(storm::storage::SparseMatrix const& fullTransitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, + static void printTransitions(const uint64_t N, ValueType const diff, storm::storage::SparseMatrix const& fullTransitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::vector> relReachability, storm::storage::BitVector const& cycleStates , storm::storage::BitVector const& cycleGoalStates ,std::vector>>& unifVectors); From 4b43a1c42c9cbe69f193deddb8da3fe59afaaef5 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 26 Nov 2017 18:15:22 +0100 Subject: [PATCH 017/647] catching case psiStates=probStates, logprints still included --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 67 ++++++++++--------- .../helper/SparseMarkovAutomatonCslHelper.h | 6 +- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8bd2ba44c..3d12a0cbe 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -141,11 +141,7 @@ namespace storm { std::vector const &exitRateVector, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, std::vector> relReachability, const storage::BitVector &cycleStates, const storage::BitVector &cycleGoalStates, - std::vector>> &unifVectors) { - - - - std::ofstream logfile("U+logfile.txt", std::ios::app); + std::vector>> &unifVectors, std::ofstream& logfile) { auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); @@ -169,12 +165,12 @@ namespace storm { } logfile << "\n"; - /*logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; + logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; for (int i =0 ; i< markovianStates.size() ; i++){ logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; - } */ + } - logfile << "Iteration for N = " << N << "maximal difference was " << " diff\n"; + logfile << "Iteration for N = " << N << "maximal difference was " << diff << "\n"; logfile << "vd: \n"; for (uint64_t i =0 ; i @@ -217,7 +211,7 @@ namespace storm { template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver){ + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -225,7 +219,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver); + calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } res+=poisson(lambda, i)*unifVectors[2][N-1-(i-k)][node]; @@ -244,11 +238,14 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver) { + std::unique_ptr> const &solver, std::ofstream& logfile) { - if (unifVectors[kind][k][node]!=-1){return;} - //std::ofstream logfile("U+logfile.txt", std::ios::app); - //logfile << "calculating vector " << kind << " for k = " << k << " node "<< node << " \t"; + + if (unifVectors[kind][k][node]!=-1){ + logfile << "already calculated for k = " << k << " node = " << node << "\n"; + return; + } + std::string print = std::string("calculating vector ") + std::to_string(kind) + " for k = " + std::to_string(k) + " node " + std::to_string(node) +" \t"; auto probabilisticStates = ~markovianStates; auto numberOfProbStates = probabilisticStates.getNumberOfSetBits(); @@ -259,7 +256,7 @@ namespace storm { // First Case, k==N, independent from kind of state if (k==N){ - //logfile << "k == N! res = 0\n"; + logfile << print << "k == N! res = 0\n"; unifVectors[kind][k][node]=0; return; } @@ -278,31 +275,29 @@ namespace storm { // WU unifVectors[kind][k][node]=1; } - //logfile << "goal state node " << node << " res = " << res << "\n"; + logfile << print << "goal state node " << node << " res = " << res << "\n"; return; } //markovian non-goal State if (markovianStates[node]){ - //logfile << "markovian state: "; res = 0; auto line = fullTransitionMatrix.getRow(rowGroupIndices[node]); for (auto &element : line){ uint64_t to = element.getColumn(); if (unifVectors[kind][k+1][to]==-1){ - calculateUnifPlusVector(k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); + calculateUnifPlusVector(k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); } res+=element.getValue()*unifVectors[kind][k+1][to]; } unifVectors[kind][k][node]=res; - //logfile << " res = " << res << "\n"; + logfile << print << "markovian state: " << " res = " << res << "\n"; return; } //probabilistic non-goal State if (probabilisticStates[node]){ - //logfile << "probabilistic state: "; std::vector b(probSize, 0), x(numberOfProbStates,0); //calculate b uint64_t lineCounter=0; @@ -322,7 +317,7 @@ namespace storm { if (unifVectors[kind][k][to] == -1) { calculateUnifPlusVector(k, to, kind, lambda, probSize, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, - psiStates, solver); + psiStates, solver, logfile); } res = res + relativeReachability[j][to] * unifVectors[kind][k][to]; } @@ -340,7 +335,7 @@ namespace storm { unifVectors[kind][k][trueI]=x[i]; } - //logfile << " res = " << unifVectors[kind][k][node] << " but calculated more \n"; + logfile << print << "probabilistic state: "<< " res = " << unifVectors[kind][k][node] << " but calculated more \n"; } //end probabilistic states } @@ -467,12 +462,16 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ + std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + + + std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = storm::utility::zero(); //bitvectors to identify different kind of states + storm::storage::BitVector markovianStates = markovStates; storm::storage::BitVector allStates(markovianStates.size(), true); storm::storage::BitVector probabilisticStates = ~markovianStates; @@ -482,6 +481,14 @@ namespace storm { std::vector>> unifVectors{}; + //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! + for (uint64_t i =0 ; i exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); @@ -595,22 +602,22 @@ namespace storm { // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); - calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); - calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver); + calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); + calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); + calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); } } - printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors); //TODO remove - + printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors, logfile); //TODO remove // (6) double lambda lambda=2*lambda; } while (maxNorm>epsilon*(1-kappa)); + logfile.close(); return unifVectors[0][0]; } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 49970334b..b2ad305a1 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -57,7 +57,7 @@ namespace storm { private: template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); + static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -100,7 +100,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile); @@ -114,7 +114,7 @@ namespace storm { template ::SupportsExponential, int>::type=0> static void printTransitions(const uint64_t N, ValueType const diff, storm::storage::SparseMatrix const& fullTransitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::vector> relReachability, - storm::storage::BitVector const& cycleStates , storm::storage::BitVector const& cycleGoalStates ,std::vector>>& unifVectors); + storm::storage::BitVector const& cycleStates , storm::storage::BitVector const& cycleGoalStates ,std::vector>>& unifVectors, std::ofstream& logfile); template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From b155abc0994b8321dce1bc381990ba3766d049cd Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 26 Nov 2017 18:55:17 +0100 Subject: [PATCH 018/647] fixed stupid, big bug. add exit for stock-case --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 3d12a0cbe..d88a50cec 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -469,6 +469,7 @@ namespace storm { std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = storm::utility::zero(); + ValueType oldDiff = -storm::utility::zero(); //bitvectors to identify different kind of states storm::storage::BitVector markovianStates = markovStates; @@ -556,6 +557,7 @@ namespace storm { } // while not close enough to precision: do { + maxNorm = storm::utility::zero(); // (2) update parameter N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); @@ -615,6 +617,14 @@ namespace storm { // (6) double lambda lambda=2*lambda; + // (7) escape if not coming closer to solution + if (oldDiff!=-1){ + if (oldDiff==maxNorm){ + std::cout << "Not coming closer to solution as " << maxNorm << "/n"; + break; + } + } + oldDiff = maxNorm; } while (maxNorm>epsilon*(1-kappa)); logfile.close(); From 7cdff078419ca3c93fd650335fc412787f25ee76 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 27 Nov 2017 13:06:42 +0100 Subject: [PATCH 019/647] back copz fox glznn ' --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 26 +- .../helper/SparseMarkovAutomatonCslHelper.h | 319 +++++++++++++++++- 2 files changed, 331 insertions(+), 14 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index d88a50cec..a9d8c0158 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -211,7 +211,7 @@ namespace storm { template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile){ + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -219,10 +219,10 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile); + calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } - res+=poisson(lambda, i)*unifVectors[2][N-1-(i-k)][node]; + res+=poisson[i]*unifVectors[2][N-1-(i-k)][node]; } unifVectors[1][k][node]=res; } @@ -238,7 +238,7 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver, std::ofstream& logfile) { + std::unique_ptr> const &solver, std::ofstream& logfile, std::vector poisson) { if (unifVectors[kind][k][node]!=-1){ @@ -267,7 +267,7 @@ namespace storm { // Vd res = storm::utility::zero(); for (uint64_t i = k ; i SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - - std::ofstream logfile("U+logfile.txt", std::ios::app); ValueType maxNorm = storm::utility::zero(); ValueType oldDiff = -storm::utility::zero(); @@ -589,6 +587,9 @@ namespace storm { exitRate[i] = exitNew; } + // calculate poisson distribution + std::vector poisson = foxGlynnProb(lambda*T, N, epsilon*kappa); + // (4) define vectors/matrices std::vector init(numberOfStates, -1); vd = std::vector> (N + 1, init); @@ -604,9 +605,9 @@ namespace storm { // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); - calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); - calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile); + calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); + calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); + calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); @@ -615,6 +616,7 @@ namespace storm { printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors, logfile); //TODO remove // (6) double lambda + lambda=2*lambda; // (7) escape if not coming closer to solution diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index b2ad305a1..5e8c16c33 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -57,7 +57,7 @@ namespace storm { private: template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile); + static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -80,6 +80,321 @@ namespace storm { template ::SupportsExponential, int>::type=0> static storm::storage::BitVector identifyProbCycles(storm::storage::SparseMatrix const& TransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + + //TODO: move this + + typedef struct FoxGlynn + { + int left; + int right; + double total_weight; + double *weights; + } FoxGlynn; + + static std::vector foxGlynnProb(double lambdaT, int N, double precision){ + + FoxGlynn* fg = NULL; + if(!fox_glynn(lambdaT, DBL_MIN, DBL_MAX, precision, &fg)) { + printf("ERROR: fox-glynn failed\n"); + return std::vector{}; + } + + long double sumOfPoissonProbs = 0.0; + std::vector poisson_p(N,0.0); + unsigned long iter_num; + + //for(int i=fg->left; i<=fg->right; i++) { + for (int i = 0; iweights[i-fg->left]/fg->total_weight; + sumOfPoissonProbs+=poisson_p[i]; + } + + /*for(int i=fg->left-1; i>=0; i--) { + poisson_p[i] = poisson_p[i+1]*((i+1)/(lambdaT)); + sumOfPoissonProbs+=poisson_p[i]; + }*/ + + iter_num = fg->right; + + freeFG(fg); + + return poisson_p; + } + + static bool finder(const int m, const double lambda, const double tau, const double omega, + const double epsilon, double * pw_m, FoxGlynn *pFG) + { + /*The pi constant*/ + static const double pi = 3.14159265358979323846264; + static const double lambda_25 = 25.0; + static const double lambda_400 = 40; + + const double sqrt_2_pi = sqrt( 2.0 * pi ); + const double sqrt_2 = sqrt(2.0); + const double sqrt_lambda = sqrt(lambda); + double lambda_max, k, k_rtp = HUGE_VAL, k_prime, c_m_inf, result, al, dkl, bl; + + /*Simple bad cases, when we quit*/ + if( lambda == 0.0 ) + { + printf("ERROR: Fox-Glynn: lambda = 0, terminating the algorithm\n"); + return false; + } + /* The requested error level must not be smaller than the minimum machine precision + (needed to guarantee the convergence of the error conditions) */ + if( epsilon < tau) + { + printf("ERROR: Fox-Glynn: epsilon < tau, invalid error level, terminating the algorithm\n"); + printf("epsilon %f, tau %f\n",epsilon,tau); + return false; + } + /* zero is used as left truncation point for lambda <= 25 */ + pFG->left = 0; + lambda_max = lambda; + + /* for lambda below 25 the exponential can be smaller than tau */ + /* if that is the case we expect underflows and warn the user */ + if( 0.0 < lambda && lambda <= lambda_25 ) + { + if( exp( -lambda ) <= tau ) + { + printf("ERROR: Fox-Glynn: 0 < lambda < 25, underflow. The results are UNRELIABLE.\n"); + } + } + + bl = (1.0 + 1.0/lambda) * exp(1.0 / (8.0 * lambda)); + + /****Compute pFG->right truncation point****/ + /*According to Fox-Glynn, if lambda < 400 we should take lambda = 400, + otherwise use the original value. This is for computing the right truncation point*/ + if(lambda < lambda_400) + lambda_max = lambda_400; + k = 4; + al = (1.0+1.0/lambda_max) * exp(1.0/16.0) * sqrt_2; + dkl = exp(-2.0/9.0 * (k * sqrt(2.0 * lambda_max) + 1.5 )); + dkl = 1.0 / (1.0 - dkl); + /* find right truncation point */ + + /* This loop is a modification to the original Fox-Glynn paper. + The search for the right truncation point is only terminated by + the error condition and not by the stop index from the FG paper. + This can yield more accurate results if neccesary.*/ + while((epsilon/2.0) < ((al * dkl * exp(-(k*k)/2.0))/(k*sqrt_2_pi))) + { + k++; + dkl = exp(-2.0/9.0 * (k * sqrt_2 * sqrt(lambda_max) + 1.5 )); + dkl = 1.0 / (1.0 - dkl); + } + k_rtp = k; + pFG->right = (int)ceil(m + k_rtp * sqrt_2 * sqrt(lambda_max) + 1.5 ); + + + /****Compute pFG->left truncation point****/ + /* compute the left truncation point for lambda > 25 */ + /* for lambda <= 25 we use zero as left truncation point */ + if(lambda > lambda_25) + { + /*Start looking for the left truncation point*/ + /* start search at k=4 (taken from original Fox-Glynn paper */ + k = 4; + /* increase the left truncation point as long as we fulfill the error condition */ + + /* This loop is a modification to the original Fox-Glynn paper. + The search for the left truncation point is only terminated by + the error condition and not by the stop index from the FG paper. + This can yield more accurate results if neccesary.*/ + while((epsilon/2.0) < ((bl * exp(-(k*k)/2.0))/(k * sqrt_2_pi))) + k++; + /*Finally the left truncation point is found*/ + pFG->left = (int)floor(m - k*sqrt(lambda)- 1.5 ); + /* for small lambda the above calculation can yield negative truncation points, crop them here */ + if(pFG->left < 0) + pFG->left = 0; + /* perform underflow check */ + k_prime = k + 3.0 / (2.0 * sqrt_lambda); + /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25 + c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/ + c_m_inf = 0.02935 / sqrt((double) m); + result = 0.0; + if( 0.0 < k_prime && k_prime <= sqrt_lambda / 2.0 ) + { + result = c_m_inf * exp( - pow(k_prime,2.0) / 2.0 - pow(k_prime, 3.0) / (3.0 * sqrt_lambda) ); + } + else + { + if( k_prime <= sqrt( m + 1.0 ) / m ) + { + double result_1 = c_m_inf * pow( + 1.0 - k_prime / sqrt((double) (m + 1)), + k_prime * sqrt((double) (m + 1))); + double result_2 = exp( - lambda ); + /*Take the maximum*/ + result = ( result_1 > result_2 ? result_1 : result_2); + } + else + { + /*NOTE: It will be an underflow error*/; + printf("ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n"); + } + } + if ( result * omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ) <= tau ) + { + printf("ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n"); + } + } + + + + /*We still have to perform an underflow check for the right truncation point when lambda >= 400*/ + if( lambda >= lambda_400 ) + { + k_prime = k_rtp * sqrt_2 + 3.0 / (2.0 * sqrt_lambda); + /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25 + c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/ + c_m_inf = 0.02935 / sqrt((double) m); + result = c_m_inf * exp( - pow( k_prime + 1.0 , 2.0 ) / 2.0 ); + if( result * omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ) <= tau) + { + printf("ERROR: Fox-Glynn: lambda >= 400, underflow. The results are UNRELIABLE.\n"); + } + } + /*Time to set the initial value for weights*/ + *pw_m = omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ); + + return true; + } + +/***************************************************************************** +Name : weighter +Role : The WEIGHTER function from the Fox-Glynn algorithm +@param : double lambda: (rate of uniformization)*(mission time) +@param : double tau: underflow +@param : double omega: overflow +@param : double epsilon: error bound +@param : FoxGlynn *: return by reference +@return : TRUE if everything is fine, otherwise FALSE. + This is the F parameter of Fox-Glynn finder function. +remark : +******************************************************************************/ + static bool weighter(const double lambda, const double tau, const double omega, const double epsilon, FoxGlynn *pFG) + { + static const double pi = 3.14159265358979323846264; + static const double lambda_25 = 25.0; + static const double lambda_400 = 40; + /*The magic m point*/ + const int m = (int)floor(lambda); + double w_m = 0; + int j, s, t; + + if( ! finder( m, lambda, tau, omega, epsilon, &w_m, pFG ) ) + return false; + + /*Allocate space for weights*/ + pFG->weights = (double *) calloc((size_t) (pFG->right - pFG->left + 1), + sizeof(double)); + /*Set an initial weight*/ + pFG->weights[ m - pFG->left ] = w_m; + + /*Fill the left side of the array*/ + for( j = m; j > pFG->left; j-- ) + pFG->weights[ ( j - pFG->left ) - 1 ] = ( j / lambda ) * pFG->weights[ j - pFG->left ]; + + /*Fill the right side of the array, have two cases lambda < 400 & lambda >= 400*/ + if( lambda < lambda_400 ) + { + /*Perform the underflow check, according to Fox-Glynn*/ + if( pFG->right > 600 ) + { + printf("ERROR: Fox-Glynn: pFG->right > 600, underflow is possible\n"); + return false; + } + /*Compute weights*/ + for( j = m; j < pFG->right; j++ ) + { + double q = lambda / ( j + 1 ); + if( pFG->weights[ j - pFG->left ] > tau / q ) + { + pFG->weights[ ( j - pFG->left ) + 1 ] = q * pFG->weights[ j - pFG->left ]; + }else{ + pFG->right = j; + break; /*It's time to compute W*/ + } + } + }else{ + /*Compute weights*/ + for( j = m; j < pFG->right; j++ ) + pFG->weights[ ( j - pFG->left ) + 1 ] = ( lambda / ( j + 1 ) ) * pFG->weights[ j - pFG->left ]; + } + + /*It is time to compute the normalization weight W*/ + pFG->total_weight = 0.0; + s = pFG->left; + t = pFG->right; + + while( s < t ) + { + if( pFG->weights[ s - pFG->left ] <= pFG->weights[ t - pFG->left ] ) + { + pFG->total_weight += pFG->weights[ s - pFG->left ]; + s++; + }else{ + pFG->total_weight += pFG->weights[ t - pFG->left ]; + t--; + } + } + pFG->total_weight += pFG->weights[ s - pFG->left ]; + + /* printf("Fox-Glynn: ltp = %d, rtp = %d, w = %10.15le \n", pFG->left, pFG->right, pFG->total_weight); */ + + return true; + } + +/***************************************************************************** +Name : fox_glynn +Role : get poisson probabilities. +@param : double lambda: (rate of uniformization)*(mission time) +@param : double tau: underflow +@param : double omega: overflow +@param : double epsilon: error bound +@param : FoxGlynn **: return a new FoxGlynn structure by reference +@return : TRUE if it worked fine, otherwise false +remark : +******************************************************************************/ + static bool fox_glynn(const double lambda, const double tau, const double omega, const double epsilon, FoxGlynn **ppFG) + { + /* printf("Fox-Glynn: lambda = %3.3le, epsilon = %1.8le\n",lambda, epsilon); */ + + *ppFG = (FoxGlynn *) calloc((size_t) 1, sizeof(FoxGlynn)); + (*ppFG)->weights = NULL; + + return weighter(lambda, tau, omega, epsilon, *ppFG); + } + + +/** +* Fries the memory allocated for the FoxGlynn structure +* @param fg the structure to free +*/ + static void freeFG(FoxGlynn * fg) + { + if( fg ){ + if( fg->weights ) + free(fg->weights); + free(fg); + } + } + + /*! + * Computes the poission-distribution + * + * + * @param parameter lambda to use + * @param point i + * TODO: replace with Fox-Lynn + * @return the probability + */ + + /*! * Computes the poission-distribution * @@ -100,7 +415,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson); From 2e69c59c7868648364cbd9b83ebce13b4c9c73b1 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Mon, 27 Nov 2017 13:36:43 +0100 Subject: [PATCH 020/647] references for poisson --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 4 ++-- .../modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index a9d8c0158..d83286338 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -211,7 +211,7 @@ namespace storm { template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson){ + void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -238,7 +238,7 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver, std::ofstream& logfile, std::vector poisson) { + std::unique_ptr> const &solver, std::ofstream& logfile, std::vector const& poisson) { if (unifVectors[kind][k][node]!=-1){ diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 5e8c16c33..ff536e71f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -57,7 +57,7 @@ namespace storm { private: template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson); + static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -415,7 +415,7 @@ remark : * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector poisson); + static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); From 7db58c6374662f61ffb829494cde5f0023dad097 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 28 Nov 2017 17:22:30 +0100 Subject: [PATCH 021/647] using existing fox glynn now --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 340 ++++++++++-------- .../helper/SparseMarkovAutomatonCslHelper.h | 3 + 2 files changed, 196 insertions(+), 147 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index d83286338..4264a9b28 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -369,6 +369,45 @@ namespace storm { return finish[node]; } + template::SupportsExponential, int>::type= 0> + void SparseMarkovAutomatonCslHelper::identify( + storm::storage::SparseMatrix const &fullTransitionMatrix, + storm::storage::BitVector const &markovianStates, storm::storage::BitVector const& psiStates) { + auto indices = fullTransitionMatrix.getRowGroupIndices(); + bool realProb = false; + bool NDM = false; + bool Alternating = true; + bool probStates = false; + bool markStates = false; + + for (uint64_t i=0; i::SupportsExponential, int>::type=0> storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates) { @@ -463,174 +502,181 @@ namespace storm { template ::SupportsExponential, int>::type> std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ - STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - - std::ofstream logfile("U+logfile.txt", std::ios::app); - ValueType maxNorm = storm::utility::zero(); - ValueType oldDiff = -storm::utility::zero(); - - //bitvectors to identify different kind of states - storm::storage::BitVector markovianStates = markovStates; - storm::storage::BitVector allStates(markovianStates.size(), true); - storm::storage::BitVector probabilisticStates = ~markovianStates; - - - //vectors to save calculation - std::vector> vd,vu,wu; - std::vector>> unifVectors{}; - - - //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! - for (uint64_t i =0 ; i exitRate{exitRateVector}; - typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); - // delete diagonals - deleteProbDiagonals(fullTransitionMatrix, markovianStates); - typename storm::storage::SparseMatrix probMatrix{}; - uint64_t probSize =0; - if (probabilisticStates.getNumberOfSetBits()!=0){ //work around in case there are no prob states - probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates , probabilisticStates, true); - probSize = probMatrix.getRowCount(); - } - auto& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + std::ofstream logfile("U+logfile.txt", std::ios::app); + ValueType maxNorm = storm::utility::zero(); + ValueType oldDiff = -storm::utility::zero(); + //bitvectors to identify different kind of states + storm::storage::BitVector markovianStates = markovStates; + storm::storage::BitVector allStates(markovianStates.size(), true); + storm::storage::BitVector probabilisticStates = ~markovianStates; - //(1) define horizon, epsilon, kappa , N, lambda, - uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); - double T = boundsPair.second; - ValueType kappa = storm::utility::one() /10; // would be better as option-parameter - ValueType epsilon = storm::settings::getModule().getPrecision(); - ValueType lambda = exitRateVector[0]; - for (ValueType act: exitRateVector) { - lambda = std::max(act, lambda); - } - uint64_t N; + //vectors to save calculation + std::vector> vd,vu,wu; + std::vector>> unifVectors{}; - //calculate relative ReachabilityVectors - std::vector in(numberOfStates, 0); - std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); + //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! + for (uint64_t i =0 ; i exitRate{exitRateVector}; + typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); + // delete diagonals + deleteProbDiagonals(fullTransitionMatrix, markovianStates); + typename storm::storage::SparseMatrix probMatrix{}; + uint64_t probSize =0; + if (probabilisticStates.getNumberOfSetBits()!=0){ //work around in case there are no prob states + probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates , probabilisticStates, true); + probSize = probMatrix.getRowCount(); + } + auto& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - //calculate relative reachability - for(uint64_t i=0 ; i() /10; // would be better as option-parameter + ValueType epsilon = storm::settings::getModule().getPrecision(); + ValueType lambda = exitRateVector[0]; + for (ValueType act: exitRateVector) { + lambda = std::max(act, lambda); } - auto from = rowGroupIndices[i]; - auto to = rowGroupIndices[i+1]; - for (auto j=from ; j& act = relReachability[j]; - for(auto element: fullTransitionMatrix.getRow(j)){ - if (markovianStates[element.getColumn()]){ - act[element.getColumn()]=element.getValue(); - } - } - } - } + uint64_t N; - //create equitation solver - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); - requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - std::unique_ptr> solver; - if (probSize!=0){ - solver = minMaxLinearEquationSolverFactory.create(probMatrix); - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - } - // while not close enough to precision: - do { - maxNorm = storm::utility::zero(); - // (2) update parameter - N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); - - // (3) uniform - just applied to markovian states - for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { - if (!markovianStates[i]) { - continue; - } - uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row - if (exitRate[i] == lambda) { - continue; //already unified - } - auto line = fullTransitionMatrix.getRow(from); - ValueType exitOld = exitRate[i]; - ValueType exitNew = lambda; - for (auto &v : line) { - if (v.getColumn() == i) { //diagonal element - ValueType newSelfLoop = exitNew - exitOld + v.getValue(); - ValueType newRate = newSelfLoop / exitNew; - v.setValue(newRate); - } else { //modify probability - ValueType propOld = v.getValue(); - ValueType propNew = propOld * exitOld / exitNew; - v.setValue(propNew); - } - } - exitRate[i] = exitNew; - } + //calculate relative ReachabilityVectors + std::vector in(numberOfStates, 0); + std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); - // calculate poisson distribution - std::vector poisson = foxGlynnProb(lambda*T, N, epsilon*kappa); - - // (4) define vectors/matrices - std::vector init(numberOfStates, -1); - vd = std::vector> (N + 1, init); - vu = std::vector> (N + 1, init); - wu = std::vector> (N + 1, init); - - unifVectors.clear(); - unifVectors.push_back(vd); - unifVectors.push_back(vd); - unifVectors.push_back(vd); - - //define 0=vd 1=vu 2=wu - // (5) calculate vectors and maxNorm - for (uint64_t i = 0; i < numberOfStates; i++) { - for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); - calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); - calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); - //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove - ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); - maxNorm = std::max(maxNorm, diff); - } - } - printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors, logfile); //TODO remove - // (6) double lambda - lambda=2*lambda; + //calculate relative reachability - // (7) escape if not coming closer to solution - if (oldDiff!=-1){ - if (oldDiff==maxNorm){ - std::cout << "Not coming closer to solution as " << maxNorm << "/n"; - break; - } - } - oldDiff = maxNorm; - } while (maxNorm>epsilon*(1-kappa)); + for(uint64_t i=0 ; i& act = relReachability[j]; + for(auto element: fullTransitionMatrix.getRow(j)){ + if (markovianStates[element.getColumn()]){ + act[element.getColumn()]=element.getValue(); + } + } + } + } + + //create equitation solver + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); + requirements.clearBounds(); + STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + + std::unique_ptr> solver; + if (probSize!=0){ + solver = minMaxLinearEquationSolverFactory.create(probMatrix); + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + } + // while not close enough to precision: + do { + maxNorm = storm::utility::zero(); + // (2) update parameter + N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); + + // (3) uniform - just applied to markovian states + for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + if (!markovianStates[i]) { + continue; + } + uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row + + if (exitRate[i] == lambda) { + continue; //already unified + } + + auto line = fullTransitionMatrix.getRow(from); + ValueType exitOld = exitRate[i]; + ValueType exitNew = lambda; + for (auto &v : line) { + if (v.getColumn() == i) { //diagonal element + ValueType newSelfLoop = exitNew - exitOld + v.getValue(); + ValueType newRate = newSelfLoop / exitNew; + v.setValue(newRate); + } else { //modify probability + ValueType propOld = v.getValue(); + ValueType propNew = propOld * exitOld / exitNew; + v.setValue(propNew); + } + } + exitRate[i] = exitNew; + } + + // calculate poisson distribution + std::tuple> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff(T*lambda, 1e+300, epsilon*kappa/ 8.0); + + // Scale the weights so they add up to one. + for (auto& element : std::get<3>(foxGlynnResult)) { + element /= std::get<2>(foxGlynnResult); + } + // (4) define vectors/matrices + std::vector init(numberOfStates, -1); + vd = std::vector> (N + 1, init); + vu = std::vector> (N + 1, init); + wu = std::vector> (N + 1, init); + + unifVectors.clear(); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + + //define 0=vd 1=vu 2=wu + // (5) calculate vectors and maxNorm + for (uint64_t i = 0; i < numberOfStates; i++) { + for (uint64_t k = N; k <= N; k--) { + calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); + calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); + calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); + //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove + ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); + maxNorm = std::max(maxNorm, diff); + } + } + printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors, logfile); //TODO remove + + // (6) double lambda + + lambda=2*lambda; + + // (7) escape if not coming closer to solution + if (oldDiff!=-1){ + if (oldDiff==maxNorm){ + std::cout << "Not coming closer to solution as " << maxNorm << "/n"; + break; + } + } + oldDiff = maxNorm; + } while (maxNorm>epsilon*(1-kappa)); + + logfile.close(); + return unifVectors[0][0]; - logfile.close(); - return unifVectors[0][0]; } template ::SupportsExponential, int>::type> diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index ff536e71f..ab036c8c3 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -56,6 +56,9 @@ namespace storm { static std::vector computeReachabilityTimes(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + template ::SupportsExponential, int>::type=0> + static void identify(storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,storm::storage::BitVector const& psiStates); + template ::SupportsExponential, int>::type=0> static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); From 535a6017e3c0336d96a66213886645ddc80351a8 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Wed, 29 Nov 2017 17:56:58 +0100 Subject: [PATCH 022/647] fixed use of FoxLynn after CutOff --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 336 ++++++++++-------- 1 file changed, 180 insertions(+), 156 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 4264a9b28..b4c7b0526 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -242,7 +242,7 @@ namespace storm { if (unifVectors[kind][k][node]!=-1){ - logfile << "already calculated for k = " << k << " node = " << node << "\n"; + //logfile << "already calculated for k = " << k << " node = " << node << "\n"; return; } std::string print = std::string("calculating vector ") + std::to_string(kind) + " for k = " + std::to_string(k) + " node " + std::to_string(node) +" \t"; @@ -267,8 +267,10 @@ namespace storm { // Vd res = storm::utility::zero(); for (uint64_t i = k ; i::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory){ - STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + template::SupportsExponential, int>::type> + std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, + std::pair const &boundsPair, + std::vector const &exitRateVector, + storm::storage::SparseMatrix const &transitionMatrix, + storm::storage::BitVector const &markovStates, + storm::storage::BitVector const &psiStates, + storm::solver::MinMaxLinearEquationSolverFactory const &minMaxLinearEquationSolverFactory) { + STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + + + std::ofstream logfile("U+logfile.txt", std::ios::app); + ValueType maxNorm = storm::utility::zero(); + ValueType oldDiff = -storm::utility::zero(); + + //bitvectors to identify different kind of states + storm::storage::BitVector markovianStates = markovStates; + storm::storage::BitVector allStates(markovianStates.size(), true); + storm::storage::BitVector probabilisticStates = ~markovianStates; + + + //vectors to save calculation + std::vector> vd, vu, wu; + std::vector>> unifVectors{}; + + + //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! + for (uint64_t i = 0; i < psiStates.size(); i++) { + if (psiStates[i]) { + markovianStates.set(i, true); + probabilisticStates.set(i, false); + } + } + + //transition matrix with diagonal entries. The values can be changed during uniformisation + std::vector exitRate{exitRateVector}; + typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix( + true, allStates, allStates, true); + // delete diagonals + deleteProbDiagonals(fullTransitionMatrix, markovianStates); + typename storm::storage::SparseMatrix probMatrix{}; + uint64_t probSize = 0; + if (probabilisticStates.getNumberOfSetBits() != 0) { //work around in case there are no prob states + probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates, probabilisticStates, + true); + probSize = probMatrix.getRowCount(); + } + + auto &rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + + //(1) define horizon, epsilon, kappa , N, lambda, + uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); + double T = boundsPair.second; + ValueType kappa = storm::utility::one() / 10; // would be better as option-parameter + ValueType epsilon = storm::settings::getModule().getPrecision(); + ValueType lambda = exitRateVector[0]; + for (ValueType act: exitRateVector) { + lambda = std::max(act, lambda); + } + uint64_t N; + - std::ofstream logfile("U+logfile.txt", std::ios::app); - ValueType maxNorm = storm::utility::zero(); - ValueType oldDiff = -storm::utility::zero(); - //bitvectors to identify different kind of states - storm::storage::BitVector markovianStates = markovStates; - storm::storage::BitVector allStates(markovianStates.size(), true); - storm::storage::BitVector probabilisticStates = ~markovianStates; + //calculate relative ReachabilityVectors + std::vector in(numberOfStates, 0); + std::vector> relReachability(fullTransitionMatrix.getRowCount(), in); - //vectors to save calculation - std::vector> vd,vu,wu; - std::vector>> unifVectors{}; + //calculate relative reachability - //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! - for (uint64_t i =0 ; i &act = relReachability[j]; + for (auto element: fullTransitionMatrix.getRow(j)) { + if (markovianStates[element.getColumn()]) { + act[element.getColumn()] = element.getValue(); } } - - //transition matrix with diagonal entries. The values can be changed during uniformisation - std::vector exitRate{exitRateVector}; - typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates , allStates , true); - // delete diagonals - deleteProbDiagonals(fullTransitionMatrix, markovianStates); - typename storm::storage::SparseMatrix probMatrix{}; - uint64_t probSize =0; - if (probabilisticStates.getNumberOfSetBits()!=0){ //work around in case there are no prob states - probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates , probabilisticStates, true); - probSize = probMatrix.getRowCount(); } + } - auto& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + //create equitation solver + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements( + true, dir); + requirements.clearBounds(); + STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, + "Cannot establish requirements for solver."); + + std::unique_ptr> solver; + if (probSize != 0) { + solver = minMaxLinearEquationSolverFactory.create(probMatrix); + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + } + // while not close enough to precision: + do { + maxNorm = storm::utility::zero(); + // (2) update parameter + N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); + + // (3) uniform - just applied to markovian states + for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + if (!markovianStates[i]) { + continue; + } + uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row + if (exitRate[i] == lambda) { + continue; //already unified + } - //(1) define horizon, epsilon, kappa , N, lambda, - uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); - double T = boundsPair.second; - ValueType kappa = storm::utility::one() /10; // would be better as option-parameter - ValueType epsilon = storm::settings::getModule().getPrecision(); - ValueType lambda = exitRateVector[0]; - for (ValueType act: exitRateVector) { - lambda = std::max(act, lambda); + auto line = fullTransitionMatrix.getRow(from); + ValueType exitOld = exitRate[i]; + ValueType exitNew = lambda; + for (auto &v : line) { + if (v.getColumn() == i) { //diagonal element + ValueType newSelfLoop = exitNew - exitOld + v.getValue(); + ValueType newRate = newSelfLoop / exitNew; + v.setValue(newRate); + } else { //modify probability + ValueType propOld = v.getValue(); + ValueType propNew = propOld * exitOld / exitNew; + v.setValue(propNew); + } + } + exitRate[i] = exitNew; } - uint64_t N; + // calculate poisson distribution + std::tuple> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff( + T * lambda, 1e+300, epsilon * epsilon * kappa); - //calculate relative ReachabilityVectors - std::vector in(numberOfStates, 0); - std::vector> relReachability(fullTransitionMatrix.getRowCount(),in); + // Scale the weights so they add up to one. + for (auto &element : std::get<3>(foxGlynnResult)) { + element /= std::get<2>(foxGlynnResult); + } + // (4) define vectors/matrices + std::vector init(numberOfStates, -1); + vd = std::vector>(N + 1, init); + vu = std::vector>(N + 1, init); + wu = std::vector>(N + 1, init); + + unifVectors.clear(); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + unifVectors.push_back(vd); + + //define 0=vd 1=vu 2=wu + // (5) calculate vectors and maxNorm + for (uint64_t i = 0; i < numberOfStates; i++) { + for (uint64_t k = N; k <= N; k--) { + calculateUnifPlusVector(k, i, 0, lambda, probSize, relReachability, dir, unifVectors, + fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + std::get<3>(foxGlynnResult)); + calculateUnifPlusVector(k, i, 2, lambda, probSize, relReachability, dir, unifVectors, + fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + std::get<3>(foxGlynnResult)); + calculateVu(relReachability, dir, k, i, 1, lambda, probSize, unifVectors, + fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + std::get<3>(foxGlynnResult)); + //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove + ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); + maxNorm = std::max(maxNorm, diff); + } + } + printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove - //calculate relative reachability + // (6) double lambda - for(uint64_t i=0 ; i& act = relReachability[j]; - for(auto element: fullTransitionMatrix.getRow(j)){ - if (markovianStates[element.getColumn()]){ - act[element.getColumn()]=element.getValue(); - } - } - } - } + lambda = 2 * lambda; - //create equitation solver - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir); - requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - - std::unique_ptr> solver; - if (probSize!=0){ - solver = minMaxLinearEquationSolverFactory.create(probMatrix); - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); - } - // while not close enough to precision: - do { - maxNorm = storm::utility::zero(); - // (2) update parameter - N = ceil(lambda*T*exp(2)-log(kappa*epsilon)); - - // (3) uniform - just applied to markovian states - for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { - if (!markovianStates[i]) { - continue; - } - uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row - - if (exitRate[i] == lambda) { - continue; //already unified - } - - auto line = fullTransitionMatrix.getRow(from); - ValueType exitOld = exitRate[i]; - ValueType exitNew = lambda; - for (auto &v : line) { - if (v.getColumn() == i) { //diagonal element - ValueType newSelfLoop = exitNew - exitOld + v.getValue(); - ValueType newRate = newSelfLoop / exitNew; - v.setValue(newRate); - } else { //modify probability - ValueType propOld = v.getValue(); - ValueType propNew = propOld * exitOld / exitNew; - v.setValue(propNew); - } - } - exitRate[i] = exitNew; - } - - // calculate poisson distribution - std::tuple> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff(T*lambda, 1e+300, epsilon*kappa/ 8.0); - - // Scale the weights so they add up to one. - for (auto& element : std::get<3>(foxGlynnResult)) { - element /= std::get<2>(foxGlynnResult); - } - // (4) define vectors/matrices - std::vector init(numberOfStates, -1); - vd = std::vector> (N + 1, init); - vu = std::vector> (N + 1, init); - wu = std::vector> (N + 1, init); - - unifVectors.clear(); - unifVectors.push_back(vd); - unifVectors.push_back(vd); - unifVectors.push_back(vd); - - //define 0=vd 1=vu 2=wu - // (5) calculate vectors and maxNorm - for (uint64_t i = 0; i < numberOfStates; i++) { - for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(k,i,0,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); - calculateUnifPlusVector(k,i,2,lambda,probSize,relReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); - calculateVu(relReachability,dir,k,i,1,lambda,probSize,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, std::get<3>(foxGlynnResult)); - //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove - ValueType diff = std::abs(unifVectors[0][k][i]-unifVectors[1][k][i]); - maxNorm = std::max(maxNorm, diff); - } - } - printTransitions(N, maxNorm, fullTransitionMatrix,exitRate,markovianStates,psiStates,relReachability,psiStates, psiStates,unifVectors, logfile); //TODO remove - - // (6) double lambda - - lambda=2*lambda; - - // (7) escape if not coming closer to solution - if (oldDiff!=-1){ - if (oldDiff==maxNorm){ - std::cout << "Not coming closer to solution as " << maxNorm << "/n"; - break; - } - } - oldDiff = maxNorm; - } while (maxNorm>epsilon*(1-kappa)); - - logfile.close(); - return unifVectors[0][0]; + // (7) escape if not coming closer to solution + if (oldDiff != -1) { + if (oldDiff == maxNorm) { + std::cout << "Not coming closer to solution as " << maxNorm << "/n"; + break; + } + } + oldDiff = maxNorm; + } while (maxNorm > epsilon * (1 - kappa)); + + logfile.close(); + return unifVectors[0][0]; } From d2b14cfac28f32768f1baf735c84f62a751c930b Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Wed, 29 Nov 2017 17:58:43 +0100 Subject: [PATCH 023/647] skript for easier running one singe instance --- pstorm.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 pstorm.py diff --git a/pstorm.py b/pstorm.py new file mode 100644 index 000000000..aaa5a6b25 --- /dev/null +++ b/pstorm.py @@ -0,0 +1,15 @@ +import sys +import os +import subprocess +prop = ' --prop \"Pmax=? [F<1 \\"goal\\"]\" --ma:technique unifplus' +storm= '/home/timo/ustorm/build/bin/storm' + + +if len(sys.argv)<2: + print("no input file found\n") + exit() + +for a in sys.argv[1:]: + file = " --prism " + a + cmd = storm + file + prop + os.system(cmd) From 2a1487dc390049fc438f7c1c11057d6e782e28a5 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Wed, 29 Nov 2017 20:05:25 +0100 Subject: [PATCH 024/647] back to copied version of foxglynn, leaving too small values --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 11 ++++++----- .../csl/helper/SparseMarkovAutomatonCslHelper.h | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index b4c7b0526..23a8accde 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -267,7 +267,7 @@ namespace storm { // Vd res = storm::utility::zero(); for (uint64_t i = k ; i1e-300){ ValueType between = poisson[i]; res+=between; } @@ -652,6 +652,8 @@ namespace storm { } + std::vector poisson = foxGlynnProb(lambda*T, N+1, epsilon*kappa); + // (4) define vectors/matrices std::vector init(numberOfStates, -1); vd = std::vector>(N + 1, init); @@ -669,13 +671,13 @@ namespace storm { for (uint64_t k = N; k <= N; k--) { calculateUnifPlusVector(k, i, 0, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - std::get<3>(foxGlynnResult)); + poisson); calculateUnifPlusVector(k, i, 2, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - std::get<3>(foxGlynnResult)); + poisson); calculateVu(relReachability, dir, k, i, 1, lambda, probSize, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - std::get<3>(foxGlynnResult)); + poisson); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); @@ -700,7 +702,6 @@ namespace storm { logfile.close(); return unifVectors[0][0]; - } template ::SupportsExponential, int>::type> diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index ab036c8c3..4ce22a17b 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -106,16 +106,17 @@ namespace storm { std::vector poisson_p(N,0.0); unsigned long iter_num; + std::cout << "fg left " << fg->left << " fh right " << fg->right <<"\n"; //for(int i=fg->left; i<=fg->right; i++) { for (int i = 0; iweights[i-fg->left]/fg->total_weight; sumOfPoissonProbs+=poisson_p[i]; } - /*for(int i=fg->left-1; i>=0; i--) { + for(int i=fg->left-1; i>=0; i--) { poisson_p[i] = poisson_p[i+1]*((i+1)/(lambdaT)); sumOfPoissonProbs+=poisson_p[i]; - }*/ + } iter_num = fg->right; From b42aa5f473dd33c9b75b4c30d40eb7e91aba5538 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 30 Nov 2017 17:30:24 +0100 Subject: [PATCH 025/647] initial implementation for quick and sound vi for DTMCs --- .../modules/NativeEquationSolverSettings.cpp | 4 +- .../solver/NativeLinearEquationSolver.cpp | 99 ++++++++++++++++++- src/storm/solver/NativeLinearEquationSolver.h | 1 + src/storm/solver/SolverSelectionOptions.cpp | 2 + src/storm/solver/SolverSelectionOptions.h | 2 +- src/storm/utility/constants.cpp | 6 +- src/storm/utility/constants.h | 2 + .../DtmcPrctlModelCheckerTest.cpp | 19 ++++ .../storm/solver/LinearEquationSolverTest.cpp | 16 +++ 9 files changed, 146 insertions(+), 5 deletions(-) diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 664818b97..628e0bd75 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -25,7 +25,7 @@ namespace storm { const std::string NativeEquationSolverSettings::powerMethodMultiplicationStyleOptionName = "powmult"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch" }; + std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch", "qpower" }; this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); @@ -63,6 +63,8 @@ namespace storm { return storm::solver::NativeLinearEquationSolverMethod::Power; } else if (linearEquationSystemTechniqueAsString == "ratsearch") { return storm::solver::NativeLinearEquationSolverMethod::RationalSearch; + } else if (linearEquationSystemTechniqueAsString == "qpower") { + return storm::solver::NativeLinearEquationSolverMethod::QuickPower; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown solution technique '" << linearEquationSystemTechniqueAsString << "' selected."); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index c9974a700..d2dc18e68 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -555,6 +555,99 @@ namespace storm { return converged; } + + + template + bool NativeLinearEquationSolver::solveEquationsQuickSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (QuickPower)"); + // Prepare the solution vectors. + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::zero()); + } else { + this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::zero()); + } + if (!this->cachedRowVector2) { + this->cachedRowVector2 = std::make_unique>(getMatrixRowCount(), storm::utility::one()); + } else { + this->cachedRowVector2->assign(getMatrixRowCount(), storm::utility::one()); + } + + std::vector* stepBoundedValues = this->cachedRowVector.get(); + std::vector* stepBoundedStayProbabilities = this->cachedRowVector2.get(); + + std::vector* tmp = &x; + + bool converged = false; + bool terminate = false; + uint64_t iterations = 0; + bool doConvergenceCheck = true; + bool useDiffs = this->hasRelevantValues(); + ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); + ValueType lowerValueBound, upperValueBound; + bool relative = env.solver().native().getRelativeTerminationCriterion(); + if (!relative) { + precision *= storm::utility::convertNumber(2.0); + } + uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); + this->startMeasureProgress(); + auto firstProb1EntryIt = stepBoundedStayProbabilities->begin(); + while (!converged && !terminate && iterations < maxIter) { + this->multiplier.multAdd(*this->A, *stepBoundedValues, &b, *tmp); + std::swap(tmp, stepBoundedValues); + this->multiplier.multAdd(*this->A, *stepBoundedStayProbabilities, nullptr, *tmp); + std::swap(tmp, stepBoundedStayProbabilities); + for (; firstProb1EntryIt != stepBoundedStayProbabilities->end(); ++firstProb1EntryIt) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(*firstProb1EntryIt)) { + break; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(*firstProb1EntryIt))) { + break; + } + } + } + if (firstProb1EntryIt == stepBoundedStayProbabilities->end()) { + auto valIt = stepBoundedValues->begin(); + auto valIte = stepBoundedValues->end(); + auto probIt = stepBoundedStayProbabilities->begin(); + STORM_LOG_ASSERT(!storm::utility::isOne(*probIt), "Did not expect staying-probability 1 at this point."); + lowerValueBound = *valIt / (storm::utility::one() - *probIt); + upperValueBound = lowerValueBound; + ValueType largestStayProb = *probIt; + for (; valIt != valIte; ++valIt, ++probIt) { + ValueType currentBound = *valIt / (storm::utility::one() - *probIt); + lowerValueBound = std::min(lowerValueBound, currentBound); + upperValueBound = std::max(upperValueBound, currentBound); + largestStayProb = std::max(largestStayProb, *probIt); + } + STORM_LOG_ASSERT(!relative, "Relative termination criterion not implemented currently."); + converged = largestStayProb * (upperValueBound - lowerValueBound) < precision; + } + + // Potentially show progress. + this->showProgressIterative(iterations); + + // Set up next iteration. + ++iterations; + + } + + // Finally set up the solution vector + ValueType meanBound = (upperValueBound - lowerValueBound) / storm::utility::convertNumber(2.0); + storm::utility::vector::applyPointwise(*stepBoundedValues, *stepBoundedStayProbabilities, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + + if (!this->isCachingEnabled()) { + clearCache(); + } + + this->logIterations(converged, terminate, iterations); + + return converged; + + } + template bool NativeLinearEquationSolver::solveEquationsRationalSearch(Environment const& env, std::vector& x, std::vector const& b) const { return solveEquationsRationalSearchHelper(env, x, b); @@ -828,7 +921,7 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } - } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::Power && method != NativeLinearEquationSolverMethod::RationalSearch) { + } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::Power && method != NativeLinearEquationSolverMethod::RationalSearch && method != NativeLinearEquationSolverMethod::QuickPower) { if (env.solver().native().isMethodSetFromDefault()) { method = NativeLinearEquationSolverMethod::Power; STORM_LOG_INFO("Selecting '" + toString(method) + "' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); @@ -857,6 +950,8 @@ namespace storm { } else { return this->solveEquationsPower(env, x, b); } + case NativeLinearEquationSolverMethod::QuickPower: + return this->solveEquationsQuickSoundPower(env, x, b); case NativeLinearEquationSolverMethod::RationalSearch: return this->solveEquationsRationalSearch(env, x, b); } @@ -921,7 +1016,7 @@ namespace storm { template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::RationalSearch) { + if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::QuickPower) { return LinearEquationSolverProblemFormat::FixedPointSystem; } else { return LinearEquationSolverProblemFormat::EquationSystem; diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 136c8f68f..34ff42bf7 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -71,6 +71,7 @@ namespace storm { virtual bool solveEquationsWalkerChae(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; + virtual bool solveEquationsQuickSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsRationalSearch(storm::Environment const& env, std::vector& x, std::vector const& b) const; template diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 504f3e2a7..0393e6912 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -78,6 +78,8 @@ namespace storm { return "Power"; case NativeLinearEquationSolverMethod::RationalSearch: return "RationalSearch"; + case NativeLinearEquationSolverMethod::QuickPower: + return "QuickPower"; } return "invalid"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index ed4605ecb..e5c7a55eb 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -14,7 +14,7 @@ namespace storm { ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination) ExtendEnumsWithSelectionField(SmtSolverType, Z3, Mathsat) - ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, RationalSearch) + ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, RationalSearch, QuickPower) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverMethod, Bicgstab, Qmr, Gmres) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverPreconditioner, Ilu, Diagonal, None) ExtendEnumsWithSelectionField(EigenLinearEquationSolverMethod, SparseLU, Bicgstab, DGmres, Gmres) diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index cd6556fed..2a968422f 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -48,7 +48,11 @@ namespace storm { bool isAlmostZero(double const& a) { return a < 1e-12 && a > -1e-12; } - + + bool isAlmostOne(double const& a) { + return a < (1.0 + 1e-12) && a > (1.0 - 1e-12); + } + template bool isConstant(ValueType const&) { return true; diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 5eb1d1fc5..360128f00 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -44,6 +44,8 @@ namespace storm { bool isZero(ValueType const& a); bool isAlmostZero(double const& a); + + bool isAlmostOne(double const& a); template bool isConstant(ValueType const& a); diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index d1dc5a369..a19b04c9c 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -222,6 +222,24 @@ namespace { } }; + class SparseNativeQuickSoundPowerEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::Dtmc ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setForceSoundness(true); + env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::QuickPower); + env.solver().native().setRelativeTerminationCriterion(false); + env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); + return env; + } + }; + class SparseNativeRationalSearchEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models @@ -447,6 +465,7 @@ namespace { SparseNativeSorEnvironment, SparseNativePowerEnvironment, SparseNativeSoundPowerEnvironment, + SparseNativeQuickSoundPowerEnvironment, SparseNativeRationalSearchEnvironment, HybridSylvanGmmxxGmresEnvironment, HybridCuddNativeJacobiEnvironment, diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index 696654658..b4d7501eb 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -38,6 +38,21 @@ namespace { } }; + class NativeDoubleQuickSoundPowerEnvironment { + public: + typedef double ValueType; + static const bool isExact = false; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setForceSoundness(true); + env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::QuickPower); + env.solver().native().setRelativeTerminationCriterion(false); + env.solver().native().setPrecision(storm::utility::convertNumber("1e-6")); + return env; + } + }; + class NativeDoubleJacobiEnvironment { public: typedef double ValueType; @@ -265,6 +280,7 @@ namespace { typedef ::testing::Types< NativeDoublePowerEnvironment, NativeDoubleSoundPowerEnvironment, + NativeDoubleQuickSoundPowerEnvironment, NativeDoubleJacobiEnvironment, NativeDoubleGaussSeidelEnvironment, NativeDoubleSorEnvironment, From 3c65a4a10a74f9fd0096c9dc55f1261de789c2fe Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 1 Dec 2017 10:18:56 +0100 Subject: [PATCH 026/647] added a missing assertion --- src/storm/solver/NativeLinearEquationSolver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index d2dc18e68..3545cb8d3 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -617,6 +617,7 @@ namespace storm { upperValueBound = lowerValueBound; ValueType largestStayProb = *probIt; for (; valIt != valIte; ++valIt, ++probIt) { + STORM_LOG_ASSERT(!storm::utility::isOne(*probIt), "Did not expect staying-probability 1 at this point."); ValueType currentBound = *valIt / (storm::utility::one() - *probIt); lowerValueBound = std::min(lowerValueBound, currentBound); upperValueBound = std::max(upperValueBound, currentBound); From e0b5fa51c4c9fe27df1d4535b70ab96595da7e7c Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Fri, 1 Dec 2017 13:26:26 +0100 Subject: [PATCH 027/647] new FoxGlynn not included yet --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index fc329c1e7..6bb648e5f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -456,7 +456,6 @@ namespace storm { return goalStates; } - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { template ::SupportsExponential, int>::type=0> storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCycles(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ @@ -666,7 +665,7 @@ namespace storm { // calculate poisson distribution - std::tuple> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff( + /*std::tuple> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff( T * lambda, 1e+300, epsilon * epsilon * kappa); @@ -674,7 +673,7 @@ namespace storm { for (auto &element : std::get<3>(foxGlynnResult)) { element /= std::get<2>(foxGlynnResult); } - +*/ std::vector poisson = foxGlynnProb(lambda*T, N+1, epsilon*kappa); From 382bc61d6b072d2f6f4845d95bf632c776a4a5a3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Dec 2017 14:23:56 +0100 Subject: [PATCH 028/647] some fixes related to introduction of environments --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 47 +++++++++---------- .../helper/SparseMarkovAutomatonCslHelper.h | 8 ++-- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 6bb648e5f..d72eeee13 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -158,7 +158,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } - template::SupportsExponential, int>::type= 0> + template::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::printTransitions(const uint64_t N, ValueType const diff, storm::storage::SparseMatrix const &fullTransitionMatrix, std::vector const &exitRateVector, storm::storage::BitVector const &markovianStates, @@ -234,7 +234,7 @@ namespace storm { template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ + void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -242,7 +242,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); + calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } res+=poisson[i]*unifVectors[2][N-1-(i-k)][node]; @@ -253,8 +253,8 @@ namespace storm { - template::SupportsExponential, int>::type= 0> - void SparseMarkovAutomatonCslHelper::calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, + template::SupportsExponential, int>::type> + void SparseMarkovAutomatonCslHelper::calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const &relativeReachability, OptimizationDirection dir, std::vector>> &unifVectors, @@ -312,7 +312,7 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (unifVectors[kind][k+1][to]==-1){ - calculateUnifPlusVector(k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); + calculateUnifPlusVector(env, k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); } res+=element.getValue()*unifVectors[kind][k+1][to]; } @@ -340,7 +340,7 @@ namespace storm { continue; } if (unifVectors[kind][k][to] == -1) { - calculateUnifPlusVector(k, to, kind, lambda, probSize, relativeReachability, dir, + calculateUnifPlusVector(env, k, to, kind, lambda, probSize, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, poisson); } @@ -351,7 +351,7 @@ namespace storm { } } - solver->solveEquations(dir, x, b); + solver->solveEquations(env, dir, x, b); @@ -366,7 +366,7 @@ namespace storm { } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> uint64_t SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { auto const& rowGroupIndice = transitionMatrix.getRowGroupIndices(); @@ -394,7 +394,7 @@ namespace storm { return finish[node]; } - template::SupportsExponential, int>::type= 0> + template::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::identify( storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const& psiStates) { @@ -433,7 +433,7 @@ namespace storm { std:: cout << "prob States :" << probStates <<" markovian States: " << markStates << " realProb: "<< realProb << " NDM: " << NDM << " Alternating: " << Alternating << "\n"; } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates) { storm::storage::BitVector goalStates(cycleStates.size(), false); @@ -457,7 +457,7 @@ namespace storm { } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCycles(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ storm::storage::BitVector const& probabilisticStates = ~markovianStates; @@ -491,7 +491,7 @@ namespace storm { } - template ::SupportsExponential, int>::type=0> + template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); @@ -526,7 +526,7 @@ namespace storm { } template::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::unifPlus(OptimizationDirection dir, + std::vector SparseMarkovAutomatonCslHelper::unifPlus(Environment const& env, OptimizationDirection dir, std::pair const &boundsPair, std::vector const &exitRateVector, storm::storage::SparseMatrix const &transitionMatrix, @@ -615,15 +615,14 @@ namespace storm { } //create equitation solver - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements( - true, dir); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); std::unique_ptr> solver; if (probSize != 0) { - solver = minMaxLinearEquationSolverFactory.create(probMatrix); + solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); solver->setHasUniqueSolution(); solver->setBounds(storm::utility::zero(), storm::utility::one()); solver->setRequirementsChecked(); @@ -692,13 +691,13 @@ namespace storm { // (5) calculate vectors and maxNorm for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(k, i, 0, lambda, probSize, relReachability, dir, unifVectors, + calculateUnifPlusVector(env, k, i, 0, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, poisson); - calculateUnifPlusVector(k, i, 2, lambda, probSize, relReachability, dir, unifVectors, + calculateUnifPlusVector(env, k, i, 2, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, poisson); - calculateVu(relReachability, dir, k, i, 1, lambda, probSize, unifVectors, + calculateVu(env, relReachability, dir, k, i, 1, lambda, probSize, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, poisson); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove @@ -728,7 +727,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilitiesImca(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilitiesImca(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { STORM_LOG_TRACE("Using IMCA's technique to compute bounded until probabilities."); uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -793,15 +792,15 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { auto const& markovAutomatonSettings = storm::settings::getModule(); if (markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::Imca) { - return computeBoundedUntilProbabilitiesImca(dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair, minMaxLinearEquationSolverFactory); + return computeBoundedUntilProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair, minMaxLinearEquationSolverFactory); } else { STORM_LOG_ASSERT(markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus, "Unknown solution technique."); - return unifPlus(dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); + return unifPlus(env, dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates, minMaxLinearEquationSolverFactory); } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 73e37cf81..bff568487 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -30,13 +30,13 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static std::vector unifPlus(OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector unifPlus(Environment const& env, OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilitiesImca(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilitiesImca(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template ::SupportsExponential, int>::type = 0> static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); @@ -62,7 +62,7 @@ namespace storm { static void identify(storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,storm::storage::BitVector const& psiStates); template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); + static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -421,7 +421,7 @@ remark : * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); + static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); From 4484cea360448baa6b83a7e107a9ae786cf54a2a Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 1 Dec 2017 15:21:39 +0100 Subject: [PATCH 029/647] fixing quick power iteration --- src/storm/solver/NativeLinearEquationSolver.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 3545cb8d3..70d80e55d 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -580,8 +580,6 @@ namespace storm { bool converged = false; bool terminate = false; uint64_t iterations = 0; - bool doConvergenceCheck = true; - bool useDiffs = this->hasRelevantValues(); ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); ValueType lowerValueBound, upperValueBound; bool relative = env.solver().native().getRelativeTerminationCriterion(); @@ -590,25 +588,25 @@ namespace storm { } uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); this->startMeasureProgress(); - auto firstProb1EntryIt = stepBoundedStayProbabilities->begin(); + uint64_t firstProb1Entry = 0; while (!converged && !terminate && iterations < maxIter) { this->multiplier.multAdd(*this->A, *stepBoundedValues, &b, *tmp); std::swap(tmp, stepBoundedValues); this->multiplier.multAdd(*this->A, *stepBoundedStayProbabilities, nullptr, *tmp); std::swap(tmp, stepBoundedStayProbabilities); - for (; firstProb1EntryIt != stepBoundedStayProbabilities->end(); ++firstProb1EntryIt) { + for (; firstProb1Entry != stepBoundedStayProbabilities->size(); ++firstProb1Entry) { static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); if (NumberTraits::IsExact) { - if (storm::utility::isOne(*firstProb1EntryIt)) { + if (storm::utility::isOne(stepBoundedStayProbabilities->at(firstProb1Entry))) { break; } } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(*firstProb1EntryIt))) { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbabilities->at(firstProb1Entry)))) { break; } } } - if (firstProb1EntryIt == stepBoundedStayProbabilities->end()) { + if (firstProb1Entry == stepBoundedStayProbabilities->size()) { auto valIt = stepBoundedValues->begin(); auto valIte = stepBoundedValues->end(); auto probIt = stepBoundedStayProbabilities->begin(); @@ -625,6 +623,7 @@ namespace storm { } STORM_LOG_ASSERT(!relative, "Relative termination criterion not implemented currently."); converged = largestStayProb * (upperValueBound - lowerValueBound) < precision; + STORM_LOG_INFO_COND(!converged, "Lower value bound: " << lowerValueBound << " Upper value bound: " << upperValueBound << " Largest stay prob.: " << largestStayProb); } // Potentially show progress. From a77b0267f8e9d3defbb6d78e04c536e21a90ccb4 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Fri, 1 Dec 2017 20:10:48 +0100 Subject: [PATCH 030/647] using the new version of FoxGlynn --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 35 +- .../helper/SparseMarkovAutomatonCslHelper.h | 324 ------------------ 2 files changed, 10 insertions(+), 349 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index d72eeee13..529ce05b0 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -219,20 +219,6 @@ namespace storm { } } - template - ValueType SparseMarkovAutomatonCslHelper::poisson(ValueType lambda, uint64_t i) { - ValueType res = pow(lambda, i); - ValueType fac = 1; - for (uint64_t j = i ; j>0 ; j--){ - fac = fac *j; - } - res = res / fac ; - res = res * exp(-lambda); - return res; - } - - - template ::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. @@ -245,7 +231,9 @@ namespace storm { calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } - res+=poisson[i]*unifVectors[2][N-1-(i-k)][node]; + if (i(); for (uint64_t i = k ; i1e-300){ + if (i> foxGlynnResult = storm::utility::numerical::getFoxGlynnCutoff( - T * lambda, 1e+300, epsilon * epsilon * kappa); + storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda*T, epsilon*kappa); // Scale the weights so they add up to one. - for (auto &element : std::get<3>(foxGlynnResult)) { - element /= std::get<2>(foxGlynnResult); + for (auto& element : foxGlynnResult.weights) { + element /= foxGlynnResult.totalWeight; } -*/ - std::vector poisson = foxGlynnProb(lambda*T, N+1, epsilon*kappa); // (4) define vectors/matrices std::vector init(numberOfStates, -1); @@ -693,13 +678,13 @@ namespace storm { for (uint64_t k = N; k <= N; k--) { calculateUnifPlusVector(env, k, i, 0, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - poisson); + foxGlynnResult.weights); calculateUnifPlusVector(env, k, i, 2, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - poisson); + foxGlynnResult.weights); calculateVu(env, relReachability, dir, k, i, 1, lambda, probSize, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - poisson); + foxGlynnResult.weights); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index bff568487..2b62d244f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -88,330 +88,6 @@ namespace storm { //TODO: move this - typedef struct FoxGlynn - { - int left; - int right; - double total_weight; - double *weights; - } FoxGlynn; - - static std::vector foxGlynnProb(double lambdaT, int N, double precision){ - - FoxGlynn* fg = NULL; - if(!fox_glynn(lambdaT, DBL_MIN, DBL_MAX, precision, &fg)) { - printf("ERROR: fox-glynn failed\n"); - return std::vector{}; - } - - long double sumOfPoissonProbs = 0.0; - std::vector poisson_p(N,0.0); - unsigned long iter_num; - - std::cout << "fg left " << fg->left << " fh right " << fg->right <<"\n"; - //for(int i=fg->left; i<=fg->right; i++) { - for (int i = 0; iweights[i-fg->left]/fg->total_weight; - sumOfPoissonProbs+=poisson_p[i]; - } - - for(int i=fg->left-1; i>=0; i--) { - poisson_p[i] = poisson_p[i+1]*((i+1)/(lambdaT)); - sumOfPoissonProbs+=poisson_p[i]; - } - - iter_num = fg->right; - - freeFG(fg); - - return poisson_p; - } - - static bool finder(const int m, const double lambda, const double tau, const double omega, - const double epsilon, double * pw_m, FoxGlynn *pFG) - { - /*The pi constant*/ - static const double pi = 3.14159265358979323846264; - static const double lambda_25 = 25.0; - static const double lambda_400 = 40; - - const double sqrt_2_pi = sqrt( 2.0 * pi ); - const double sqrt_2 = sqrt(2.0); - const double sqrt_lambda = sqrt(lambda); - double lambda_max, k, k_rtp = HUGE_VAL, k_prime, c_m_inf, result, al, dkl, bl; - - /*Simple bad cases, when we quit*/ - if( lambda == 0.0 ) - { - printf("ERROR: Fox-Glynn: lambda = 0, terminating the algorithm\n"); - return false; - } - /* The requested error level must not be smaller than the minimum machine precision - (needed to guarantee the convergence of the error conditions) */ - if( epsilon < tau) - { - printf("ERROR: Fox-Glynn: epsilon < tau, invalid error level, terminating the algorithm\n"); - printf("epsilon %f, tau %f\n",epsilon,tau); - return false; - } - /* zero is used as left truncation point for lambda <= 25 */ - pFG->left = 0; - lambda_max = lambda; - - /* for lambda below 25 the exponential can be smaller than tau */ - /* if that is the case we expect underflows and warn the user */ - if( 0.0 < lambda && lambda <= lambda_25 ) - { - if( exp( -lambda ) <= tau ) - { - printf("ERROR: Fox-Glynn: 0 < lambda < 25, underflow. The results are UNRELIABLE.\n"); - } - } - - bl = (1.0 + 1.0/lambda) * exp(1.0 / (8.0 * lambda)); - - /****Compute pFG->right truncation point****/ - /*According to Fox-Glynn, if lambda < 400 we should take lambda = 400, - otherwise use the original value. This is for computing the right truncation point*/ - if(lambda < lambda_400) - lambda_max = lambda_400; - k = 4; - al = (1.0+1.0/lambda_max) * exp(1.0/16.0) * sqrt_2; - dkl = exp(-2.0/9.0 * (k * sqrt(2.0 * lambda_max) + 1.5 )); - dkl = 1.0 / (1.0 - dkl); - /* find right truncation point */ - - /* This loop is a modification to the original Fox-Glynn paper. - The search for the right truncation point is only terminated by - the error condition and not by the stop index from the FG paper. - This can yield more accurate results if neccesary.*/ - while((epsilon/2.0) < ((al * dkl * exp(-(k*k)/2.0))/(k*sqrt_2_pi))) - { - k++; - dkl = exp(-2.0/9.0 * (k * sqrt_2 * sqrt(lambda_max) + 1.5 )); - dkl = 1.0 / (1.0 - dkl); - } - k_rtp = k; - pFG->right = (int)ceil(m + k_rtp * sqrt_2 * sqrt(lambda_max) + 1.5 ); - - - /****Compute pFG->left truncation point****/ - /* compute the left truncation point for lambda > 25 */ - /* for lambda <= 25 we use zero as left truncation point */ - if(lambda > lambda_25) - { - /*Start looking for the left truncation point*/ - /* start search at k=4 (taken from original Fox-Glynn paper */ - k = 4; - /* increase the left truncation point as long as we fulfill the error condition */ - - /* This loop is a modification to the original Fox-Glynn paper. - The search for the left truncation point is only terminated by - the error condition and not by the stop index from the FG paper. - This can yield more accurate results if neccesary.*/ - while((epsilon/2.0) < ((bl * exp(-(k*k)/2.0))/(k * sqrt_2_pi))) - k++; - /*Finally the left truncation point is found*/ - pFG->left = (int)floor(m - k*sqrt(lambda)- 1.5 ); - /* for small lambda the above calculation can yield negative truncation points, crop them here */ - if(pFG->left < 0) - pFG->left = 0; - /* perform underflow check */ - k_prime = k + 3.0 / (2.0 * sqrt_lambda); - /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25 - c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/ - c_m_inf = 0.02935 / sqrt((double) m); - result = 0.0; - if( 0.0 < k_prime && k_prime <= sqrt_lambda / 2.0 ) - { - result = c_m_inf * exp( - pow(k_prime,2.0) / 2.0 - pow(k_prime, 3.0) / (3.0 * sqrt_lambda) ); - } - else - { - if( k_prime <= sqrt( m + 1.0 ) / m ) - { - double result_1 = c_m_inf * pow( - 1.0 - k_prime / sqrt((double) (m + 1)), - k_prime * sqrt((double) (m + 1))); - double result_2 = exp( - lambda ); - /*Take the maximum*/ - result = ( result_1 > result_2 ? result_1 : result_2); - } - else - { - /*NOTE: It will be an underflow error*/; - printf("ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n"); - } - } - if ( result * omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ) <= tau ) - { - printf("ERROR: Fox-Glynn: lambda >= 25, underflow. The results are UNRELIABLE.\n"); - } - } - - - - /*We still have to perform an underflow check for the right truncation point when lambda >= 400*/ - if( lambda >= lambda_400 ) - { - k_prime = k_rtp * sqrt_2 + 3.0 / (2.0 * sqrt_lambda); - /*We take the c_m_inf = 0.02935 / sqrt( m ), as for lambda >= 25 - c_m = 1 / ( sqrt( 2.0 * pi * m ) ) * exp( m - lambda - 1 / ( 12.0 * m ) ) => c_m_inf*/ - c_m_inf = 0.02935 / sqrt((double) m); - result = c_m_inf * exp( - pow( k_prime + 1.0 , 2.0 ) / 2.0 ); - if( result * omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ) <= tau) - { - printf("ERROR: Fox-Glynn: lambda >= 400, underflow. The results are UNRELIABLE.\n"); - } - } - /*Time to set the initial value for weights*/ - *pw_m = omega / ( 1.0e+10 * ( pFG->right - pFG->left ) ); - - return true; - } - -/***************************************************************************** -Name : weighter -Role : The WEIGHTER function from the Fox-Glynn algorithm -@param : double lambda: (rate of uniformization)*(mission time) -@param : double tau: underflow -@param : double omega: overflow -@param : double epsilon: error bound -@param : FoxGlynn *: return by reference -@return : TRUE if everything is fine, otherwise FALSE. - This is the F parameter of Fox-Glynn finder function. -remark : -******************************************************************************/ - static bool weighter(const double lambda, const double tau, const double omega, const double epsilon, FoxGlynn *pFG) - { - static const double pi = 3.14159265358979323846264; - static const double lambda_25 = 25.0; - static const double lambda_400 = 40; - /*The magic m point*/ - const int m = (int)floor(lambda); - double w_m = 0; - int j, s, t; - - if( ! finder( m, lambda, tau, omega, epsilon, &w_m, pFG ) ) - return false; - - /*Allocate space for weights*/ - pFG->weights = (double *) calloc((size_t) (pFG->right - pFG->left + 1), - sizeof(double)); - /*Set an initial weight*/ - pFG->weights[ m - pFG->left ] = w_m; - - /*Fill the left side of the array*/ - for( j = m; j > pFG->left; j-- ) - pFG->weights[ ( j - pFG->left ) - 1 ] = ( j / lambda ) * pFG->weights[ j - pFG->left ]; - - /*Fill the right side of the array, have two cases lambda < 400 & lambda >= 400*/ - if( lambda < lambda_400 ) - { - /*Perform the underflow check, according to Fox-Glynn*/ - if( pFG->right > 600 ) - { - printf("ERROR: Fox-Glynn: pFG->right > 600, underflow is possible\n"); - return false; - } - /*Compute weights*/ - for( j = m; j < pFG->right; j++ ) - { - double q = lambda / ( j + 1 ); - if( pFG->weights[ j - pFG->left ] > tau / q ) - { - pFG->weights[ ( j - pFG->left ) + 1 ] = q * pFG->weights[ j - pFG->left ]; - }else{ - pFG->right = j; - break; /*It's time to compute W*/ - } - } - }else{ - /*Compute weights*/ - for( j = m; j < pFG->right; j++ ) - pFG->weights[ ( j - pFG->left ) + 1 ] = ( lambda / ( j + 1 ) ) * pFG->weights[ j - pFG->left ]; - } - - /*It is time to compute the normalization weight W*/ - pFG->total_weight = 0.0; - s = pFG->left; - t = pFG->right; - - while( s < t ) - { - if( pFG->weights[ s - pFG->left ] <= pFG->weights[ t - pFG->left ] ) - { - pFG->total_weight += pFG->weights[ s - pFG->left ]; - s++; - }else{ - pFG->total_weight += pFG->weights[ t - pFG->left ]; - t--; - } - } - pFG->total_weight += pFG->weights[ s - pFG->left ]; - - /* printf("Fox-Glynn: ltp = %d, rtp = %d, w = %10.15le \n", pFG->left, pFG->right, pFG->total_weight); */ - - return true; - } - -/***************************************************************************** -Name : fox_glynn -Role : get poisson probabilities. -@param : double lambda: (rate of uniformization)*(mission time) -@param : double tau: underflow -@param : double omega: overflow -@param : double epsilon: error bound -@param : FoxGlynn **: return a new FoxGlynn structure by reference -@return : TRUE if it worked fine, otherwise false -remark : -******************************************************************************/ - static bool fox_glynn(const double lambda, const double tau, const double omega, const double epsilon, FoxGlynn **ppFG) - { - /* printf("Fox-Glynn: lambda = %3.3le, epsilon = %1.8le\n",lambda, epsilon); */ - - *ppFG = (FoxGlynn *) calloc((size_t) 1, sizeof(FoxGlynn)); - (*ppFG)->weights = NULL; - - return weighter(lambda, tau, omega, epsilon, *ppFG); - } - - -/** -* Fries the memory allocated for the FoxGlynn structure -* @param fg the structure to free -*/ - static void freeFG(FoxGlynn * fg) - { - if( fg ){ - if( fg->weights ) - free(fg->weights); - free(fg); - } - } - - /*! - * Computes the poission-distribution - * - * - * @param parameter lambda to use - * @param point i - * TODO: replace with Fox-Lynn - * @return the probability - */ - - - /*! - * Computes the poission-distribution - * - * - * @param parameter lambda to use - * @param point i - * TODO: replace with Fox-glynn - * @return the probability - */ - template - static ValueType poisson(ValueType lambda, uint64_t i); template ::SupportsExponential, int>::type=0> static uint64_t trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); From d79b4caf9e0aa42a4125bdcc21ae4a4dd42ca747 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 2 Dec 2017 16:19:58 +0100 Subject: [PATCH 031/647] new implementation of relReachability to avoid waste of memory --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 529ce05b0..60c00b5fb 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -223,7 +223,7 @@ namespace storm { void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; - auto rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ @@ -258,9 +258,8 @@ namespace storm { } std::string print = std::string("calculating vector ") + std::to_string(kind) + " for k = " + std::to_string(k) + " node " + std::to_string(node) +" \t"; - auto probabilisticStates = ~markovianStates; - auto numberOfProbStates = probabilisticStates.getNumberOfSetBits(); auto numberOfStates=fullTransitionMatrix.getRowGroupCount(); + auto numberOfProbStates = numberOfStates - markovianStates.getNumberOfSetBits(); uint64_t N = unifVectors[kind].size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); ValueType res; @@ -310,7 +309,7 @@ namespace storm { } //probabilistic non-goal State - if (probabilisticStates[node]){ + if (!markovianStates[node]){ std::vector b(probSize, 0), x(numberOfProbStates,0); //calculate b uint64_t lineCounter=0; @@ -321,10 +320,11 @@ namespace storm { auto rowStart = rowGroupIndices[i]; auto rowEnd = rowGroupIndices[i + 1]; for (auto j = rowStart; j < rowEnd; j++) { + uint64_t stateCount = 0; res = 0; for (auto &element:fullTransitionMatrix.getRow(j)) { auto to = element.getColumn(); - if (probabilisticStates[to]) { + if (!markovianStates[to]) { continue; } if (unifVectors[kind][k][to] == -1) { @@ -332,7 +332,8 @@ namespace storm { unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, poisson); } - res = res + relativeReachability[j][to] * unifVectors[kind][k][to]; + res = res + relativeReachability[j][stateCount] * unifVectors[kind][k][to]; + stateCount++; } b[lineCounter] = res; lineCounter++; @@ -344,7 +345,7 @@ namespace storm { for (uint64_t i =0 ; i(); ValueType oldDiff = -storm::utility::zero(); @@ -535,7 +537,6 @@ namespace storm { //vectors to save calculation - std::vector> vd, vu, wu; std::vector>> unifVectors{}; @@ -552,7 +553,7 @@ namespace storm { typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix( true, allStates, allStates, true); // delete diagonals - deleteProbDiagonals(fullTransitionMatrix, markovianStates); + deleteProbDiagonals(fullTransitionMatrix, markovianStates); typename storm::storage::SparseMatrix probMatrix{}; uint64_t probSize = 0; if (probabilisticStates.getNumberOfSetBits() != 0) { //work around in case there are no prob states @@ -579,24 +580,23 @@ namespace storm { //calculate relative ReachabilityVectors - std::vector in(numberOfStates, 0); - std::vector> relReachability(fullTransitionMatrix.getRowCount(), in); + std::vector in{}; + std::vector> relReachability(transitionMatrix.getRowCount(), in); //calculate relative reachability for (uint64_t i = 0; i < numberOfStates; i++) { - if (markovianStates[i]) { + if (markovStates[i]) { continue; } auto from = rowGroupIndices[i]; auto to = rowGroupIndices[i + 1]; for (auto j = from; j < to; j++) { - std::vector &act = relReachability[j]; - for (auto element: fullTransitionMatrix.getRow(j)) { - if (markovianStates[element.getColumn()]) { - act[element.getColumn()] = element.getValue(); + for (auto& element: fullTransitionMatrix.getRow(j)) { + if (markovStates[element.getColumn()]) { + relReachability[j].push_back(element.getValue()); } } } @@ -618,6 +618,7 @@ namespace storm { } // while not close enough to precision: do { + logfile << "starting iteration\n"; maxNorm = storm::utility::zero(); // (2) update parameter N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); @@ -663,14 +664,12 @@ namespace storm { // (4) define vectors/matrices std::vector init(numberOfStates, -1); - vd = std::vector>(N + 1, init); - vu = std::vector>(N + 1, init); - wu = std::vector>(N + 1, init); + std::vector> v = std::vector>(N + 1, init); unifVectors.clear(); - unifVectors.push_back(vd); - unifVectors.push_back(vd); - unifVectors.push_back(vd); + unifVectors.push_back(v); + unifVectors.push_back(v); + unifVectors.push_back(v); //define 0=vd 1=vu 2=wu // (5) calculate vectors and maxNorm From f5a9a51511340b7448c0905948d1f39187779835 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 2 Dec 2017 16:41:12 +0100 Subject: [PATCH 032/647] removed logfileprints --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 60c00b5fb..c68302797 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -266,7 +266,7 @@ namespace storm { // First Case, k==N, independent from kind of state if (k==N){ - logfile << print << "k == N! res = 0\n"; + //logfile << print << "k == N! res = 0\n"; unifVectors[kind][k][node]=0; return; } @@ -287,7 +287,7 @@ namespace storm { // WU unifVectors[kind][k][node]=1; } - logfile << print << "goal state node " << node << " res = " << res << "\n"; + //logfile << print << "goal state node " << node << " res = " << res << "\n"; return; } @@ -304,7 +304,7 @@ namespace storm { res+=element.getValue()*unifVectors[kind][k+1][to]; } unifVectors[kind][k][node]=res; - logfile << print << "markovian state: " << " res = " << res << "\n"; + //logfile << print << "markovian state: " << " res = " << res << "\n"; return; } @@ -349,7 +349,7 @@ namespace storm { unifVectors[kind][k][trueI]=x[i]; } - logfile << print << "probabilistic state: "<< " res = " << unifVectors[kind][k][node] << " but calculated more \n"; + //logfile << print << "probabilistic state: "<< " res = " << unifVectors[kind][k][node] << " but calculated more \n"; } //end probabilistic states } @@ -526,7 +526,7 @@ namespace storm { std::ofstream logfile("U+logfile.txt", std::ios::app); - logfile << "Using U+\n"; + //logfile << "Using U+\n"; ValueType maxNorm = storm::utility::zero(); ValueType oldDiff = -storm::utility::zero(); @@ -618,7 +618,7 @@ namespace storm { } // while not close enough to precision: do { - logfile << "starting iteration\n"; + //logfile << "starting iteration\n"; maxNorm = storm::utility::zero(); // (2) update parameter N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); @@ -689,7 +689,7 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda From 7148319243374facb369b89b22f14c5c120fa59e Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 2 Dec 2017 16:44:25 +0100 Subject: [PATCH 033/647] typo --- .../modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index c68302797..e1a6b3375 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -690,7 +690,7 @@ namespace storm { } } //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove + // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda From b55e92bef7c696fbb591364ce8358e4da309a807 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 4 Dec 2017 11:46:27 +0100 Subject: [PATCH 034/647] Make quick power iteration respect the relevant Values --- .../solver/NativeLinearEquationSolver.cpp | 94 +++++++++++++------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 70d80e55d..a1e2c10ea 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -555,8 +555,6 @@ namespace storm { return converged; } - - template bool NativeLinearEquationSolver::solveEquationsQuickSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (QuickPower)"); @@ -577,53 +575,94 @@ namespace storm { std::vector* tmp = &x; - bool converged = false; - bool terminate = false; - uint64_t iterations = 0; ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); - ValueType lowerValueBound, upperValueBound; bool relative = env.solver().native().getRelativeTerminationCriterion(); if (!relative) { precision *= storm::utility::convertNumber(2.0); } uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); + + //std::cout << *this->A << std::endl; + //std::cout << storm::utility::vector::toString(b) << std::endl; + + //std::cout << "solving eq sys.. " << std::endl; + + uint64_t iterations = 0; + bool converged = false; + bool terminate = false; + ValueType minValueBound, maxValueBound; + uint64_t minIndex(0), maxIndex(0); + uint64_t firstStayProb1Index = 0; + uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; this->startMeasureProgress(); - uint64_t firstProb1Entry = 0; while (!converged && !terminate && iterations < maxIter) { + + // Apply step this->multiplier.multAdd(*this->A, *stepBoundedValues, &b, *tmp); std::swap(tmp, stepBoundedValues); this->multiplier.multAdd(*this->A, *stepBoundedStayProbabilities, nullptr, *tmp); std::swap(tmp, stepBoundedStayProbabilities); - for (; firstProb1Entry != stepBoundedStayProbabilities->size(); ++firstProb1Entry) { + + //std::cout << "Iteration " << iterations << std::endl; + //std::cout << "x: " << storm::utility::vector::toString(*stepBoundedValues) << std::endl; + //std::cout << "y: " << storm::utility::vector::toString(*stepBoundedStayProbabilities) << std::endl; + + // Check for convergence + // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state + for (; firstStayProb1Index != stepBoundedStayProbabilities->size(); ++firstStayProb1Index) { static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbabilities->at(firstProb1Entry))) { + if (storm::utility::isOne(stepBoundedStayProbabilities->at(firstStayProb1Index))) { break; } } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbabilities->at(firstProb1Entry)))) { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbabilities->at(firstStayProb1Index)))) { break; + // std::cout << "In Phase 1" << std::endl; } } } - if (firstProb1Entry == stepBoundedStayProbabilities->size()) { - auto valIt = stepBoundedValues->begin(); - auto valIte = stepBoundedValues->end(); - auto probIt = stepBoundedStayProbabilities->begin(); - STORM_LOG_ASSERT(!storm::utility::isOne(*probIt), "Did not expect staying-probability 1 at this point."); - lowerValueBound = *valIt / (storm::utility::one() - *probIt); - upperValueBound = lowerValueBound; - ValueType largestStayProb = *probIt; - for (; valIt != valIte; ++valIt, ++probIt) { - STORM_LOG_ASSERT(!storm::utility::isOne(*probIt), "Did not expect staying-probability 1 at this point."); - ValueType currentBound = *valIt / (storm::utility::one() - *probIt); - lowerValueBound = std::min(lowerValueBound, currentBound); - upperValueBound = std::max(upperValueBound, currentBound); - largestStayProb = std::max(largestStayProb, *probIt); + if (firstStayProb1Index == stepBoundedStayProbabilities->size()) { + STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbabilities->begin(), stepBoundedStayProbabilities->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value + // std::cout << "In Phase 2" << std::endl; + // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. + minValueBound = stepBoundedValues->at(minIndex) / (storm::utility::one() - stepBoundedStayProbabilities->at(minIndex)); + maxValueBound = stepBoundedValues->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbabilities->at(maxIndex)); + ValueType const& stayProb = stepBoundedStayProbabilities->at(firstIndexViolatingConvergence); + if (stayProb * (maxValueBound - minValueBound) < precision) { + // Compute the actual bounds now + auto valIt = stepBoundedValues->begin(); + auto valIte = stepBoundedValues->end(); + auto probIt = stepBoundedStayProbabilities->begin(); + for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { + ValueType currentBound = *valIt / (storm::utility::one() - *probIt); + if (currentBound < minValueBound) { + minIndex = index; + minValueBound = std::move(currentBound); + } else if (currentBound > maxValueBound) { + maxIndex = index; + maxValueBound = std::move(currentBound); + } + } + if (stayProb * (maxValueBound - minValueBound) < precision) { + // The current index satisfies the desired bound. We now move to the next index that violates it + do { + ++firstIndexViolatingConvergence; + if (this->hasRelevantValues()) { + firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); + } + if (firstIndexViolatingConvergence == stepBoundedStayProbabilities->size()) { + converged = true; + break; + } else if (stepBoundedStayProbabilities->at(firstIndexViolatingConvergence) * (maxValueBound - minValueBound) >= precision) { + // not converged yet + break; + } + } while (true); + } } STORM_LOG_ASSERT(!relative, "Relative termination criterion not implemented currently."); - converged = largestStayProb * (upperValueBound - lowerValueBound) < precision; - STORM_LOG_INFO_COND(!converged, "Lower value bound: " << lowerValueBound << " Upper value bound: " << upperValueBound << " Largest stay prob.: " << largestStayProb); } // Potentially show progress. @@ -635,7 +674,7 @@ namespace storm { } // Finally set up the solution vector - ValueType meanBound = (upperValueBound - lowerValueBound) / storm::utility::convertNumber(2.0); + ValueType meanBound = (maxValueBound + minValueBound) / storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*stepBoundedValues, *stepBoundedStayProbabilities, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); if (!this->isCachingEnabled()) { @@ -643,6 +682,7 @@ namespace storm { } this->logIterations(converged, terminate, iterations); + STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); return converged; From bb0c0bbeb6f534698bf9b289771e09c52636f9e2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 8 Dec 2017 14:46:31 +0100 Subject: [PATCH 035/647] implemented gauss-seidl multiplications and relative termination for quick power iteration --- .../solver/NativeLinearEquationSolver.cpp | 108 +++++++++++------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index a1e2c10ea..c19b6a8c6 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -558,23 +558,37 @@ namespace storm { template bool NativeLinearEquationSolver::solveEquationsQuickSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (QuickPower)"); + bool useGaussSeidelMultiplication = env.solver().native().getPowerMethodMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; + // Prepare the solution vectors. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::zero()); - } else { - this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::zero()); - } - if (!this->cachedRowVector2) { - this->cachedRowVector2 = std::make_unique>(getMatrixRowCount(), storm::utility::one()); + assert(x.size() == getMatrixRowCount()); + std::vector *stepBoundedX, *stepBoundedStayProbs, *tmp; + if (useGaussSeidelMultiplication) { + stepBoundedX = &x; + stepBoundedX->assign(getMatrixRowCount(), storm::utility::zero()); + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::one()); + } else { + this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::one()); + } + stepBoundedStayProbs = this->cachedRowVector.get(); + tmp = nullptr; } else { - this->cachedRowVector2->assign(getMatrixRowCount(), storm::utility::one()); + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::zero()); + } else { + this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::zero()); + } + stepBoundedX = this->cachedRowVector.get(); + if (!this->cachedRowVector2) { + this->cachedRowVector2 = std::make_unique>(getMatrixRowCount(), storm::utility::one()); + } else { + this->cachedRowVector2->assign(getMatrixRowCount(), storm::utility::one()); + } + stepBoundedStayProbs = this->cachedRowVector2.get(); + tmp = &x; } - std::vector* stepBoundedValues = this->cachedRowVector.get(); - std::vector* stepBoundedStayProbabilities = this->cachedRowVector2.get(); - - std::vector* tmp = &x; - ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); bool relative = env.solver().native().getRelativeTerminationCriterion(); if (!relative) { @@ -598,43 +612,53 @@ namespace storm { while (!converged && !terminate && iterations < maxIter) { // Apply step - this->multiplier.multAdd(*this->A, *stepBoundedValues, &b, *tmp); - std::swap(tmp, stepBoundedValues); - this->multiplier.multAdd(*this->A, *stepBoundedStayProbabilities, nullptr, *tmp); - std::swap(tmp, stepBoundedStayProbabilities); + if (useGaussSeidelMultiplication) { + this->multiplier.multAddGaussSeidelBackward(*this->A, *stepBoundedX, &b); + this->multiplier.multAddGaussSeidelBackward(*this->A, *stepBoundedStayProbs, nullptr); + } else { + this->multiplier.multAdd(*this->A, *stepBoundedX, &b, *tmp); + std::swap(tmp, stepBoundedX); + this->multiplier.multAdd(*this->A, *stepBoundedStayProbs, nullptr, *tmp); + std::swap(tmp, stepBoundedStayProbs); + } //std::cout << "Iteration " << iterations << std::endl; - //std::cout << "x: " << storm::utility::vector::toString(*stepBoundedValues) << std::endl; - //std::cout << "y: " << storm::utility::vector::toString(*stepBoundedStayProbabilities) << std::endl; + //std::cout << "x: " << storm::utility::vector::toString(*stepBoundedX) << std::endl; + //std::cout << "y: " << storm::utility::vector::toString(*stepBoundedStayProbs) << std::endl; // Check for convergence // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state - for (; firstStayProb1Index != stepBoundedStayProbabilities->size(); ++firstStayProb1Index) { + for (; firstStayProb1Index != stepBoundedStayProbs->size(); ++firstStayProb1Index) { static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbabilities->at(firstStayProb1Index))) { + if (storm::utility::isOne(stepBoundedStayProbs->at(firstStayProb1Index))) { break; } } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbabilities->at(firstStayProb1Index)))) { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstStayProb1Index)))) { break; // std::cout << "In Phase 1" << std::endl; } } } - if (firstStayProb1Index == stepBoundedStayProbabilities->size()) { - STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbabilities->begin(), stepBoundedStayProbabilities->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + if (firstStayProb1Index == stepBoundedStayProbs->size()) { + STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value // std::cout << "In Phase 2" << std::endl; // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - minValueBound = stepBoundedValues->at(minIndex) / (storm::utility::one() - stepBoundedStayProbabilities->at(minIndex)); - maxValueBound = stepBoundedValues->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbabilities->at(maxIndex)); - ValueType const& stayProb = stepBoundedStayProbabilities->at(firstIndexViolatingConvergence); - if (stayProb * (maxValueBound - minValueBound) < precision) { + minValueBound = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); + maxValueBound = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); + ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence); + // The error made in this iteration + ValueType absoluteError = stayProb * (maxValueBound - minValueBound); + // The maximal allowed error (possibly respecting relative precision) + // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. + ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + if (absoluteError <= maxAllowedError) { // Compute the actual bounds now - auto valIt = stepBoundedValues->begin(); - auto valIte = stepBoundedValues->end(); - auto probIt = stepBoundedStayProbabilities->begin(); + auto valIt = stepBoundedX->begin(); + auto valIte = stepBoundedX->end(); + auto probIt = stepBoundedStayProbs->begin(); for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { ValueType currentBound = *valIt / (storm::utility::one() - *probIt); if (currentBound < minValueBound) { @@ -645,24 +669,28 @@ namespace storm { maxValueBound = std::move(currentBound); } } - if (stayProb * (maxValueBound - minValueBound) < precision) { + absoluteError = stayProb * (maxValueBound - minValueBound); + if (absoluteError <= maxAllowedError) { // The current index satisfies the desired bound. We now move to the next index that violates it - do { + while (true) { ++firstIndexViolatingConvergence; if (this->hasRelevantValues()) { firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); } - if (firstIndexViolatingConvergence == stepBoundedStayProbabilities->size()) { + if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { converged = true; break; - } else if (stepBoundedStayProbabilities->at(firstIndexViolatingConvergence) * (maxValueBound - minValueBound) >= precision) { - // not converged yet - break; + } else { + absoluteError = stepBoundedStayProbs->at(firstIndexViolatingConvergence) * (maxValueBound - minValueBound); + maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + if (absoluteError > maxAllowedError) { + // not converged yet + break; + } } - } while (true); + } } } - STORM_LOG_ASSERT(!relative, "Relative termination criterion not implemented currently."); } // Potentially show progress. @@ -675,7 +703,7 @@ namespace storm { // Finally set up the solution vector ValueType meanBound = (maxValueBound + minValueBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(*stepBoundedValues, *stepBoundedStayProbabilities, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); if (!this->isCachingEnabled()) { clearCache(); From 9bc82f58a334c46bb166a7c2c011b0b9d24ca885 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 8 Dec 2017 14:53:34 +0100 Subject: [PATCH 036/647] temporarily extending the set of target states for reward computations --- .../prctl/helper/SparseDtmcPrctlHelper.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 0d0ec5928..eb1212419 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -209,12 +209,22 @@ namespace storm { template std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { - return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); }, targetStates, qualitative, linearEquationSolverFactory, hint); + // Extend the set of target states such that states for which target is reached without collecting any reward are included + // TODO + storm::storage::BitVector extendedTargetStates = storm::utility::graph::performProb1(backwardTransitions, rewardModel.getStatesWithZeroReward(transitionMatrix), targetStates); + STORM_LOG_INFO("Extended the set of target states from " << targetStates.getNumberOfSetBits() << " states to " << extendedTargetStates.getNumberOfSetBits() << " states."); + std::cout << "TODO: make target state extension a setting." << std::endl; + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); }, extendedTargetStates, qualitative, linearEquationSolverFactory, hint); } template std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + // TODO + storm::storage::BitVector extendedTargetStates = storm::utility::graph::performProb1(backwardTransitions, storm::utility::vector::filterZero(totalStateRewardVector), targetStates); + STORM_LOG_INFO("Extended the set of target states from " << targetStates.getNumberOfSetBits() << " states to " << extendedTargetStates.getNumberOfSetBits() << " states."); + std::cout << "TODO: make target state extension a setting" << std::endl; + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const& maybeStates) { std::vector result(numberOfRows); From f89236100b9f676e497209c7c0ff9583df94cdbf Mon Sep 17 00:00:00 2001 From: TimQu Date: Sat, 9 Dec 2017 15:21:46 +0100 Subject: [PATCH 037/647] Added topological linear equation solver --- src/storm/environment/SubEnvironment.cpp | 2 + .../environment/solver/SolverEnvironment.cpp | 19 +- .../environment/solver/SolverEnvironment.h | 4 + ...logicalLinearEquationSolverEnvironment.cpp | 38 ++ ...pologicalLinearEquationSolverEnvironment.h | 24 ++ src/storm/settings/modules/CoreSettings.cpp | 4 +- src/storm/solver/LinearEquationSolver.cpp | 6 +- src/storm/solver/SolverSelectionOptions.cpp | 2 + src/storm/solver/SolverSelectionOptions.h | 2 +- .../TopologicalLinearEquationSolver.cpp | 344 ++++++++++++++++++ .../solver/TopologicalLinearEquationSolver.h | 84 +++++ 11 files changed, 522 insertions(+), 7 deletions(-) create mode 100644 src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp create mode 100644 src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h create mode 100644 src/storm/solver/TopologicalLinearEquationSolver.cpp create mode 100644 src/storm/solver/TopologicalLinearEquationSolver.h diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index 698300f03..6227548e5 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -5,6 +5,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" namespace storm { @@ -40,6 +41,7 @@ namespace storm { template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; + template class SubEnvironment; } diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index 8371b8158..6e0eb49c0 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -5,6 +5,7 @@ #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" @@ -66,6 +67,14 @@ namespace storm { return gameSolverEnvironment.get(); } + TopologicalLinearEquationSolverEnvironment& SolverEnvironment::topological() { + return topologicalSolverEnvironment.get(); + } + + TopologicalLinearEquationSolverEnvironment const& SolverEnvironment::topological() const { + return topologicalSolverEnvironment.get(); + } + bool SolverEnvironment::isForceSoundness() const { return forceSoundness; } @@ -106,22 +115,24 @@ namespace storm { STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination, + getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination || + getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological, "The current solver type is not respected in this method."); native().setPrecision(value); gmmxx().setPrecision(value); eigen().setPrecision(value); - // Elimination solver does not have a precision + // Elimination and Topological solver do not have a precision } void SolverEnvironment::setLinearEquationSolverRelativeTerminationCriterion(bool value) { STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination, + getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination || + getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological, "The current solver type is not respected in this method."); native().setRelativeTerminationCriterion(value); - // Elimination, gmm and eigen solver do not have an option for relative termination criterion + // Elimination, gmm, eigen, and topological solver do not have an option for relative termination criterion } diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index ec591beb2..7f3260291 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -16,6 +16,7 @@ namespace storm { class NativeSolverEnvironment; class MinMaxSolverEnvironment; class GameSolverEnvironment; + class TopologicalLinearEquationSolverEnvironment; class SolverEnvironment { public: @@ -33,6 +34,8 @@ namespace storm { MinMaxSolverEnvironment const& minMax() const; GameSolverEnvironment& game(); GameSolverEnvironment const& game() const; + TopologicalLinearEquationSolverEnvironment& topological(); + TopologicalLinearEquationSolverEnvironment const& topological() const; bool isForceSoundness() const; void setForceSoundness(bool value); @@ -50,6 +53,7 @@ namespace storm { SubEnvironment gmmxxSolverEnvironment; SubEnvironment nativeSolverEnvironment; SubEnvironment gameSolverEnvironment; + SubEnvironment topologicalSolverEnvironment; SubEnvironment minMaxSolverEnvironment; storm::solver::EquationSolverType linearEquationSolverType; diff --git a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp new file mode 100644 index 000000000..e49c0c15f --- /dev/null +++ b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp @@ -0,0 +1,38 @@ +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/GameSolverSettings.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + + TopologicalLinearEquationSolverEnvironment::TopologicalLinearEquationSolverEnvironment() { + auto const& topologicalSettings = storm::settings::getModule(); + std::cout << "TODO: get actual settings in topo environment." << std::endl; + underlyingSolverType = storm::solver::EquationSolverType::Native; + underlyingSolverTypeSetFromDefault = true; + } + + TopologicalLinearEquationSolverEnvironment::~TopologicalLinearEquationSolverEnvironment() { + // Intentionally left empty + } + + storm::solver::EquationSolverType const& TopologicalLinearEquationSolverEnvironment::getUnderlyingSolverType() const { + return underlyingSolverType; + } + + bool const& TopologicalLinearEquationSolverEnvironment::isUnderlyingSolverTypeSetFromDefault() const { + return underlyingSolverTypeSetFromDefault; + } + + void TopologicalLinearEquationSolverEnvironment::setUnderlyingSolverType(storm::solver::EquationSolverType value) { + STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); + underlyingSolverTypeSetFromDefault = false; + underlyingSolverType = value; + } + + + +} diff --git a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h new file mode 100644 index 000000000..b79ed66a9 --- /dev/null +++ b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h @@ -0,0 +1,24 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class TopologicalLinearEquationSolverEnvironment { + public: + + TopologicalLinearEquationSolverEnvironment(); + ~TopologicalLinearEquationSolverEnvironment(); + + storm::solver::EquationSolverType const& getUnderlyingSolverType() const; + bool const& isUnderlyingSolverTypeSetFromDefault() const; + void setUnderlyingSolverType(storm::solver::EquationSolverType value); + + private: + storm::solver::EquationSolverType underlyingSolverType; + bool underlyingSolverTypeSetFromDefault; + }; +} + diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index b01aee3f7..9bcd4d77c 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -43,7 +43,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, engineOptionName, false, "Sets which engine is used for model building and model checking.").setShortName(engineOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("sparse").build()).build()); - std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; + std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, eqSolverOptionName, false, "Sets which solver is preferred for solving systems of linear equations.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); @@ -86,6 +86,8 @@ namespace storm { return storm::solver::EquationSolverType::Eigen; } else if (equationSolverName == "elimination") { return storm::solver::EquationSolverType::Elimination; + } else if (equationSolverName == "topological") { + return storm::solver::EquationSolverType::Topological; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown equation solver '" << equationSolverName << "'."); } diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index caff69756..193f2cc09 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -7,6 +7,7 @@ #include "storm/solver/NativeLinearEquationSolver.h" #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/solver/EliminationLinearEquationSolver.h" +#include "storm/solver/TopologicalLinearEquationSolver.h" #include "storm/utility/vector.h" @@ -179,6 +180,7 @@ namespace storm { case EquationSolverType::Native: return std::make_unique>(); case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; @@ -198,6 +200,7 @@ namespace storm { switch (type) { case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; @@ -209,7 +212,7 @@ namespace storm { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if none was specified and we want sound computations - if (env.solver().isForceSoundness() && task != LinearEquationSolverTask::Multiply && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination) { + if (env.solver().isForceSoundness() && task != LinearEquationSolverTask::Multiply && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { if (env.solver().isLinearEquationSolverTypeSetFromDefaultValue()) { type = EquationSolverType::Native; STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver to guarantee sound results. If you want to override this, please explicitly specify a different solver."); @@ -223,6 +226,7 @@ namespace storm { case EquationSolverType::Native: return std::make_unique>(); case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 0393e6912..7b8e19c65 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -50,6 +50,8 @@ namespace storm { return "Eigen"; case EquationSolverType::Elimination: return "Elimination"; + case EquationSolverType::Topological: + return "Topological"; } return "invalid"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index e5c7a55eb..446e173bd 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -11,7 +11,7 @@ namespace storm { ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) ExtendEnumsWithSelectionField(LpSolverType, Gurobi, Glpk, Z3) - ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination) + ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination, Topological) ExtendEnumsWithSelectionField(SmtSolverType, Z3, Mathsat) ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, RationalSearch, QuickPower) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp new file mode 100644 index 000000000..c7ebee971 --- /dev/null +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -0,0 +1,344 @@ +#include "storm/solver/TopologicalLinearEquationSolver.h" + +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" + +#include "storm/utility/constants.h" +#include "storm/utility/vector.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace solver { + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver() : localA(nullptr), A(nullptr) { + // Intentionally left empty. + } + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(nullptr) { + this->setMatrix(A); + } + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(nullptr), A(nullptr) { + this->setMatrix(std::move(A)); + } + + template + void TopologicalLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& A) { + localA.reset(); + this->A = &A; + clearCache(); + } + + template + void TopologicalLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& A) { + localA = std::make_unique>(std::move(A)); + this->A = localA.get(); + clearCache(); + } + + template + storm::Environment TopologicalLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env) const { + storm::Environment subEnv(env); + subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingSolverType()); + return subEnv; + } + + template + bool TopologicalLinearEquationSolver::internalSolveEquations(Environment const& env, std::vector& x, std::vector const& b) const { + + if (!this->sortedSccDecomposition) { + STORM_LOG_TRACE("Creating SCC decomposition."); + createSortedSccDecomposition(); + } + + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env); + + // Handle the case where there is just one large SCC + if (this->sortedSccDecomposition->size() == 1) { + return solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b); + } + + storm::storage::BitVector sccAsBitVector(x.size(), false); + bool returnValue = true; + for (auto const& scc : *this->sortedSccDecomposition) { + if (scc.isTrivial()) { + returnValue = returnValue && solveTrivialScc(*scc.begin(), x, b); + } else { + sccAsBitVector.clear(); + for (auto const& state : scc) { + sccAsBitVector.set(state, true); + } + returnValue = returnValue && solveScc(sccSolverEnvironment, sccAsBitVector, x, b); + } + } + + if (!this->isCachingEnabled()) { + clearCache(); + } + + return returnValue; + } + + template + void TopologicalLinearEquationSolver::createSortedSccDecomposition() const { + // Obtain the scc decomposition + auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*this->A); + + // Get a mapping from matrix row to the corresponding scc + STORM_LOG_THROW(sccDecomposition.size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); + std::vector sccIndices(this->A->getRowCount(), std::numeric_limits::max()); + uint32_t sccIndex = 0; + for (auto const& scc : sccDecomposition) { + for (auto const& row : scc) { + sccIndices[row] = sccIndex; + } + ++sccIndex; + } + + // Prepare the resulting set of sorted sccs + this->sortedSccDecomposition = std::make_unique>(); + std::vector& sortedSCCs = *this->sortedSccDecomposition; + sortedSCCs.reserve(sccDecomposition.size()); + + // Find a topological sort via DFS. + storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); + std::vector sccStack; + uint32_t const token = std::numeric_limits::max(); + std::set successorSCCs; + + for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { + + sccStack.push_back(firstUnsortedScc); + while (!sccStack.empty()) { + auto const& currentSccIndex = sccStack.back(); + if (currentSccIndex != token) { + // Check whether the SCC is still unprocessed + if (unsortedSCCs.get(currentSccIndex)) { + // Explore the successors of the scc. + storm::storage::StronglyConnectedComponent const& currentScc = sccDecomposition.getBlock(currentSccIndex); + // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. + sccStack.push_back(token); + // Now add all successors that are not already sorted. + // Successors should only be added once, so we first prepare a set of them and add them afterwards. + successorSCCs.clear(); + for (auto const& row : currentScc) { + for (auto const& entry : this->A->getRow(row)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { + successorSCCs.insert(successorSCC); + } + } + } + sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); + + } + } else { + // all successors of the current scc have already been explored. + sccStack.pop_back(); // pop the token + sortedSCCs.push_back(std::move(sccDecomposition.getBlock(sccStack.back()))); + unsortedSCCs.set(sccStack.back(), false); + sccStack.pop_back(); // pop the current scc index + } + } + } + } + + template + bool TopologicalLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, std::vector& globalX, std::vector const& globalB) const { + ValueType& xi = globalX[sccState]; + xi = globalB[sccState]; + bool hasDiagonalEntry = false; + ValueType denominator; + for (auto const& entry : this->A->getRow(sccState)) { + if (entry.getColumn() == sccState) { + STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1."); + hasDiagonalEntry = true; + denominator = storm::utility::one() - entry.getValue(); + } else { + xi += entry.getValue() * globalX[entry.getColumn()]; + } + } + + if (hasDiagonalEntry) { + xi /= denominator; + } + return true; + } + + template + bool TopologicalLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, std::vector& x, std::vector const& b) const { + if (!this->sccSolver) { + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment, LinearEquationSolverTask::SolveEquations); + this->sccSolver->setCachingEnabled(true); + this->sccSolver->setBoundsFromOtherSolver(*this); + if (this->sccSolver->getEquationProblemFormat(sccSolverEnvironment) == LinearEquationSolverProblemFormat::EquationSystem) { + // Convert the matrix to an equation system. Note that we need to insert diagonal entries. + storm::storage::SparseMatrix eqSysA(*this->A, true); + eqSysA.convertToEquationSystem(); + this->sccSolver->setMatrix(std::move(eqSysA)); + } else { + this->sccSolver->setMatrix(*this->A); + } + } + return this->sccSolver->solveEquations(sccSolverEnvironment, x, b); + } + + template + bool TopologicalLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, storm::storage::BitVector const& scc, std::vector& globalX, std::vector const& globalB) const { + + // Set up the SCC solver + if (!this->sccSolver) { + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment, LinearEquationSolverTask::SolveEquations); + this->sccSolver->setCachingEnabled(true); + } + + // Matrix + bool asEquationSystem = this->sccSolver->getEquationProblemFormat(sccSolverEnvironment) == LinearEquationSolverProblemFormat::EquationSystem; + storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, scc, scc, asEquationSystem); + if (asEquationSystem) { + sccA.convertToEquationSystem(); + } + this->sccSolver->setMatrix(std::move(sccA)); + + // x Vector + auto sccX = storm::utility::vector::filterVector(globalX, scc); + + // b Vector + std::vector sccB; + sccB.reserve(scc.getNumberOfSetBits()); + for (auto const& row : scc) { + ValueType bi = globalB[row]; + for (auto const& entry : this->A->getRow(row)) { + if (!scc.get(entry.getColumn())) { + bi += entry.getValue() * globalX[entry.getColumn()]; + } + } + sccB.push_back(std::move(bi)); + } + + // lower/upper bounds + if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setLowerBound(this->getLowerBound()); + } else if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setLowerBounds(storm::utility::vector::filterVector(this->getLowerBounds(), scc)); + } + if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setUpperBound(this->getUpperBound()); + } else if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), scc)); + } + + return this->sccSolver->solveEquations(sccSolverEnvironment, sccX, sccB); + } + + + template + void TopologicalLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { + if (&x != &result) { + multiplier.multAdd(*A, x, b, result); + } else { + // If the two vectors are aliases, we need to create a temporary. + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(getMatrixRowCount()); + } + + multiplier.multAdd(*A, x, b, *this->cachedRowVector); + result.swap(*this->cachedRowVector); + + if (!this->isCachingEnabled()) { + clearCache(); + } + } + } + + template + void TopologicalLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { + if (&x != &result) { + multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, result, choices); + } else { + // If the two vectors are aliases, we need to create a temporary. + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(getMatrixRowCount()); + } + + multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, *this->cachedRowVector, choices); + result.swap(*this->cachedRowVector); + + if (!this->isCachingEnabled()) { + clearCache(); + } + } + } + + template + bool TopologicalLinearEquationSolver::supportsGaussSeidelMultiplication() const { + return true; + } + + template + void TopologicalLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { + STORM_LOG_ASSERT(this->A->getRowCount() == this->A->getColumnCount(), "This function is only applicable for square matrices."); + multiplier.multAddGaussSeidelBackward(*A, x, b); + } + + template + void TopologicalLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); + } + + template + LinearEquationSolverProblemFormat TopologicalLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { + return LinearEquationSolverProblemFormat::FixedPointSystem; + } + + template + LinearEquationSolverRequirements TopologicalLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + // Return the requirements of the underlying solver + return GeneralLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), task); + } + + template + void TopologicalLinearEquationSolver::clearCache() const { + sortedSccDecomposition.reset(); + sccSolver.reset(); + LinearEquationSolver::clearCache(); + } + + template + uint64_t TopologicalLinearEquationSolver::getMatrixRowCount() const { + return this->A->getRowCount(); + } + + template + uint64_t TopologicalLinearEquationSolver::getMatrixColumnCount() const { + return this->A->getColumnCount(); + } + + template + std::unique_ptr> TopologicalLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + return std::make_unique>(); + } + + template + std::unique_ptr> TopologicalLinearEquationSolverFactory::clone() const { + return std::make_unique>(*this); + } + + // Explicitly instantiate the linear equation solver. + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + +#ifdef STORM_HAVE_CARL + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + +#endif + } +} diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h new file mode 100644 index 000000000..a3d25c1c1 --- /dev/null +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -0,0 +1,84 @@ +#pragma once + +#include "storm/solver/LinearEquationSolver.h" + +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/NativeMultiplier.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" + +namespace storm { + + class Environment; + + namespace solver { + + template + class TopologicalLinearEquationSolver : public LinearEquationSolver { + public: + TopologicalLinearEquationSolver(); + TopologicalLinearEquationSolver(storm::storage::SparseMatrix const& A); + TopologicalLinearEquationSolver(storm::storage::SparseMatrix&& A); + + virtual void setMatrix(storm::storage::SparseMatrix const& A) override; + virtual void setMatrix(storm::storage::SparseMatrix&& A) override; + + virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual bool supportsGaussSeidelMultiplication() const override; + virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + + virtual void clearCache() const override; + + protected: + virtual bool internalSolveEquations(storm::Environment const& env, std::vector& x, std::vector const& b) const override; + + private: + + virtual uint64_t getMatrixRowCount() const override; + virtual uint64_t getMatrixColumnCount() const override; + + storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env) const; + + // Creates an SCC decomposition and sorts the SCCs according to a topological sort. + void createSortedSccDecomposition() const; + + // Solves the SCC with the given index + // ... for the case that the SCC is trivial + bool solveTrivialScc(uint64_t const& sccState, std::vector& globalX, std::vector const& globalB) const; + // ... for the case that there is just one large SCC + bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, std::vector& x, std::vector const& b) const; + // ... for the remaining cases (1 < scc.size() < x.size()) + bool solveScc(storm::Environment const& sccSolverEnvironment, storm::storage::BitVector const& scc, std::vector& globalX, std::vector const& globalB) const; + + // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted + // when the solver is destructed. + std::unique_ptr> localA; + + // A pointer to the original sparse matrix given to this solver. If the solver takes posession of the matrix + // the pointer refers to localA. + storm::storage::SparseMatrix const* A; + + // An object to dispatch all multiplication operations. + NativeMultiplier multiplier; + + // cached auxiliary data + mutable std::unique_ptr> sortedSccDecomposition; + mutable std::unique_ptr> sccSolver; + }; + + template + class TopologicalLinearEquationSolverFactory : public LinearEquationSolverFactory { + public: + using LinearEquationSolverFactory::create; + + virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + + virtual std::unique_ptr> clone() const override; + + }; + } +} From eae92517e820148e2b516a8b6b034ef05b9379f5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Sat, 9 Dec 2017 15:22:18 +0100 Subject: [PATCH 038/647] test for topological linear equation solver --- .../modelchecker/DtmcPrctlModelCheckerTest.cpp | 18 ++++++++++++++++++ .../storm/solver/LinearEquationSolverTest.cpp | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index 2d5973cc0..0040dd81f 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -25,6 +25,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" namespace { @@ -255,6 +256,22 @@ namespace { } }; + class SparseTopologicalEigenLUEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = true; + typedef storm::RationalNumber ValueType; + typedef storm::models::sparse::Dtmc ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological); + env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen); + env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); + return env; + } + }; + class HybridSylvanGmmxxGmresEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; @@ -467,6 +484,7 @@ namespace { SparseNativeSoundPowerEnvironment, SparseNativeQuickSoundPowerEnvironment, SparseNativeRationalSearchEnvironment, + SparseTopologicalEigenLUEnvironment, HybridSylvanGmmxxGmresEnvironment, HybridCuddNativeJacobiEnvironment, HybridCuddNativeSoundPowerEnvironment, diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index b4d7501eb..0ab4c1a55 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -6,6 +6,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" +#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" #include "storm/utility/vector.h" namespace { @@ -265,6 +266,19 @@ namespace { } }; + class TopologicalEigenRationalLUEnvironment { + public: + typedef storm::RationalNumber ValueType; + static const bool isExact = true; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological); + env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen); + env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); + return env; + } + }; + template class LinearEquationSolverTest : public ::testing::Test { public: @@ -296,7 +310,8 @@ namespace { EigenGmresIluEnvironment, EigenBicgstabNoneEnvironment, EigenDoubleLUEnvironment, - EigenRationalLUEnvironment + EigenRationalLUEnvironment, + TopologicalEigenRationalLUEnvironment > TestingTypes; TYPED_TEST_CASE(LinearEquationSolverTest, TestingTypes); From 4b2ddf3c6f01917c03a2f7e0edb2cb00f7f2b5ea Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 9 Dec 2017 16:06:55 +0100 Subject: [PATCH 039/647] leaving probloop deletion --- .../modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index e1a6b3375..450af4410 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -553,7 +553,7 @@ namespace storm { typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix( true, allStates, allStates, true); // delete diagonals - deleteProbDiagonals(fullTransitionMatrix, markovianStates); + //deleteProbDiagonals(fullTransitionMatrix, markovianStates); //for now leaving this out typename storm::storage::SparseMatrix probMatrix{}; uint64_t probSize = 0; if (probabilisticStates.getNumberOfSetBits() != 0) { //work around in case there are no prob states From fcd91ecb303ed29d06982b97df233afa871c55d2 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sun, 10 Dec 2017 15:11:53 +0100 Subject: [PATCH 040/647] fixed typo --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 450af4410..e9b2edfc5 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -588,14 +588,14 @@ namespace storm { //calculate relative reachability for (uint64_t i = 0; i < numberOfStates; i++) { - if (markovStates[i]) { + if (markovianStates[i]) { continue; } auto from = rowGroupIndices[i]; auto to = rowGroupIndices[i + 1]; for (auto j = from; j < to; j++) { for (auto& element: fullTransitionMatrix.getRow(j)) { - if (markovStates[element.getColumn()]) { + if (markovianStates[element.getColumn()]) { relReachability[j].push_back(element.getValue()); } } From bc524b0f4832126fecbcd3e1adbdab5a97e655b7 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 11:29:49 +0100 Subject: [PATCH 041/647] fixes for topological linear equation solver --- .../TopologicalLinearEquationSolver.cpp | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index c7ebee971..31e8d3308 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -49,14 +49,32 @@ namespace storm { template bool TopologicalLinearEquationSolver::internalSolveEquations(Environment const& env, std::vector& x, std::vector const& b) const { + //std::cout << "Solving equation system with fixpoint characterization " << std::endl; + //std::cout << *this->A << std::endl; + //std::cout << storm::utility::vector::toString(b) << std::endl; + //std::cout << "Initial solution vector: " << std::endl; + //std::cout << storm::utility::vector::toString(x) << std::endl; + if (!this->sortedSccDecomposition) { STORM_LOG_TRACE("Creating SCC decomposition."); createSortedSccDecomposition(); } + //std::cout << "Sorted SCC decomposition: " << std::endl; + for (auto const& scc : *this->sortedSccDecomposition) { + //std::cout << "SCC: "; + for (auto const& row : scc) { + //std::cout << row << " "; + } + //std::cout << std::endl; + } + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env); + std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(x.size()) / + static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + // Handle the case where there is just one large SCC if (this->sortedSccDecomposition->size() == 1) { return solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b); @@ -66,13 +84,13 @@ namespace storm { bool returnValue = true; for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { - returnValue = returnValue && solveTrivialScc(*scc.begin(), x, b); + returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; } else { sccAsBitVector.clear(); for (auto const& state : scc) { sccAsBitVector.set(state, true); } - returnValue = returnValue && solveScc(sccSolverEnvironment, sccAsBitVector, x, b); + returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue; } } @@ -166,6 +184,7 @@ namespace storm { if (hasDiagonalEntry) { xi /= denominator; } + //std::cout << "Solved trivial scc " << sccState << " with result " << globalX[sccState] << std::endl; return true; } @@ -202,6 +221,8 @@ namespace storm { if (asEquationSystem) { sccA.convertToEquationSystem(); } + //std::cout << "Solving SCC " << scc << std::endl; + //std::cout << "Matrix is " << sccA << std::endl; this->sccSolver->setMatrix(std::move(sccA)); // x Vector @@ -231,8 +252,13 @@ namespace storm { } else if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), scc)); } - - return this->sccSolver->solveEquations(sccSolverEnvironment, sccX, sccB); + + //std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl; + //std::cout << "x is " << storm::utility::vector::toString(sccX) << std::endl; + + bool returnvalue = this->sccSolver->solveEquations(sccSolverEnvironment, sccX, sccB); + storm::utility::vector::setVectorValues(globalX, scc, sccX); + return returnvalue; } From 304b8e32c6af9748bfe41d1c585c8693a8913de9 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 14:52:28 +0100 Subject: [PATCH 042/647] introduced topological equation solver settings --- ...logicalLinearEquationSolverEnvironment.cpp | 9 ++- src/storm/settings/SettingsManager.cpp | 2 + .../TopologicalEquationSolverSettings.cpp | 67 +++++++++++++++++++ .../TopologicalEquationSolverSettings.h | 55 +++++++++++++++ 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 src/storm/settings/modules/TopologicalEquationSolverSettings.cpp create mode 100644 src/storm/settings/modules/TopologicalEquationSolverSettings.h diff --git a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp index e49c0c15f..a0f3ac030 100644 --- a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp +++ b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp @@ -1,7 +1,7 @@ #include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" #include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/GameSolverSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -9,10 +9,9 @@ namespace storm { TopologicalLinearEquationSolverEnvironment::TopologicalLinearEquationSolverEnvironment() { - auto const& topologicalSettings = storm::settings::getModule(); - std::cout << "TODO: get actual settings in topo environment." << std::endl; - underlyingSolverType = storm::solver::EquationSolverType::Native; - underlyingSolverTypeSetFromDefault = true; + auto const& topologicalSettings = storm::settings::getModule(); + underlyingSolverType = topologicalSettings.getUnderlyingEquationSolverType(); + underlyingSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); } TopologicalLinearEquationSolverEnvironment::~TopologicalLinearEquationSolverEnvironment() { diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 188d1cba2..80cfbb58b 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -31,6 +31,7 @@ #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" #include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/AbstractionSettings.h" @@ -527,6 +528,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp new file mode 100644 index 000000000..906a6e472 --- /dev/null +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -0,0 +1,67 @@ +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" + + +#include "storm/settings/modules/CoreSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/SettingMemento.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" +#include "storm/solver/SolverSelectionOptions.h" + +#include "storm/storage/dd/DdType.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" +#include "storm/exceptions/InvalidOptionException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string TopologicalEquationSolverSettings::moduleName = "topological"; + const std::string TopologicalEquationSolverSettings::underlyingEquationSolverOptionName = "eqsolver"; + + TopologicalEquationSolverSettings::TopologicalEquationSolverSettings() : ModuleSettings(moduleName) { + std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; + this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, false, "Sets which solver is considered for solving the underlying equation systems.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); + } + + bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSet() const { + return this->getOption(underlyingEquationSolverOptionName).getHasOptionBeenSet(); + } + + bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSetFromDefaultValue() const { + return !this->getOption(underlyingEquationSolverOptionName).getHasOptionBeenSet() || this->getOption(underlyingEquationSolverOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + + storm::solver::EquationSolverType TopologicalEquationSolverSettings::getUnderlyingEquationSolverType() const { + std::string equationSolverName = this->getOption(underlyingEquationSolverOptionName).getArgumentByName("name").getValueAsString(); + if (equationSolverName == "gmm++") { + return storm::solver::EquationSolverType::Gmmxx; + } else if (equationSolverName == "native") { + return storm::solver::EquationSolverType::Native; + } else if (equationSolverName == "eigen") { + return storm::solver::EquationSolverType::Eigen; + } else if (equationSolverName == "elimination") { + return storm::solver::EquationSolverType::Elimination; + } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << equationSolverName << "'."); + } + + bool TopologicalEquationSolverSettings::check() const { + if (this->isUnderlyingEquationSolverTypeSet() && getUnderlyingEquationSolverType() == storm::solver::EquationSolverType::Topological) { + STORM_LOG_WARN("Underlying solver type of the topological solver can not be the topological solver."); + return false; + } + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm + + diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.h b/src/storm/settings/modules/TopologicalEquationSolverSettings.h new file mode 100644 index 000000000..45014db32 --- /dev/null +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.h @@ -0,0 +1,55 @@ +#pragma once + +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for the native equation solver. + */ + class TopologicalEquationSolverSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of native equation solver settings. + */ + TopologicalEquationSolverSettings(); + + /*! + * Retrieves whether the underlying equation solver type has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isUnderlyingEquationSolverTypeSet() const; + + /*! + * Retrieves whether the underlying equation solver type is set from its default value. + * + * @return True iff it was set from its default value. + */ + bool isUnderlyingEquationSolverTypeSetFromDefaultValue() const; + + /*! + * Retrieves the method that is to be used for solving systems of linear equations. + * + * @return The method to use. + */ + storm::solver::EquationSolverType getUnderlyingEquationSolverType() const; + + bool check() const override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string underlyingEquationSolverOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm From 1cff0fcbbb6f0eb553e6c0ee0ed1593da2c8e279 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 14:53:39 +0100 Subject: [PATCH 043/647] improved interface of solver environment --- .../environment/solver/SolverEnvironment.cpp | 58 ++++++++++--------- .../environment/solver/SolverEnvironment.h | 9 ++- .../IterativeMinMaxLinearEquationSolver.cpp | 52 ++++++++++++----- src/storm/solver/StandardGameSolver.cpp | 27 ++++++++- .../SymbolicMinMaxLinearEquationSolver.cpp | 52 ++++++++++++----- 5 files changed, 137 insertions(+), 61 deletions(-) diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index 6e0eb49c0..b9635757c 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -13,6 +13,7 @@ #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { @@ -87,8 +88,8 @@ namespace storm { return linearEquationSolverType; } - void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value) { - linearEquationSolverTypeSetFromDefault = false; + void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault) { + linearEquationSolverTypeSetFromDefault = assumeSetFromDefault; linearEquationSolverType = value; } @@ -96,46 +97,49 @@ namespace storm { return linearEquationSolverTypeSetFromDefault; } - boost::optional SolverEnvironment::getPrecisionOfCurrentLinearEquationSolver() const { - switch (getLinearEquationSolverType()) { + std::pair, boost::optional> SolverEnvironment::getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const { + std::pair, boost::optional> result; + switch (solverType) { case storm::solver::EquationSolverType::Gmmxx: - return gmmxx().getPrecision(); + result.first = gmmxx().getPrecision(); + break; case storm::solver::EquationSolverType::Eigen: - return eigen().getPrecision(); + result.first = eigen().getPrecision(); + break; case storm::solver::EquationSolverType::Native: - return native().getPrecision(); + result.first = native().getPrecision(); + result.second = native().getRelativeTerminationCriterion(); + break; case storm::solver::EquationSolverType::Elimination: - return boost::none; + break; + case storm::solver::EquationSolverType::Topological: + result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingSolverType()); + break; default: - STORM_LOG_ASSERT(false, "The selected solver type is unknown."); + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "The selected solver type is unknown."); } + return result; } - void SolverEnvironment::setLinearEquationSolverPrecision(storm::RationalNumber const& value) { + void SolverEnvironment::setLinearEquationSolverPrecision(boost::optional const& newPrecision, boost::optional const& relativePrecision) { + // Assert that each solver type is handled in this method. STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination || getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological, "The current solver type is not respected in this method."); - native().setPrecision(value); - gmmxx().setPrecision(value); - eigen().setPrecision(value); - // Elimination and Topological solver do not have a precision - } - - void SolverEnvironment::setLinearEquationSolverRelativeTerminationCriterion(bool value) { - STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological, - "The current solver type is not respected in this method."); - native().setRelativeTerminationCriterion(value); - // Elimination, gmm, eigen, and topological solver do not have an option for relative termination criterion + if (newPrecision) { + native().setPrecision(newPrecision.get()); + gmmxx().setPrecision(newPrecision.get()); + eigen().setPrecision(newPrecision.get()); + // Elimination and Topological solver do not have a precision + } + if (relativePrecision) { + native().setRelativeTerminationCriterion(relativePrecision.get()); + // gmm, eigen, elimination, and topological solvers do not have a precision + } } - - } diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index 7f3260291..614fd1d02 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -41,12 +41,11 @@ namespace storm { void setForceSoundness(bool value); storm::solver::EquationSolverType const& getLinearEquationSolverType() const; - void setLinearEquationSolverType(storm::solver::EquationSolverType const& value); + void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault = false); bool isLinearEquationSolverTypeSetFromDefaultValue() const; - - boost::optional getPrecisionOfCurrentLinearEquationSolver() const; - void setLinearEquationSolverPrecision(storm::RationalNumber const& value); - void setLinearEquationSolverRelativeTerminationCriterion(bool value); + + std::pair, boost::optional> getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const; + void setLinearEquationSolverPrecision(boost::optional const& newPrecision, boost::optional const& relativePrecision = boost::none); private: SubEnvironment eigenSolverEnvironment; diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index fb71fa43f..059cdb5a8 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -114,19 +114,32 @@ namespace storm { // The solver that we will use throughout the procedure. std::unique_ptr> solver; // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } - + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + SolverStatus status = SolverStatus::InProgress; uint64_t iterations = 0; this->startMeasureProgress(); do { // Solve the equation system for the 'DTMC'. - solveInducedEquationSystem(environmentOfSolver ? *environmentOfSolver : env, solver, scheduler, x, subB, b); + solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b); // Go through the multiplication result and see whether we can improve any of the choices. bool schedulerImproved = false; @@ -311,14 +324,27 @@ namespace storm { // Solve the equation system induced by the initial scheduler. std::unique_ptr> linEqSolver; // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; - solveInducedEquationSystem(environmentOfSolver ? *environmentOfSolver : env, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b); + solveInducedEquationSystem(environmentOfSolver, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b); // If we were given an initial scheduler and are maximizing (minimizing), our current solution becomes // always less-or-equal (greater-or-equal) than the actual solution. guarantee = maximize(dir) ? SolverGuarantee::LessOrEqual : SolverGuarantee::GreaterOrEqual; diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 26d4cc3d0..bd1024a86 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -76,13 +76,34 @@ namespace storm { uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); + // The linear equation solver should be at least as precise as this solver + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().game().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().game().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().game().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } + } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); - if (this->linearEquationSolverFactory->getEquationProblemFormat(env) == LinearEquationSolverProblemFormat::EquationSystem) { + if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { submatrix.convertToEquationSystem(); } - auto submatrixSolver = linearEquationSolverFactory->create(env, std::move(submatrix)); + auto submatrixSolver = linearEquationSolverFactory->create(environmentOfSolver, std::move(submatrix)); if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); } if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); } submatrixSolver->setCachingEnabled(true); @@ -92,7 +113,7 @@ namespace storm { do { // Solve the equation system for the 'DTMC'. // FIXME: we need to remove the 0- and 1- states to make the solution unique. - submatrixSolver->solveEquations(env, x, subB); + submatrixSolver->solveEquations(environmentOfSolver, x, subB); bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, player1Choices, player2Choices); diff --git a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp index b1501fd32..b599face7 100644 --- a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp @@ -244,13 +244,26 @@ namespace storm { // If we were given an initial scheduler, we take its solution as the starting point. if (this->hasInitialScheduler()) { // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } - localX = solveEquationsWithScheduler(environmentOfSolver ? *environmentOfSolver : env, this->getInitialScheduler(), x, b); + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + localX = solveEquationsWithScheduler(environmentOfSolver, this->getInitialScheduler(), x, b); } else { localX = this->getLowerBoundsVector(); } @@ -311,20 +324,33 @@ namespace storm { // Initialize linear equation solver. // It should be at least as precise as this solver. - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; - std::unique_ptr> linearEquationSolver = linearEquationSolverFactory->create(environmentOfSolver ? *environmentOfSolver : env, this->allRows, this->rowMetaVariables, this->columnMetaVariables, this->rowColumnMetaVariablePairs); + std::unique_ptr> linearEquationSolver = linearEquationSolverFactory->create(environmentOfSolver, this->allRows, this->rowMetaVariables, this->columnMetaVariables, this->rowColumnMetaVariablePairs); this->forwardBounds(*linearEquationSolver); // Iteratively solve and improve the scheduler. uint64_t maxIter = env.solver().minMax().getMaximalNumberOfIterations(); while (!converged && iterations < maxIter) { - storm::dd::Add schedulerX = solveEquationsWithScheduler(environmentOfSolver ? *environmentOfSolver : env, *linearEquationSolver, scheduler, currentSolution, b, diagonal); + storm::dd::Add schedulerX = solveEquationsWithScheduler(environmentOfSolver, *linearEquationSolver, scheduler, currentSolution, b, diagonal); // Policy improvement step. storm::dd::Add choiceValues = this->A.multiplyMatrix(schedulerX.swapVariables(this->rowColumnMetaVariablePairs), this->columnMetaVariables) + b; From 636d2638a5cff685367e815938b4ab68673044d2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 14:54:06 +0100 Subject: [PATCH 044/647] added missing switch case --- src/storm/solver/StandardMinMaxLinearEquationSolver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index a8b042dc7..d396575db 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -5,6 +5,7 @@ #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/solver/NativeLinearEquationSolver.h" #include "storm/solver/EliminationLinearEquationSolver.h" +#include "storm/solver/TopologicalLinearEquationSolver.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" @@ -92,6 +93,7 @@ namespace storm { case EquationSolverType::Eigen: linearEquationSolverFactory = std::make_unique>(); break; case EquationSolverType::Native: linearEquationSolverFactory = std::make_unique>(); break; case EquationSolverType::Elimination: linearEquationSolverFactory = std::make_unique>(); break; + case EquationSolverType::Topological: linearEquationSolverFactory = std::make_unique>(); break; } } From 3b7b60aa6cd251a9cd8e1d30b2a52c3307e6d3f6 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 14:57:40 +0100 Subject: [PATCH 045/647] topological linear equation solver now respects sound computations --- .../TopologicalLinearEquationSolver.cpp | 67 ++++++++++++++----- .../solver/TopologicalLinearEquationSolver.h | 5 +- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 31e8d3308..c08b30134 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -41,9 +41,14 @@ namespace storm { } template - storm::Environment TopologicalLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env) const { + storm::Environment TopologicalLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const { storm::Environment subEnv(env); - subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingSolverType()); + subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingSolverType(), env.solver().topological().isUnderlyingSolverTypeSetFromDefault()); + if (adaptPrecision) { + STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed."); + auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType()); + subEnv.solver().setLinearEquationSolverPrecision(static_cast(subEnvPrec.first.get() / storm::utility::convertNumber(this->longestSccChainSize.get()))); + } return subEnv; } @@ -55,25 +60,32 @@ namespace storm { //std::cout << "Initial solution vector: " << std::endl; //std::cout << storm::utility::vector::toString(x) << std::endl; + // For sound computations we need to increase the precision in each SCC + bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingSolverType()).first.is_initialized(); - if (!this->sortedSccDecomposition) { + if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) { STORM_LOG_TRACE("Creating SCC decomposition."); - createSortedSccDecomposition(); + createSortedSccDecomposition(needAdaptPrecision); } //std::cout << "Sorted SCC decomposition: " << std::endl; - for (auto const& scc : *this->sortedSccDecomposition) { + //for (auto const& scc : *this->sortedSccDecomposition) { //std::cout << "SCC: "; - for (auto const& row : scc) { + // for (auto const& row : scc) { //std::cout << row << " "; - } + // } //std::cout << std::endl; - } + //} + + // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) + needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->getMatrixRowCount()); - storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env); + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); - std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(x.size()) / - static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + if (this->longestSccChainSize) { + std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl; + } // Handle the case where there is just one large SCC if (this->sortedSccDecomposition->size() == 1) { @@ -102,7 +114,7 @@ namespace storm { } template - void TopologicalLinearEquationSolver::createSortedSccDecomposition() const { + void TopologicalLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { // Obtain the scc decomposition auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*this->A); @@ -124,7 +136,11 @@ namespace storm { // Find a topological sort via DFS. storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); - std::vector sccStack; + std::vector sccStack, chainSizes; + if (needLongestChainSize) { + chainSizes.resize(this->sortedSccDecomposition->size(), 1u); + } + uint32_t longestChainSize = 0; uint32_t const token = std::numeric_limits::max(); std::set successorSCCs; @@ -132,7 +148,7 @@ namespace storm { sccStack.push_back(firstUnsortedScc); while (!sccStack.empty()) { - auto const& currentSccIndex = sccStack.back(); + uint32_t currentSccIndex = sccStack.back(); if (currentSccIndex != token) { // Check whether the SCC is still unprocessed if (unsortedSCCs.get(currentSccIndex)) { @@ -157,12 +173,31 @@ namespace storm { } else { // all successors of the current scc have already been explored. sccStack.pop_back(); // pop the token - sortedSCCs.push_back(std::move(sccDecomposition.getBlock(sccStack.back()))); - unsortedSCCs.set(sccStack.back(), false); + + currentSccIndex = sccStack.back(); + storm::storage::StronglyConnectedComponent& scc = sccDecomposition.getBlock(currentSccIndex); + + // Compute the longest chain size for this scc + if (needLongestChainSize) { + uint32_t& currentChainSize = chainSizes[currentSccIndex]; + for (auto const& row : scc) { + for (auto const& entry : this->A->getRow(row)) { + currentChainSize = std::max(currentChainSize, chainSizes[sccIndices[entry.getColumn()]] + 1); + } + } + longestChainSize = std::max(longestChainSize, currentChainSize); + } + + unsortedSCCs.set(currentSccIndex, false); sccStack.pop_back(); // pop the current scc index + sortedSCCs.push_back(std::move(scc)); } } } + + if (longestChainSize > 0) { + this->longestSccChainSize = longestChainSize; + } } template diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h index a3d25c1c1..bb888b52b 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.h +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -41,10 +41,10 @@ namespace storm { virtual uint64_t getMatrixRowCount() const override; virtual uint64_t getMatrixColumnCount() const override; - storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env) const; + storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const; // Creates an SCC decomposition and sorts the SCCs according to a topological sort. - void createSortedSccDecomposition() const; + void createSortedSccDecomposition(bool needLongestChainSize) const; // Solves the SCC with the given index // ... for the case that the SCC is trivial @@ -67,6 +67,7 @@ namespace storm { // cached auxiliary data mutable std::unique_ptr> sortedSccDecomposition; + mutable boost::optional longestSccChainSize; mutable std::unique_ptr> sccSolver; }; From bff609961fd8eea94888300f2ad32d6bd4cffe25 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 16:01:12 +0100 Subject: [PATCH 046/647] fixed wrong computation of chain sizes --- src/storm/solver/TopologicalLinearEquationSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index c08b30134..59f0b8006 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -138,7 +138,7 @@ namespace storm { storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); std::vector sccStack, chainSizes; if (needLongestChainSize) { - chainSizes.resize(this->sortedSccDecomposition->size(), 1u); + chainSizes.resize(sccDecomposition.size(), 1u); } uint32_t longestChainSize = 0; uint32_t const token = std::numeric_limits::max(); From 35fbb86af4f7e07a3fcb7f5a06199032ba73273c Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 16:01:45 +0100 Subject: [PATCH 047/647] fixed topological:eqsolver option: it should require module name prefix --- .../settings/modules/TopologicalEquationSolverSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index 906a6e472..c5f74a124 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -26,7 +26,7 @@ namespace storm { TopologicalEquationSolverSettings::TopologicalEquationSolverSettings() : ModuleSettings(moduleName) { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; - this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, false, "Sets which solver is considered for solving the underlying equation systems.") + this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, true, "Sets which solver is considered for solving the underlying equation systems.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); } From 46074aa8bce3bf9b689ecc127001b3ed196ba19e Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 11 Dec 2017 16:41:33 +0100 Subject: [PATCH 048/647] fixed chain size computation --- src/storm/solver/TopologicalLinearEquationSolver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 59f0b8006..69a3efe18 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -182,7 +182,10 @@ namespace storm { uint32_t& currentChainSize = chainSizes[currentSccIndex]; for (auto const& row : scc) { for (auto const& entry : this->A->getRow(row)) { - currentChainSize = std::max(currentChainSize, chainSizes[sccIndices[entry.getColumn()]] + 1); + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex) { + currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); + } } } longestChainSize = std::max(longestChainSize, currentChainSize); From 79ba044c496be8e3147c4068032d42ddc6b34f3f Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 12 Dec 2017 13:34:47 +0100 Subject: [PATCH 049/647] prints --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index e9b2edfc5..93758ee94 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -661,6 +661,13 @@ namespace storm { element /= foxGlynnResult.totalWeight; } + ValueType leftSum=0; + for (int i =0 ; i< foxGlynnResult.left; i++){ + leftSum += foxGlynnResult.weights[i]; + std::cout << foxGlynnResult.weights[i] << "\n"; + } + std::cout<< "sum Left is " << leftSum <<"\n"; + // (4) define vectors/matrices std::vector init(numberOfStates, -1); From 9dda579e58773f894d81cf74bfac267f171c47ea Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 13 Dec 2017 16:18:13 +0100 Subject: [PATCH 050/647] slightly patched Fox-Glynn --- src/storm/utility/numerical.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm/utility/numerical.cpp b/src/storm/utility/numerical.cpp index cec474ff7..9c17928ab 100644 --- a/src/storm/utility/numerical.cpp +++ b/src/storm/utility/numerical.cpp @@ -229,6 +229,7 @@ namespace storm { } else { t = j; result.right = j + result.left; + result.weights.resize(result.right - result.left + 1); // It's time to compute W. break; @@ -257,7 +258,7 @@ namespace storm { } result.totalWeight += result.weights[j]; - STORM_LOG_TRACE("Fox-Glynn: ltp = " << result.left << ", rtp = " << result.right << ", w = " << result.totalWeight << "."); + STORM_LOG_TRACE("Fox-Glynn: ltp = " << result.left << ", rtp = " << result.right << ", w = " << result.totalWeight << ", " << result.weights.size() << " weights."); return result; } From 95c12cf6d8a60539c89354afa04bdef9bb37c6a7 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Wed, 13 Dec 2017 16:25:29 +0100 Subject: [PATCH 051/647] new use of FixGlynn --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 37 +++++++++---------- .../helper/SparseMarkovAutomatonCslHelper.h | 5 ++- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 93758ee94..b64a04459 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -22,7 +22,7 @@ #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/utility/numerical.h" +//#include "storm/utility/numerical.h" #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/solver/LpSolver.h" @@ -220,7 +220,7 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson){ + void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -231,8 +231,8 @@ namespace storm { calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } - if (i=poisson.left && i<=poisson.right){ + res+=poisson.weights[i-poisson.left]*unifVectors[2][N-1-(i-k)][node]; } } unifVectors[1][k][node]=res; @@ -249,7 +249,7 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver, std::ofstream& logfile, std::vector const& poisson) { + std::unique_ptr> const &solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson) { if (unifVectors[kind][k][node]!=-1){ @@ -277,8 +277,8 @@ namespace storm { // Vd res = storm::utility::zero(); for (uint64_t i = k ; i=poisson.left && i<=poisson.right){ + ValueType between = poisson.weights[i-poisson.left]; res+=between; } } @@ -621,7 +621,6 @@ namespace storm { //logfile << "starting iteration\n"; maxNorm = storm::utility::zero(); // (2) update parameter - N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); // (3) uniform - just applied to markovian states for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { @@ -655,18 +654,18 @@ namespace storm { storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda*T, epsilon*kappa); + N = std::max(ceil(lambda * T * exp(2) - log(kappa * epsilon)), ceil(foxGlynnResult.right - foxGlynnResult.left +1 )); // Scale the weights so they add up to one. for (auto& element : foxGlynnResult.weights) { element /= foxGlynnResult.totalWeight; } - ValueType leftSum=0; - for (int i =0 ; i< foxGlynnResult.left; i++){ - leftSum += foxGlynnResult.weights[i]; - std::cout << foxGlynnResult.weights[i] << "\n"; + ValueType sum = 0; + for (auto i = foxGlynnResult.left ; i<=foxGlynnResult.right; i++){ + sum+=foxGlynnResult.weights[i-foxGlynnResult.left]; } - std::cout<< "sum Left is " << leftSum <<"\n"; + std::cout << " left " << foxGlynnResult.left << " right " << foxGlynnResult.right << " size " << foxGlynnResult.weights.size() << " sum " << sum << "\n"; // (4) define vectors/matrices @@ -684,20 +683,20 @@ namespace storm { for (uint64_t k = N; k <= N; k--) { calculateUnifPlusVector(env, k, i, 0, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult.weights); + foxGlynnResult); calculateUnifPlusVector(env, k, i, 2, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult.weights); + foxGlynnResult); calculateVu(env, relReachability, dir, k, i, 1, lambda, probSize, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult.weights); + foxGlynnResult); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); maxNorm = std::max(maxNorm, diff); } } - //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove + printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda @@ -706,7 +705,7 @@ namespace storm { // (7) escape if not coming closer to solution if (oldDiff != -1) { if (oldDiff == maxNorm) { - std::cout << "Not coming closer to solution as " << maxNorm << "/n"; + std::cout << "Not coming closer to solution as " << maxNorm << "\n"; break; } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 2b62d244f..ac005ce38 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -1,6 +1,7 @@ #ifndef STORM_MODELCHECKER_SPARSE_MARKOVAUTOMATON_CSL_MODELCHECKER_HELPER_H_ #define STORM_MODELCHECKER_SPARSE_MARKOVAUTOMATON_CSL_MODELCHECKER_HELPER_H_ +#include #include "storm/storage/BitVector.h" #include "storm/storage/MaximalEndComponent.h" #include "storm/solver/OptimizationDirection.h" @@ -62,7 +63,7 @@ namespace storm { static void identify(storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,storm::storage::BitVector const& psiStates); template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); + static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -97,7 +98,7 @@ namespace storm { * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, std::vector const& poisson); + static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson); From cc8b6f6af0a6ec60f5c43b7792722e3fac2e96fc Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Wed, 13 Dec 2017 21:04:58 +0100 Subject: [PATCH 052/647] fixed stupid uniformisation bug --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index b64a04459..b427bcfbd 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -570,15 +570,12 @@ namespace storm { double T = boundsPair.second; ValueType kappa = storm::utility::one() / 10; // would be better as option-parameter ValueType epsilon = storm::settings::getModule().getPrecision(); - ValueType lambda = exitRateVector[0]; - for (ValueType act: exitRateVector) { + ValueType lambda = exitRate[0]; + for (ValueType act: exitRate) { lambda = std::max(act, lambda); } uint64_t N; - - - //calculate relative ReachabilityVectors std::vector in{}; std::vector> relReachability(transitionMatrix.getRowCount(), in); @@ -621,10 +618,11 @@ namespace storm { //logfile << "starting iteration\n"; maxNorm = storm::utility::zero(); // (2) update parameter + N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); // (3) uniform - just applied to markovian states - for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { - if (!markovianStates[i]) { + for (uint64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + if (!markovianStates[i] || psiStates[i]) { continue; } uint64_t from = rowGroupIndices[i]; //markovian state -> no Nondeterminism -> only one row @@ -638,7 +636,7 @@ namespace storm { ValueType exitNew = lambda; for (auto &v : line) { if (v.getColumn() == i) { //diagonal element - ValueType newSelfLoop = exitNew - exitOld + v.getValue(); + ValueType newSelfLoop = exitNew - exitOld + v.getValue()*exitOld; ValueType newRate = newSelfLoop / exitNew; v.setValue(newRate); } else { //modify probability @@ -654,8 +652,6 @@ namespace storm { storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda*T, epsilon*kappa); - N = std::max(ceil(lambda * T * exp(2) - log(kappa * epsilon)), ceil(foxGlynnResult.right - foxGlynnResult.left +1 )); - // Scale the weights so they add up to one. for (auto& element : foxGlynnResult.weights) { element /= foxGlynnResult.totalWeight; @@ -695,8 +691,8 @@ namespace storm { maxNorm = std::max(maxNorm, diff); } } - printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove + //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda From e5f71aa851431aaa5bc414d2053be0b771c8b9c1 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 19 Dec 2017 10:30:09 +0100 Subject: [PATCH 053/647] prints for foxGlynn --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index b427bcfbd..ad8c44b0f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -193,7 +193,8 @@ namespace storm { logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; } - logfile << "Iteration for N = " << N << "maximal difference was " << diff << "\n"; + logfile << "Iteration for N = " << N << " maximal difference was " << diff << "\n"; + logfile << "vd: \n"; for (uint64_t i =0 ; i foxGlynnResult = storm::utility::numerical::foxGlynn(lambda*T, epsilon*kappa); + storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda*T, epsilon*kappa/100); // Scale the weights so they add up to one. for (auto& element : foxGlynnResult.weights) { @@ -660,6 +661,8 @@ namespace storm { ValueType sum = 0; for (auto i = foxGlynnResult.left ; i<=foxGlynnResult.right; i++){ sum+=foxGlynnResult.weights[i-foxGlynnResult.left]; + logfile << i << "\t" << foxGlynnResult.weights[i-foxGlynnResult.left]; + logfile << i << "\t" << sum; } std::cout << " left " << foxGlynnResult.left << " right " << foxGlynnResult.right << " size " << foxGlynnResult.weights.size() << " sum " << sum << "\n"; @@ -706,6 +709,7 @@ namespace storm { } } oldDiff = maxNorm; + std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; } while (maxNorm > epsilon * (1 - kappa)); logfile.close(); From 7577ca48ec8d5d4b03259eab209cd29dd4ac724d Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 19 Dec 2017 17:17:51 +0100 Subject: [PATCH 054/647] changed loop of diff checking; ; --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index ad8c44b0f..819d684c5 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -690,10 +690,15 @@ namespace storm { fullTransitionMatrix, markovianStates, psiStates, solver, logfile, foxGlynnResult); //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove - ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); - maxNorm = std::max(maxNorm, diff); + //ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); } } + + //only iterate over result vector, as the results can only get more precise + for (uint64_t i = 0; i < numberOfStates; i++){ + ValueType diff = std::abs(unifVectors[0][0][i]-unifVectors[1][0][i]); + maxNorm = std::max(maxNorm, diff); + } //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove From 95c23b50d14d5fed337a69a482d5b4d5b33bf99d Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 19 Dec 2017 18:26:56 +0100 Subject: [PATCH 055/647] removing log prints again --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 819d684c5..e56e03044 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -658,15 +658,6 @@ namespace storm { element /= foxGlynnResult.totalWeight; } - ValueType sum = 0; - for (auto i = foxGlynnResult.left ; i<=foxGlynnResult.right; i++){ - sum+=foxGlynnResult.weights[i-foxGlynnResult.left]; - logfile << i << "\t" << foxGlynnResult.weights[i-foxGlynnResult.left]; - logfile << i << "\t" << sum; - } - std::cout << " left " << foxGlynnResult.left << " right " << foxGlynnResult.right << " size " << foxGlynnResult.weights.size() << " sum " << sum << "\n"; - - // (4) define vectors/matrices std::vector init(numberOfStates, -1); std::vector> v = std::vector>(N + 1, init); @@ -714,7 +705,7 @@ namespace storm { } } oldDiff = maxNorm; - std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; + //std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; } while (maxNorm > epsilon * (1 - kappa)); logfile.close(); From 0004c9b2bb21d28e9f4e11ef39bca8d6d4967984 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Thu, 21 Dec 2017 01:08:57 +0100 Subject: [PATCH 056/647] adding version with value iteration --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 80 ++++++++----------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index e56e03044..a5b70f3d2 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -310,49 +310,36 @@ namespace storm { } //probabilistic non-goal State - if (!markovianStates[node]){ - std::vector b(probSize, 0), x(numberOfProbStates,0); - //calculate b - uint64_t lineCounter=0; - for (int i =0; isolveEquations(env, dir, x, b); - - - - for (uint64_t i =0 ; i fullTransitionMatrix = transitionMatrix.getSubmatrix( true, allStates, allStates, true); // delete diagonals - //deleteProbDiagonals(fullTransitionMatrix, markovianStates); //for now leaving this out + deleteProbDiagonals(fullTransitionMatrix, markovianStates); //for now leaving this out typename storm::storage::SparseMatrix probMatrix{}; uint64_t probSize = 0; if (probabilisticStates.getNumberOfSetBits() != 0) { //work around in case there are no prob states @@ -584,7 +571,7 @@ namespace storm { //calculate relative reachability - + /* for (uint64_t i = 0; i < numberOfStates; i++) { if (markovianStates[i]) { continue; @@ -600,20 +587,21 @@ namespace storm { } } - //create equitation solver + //create equitation solver storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); + requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - + */ std::unique_ptr> solver; - if (probSize != 0) { + /*if (probSize != 0) { solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); solver->setHasUniqueSolution(); solver->setBounds(storm::utility::zero(), storm::utility::one()); solver->setRequirementsChecked(); solver->setCachingEnabled(true); - } + } */ // while not close enough to precision: do { //logfile << "starting iteration\n"; @@ -690,8 +678,8 @@ namespace storm { ValueType diff = std::abs(unifVectors[0][0][i]-unifVectors[1][0][i]); maxNorm = std::max(maxNorm, diff); } - //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove + printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda @@ -705,7 +693,7 @@ namespace storm { } } oldDiff = maxNorm; - //std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; + std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; } while (maxNorm > epsilon * (1 - kappa)); logfile.close(); From 3a94b8ad690864d080a479c8ce189db5649673d4 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Thu, 21 Dec 2017 17:50:54 +0100 Subject: [PATCH 057/647] ignoring kappa, taking in account epsilon --- .../modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index a5b70f3d2..07939614f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -694,7 +694,7 @@ namespace storm { } oldDiff = maxNorm; std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; - } while (maxNorm > epsilon * (1 - kappa)); + } while (maxNorm > epsilon /* * (1 - kappa)*/); logfile.close(); return unifVectors[0][0]; From b9007aa2e9f78a5a555e6bb81be96c69818b5bcf Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Tue, 2 Jan 2018 10:34:44 +0100 Subject: [PATCH 058/647] removed logprints --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 07939614f..4b419d92e 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -678,8 +678,8 @@ namespace storm { ValueType diff = std::abs(unifVectors[0][0][i]-unifVectors[1][0][i]); maxNorm = std::max(maxNorm, diff); } - printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove + //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, + // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove // (6) double lambda From 8260455a5559519d599b8afbc597f900430ad54d Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 2 Jan 2018 11:55:43 +0100 Subject: [PATCH 059/647] Added multiplication of a single matrix row with a vector to the linear equation solver interface --- src/storm/solver/EigenLinearEquationSolver.cpp | 7 +++++++ src/storm/solver/EigenLinearEquationSolver.h | 2 ++ src/storm/solver/EliminationLinearEquationSolver.cpp | 5 +++++ src/storm/solver/EliminationLinearEquationSolver.h | 2 ++ src/storm/solver/GmmxxLinearEquationSolver.cpp | 6 ++++++ src/storm/solver/GmmxxLinearEquationSolver.h | 1 + src/storm/solver/GmmxxMultiplier.cpp | 8 ++++++++ src/storm/solver/GmmxxMultiplier.h | 2 ++ src/storm/solver/LinearEquationSolver.h | 8 ++++++++ src/storm/solver/NativeLinearEquationSolver.cpp | 6 ++++++ src/storm/solver/NativeLinearEquationSolver.h | 3 ++- src/storm/solver/NativeMultiplier.cpp | 4 ++++ src/storm/solver/NativeMultiplier.h | 2 ++ src/storm/solver/TopologicalLinearEquationSolver.cpp | 5 +++++ src/storm/solver/TopologicalLinearEquationSolver.h | 3 ++- 15 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/storm/solver/EigenLinearEquationSolver.cpp b/src/storm/solver/EigenLinearEquationSolver.cpp index 874d6f4c4..bcba06888 100644 --- a/src/storm/solver/EigenLinearEquationSolver.cpp +++ b/src/storm/solver/EigenLinearEquationSolver.cpp @@ -268,6 +268,13 @@ namespace storm { } } + template + ValueType EigenLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { + auto eigenX = StormEigen::Matrix::Map(x.data(), x.size()); + return (eigenA->row(rowIndex) * eigenX)(0); + } + + template LinearEquationSolverProblemFormat EigenLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::EquationSystem; diff --git a/src/storm/solver/EigenLinearEquationSolver.h b/src/storm/solver/EigenLinearEquationSolver.h index a6bbae91a..0bdeabba1 100644 --- a/src/storm/solver/EigenLinearEquationSolver.h +++ b/src/storm/solver/EigenLinearEquationSolver.h @@ -21,6 +21,8 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix&& A) override; virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; diff --git a/src/storm/solver/EliminationLinearEquationSolver.cpp b/src/storm/solver/EliminationLinearEquationSolver.cpp index 3e84b7f0c..2e67119d6 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.cpp +++ b/src/storm/solver/EliminationLinearEquationSolver.cpp @@ -109,6 +109,11 @@ namespace storm { } } } + + template + ValueType EliminationLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { + return A->multiplyRowWithVector(rowIndex, x); + } template LinearEquationSolverProblemFormat EliminationLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { diff --git a/src/storm/solver/EliminationLinearEquationSolver.h b/src/storm/solver/EliminationLinearEquationSolver.h index 60403336e..57da6bbaa 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.h +++ b/src/storm/solver/EliminationLinearEquationSolver.h @@ -22,6 +22,8 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix&& A) override; virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index 0f517d5a9..f87a02a96 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -145,6 +145,12 @@ namespace storm { multiplier.multAddReduceGaussSeidel(dir, rowGroupIndices, *gmmxxA, x, b, choices); } + template + ValueType GmmxxLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { + return multiplier.multiplyRow(*gmmxxA, rowIndex, x); + } + + template LinearEquationSolverProblemFormat GmmxxLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::EquationSystem; diff --git a/src/storm/solver/GmmxxLinearEquationSolver.h b/src/storm/solver/GmmxxLinearEquationSolver.h index bb08cf007..434d5688a 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.h +++ b/src/storm/solver/GmmxxLinearEquationSolver.h @@ -32,6 +32,7 @@ namespace storm { virtual bool supportsGaussSeidelMultiplication() const override; virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index b05ef8bcc..5158d03fb 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -231,6 +231,14 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } + template + T GmmxxMultiplier::multiplyRow(gmm::csr_matrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const { + return vect_sp(gmm::mat_const_row(matrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); + } + + + + template class GmmxxMultiplier; #ifdef STORM_HAVE_CARL diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index 237f56b63..aebdb069d 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -23,6 +23,8 @@ namespace storm { void multAddParallel(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + T multiplyRow(gmm::csr_matrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const; + private: void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; }; diff --git a/src/storm/solver/LinearEquationSolver.h b/src/storm/solver/LinearEquationSolver.h index b4b49d627..cc2f73a7a 100644 --- a/src/storm/solver/LinearEquationSolver.h +++ b/src/storm/solver/LinearEquationSolver.h @@ -109,6 +109,14 @@ namespace storm { */ virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + /*! + * Multiplies the row with the given index with x and adds the given offset + * @param rowIndex The index of the considered row + * @param x The input vector with which the row is multiplied + * @param offset A value that is added to the matrix-vector multiplication result + */ + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const = 0; + /*! * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After * performing the necessary multiplications, the result is written to the input vector x. Note that the diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index c140dcf3f..0199857d1 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -1081,6 +1081,12 @@ namespace storm { multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); } + template + ValueType NativeLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { + return multiplier.multiplyRow(*A, rowIndex, x); + } + + template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 34ff42bf7..fbb5d4357 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -35,7 +35,8 @@ namespace storm { virtual bool supportsGaussSeidelMultiplication() const override; virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index f5fc1d903..ddbeb235f 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -89,6 +89,10 @@ namespace storm { #endif } + template + ValueType NativeMultiplier::multiplyRow(storm::storage::SparseMatrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const { + return matrix.multiplyRowWithVector(rowIndex, x); + } template class NativeMultiplier; diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index 01233b1ba..ea8f543d4 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -25,6 +25,8 @@ namespace storm { void multAddParallel(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + + ValueType multiplyRow(storm::storage::SparseMatrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const; }; } diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 69a3efe18..9f6dcdebf 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -354,6 +354,11 @@ namespace storm { multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); } + template + ValueType TopologicalLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { + return multiplier.multiplyRow(*A, rowIndex, x); + } + template LinearEquationSolverProblemFormat TopologicalLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::FixedPointSystem; diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h index bb888b52b..7403423b7 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.h +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -27,7 +27,8 @@ namespace storm { virtual bool supportsGaussSeidelMultiplication() const override; virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; From 9c96bd0a1cdefdf28a0b812a8c5d91c943812e67 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 2 Jan 2018 13:54:57 +0100 Subject: [PATCH 060/647] First implementation of quick value iteration for MinMax Equation systems --- .../modules/MinMaxEquationSolverSettings.cpp | 4 +- .../IterativeMinMaxLinearEquationSolver.cpp | 291 +++++++++++++++++- .../IterativeMinMaxLinearEquationSolver.h | 2 + .../solver/MinMaxLinearEquationSolver.cpp | 4 +- src/storm/solver/SolverSelectionOptions.cpp | 2 + src/storm/solver/SolverSelectionOptions.h | 2 +- .../StandardMinMaxLinearEquationSolver.cpp | 2 +- .../modelchecker/MdpPrctlModelCheckerTest.cpp | 17 + 8 files changed, 313 insertions(+), 11 deletions(-) diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 15254ead1..7141d0eb4 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -21,7 +21,7 @@ namespace storm { const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch"}; + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); @@ -50,6 +50,8 @@ namespace storm { return storm::solver::MinMaxMethod::LinearProgramming; } else if (minMaxEquationSolvingTechnique == "ratsearch") { return storm::solver::MinMaxMethod::RationalSearch; + } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { + return storm::solver::MinMaxMethod::QuickValueIteration; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown min/max equation solving technique '" << minMaxEquationSolvingTechnique << "'."); } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 059cdb5a8..3f214176e 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -1,3 +1,5 @@ +#include + #include "storm/solver/IterativeMinMaxLinearEquationSolver.h" #include "storm/utility/ConstantsComparator.h" @@ -46,7 +48,7 @@ namespace storm { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } } - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); return method; } @@ -67,6 +69,9 @@ namespace storm { case MinMaxMethod::RationalSearch: result = solveEquationsRationalSearch(env, dir, x, b); break; + case MinMaxMethod::QuickValueIteration: + result = solveEquationsQuickSoundValueIteration(env, dir, x, b); + break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); } @@ -211,10 +216,8 @@ namespace storm { // Start by getting the requirements of the linear equation solver. LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::RationalSearch) { - if (!this->hasInitialScheduler() && assumeNoInitialScheduler) { - linEqTask = LinearEquationSolverTask::Multiply; - } + if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && assumeNoInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + linEqTask = LinearEquationSolverTask::Multiply; } MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); @@ -250,6 +253,10 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireValidInitialScheduler(); } + } else if (method == MinMaxMethod::QuickValueIteration) { + if (!this->hasUniqueSolution()) { + requirements.requireNoEndComponents(); + } } else { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver."); } @@ -596,6 +603,278 @@ namespace storm { return status == SolverStatus::Converged; } + + template + bool IterativeMinMaxLinearEquationSolver::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + + if (!this->linEqSolverA) { + this->createLinearEquationSolver(env); + this->linEqSolverA->setCachingEnabled(true); + } + + // Allow aliased multiplications. + bool useGaussSeidelMultiplication = this->linEqSolverA->supportsGaussSeidelMultiplication() && env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; + + // Prepare the solution vectors. + assert(x.size() == this->A->getRowGroupCount()); + std::vector *stepBoundedX, *stepBoundedStayProbs, *tmp; + if (useGaussSeidelMultiplication) { + stepBoundedX = &x; + stepBoundedX->assign(this->A->getRowGroupCount(), storm::utility::zero()); + if (!this->auxiliaryRowGroupVector) { + this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); + } else { + this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::one()); + } + stepBoundedStayProbs = this->auxiliaryRowGroupVector.get(); + tmp = nullptr; + } else { + if (!this->auxiliaryRowGroupVector) { + this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::zero()); + } else { + this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::zero()); + } + stepBoundedX = this->auxiliaryRowGroupVector.get(); + if (!this->auxiliaryRowGroupVector2) { + this->auxiliaryRowGroupVector2 = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); + } else { + this->auxiliaryRowGroupVector2->assign(this->A->getRowGroupCount(), storm::utility::one()); + } + stepBoundedStayProbs = this->auxiliaryRowGroupVector2.get(); + tmp = &x; + } + + // Get the precision + bool relative = env.solver().minMax().getRelativeTerminationCriterion(); + ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + if (!relative) { + precision *= storm::utility::convertNumber(2.0); + } + this->startMeasureProgress(); + + // Prepare some data used in the iterations. + // We store the current lower (upper) bound for the minimal (maximal) value occurring at some index (if already found) + // Moreover, we store a decisionValue: When minimizing (maximizing) this is the largest (smallest) possible lower (upper) bound + // for which the performed scheduler decisions are valid. + // All these values might not be available yet. + ValueType currentLowerBound, currentUpperBound, decisionValue; + bool hasCurrentLowerBound(false), hasCurrentUpperBound(false), hasDecisionValue(false); + if (this->hasLowerBound(AbstractEquationSolver::BoundType::Global)) { + currentLowerBound = this->getLowerBound(); + hasCurrentLowerBound = true; + } else if (this->hasLowerBound(AbstractEquationSolver::BoundType::Local)) { + currentLowerBound = *std::min_element(this->getLowerBounds().begin(), this->getLowerBounds().end()); + hasCurrentLowerBound = true; + } + if (this->hasUpperBound(AbstractEquationSolver::BoundType::Global)) { + currentUpperBound = this->getUpperBound(); + hasCurrentUpperBound = true; + } else if (this->hasUpperBound(AbstractEquationSolver::BoundType::Local)) { + currentUpperBound = *std::max_element(this->getUpperBounds().begin(), this->getUpperBounds().end()); + hasCurrentUpperBound = true; + } + + // reduce the number of case distinctions w.r.t. minimizing/maximizing optimization direction + std::function better, betterEqual; + if (minimize(dir)) { + better = std::less(); + betterEqual = std::less_equal(); + } else { + better = std::greater(); + betterEqual = std::greater_equal(); + } + // If minimizing, the primary bound is the lower bound; if maximizing, the primary bound is the upper bound. + ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound; + bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; + + // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. + SolverStatus status = SolverStatus::InProgress; + uint64_t iterations = 0; + std::vector xTmp, yTmp; + uint64_t minIndex(0), maxIndex(0); + uint64_t firstStayProb1Index = 0; + uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; + while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { + + //Perform the iteration step + auto xIt = stepBoundedX->rbegin(); + auto yIt = stepBoundedStayProbs->rbegin(); + auto groupStartIt = this->A->getRowGroupIndices().rbegin(); + ++groupStartIt; + auto groupEndIt = this->A->getRowGroupIndices().rbegin(); + while (groupStartIt != this->A->getRowGroupIndices().rend()) { + // Handle Row Groups of size 1 quickly + if (*groupStartIt + 1 == *groupEndIt) { + *xIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedX) + b[*groupStartIt]; + *yIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedStayProbs); + } else { + // First pass through the group: get the multiplication results + xTmp.clear(); + yTmp.clear(); + for (uint64_t row = *groupStartIt; row < *groupEndIt; ++row) { + xTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedX) + b[row]); + yTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedStayProbs)); + } + + // Second pass: get the best choice + uint64_t bestChoice = 0; + if (hasPrimaryBound) { + // Second pass: get the best choice + ValueType bestValue = xTmp.front() + yTmp.front() * primaryBound; + for (uint64_t choice = 1; choice < xTmp.size(); ++choice) { + ValueType value = xTmp[choice] + yTmp[choice] * primaryBound; + if (betterEqual(value, bestValue) && (value != bestValue || yTmp[choice] < yTmp[bestChoice])) { + bestValue = std::move(value); + bestChoice = choice; + } + } + } else { + // If no bound is known, we implicitly assume a sufficiently large (or low) bound + ValueType bestValue = yTmp.front(); + for (uint64_t choice = 1; choice < xTmp.size(); ++choice) { + ValueType const& value = yTmp[choice]; + if (betterEqual(value, bestValue) && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) { + bestValue = std::move(value); + bestChoice = choice; + } + } + } + *xIt = xTmp[bestChoice]; + *yIt = yTmp[bestChoice]; + + // Third pass: Update the decision value + for (uint64_t choice = 0; choice < xTmp.size(); ++choice) { + if (choice != bestChoice) { + ValueType deltaY = *yIt - yTmp[choice]; + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (xTmp[choice] - *xIt) / deltaY; + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + // std::cout << "Updating decision value to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; + } + } + } + } + } + ++groupStartIt; + ++groupEndIt; + ++xIt; + ++yIt; + } + + // Update bounds and check for convergence + // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state + for (; firstStayProb1Index != stepBoundedStayProbs->size(); ++firstStayProb1Index) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(stepBoundedStayProbs->at(firstStayProb1Index))) { + break; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstStayProb1Index)))) { + break; + } + } + } + if (firstStayProb1Index == stepBoundedStayProbs->size()) { + STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value + // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. + currentLowerBound = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); + currentUpperBound = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); + // Potentially correct the primary bound so that scheduler choices remain valid + if (hasDecisionValue && better(decisionValue, primaryBound)) { + primaryBound = decisionValue; + } + ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence); + // The error made in this iteration + ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound); + // The maximal allowed error (possibly respecting relative precision) + // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. + ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + if (absoluteError <= maxAllowedError) { + // Compute the actual bounds now + auto valIt = stepBoundedX->begin(); + auto valIte = stepBoundedX->end(); + auto probIt = stepBoundedStayProbs->begin(); + for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { + ValueType currentBound = *valIt / (storm::utility::one() - *probIt); + if (currentBound < currentLowerBound) { + minIndex = index; + currentLowerBound = std::move(currentBound); + } else if (currentBound > currentUpperBound) { + maxIndex = index; + currentUpperBound = std::move(currentBound); + } + } + // Potentially correct the primary bound so that scheduler choices remain valid + if (hasDecisionValue && better(decisionValue, primaryBound)) { + primaryBound = decisionValue; + } + hasCurrentUpperBound = true; + hasCurrentLowerBound = true; + absoluteError = stayProb * (currentUpperBound - currentLowerBound); + if (absoluteError <= maxAllowedError) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (this->hasRelevantValues()) { + firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); + } + if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { + status = SolverStatus::Converged; + break; + } else { + absoluteError = stepBoundedStayProbs->at(firstIndexViolatingConvergence) * (currentUpperBound - currentLowerBound); + maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + if (absoluteError > maxAllowedError) { + // not converged yet + break; + } + } + } + } + } + } + + + // Update environment variables. + ++iterations; + // TODO: Implement custom termination criterion. We would need to add our errors to the stepBoundedX values (only if in second phase) + status = updateStatusIfNotConverged(status, *stepBoundedX, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); + + // Potentially show progress. + this->showProgressIterative(iterations); + } + + reportStatus(status, iterations); + + STORM_LOG_WARN_COND(hasCurrentLowerBound && hasCurrentUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); + + // Finally set up the solution vector + ValueType meanBound = (currentUpperBound + currentLowerBound) / storm::utility::convertNumber(2.0); + storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = std::vector(this->A->getRowGroupCount()); + this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); + } + STORM_LOG_INFO("Quick Value Iteration terminated with lower value bound " + << (hasCurrentLowerBound ? currentLowerBound : storm::utility::zero()) << (hasCurrentLowerBound ? "" : "(none)") + << " and upper value bound " + << (hasCurrentUpperBound ? currentUpperBound : storm::utility::zero()) << (hasCurrentUpperBound ? "" : "(none)") + << ". Decision value is " + << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") + << "."); + if (!this->isCachingEnabled()) { + clearCache(); + } + + return status == SolverStatus::Converged; + } + template bool IterativeMinMaxLinearEquationSolver::isSolution(storm::OptimizationDirection dir, storm::storage::SparseMatrix const& matrix, std::vector const& values, std::vector const& b) { storm::utility::ConstantsComparator comparator; @@ -954,7 +1233,7 @@ namespace storm { STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); auto method = env.solver().minMax().getMethod(); - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone()); result->setRequirementsChecked(this->isRequirementsCheckedSet()); diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index f29fa0318..fac4555fc 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -38,6 +38,8 @@ namespace storm { bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; template diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index a061c451d..c250c17a0 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -196,7 +196,7 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::Topological) { result = std::make_unique>(); @@ -213,7 +213,7 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::LinearProgramming) { result = std::make_unique>(std::make_unique>(), std::make_unique>()); diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 7b8e19c65..3461f2bc6 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -14,6 +14,8 @@ namespace storm { return "topological"; case MinMaxMethod::RationalSearch: return "ratsearch"; + case MinMaxMethod::QuickValueIteration: + return "QuickValueIteration"; } return "invalid"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index 446e173bd..fc9750611 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -6,7 +6,7 @@ namespace storm { namespace solver { - ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch) + ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, QuickValueIteration) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index d396575db..853f84cf3 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -111,7 +111,7 @@ namespace storm { std::unique_ptr> StandardMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { result = std::make_unique>(this->linearEquationSolverFactory->clone()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The selected min max method is not supported by this solver."); diff --git a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp index 5c37d24d0..99cf434f6 100644 --- a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp @@ -55,6 +55,22 @@ namespace { return env; } }; + class SparseDoubleQuickValueIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::Mdp ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setForceSoundness(true); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::QuickValueIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); + env.solver().minMax().setRelativeTerminationCriterion(false); + return env; + } + }; class SparseRationalPolicyIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models @@ -283,6 +299,7 @@ namespace { typedef ::testing::Types< SparseDoubleValueIterationEnvironment, SparseDoubleSoundValueIterationEnvironment, + SparseDoubleQuickValueIterationEnvironment, SparseRationalPolicyIterationEnvironment, SparseRationalRationalSearchEnvironment, HybridCuddDoubleValueIterationEnvironment, From f65bb48195db82a0231f722678096f0afaaa00c5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 2 Jan 2018 17:21:56 +0100 Subject: [PATCH 061/647] fixed missing initialized value in progressMeasurement --- src/storm/utility/ProgressMeasurement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/utility/ProgressMeasurement.cpp b/src/storm/utility/ProgressMeasurement.cpp index db471035f..ff9abdc53 100644 --- a/src/storm/utility/ProgressMeasurement.cpp +++ b/src/storm/utility/ProgressMeasurement.cpp @@ -9,7 +9,7 @@ namespace storm { namespace utility { - ProgressMeasurement::ProgressMeasurement(std::string const& itemName) : itemName(itemName) { + ProgressMeasurement::ProgressMeasurement(std::string const& itemName) : itemName(itemName), maxCount(0) { delay = storm::settings::getModule().getShowProgressDelay(); } From 116bd58b226ded90daf89cdcd7f472a289a46d6a Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 2 Jan 2018 17:22:30 +0100 Subject: [PATCH 062/647] log improvements + minor bugfixes for qvi --- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 3f214176e..dfda44387 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -257,6 +257,7 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireNoEndComponents(); } + requirements.requireBounds(); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver."); } @@ -686,6 +687,7 @@ namespace storm { // If minimizing, the primary bound is the lower bound; if maximizing, the primary bound is the upper bound. ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound; bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; + STORM_LOG_INFO_COND(!hasPrimaryBound, "Initial bound on the result is " << primaryBound); // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. SolverStatus status = SolverStatus::InProgress; @@ -733,7 +735,7 @@ namespace storm { ValueType bestValue = yTmp.front(); for (uint64_t choice = 1; choice < xTmp.size(); ++choice) { ValueType const& value = yTmp[choice]; - if (betterEqual(value, bestValue) && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) { + if (value >= bestValue && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) { bestValue = std::move(value); bestChoice = choice; } @@ -749,7 +751,7 @@ namespace storm { if (deltaY > storm::utility::zero()) { ValueType newDecisionValue = (xTmp[choice] - *xIt) / deltaY; if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { - // std::cout << "Updating decision value to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; + // std::cout << "Updating decision value in Iteration " << iterations << " to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; decisionValue = std::move(newDecisionValue); hasDecisionValue = true; } From 7aac41d8f2c089a7fb1d6c27dbe2dc721e308c77 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 3 Jan 2018 09:00:37 +0100 Subject: [PATCH 063/647] optimized qvi implementation --- .../IterativeMinMaxLinearEquationSolver.cpp | 180 +++++++++++------- 1 file changed, 111 insertions(+), 69 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index dfda44387..aa1925579 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -9,6 +9,7 @@ #include "storm/utility/KwekMehlhorn.h" #include "storm/utility/NumberTraits.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" @@ -607,43 +608,21 @@ namespace storm { template bool IterativeMinMaxLinearEquationSolver::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - if (!this->linEqSolverA) { this->createLinearEquationSolver(env); this->linEqSolverA->setCachingEnabled(true); } - // Allow aliased multiplications. - bool useGaussSeidelMultiplication = this->linEqSolverA->supportsGaussSeidelMultiplication() && env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; - // Prepare the solution vectors. assert(x.size() == this->A->getRowGroupCount()); - std::vector *stepBoundedX, *stepBoundedStayProbs, *tmp; - if (useGaussSeidelMultiplication) { - stepBoundedX = &x; - stepBoundedX->assign(this->A->getRowGroupCount(), storm::utility::zero()); - if (!this->auxiliaryRowGroupVector) { - this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); - } else { - this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::one()); - } - stepBoundedStayProbs = this->auxiliaryRowGroupVector.get(); - tmp = nullptr; + std::vector& stepBoundedX = x; + stepBoundedX.assign(this->A->getRowGroupCount(), storm::utility::zero()); + if (!this->auxiliaryRowGroupVector) { + this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); } else { - if (!this->auxiliaryRowGroupVector) { - this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::zero()); - } else { - this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::zero()); - } - stepBoundedX = this->auxiliaryRowGroupVector.get(); - if (!this->auxiliaryRowGroupVector2) { - this->auxiliaryRowGroupVector2 = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); - } else { - this->auxiliaryRowGroupVector2->assign(this->A->getRowGroupCount(), storm::utility::one()); - } - stepBoundedStayProbs = this->auxiliaryRowGroupVector2.get(); - tmp = &x; + this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::one()); } + std::vector& stepBoundedStayProbs = *this->auxiliaryRowGroupVector; // Get the precision bool relative = env.solver().minMax().getRelativeTerminationCriterion(); @@ -689,41 +668,98 @@ namespace storm { bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; STORM_LOG_INFO_COND(!hasPrimaryBound, "Initial bound on the result is " << primaryBound); + storm::utility::Stopwatch sw1, sw2, sw3, sw4, sw5; // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. SolverStatus status = SolverStatus::InProgress; uint64_t iterations = 0; + std::vector xTmp, yTmp; + uint64_t minIndex(0), maxIndex(0); uint64_t firstStayProb1Index = 0; uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { //Perform the iteration step - auto xIt = stepBoundedX->rbegin(); - auto yIt = stepBoundedStayProbs->rbegin(); + auto xIt = stepBoundedX.rbegin(); + auto yIt = stepBoundedStayProbs.rbegin(); auto groupStartIt = this->A->getRowGroupIndices().rbegin(); ++groupStartIt; auto groupEndIt = this->A->getRowGroupIndices().rbegin(); while (groupStartIt != this->A->getRowGroupIndices().rend()) { - // Handle Row Groups of size 1 quickly - if (*groupStartIt + 1 == *groupEndIt) { - *xIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedX) + b[*groupStartIt]; - *yIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedStayProbs); - } else { - // First pass through the group: get the multiplication results + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + uint64_t rowEnd = *groupEndIt; + ValueType xBest = b[row]; + ValueType yBest = storm::utility::zero(); + for (auto const& entry : this->A->getRow(row)) { + xBest += entry.getValue() * stepBoundedX[entry.getColumn()]; + yBest += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; + } + ++row; + // Only do more work if there are still rows in this row group + if (row != rowEnd) { xTmp.clear(); yTmp.clear(); - for (uint64_t row = *groupStartIt; row < *groupEndIt; ++row) { - xTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedX) + b[row]); - yTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedStayProbs)); + if (hasPrimaryBound) { + ValueType bestValue = xBest + yBest * primaryBound; + for (;row < *groupEndIt; ++row) { + // Get the multiplication results + ValueType xi = b[row]; + ValueType yi = storm::utility::zero(); + for (auto const& entry : this->A->getRow(row)) { + xi += entry.getValue() * stepBoundedX[entry.getColumn()]; + yi += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; + } + // Update the best choice + ValueType currentValue = xi + yi * primaryBound; + if (better(currentValue, bestValue)) { + if (yBest < yi) { + xTmp.push_back(std::move(xBest)); + yTmp.push_back(std::move(yBest)); + } + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (yBest > yi) { + if (currentValue == bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp.push_back(std::move(xi)); + yTmp.push_back(std::move(yi)); + } + } + } + } else { + for (;row < *groupEndIt; ++row) { + // Get the multiplication results + ValueType xi = b[row]; + ValueType yi = storm::utility::zero(); + for (auto const& entry : this->A->getRow(row)) { + xi += entry.getValue() * stepBoundedX[entry.getColumn()]; + yi += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; + } + // Update the best choice + if (yi > yBest || (yi == yBest && better(xi, xBest))) { + xTmp.push_back(std::move(xBest)); + yTmp.push_back(std::move(yBest)); + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp.push_back(std::move(xi)); + yTmp.push_back(std::move(yi)); + } + } } + /* // Second pass: get the best choice uint64_t bestChoice = 0; if (hasPrimaryBound) { // Second pass: get the best choice ValueType bestValue = xTmp.front() + yTmp.front() * primaryBound; - for (uint64_t choice = 1; choice < xTmp.size(); ++choice) { + for (uint64_t choice = 1; choice < groupSize; ++choice) { ValueType value = xTmp[choice] + yTmp[choice] * primaryBound; if (betterEqual(value, bestValue) && (value != bestValue || yTmp[choice] < yTmp[bestChoice])) { bestValue = std::move(value); @@ -733,7 +769,7 @@ namespace storm { } else { // If no bound is known, we implicitly assume a sufficiently large (or low) bound ValueType bestValue = yTmp.front(); - for (uint64_t choice = 1; choice < xTmp.size(); ++choice) { + for (uint64_t choice = 1; choice < groupSize; ++choice) { ValueType const& value = yTmp[choice]; if (value >= bestValue && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) { bestValue = std::move(value); @@ -743,22 +779,24 @@ namespace storm { } *xIt = xTmp[bestChoice]; *yIt = yTmp[bestChoice]; + */ - // Third pass: Update the decision value - for (uint64_t choice = 0; choice < xTmp.size(); ++choice) { - if (choice != bestChoice) { - ValueType deltaY = *yIt - yTmp[choice]; - if (deltaY > storm::utility::zero()) { - ValueType newDecisionValue = (xTmp[choice] - *xIt) / deltaY; - if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + // Update the decision value + for (auto xTmpIt = xTmp.begin(), yTmpIt = yTmp.begin(); xTmpIt != xTmp.end(); ++xTmpIt, ++yTmpIt) { + ValueType deltaY = yBest - (*yTmpIt); + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (*xTmpIt - xBest) / deltaY; + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { // std::cout << "Updating decision value in Iteration " << iterations << " to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; - decisionValue = std::move(newDecisionValue); - hasDecisionValue = true; - } + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; } } } } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + ++groupStartIt; ++groupEndIt; ++xIt; @@ -767,39 +805,39 @@ namespace storm { // Update bounds and check for convergence // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state - for (; firstStayProb1Index != stepBoundedStayProbs->size(); ++firstStayProb1Index) { + for (; firstStayProb1Index != stepBoundedStayProbs.size(); ++firstStayProb1Index) { static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbs->at(firstStayProb1Index))) { + if (storm::utility::isOne(stepBoundedStayProbs[firstStayProb1Index])) { break; } } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstStayProb1Index)))) { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs[firstStayProb1Index]))) { break; } } } - if (firstStayProb1Index == stepBoundedStayProbs->size()) { - STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + if (firstStayProb1Index == stepBoundedStayProbs.size()) { + STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs.begin(), stepBoundedStayProbs.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - currentLowerBound = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); - currentUpperBound = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); + currentLowerBound = stepBoundedX[minIndex] / (storm::utility::one() - stepBoundedStayProbs[minIndex]); + currentUpperBound = stepBoundedX[maxIndex] / (storm::utility::one() - stepBoundedStayProbs[maxIndex]); // Potentially correct the primary bound so that scheduler choices remain valid if (hasDecisionValue && better(decisionValue, primaryBound)) { primaryBound = decisionValue; } - ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence); + ValueType const& stayProb = stepBoundedStayProbs[firstIndexViolatingConvergence]; // The error made in this iteration ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound); // The maximal allowed error (possibly respecting relative precision) // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. - ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + ValueType maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; if (absoluteError <= maxAllowedError) { // Compute the actual bounds now - auto valIt = stepBoundedX->begin(); - auto valIte = stepBoundedX->end(); - auto probIt = stepBoundedStayProbs->begin(); + auto valIt = stepBoundedX.begin(); + auto valIte = stepBoundedX.end(); + auto probIt = stepBoundedStayProbs.begin(); for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { ValueType currentBound = *valIt / (storm::utility::one() - *probIt); if (currentBound < currentLowerBound) { @@ -824,12 +862,12 @@ namespace storm { if (this->hasRelevantValues()) { firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); } - if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { + if (firstIndexViolatingConvergence == stepBoundedStayProbs.size()) { status = SolverStatus::Converged; break; } else { - absoluteError = stepBoundedStayProbs->at(firstIndexViolatingConvergence) * (currentUpperBound - currentLowerBound); - maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; + absoluteError = stepBoundedStayProbs[firstIndexViolatingConvergence] * (currentUpperBound - currentLowerBound); + maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; if (absoluteError > maxAllowedError) { // not converged yet break; @@ -840,23 +878,27 @@ namespace storm { } } - // Update environment variables. ++iterations; // TODO: Implement custom termination criterion. We would need to add our errors to the stepBoundedX values (only if in second phase) - status = updateStatusIfNotConverged(status, *stepBoundedX, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); + status = updateStatusIfNotConverged(status, stepBoundedX, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); // Potentially show progress. this->showProgressIterative(iterations); } + std::cout << "sw1: " << sw1 << std::endl; + std::cout << "sw2: " << sw2 << std::endl; + std::cout << "sw3: " << sw3 << std::endl; + std::cout << "sw4: " << sw4 << std::endl; + std::cout << "sw5: " << sw5 << std::endl; reportStatus(status, iterations); STORM_LOG_WARN_COND(hasCurrentLowerBound && hasCurrentUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); // Finally set up the solution vector ValueType meanBound = (currentUpperBound + currentLowerBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + storm::utility::vector::applyPointwise(stepBoundedX, stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { From 7cd7cd60a76ccddfcb9d243d776efe34c731cb2d Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 3 Jan 2018 13:29:12 +0100 Subject: [PATCH 064/647] Added new minmax settings: force computation of a priori bouds and tweak the qvi restart heuristic --- .../solver/MinMaxSolverEnvironment.cpp | 28 ++++++++++++++++++- .../solver/MinMaxSolverEnvironment.h | 10 ++++++- .../modules/MinMaxEquationSolverSettings.cpp | 20 +++++++++++++ .../modules/MinMaxEquationSolverSettings.h | 17 +++++++++++ .../solver/LpMinMaxLinearEquationSolver.cpp | 4 +++ .../SymbolicMinMaxLinearEquationSolver.cpp | 4 +++ 6 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index ed4b6145b..d44eac259 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -17,12 +17,14 @@ namespace storm { considerRelativeTerminationCriterion = minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); multiplicationStyle = minMaxSettings.getValueIterationMultiplicationStyle(); + forceBounds = minMaxSettings.isForceBoundsSet(); + qviRestartThreshold = minMaxSettings.getQviRestartThreshold(); + qviRestartMaxIterations = minMaxSettings.getQviRestartMaxIterations(); } MinMaxSolverEnvironment::~MinMaxSolverEnvironment() { // Intentionally left empty } - storm::solver::MinMaxMethod const& MinMaxSolverEnvironment::getMethod() const { return minMaxMethod; @@ -69,6 +71,30 @@ namespace storm { multiplicationStyle = value; } + bool MinMaxSolverEnvironment::isForceBoundsSet() const { + return forceBounds; + } + + void MinMaxSolverEnvironment::setForceBounds(bool value) { + forceBounds = value; + } + + storm::RationalNumber MinMaxSolverEnvironment::getQviRestartThreshold() const { + return qviRestartThreshold; + } + + void MinMaxSolverEnvironment::setQviRestartThreshold(storm::RationalNumber value) { + qviRestartThreshold = value; + } + + uint64_t MinMaxSolverEnvironment::getQviRestartMaxIterations() const { + return qviRestartMaxIterations; + } + + void MinMaxSolverEnvironment::setQviRestartMaxIterations(uint64_t value) { + qviRestartMaxIterations = value; + } + } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.h b/src/storm/environment/solver/MinMaxSolverEnvironment.h index 6cca14221..999ed18bd 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.h +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.h @@ -25,6 +25,12 @@ namespace storm { void setRelativeTerminationCriterion(bool value); storm::solver::MultiplicationStyle const& getMultiplicationStyle() const; void setMultiplicationStyle(storm::solver::MultiplicationStyle value); + bool isForceBoundsSet() const; + void setForceBounds(bool value); + storm::RationalNumber getQviRestartThreshold() const; + void setQviRestartThreshold(storm::RationalNumber value); + uint64_t getQviRestartMaxIterations() const; + void setQviRestartMaxIterations(uint64_t value); private: storm::solver::MinMaxMethod minMaxMethod; @@ -33,7 +39,9 @@ namespace storm { storm::RationalNumber precision; bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle multiplicationStyle; - + bool forceBounds; + storm::RationalNumber qviRestartThreshold; + uint64_t qviRestartMaxIterations; }; } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 7141d0eb4..35145e829 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -19,6 +19,8 @@ namespace storm { const std::string MinMaxEquationSolverSettings::absoluteOptionName = "absolute"; const std::string MinMaxEquationSolverSettings::lraMethodOptionName = "lramethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; + const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; + const std::string MinMaxEquationSolverSettings::quickValueIterationRestartOptionName = "qvirestart"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; @@ -38,6 +40,12 @@ namespace storm { std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, minmax solver always require that a priori bounds for the solution are computed.").build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, quickValueIterationRestartOptionName, false, "Controls when a restart of quick value iteration is triggered.") + .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "The minimal (relative) bound improvement that triggers a restart").addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorIncluding(0.0, 1.0)).setDefaultValueDouble(0.5).build()) + .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("maxiters", "The maximal number of iterations within which a restart can be triggered.").setDefaultValueUnsignedInteger(300).build()).build()); } storm::solver::MinMaxMethod MinMaxEquationSolverSettings::getMinMaxEquationSolvingMethod() const { @@ -108,6 +116,18 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool MinMaxEquationSolverSettings::isForceBoundsSet() const { + return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); + } + + double MinMaxEquationSolverSettings::getQviRestartThreshold() const { + return this->getOption(quickValueIterationRestartOptionName).getArgumentByName("threshold").getValueAsDouble(); + } + + uint_fast64_t MinMaxEquationSolverSettings::getQviRestartMaxIterations() const { + return this->getOption(quickValueIterationRestartOptionName).getArgumentByName("maxiters").getValueAsUnsignedInteger(); + } + } } } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index bc9697476..eeb60be4e 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -97,6 +97,21 @@ namespace storm { */ storm::solver::MultiplicationStyle getValueIterationMultiplicationStyle() const; + /*! + * Retrieves whether the force bounds option has been set. + */ + bool isForceBoundsSet() const; + + /*! + * Retrieves the restart threshold for quick value iteration + */ + double getQviRestartThreshold() const; + + /*! + * Retrieves the maximal number of iterations within which a restart of quick value iteration can be triggered. + */ + uint_fast64_t getQviRestartMaxIterations() const; + // The name of the module. static const std::string moduleName; @@ -108,6 +123,8 @@ namespace storm { static const std::string absoluteOptionName; static const std::string lraMethodOptionName; static const std::string valueIterationMultiplicationStyleOptionName; + static const std::string forceBoundsOptionName; + static const std::string quickValueIterationRestartOptionName; }; } diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp index 80668c4fc..2067c7949 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp @@ -120,6 +120,10 @@ namespace storm { requirements.requireNoEndComponents(); } + if (env.solver().minMax().isForceBoundsSet()) { + requirements.requireBounds(); + } + return requirements; } diff --git a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp index b599face7..b9f8551c3 100644 --- a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp @@ -458,6 +458,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "The selected min max technique is not supported by this solver."); } + if (env.solver().minMax().isForceBoundsSet()) { + requirements.requireBounds(); + } + return requirements; } From 80219e4a2d3f8a8d60df7c4198bd2e5d141e9711 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 3 Jan 2018 13:38:31 +0100 Subject: [PATCH 065/647] quick value iteration restart --- .../IterativeMinMaxLinearEquationSolver.cpp | 118 ++++++++++-------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index aa1925579..c4c253282 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -258,11 +258,13 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireNoEndComponents(); } - requirements.requireBounds(); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver."); } + if (env.solver().minMax().isForceBoundsSet()) { + requirements.requireBounds(); + } return requirements; } @@ -632,6 +634,9 @@ namespace storm { } this->startMeasureProgress(); + uint64_t restartMaxIterations = env.solver().minMax().getQviRestartMaxIterations(); + ValueType restartThreshold = storm::utility::convertNumber(env.solver().minMax().getQviRestartThreshold()); + // Prepare some data used in the iterations. // We store the current lower (upper) bound for the minimal (maximal) value occurring at some index (if already found) // Moreover, we store a decisionValue: When minimizing (maximizing) this is the largest (smallest) possible lower (upper) bound @@ -667,8 +672,8 @@ namespace storm { ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound; bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; STORM_LOG_INFO_COND(!hasPrimaryBound, "Initial bound on the result is " << primaryBound); + ValueType& secondaryBound = minimize(dir) ? currentUpperBound : currentLowerBound; - storm::utility::Stopwatch sw1, sw2, sw3, sw4, sw5; // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. SolverStatus status = SolverStatus::InProgress; uint64_t iterations = 0; @@ -676,6 +681,11 @@ namespace storm { std::vector xTmp, yTmp; uint64_t minIndex(0), maxIndex(0); + uint64_t& primaryIndex = minimize(dir) ? minIndex : maxIndex; + uint64_t& secondaryIndex = minimize(dir) ? maxIndex : minIndex; + bool primaryBoundIsDecisionValue = false; + ValueType improvedPrimaryBound; + bool hasImprovedPrimaryBound = false; uint64_t firstStayProb1Index = 0; uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { @@ -753,34 +763,6 @@ namespace storm { } } - /* - // Second pass: get the best choice - uint64_t bestChoice = 0; - if (hasPrimaryBound) { - // Second pass: get the best choice - ValueType bestValue = xTmp.front() + yTmp.front() * primaryBound; - for (uint64_t choice = 1; choice < groupSize; ++choice) { - ValueType value = xTmp[choice] + yTmp[choice] * primaryBound; - if (betterEqual(value, bestValue) && (value != bestValue || yTmp[choice] < yTmp[bestChoice])) { - bestValue = std::move(value); - bestChoice = choice; - } - } - } else { - // If no bound is known, we implicitly assume a sufficiently large (or low) bound - ValueType bestValue = yTmp.front(); - for (uint64_t choice = 1; choice < groupSize; ++choice) { - ValueType const& value = yTmp[choice]; - if (value >= bestValue && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) { - bestValue = std::move(value); - bestChoice = choice; - } - } - } - *xIt = xTmp[bestChoice]; - *yIt = yTmp[bestChoice]; - */ - // Update the decision value for (auto xTmpIt = xTmp.begin(), yTmpIt = yTmp.begin(); xTmpIt != xTmp.end(); ++xTmpIt, ++yTmpIt) { ValueType deltaY = yBest - (*yTmpIt); @@ -819,42 +801,64 @@ namespace storm { } if (firstStayProb1Index == stepBoundedStayProbs.size()) { STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs.begin(), stepBoundedStayProbs.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); - // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value - // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - currentLowerBound = stepBoundedX[minIndex] / (storm::utility::one() - stepBoundedStayProbs[minIndex]); - currentUpperBound = stepBoundedX[maxIndex] / (storm::utility::one() - stepBoundedStayProbs[maxIndex]); - // Potentially correct the primary bound so that scheduler choices remain valid - if (hasDecisionValue && better(decisionValue, primaryBound)) { - primaryBound = decisionValue; - } + // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value ValueType const& stayProb = stepBoundedStayProbs[firstIndexViolatingConvergence]; - // The error made in this iteration - ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound); // The maximal allowed error (possibly respecting relative precision) // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. ValueType maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; - if (absoluteError <= maxAllowedError) { + // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. + secondaryBound = stepBoundedX[secondaryIndex] / (storm::utility::one() - stepBoundedStayProbs[secondaryIndex]); + bool computeActualBounds; + if (primaryBoundIsDecisionValue) { + improvedPrimaryBound = stepBoundedX[primaryIndex] + primaryBound * stepBoundedStayProbs[primaryIndex]; + assert(better(primaryBound, improvedPrimaryBound)); + computeActualBounds = iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound); + } else { + primaryBound = stepBoundedX[primaryIndex] / (storm::utility::one() - stepBoundedStayProbs[primaryIndex]); + computeActualBounds = hasDecisionValue && better(decisionValue, primaryBound); + } + + computeActualBounds = computeActualBounds || stayProb * (currentUpperBound - currentLowerBound) <= maxAllowedError; + + if (computeActualBounds) { // Compute the actual bounds now auto valIt = stepBoundedX.begin(); auto valIte = stepBoundedX.end(); auto probIt = stepBoundedStayProbs.begin(); for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { ValueType currentBound = *valIt / (storm::utility::one() - *probIt); - if (currentBound < currentLowerBound) { - minIndex = index; - currentLowerBound = std::move(currentBound); - } else if (currentBound > currentUpperBound) { - maxIndex = index; - currentUpperBound = std::move(currentBound); + if (primaryBoundIsDecisionValue) { + ValueType currentImprovedBound = *valIt + primaryBound * (*probIt); + if (better(currentImprovedBound, improvedPrimaryBound)) { + primaryIndex = index; + improvedPrimaryBound = std::move(currentImprovedBound); + } + if (better(secondaryBound, currentBound)) { + secondaryIndex = index; + secondaryBound = std::move(currentBound); + } + } else { + if (currentBound < currentLowerBound) { + minIndex = index; + currentLowerBound = std::move(currentBound); + } else if (currentBound > currentUpperBound) { + maxIndex = index; + currentUpperBound = std::move(currentBound); + } } } + if (primaryBoundIsDecisionValue) { + hasImprovedPrimaryBound = true; + } // Potentially correct the primary bound so that scheduler choices remain valid - if (hasDecisionValue && better(decisionValue, primaryBound)) { + if (!primaryBoundIsDecisionValue && hasDecisionValue && better(decisionValue, primaryBound)) { primaryBound = decisionValue; + primaryBoundIsDecisionValue = true; } hasCurrentUpperBound = true; hasCurrentLowerBound = true; - absoluteError = stayProb * (currentUpperBound - currentLowerBound); + // Check whether the desired precision is reached + ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound); if (absoluteError <= maxAllowedError) { // The current index satisfies the desired bound. We now move to the next index that violates it while (true) { @@ -875,6 +879,17 @@ namespace storm { } } } + // Check whether we should restart + if (primaryBoundIsDecisionValue && hasImprovedPrimaryBound && iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound)) { + STORM_LOG_INFO("Restarting QVI after " << iterations << " iterations. Improved bound from " << primaryBound << " to " << improvedPrimaryBound << "."); + stepBoundedStayProbs.assign(this->A->getRowGroupCount(), storm::utility::one()); + stepBoundedX.assign(this->A->getRowGroupCount(), storm::utility::zero()); + primaryBound = improvedPrimaryBound; + hasDecisionValue = false; + primaryBoundIsDecisionValue = false; + firstStayProb1Index = 0; + firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; + } } } @@ -887,11 +902,6 @@ namespace storm { this->showProgressIterative(iterations); } - std::cout << "sw1: " << sw1 << std::endl; - std::cout << "sw2: " << sw2 << std::endl; - std::cout << "sw3: " << sw3 << std::endl; - std::cout << "sw4: " << sw4 << std::endl; - std::cout << "sw5: " << sw5 << std::endl; reportStatus(status, iterations); STORM_LOG_WARN_COND(hasCurrentLowerBound && hasCurrentUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); From c81c7b0be5d87a696c8917d9e489660d10237604 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 4 Jan 2018 09:28:55 +0100 Subject: [PATCH 066/647] Fixed issue with restarting --- .../IterativeMinMaxLinearEquationSolver.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index c4c253282..87f3b622f 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -671,7 +671,8 @@ namespace storm { // If minimizing, the primary bound is the lower bound; if maximizing, the primary bound is the upper bound. ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound; bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; - STORM_LOG_INFO_COND(!hasPrimaryBound, "Initial bound on the result is " << primaryBound); + STORM_LOG_INFO_COND(!hasCurrentLowerBound, "Initial lower bound on the result is " << currentLowerBound); + STORM_LOG_INFO_COND(!hasCurrentUpperBound, "Initial upper bound on the result is " << currentUpperBound); ValueType& secondaryBound = minimize(dir) ? currentUpperBound : currentLowerBound; // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. @@ -806,6 +807,8 @@ namespace storm { // The maximal allowed error (possibly respecting relative precision) // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. ValueType maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; + ValueType oldLowerBound = currentLowerBound; + ValueType oldUpperBound = currentUpperBound; // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. secondaryBound = stepBoundedX[secondaryIndex] / (storm::utility::one() - stepBoundedStayProbs[secondaryIndex]); bool computeActualBounds; @@ -817,7 +820,13 @@ namespace storm { primaryBound = stepBoundedX[primaryIndex] / (storm::utility::one() - stepBoundedStayProbs[primaryIndex]); computeActualBounds = hasDecisionValue && better(decisionValue, primaryBound); } - + // If the old bounds where tighter, use them instead. + if (hasCurrentLowerBound && oldLowerBound > currentLowerBound) { + currentLowerBound = oldLowerBound; + } + if (hasCurrentUpperBound && oldUpperBound < currentUpperBound) { + currentUpperBound = oldUpperBound; + } computeActualBounds = computeActualBounds || stayProb * (currentUpperBound - currentLowerBound) <= maxAllowedError; if (computeActualBounds) { @@ -850,6 +859,13 @@ namespace storm { if (primaryBoundIsDecisionValue) { hasImprovedPrimaryBound = true; } + // If the old bounds where tighter, use them instead. + if (hasCurrentLowerBound && oldLowerBound > currentLowerBound) { + currentLowerBound = oldLowerBound; + } + if (hasCurrentUpperBound && oldUpperBound < currentUpperBound) { + currentUpperBound = oldUpperBound; + } // Potentially correct the primary bound so that scheduler choices remain valid if (!primaryBoundIsDecisionValue && hasDecisionValue && better(decisionValue, primaryBound)) { primaryBound = decisionValue; From 02152587091bdd60ddfa3724bd5315c68364a009 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 5 Jan 2018 14:18:22 +0100 Subject: [PATCH 067/647] made qvi implementation a little bit more readable --- .../IterativeMinMaxLinearEquationSolver.cpp | 525 ++++++++++-------- 1 file changed, 290 insertions(+), 235 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 87f3b622f..af83589ae 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -607,125 +607,99 @@ namespace storm { return status == SolverStatus::Converged; } - template - bool IterativeMinMaxLinearEquationSolver::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + class QuickValueIterationHelper { + public: + QuickValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + restart(); } - - // Prepare the solution vectors. - assert(x.size() == this->A->getRowGroupCount()); - std::vector& stepBoundedX = x; - stepBoundedX.assign(this->A->getRowGroupCount(), storm::utility::zero()); - if (!this->auxiliaryRowGroupVector) { - this->auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount(), storm::utility::one()); - } else { - this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::one()); - } - std::vector& stepBoundedStayProbs = *this->auxiliaryRowGroupVector; - - // Get the precision - bool relative = env.solver().minMax().getRelativeTerminationCriterion(); - ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - if (!relative) { - precision *= storm::utility::convertNumber(2.0); + + void restart() { + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + hasDecisionValue = false; + decisionValueBlocks = false; + convergencePhase1 = true; + firstIndexViolatingConvergence = 0; } - this->startMeasureProgress(); - uint64_t restartMaxIterations = env.solver().minMax().getQviRestartMaxIterations(); - ValueType restartThreshold = storm::utility::convertNumber(env.solver().minMax().getQviRestartThreshold()); + void setLowerBound(ValueType const& value) { + hasLowerBound = true; + lowerBound = value; + } - // Prepare some data used in the iterations. - // We store the current lower (upper) bound for the minimal (maximal) value occurring at some index (if already found) - // Moreover, we store a decisionValue: When minimizing (maximizing) this is the largest (smallest) possible lower (upper) bound - // for which the performed scheduler decisions are valid. - // All these values might not be available yet. - ValueType currentLowerBound, currentUpperBound, decisionValue; - bool hasCurrentLowerBound(false), hasCurrentUpperBound(false), hasDecisionValue(false); - if (this->hasLowerBound(AbstractEquationSolver::BoundType::Global)) { - currentLowerBound = this->getLowerBound(); - hasCurrentLowerBound = true; - } else if (this->hasLowerBound(AbstractEquationSolver::BoundType::Local)) { - currentLowerBound = *std::min_element(this->getLowerBounds().begin(), this->getLowerBounds().end()); - hasCurrentLowerBound = true; + void setUpperBound(ValueType const& value) { + hasUpperBound = true; + upperBound = value; } - if (this->hasUpperBound(AbstractEquationSolver::BoundType::Global)) { - currentUpperBound = this->getUpperBound(); - hasCurrentUpperBound = true; - } else if (this->hasUpperBound(AbstractEquationSolver::BoundType::Local)) { - currentUpperBound = *std::max_element(this->getUpperBounds().begin(), this->getUpperBounds().end()); - hasCurrentUpperBound = true; + + template + bool better(ValueType const& val1, ValueType const& val2) { + return maximize(dir) ? val1 > val2 : val1 < val2; } - // reduce the number of case distinctions w.r.t. minimizing/maximizing optimization direction - std::function better, betterEqual; - if (minimize(dir)) { - better = std::less(); - betterEqual = std::less_equal(); - } else { - better = std::greater(); - betterEqual = std::greater_equal(); + template + ValueType& getPrimaryBound() { + return maximize(dir) ? upperBound : lowerBound; } - // If minimizing, the primary bound is the lower bound; if maximizing, the primary bound is the upper bound. - ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound; - bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound; - STORM_LOG_INFO_COND(!hasCurrentLowerBound, "Initial lower bound on the result is " << currentLowerBound); - STORM_LOG_INFO_COND(!hasCurrentUpperBound, "Initial upper bound on the result is " << currentUpperBound); - ValueType& secondaryBound = minimize(dir) ? currentUpperBound : currentLowerBound; - // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. - SolverStatus status = SolverStatus::InProgress; - uint64_t iterations = 0; + template + bool& hasPrimaryBound() { + return maximize(dir) ? hasUpperBound : hasLowerBound; + } - std::vector xTmp, yTmp; + template + ValueType& getSecondaryBound() { + return maximize(dir) ? lowerBound : upperBound; + } - uint64_t minIndex(0), maxIndex(0); - uint64_t& primaryIndex = minimize(dir) ? minIndex : maxIndex; - uint64_t& secondaryIndex = minimize(dir) ? maxIndex : minIndex; - bool primaryBoundIsDecisionValue = false; - ValueType improvedPrimaryBound; - bool hasImprovedPrimaryBound = false; - uint64_t firstStayProb1Index = 0; - uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; - while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { + template + uint64_t& getPrimaryIndex() { + return maximize(dir) ? maxIndex : minIndex; + } - //Perform the iteration step - auto xIt = stepBoundedX.rbegin(); - auto yIt = stepBoundedStayProbs.rbegin(); - auto groupStartIt = this->A->getRowGroupIndices().rbegin(); + template + uint64_t& getSecondaryIndex() { + return maximize(dir) ? minIndex : maxIndex; + } + + void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, ValueType const& bi, ValueType& xi, ValueType& yi) { + xi = bi; + yi = storm::utility::zero(); + for (auto const& entry : A.getRow(row)) { + xi += entry.getValue() * x[entry.getColumn()]; + yi += entry.getValue() * y[entry.getColumn()]; + } + } + + template + void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; ++groupStartIt; - auto groupEndIt = this->A->getRowGroupIndices().rbegin(); - while (groupStartIt != this->A->getRowGroupIndices().rend()) { + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { // Perform the iteration for the first row in the group uint64_t row = *groupStartIt; - uint64_t rowEnd = *groupEndIt; - ValueType xBest = b[row]; - ValueType yBest = storm::utility::zero(); - for (auto const& entry : this->A->getRow(row)) { - xBest += entry.getValue() * stepBoundedX[entry.getColumn()]; - yBest += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; - } + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); ++row; // Only do more work if there are still rows in this row group - if (row != rowEnd) { + if (row != groupEnd) { xTmp.clear(); yTmp.clear(); - if (hasPrimaryBound) { - ValueType bestValue = xBest + yBest * primaryBound; - for (;row < *groupEndIt; ++row) { + ValueType xi, yi; + if (hasPrimaryBound()) { + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { // Get the multiplication results - ValueType xi = b[row]; - ValueType yi = storm::utility::zero(); - for (auto const& entry : this->A->getRow(row)) { - xi += entry.getValue() * stepBoundedX[entry.getColumn()]; - yi += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; - } - // Update the best choice - ValueType currentValue = xi + yi * primaryBound; - if (better(currentValue, bestValue)) { + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { if (yBest < yi) { + // We need to store the 'old' best value as it might be relevant for the decision value xTmp.push_back(std::move(xBest)); yTmp.push_back(std::move(yBest)); } @@ -733,6 +707,7 @@ namespace storm { yBest = std::move(yi); bestValue = std::move(currentValue); } else if (yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value if (currentValue == bestValue) { xBest = std::move(xi); yBest = std::move(yi); @@ -743,16 +718,10 @@ namespace storm { } } } else { - for (;row < *groupEndIt; ++row) { - // Get the multiplication results - ValueType xi = b[row]; - ValueType yi = storm::utility::zero(); - for (auto const& entry : this->A->getRow(row)) { - xi += entry.getValue() * stepBoundedX[entry.getColumn()]; - yi += entry.getValue() * stepBoundedStayProbs[entry.getColumn()]; - } + for (;row < groupEnd; ++row) { + multiplyRow(row, A, b[row], xi, yi); // Update the best choice - if (yi > yBest || (yi == yBest && better(xi, xBest))) { + if (yi > yBest || (yi == yBest && better(xi, xBest))) { xTmp.push_back(std::move(xBest)); yTmp.push_back(std::move(yBest)); xBest = std::move(xi); @@ -769,7 +738,7 @@ namespace storm { ValueType deltaY = yBest - (*yTmpIt); if (deltaY > storm::utility::zero()) { ValueType newDecisionValue = (*xTmpIt - xBest) / deltaY; - if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { // std::cout << "Updating decision value in Iteration " << iterations << " to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; decisionValue = std::move(newDecisionValue); hasDecisionValue = true; @@ -779,165 +748,251 @@ namespace storm { } *xIt = std::move(xBest); *yIt = std::move(yBest); - - ++groupStartIt; - ++groupEndIt; - ++xIt; - ++yIt; } + } + + bool checkRestartCriterion() { + return false; + // iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound + } + + bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { + return yi * (ub - lb) <= (relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0))); + } + + template + bool checkConvergenceUpdateBounds(uint64_t const& iterations, storm::storage::BitVector const* relevantValues = nullptr) { - // Update bounds and check for convergence - // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state - for (; firstStayProb1Index != stepBoundedStayProbs.size(); ++firstStayProb1Index) { - static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); - if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbs[firstStayProb1Index])) { - break; + if (convergencePhase1) { + if (checkConvergencePhase1()) { + firstIndexViolatingConvergence = 0; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); } } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs[firstStayProb1Index]))) { - break; - } + return false; } } - if (firstStayProb1Index == stepBoundedStayProbs.size()) { - STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs.begin(), stepBoundedStayProbs.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); - // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value - ValueType const& stayProb = stepBoundedStayProbs[firstIndexViolatingConvergence]; - // The maximal allowed error (possibly respecting relative precision) - // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. - ValueType maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; - ValueType oldLowerBound = currentLowerBound; - ValueType oldUpperBound = currentUpperBound; - // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - secondaryBound = stepBoundedX[secondaryIndex] / (storm::utility::one() - stepBoundedStayProbs[secondaryIndex]); - bool computeActualBounds; - if (primaryBoundIsDecisionValue) { - improvedPrimaryBound = stepBoundedX[primaryIndex] + primaryBound * stepBoundedStayProbs[primaryIndex]; - assert(better(primaryBound, improvedPrimaryBound)); - computeActualBounds = iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound); + STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + + // Reaching this point means that we are in Phase 2: + // The difference between lower and upper bound has to be < precision at every (relevant) value + + // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds + + ValueType lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); + ValueType upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); + // Make sure that these candidates are at least as tight as the already known bounds + if (hasLowerBound && lowerBoundCandidate < lowerBound) { + lowerBoundCandidate = lowerBound; + } + if (hasUpperBound && upperBoundCandidate > upperBound) { + upperBoundCandidate = upperBound; + } + bool computeActualBounds = isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate); + if (!computeActualBounds) { + if (decisionValueBlocks) { + ValueType improvedPrimaryBound = x[getPrimaryIndex()] + getPrimaryBound() * y[getPrimaryIndex()]; + assert(better(getPrimaryBound(), improvedPrimaryBound)); + computeActualBounds = checkRestartCriterion(); } else { - primaryBound = stepBoundedX[primaryIndex] / (storm::utility::one() - stepBoundedStayProbs[primaryIndex]); - computeActualBounds = hasDecisionValue && better(decisionValue, primaryBound); + computeActualBounds = hasDecisionValue && better(decisionValue, getPrimaryBound()); + } + } + if (computeActualBounds) { + auto xIt = x.begin(); + auto xIte = x.end(); + auto yIt = y.begin(); + ValueType improvedPrimaryBound; + bool computedImprovedPrimaryBound = false; + for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { + ValueType currentBound = *xIt / (storm::utility::one() - *yIt); + if (decisionValueBlocks) { + ValueType currentImprovedBound = *xIt + getPrimaryBound() * (*yIt); + if (!computedImprovedPrimaryBound || better(currentImprovedBound, improvedPrimaryBound)) { + computedImprovedPrimaryBound = true; + getPrimaryIndex() = index; + improvedPrimaryBound = std::move(currentImprovedBound); + } + if (better(getSecondaryBound(), currentBound)) { + getSecondaryIndex() = index; + getSecondaryBound() = std::move(currentBound); + } + } else { + if (currentBound < lowerBoundCandidate) { + minIndex = index; + lowerBoundCandidate = std::move(currentBound); + } else if (currentBound > upperBoundCandidate) { + maxIndex = index; + upperBoundCandidate = std::move(currentBound); + } + } } - // If the old bounds where tighter, use them instead. - if (hasCurrentLowerBound && oldLowerBound > currentLowerBound) { - currentLowerBound = oldLowerBound; + if ((maximize(dir) || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { + setLowerBound(lowerBoundCandidate); } - if (hasCurrentUpperBound && oldUpperBound < currentUpperBound) { - currentUpperBound = oldUpperBound; + if ((minimize(dir) || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { + setUpperBound(upperBoundCandidate); } - computeActualBounds = computeActualBounds || stayProb * (currentUpperBound - currentLowerBound) <= maxAllowedError; - if (computeActualBounds) { - // Compute the actual bounds now - auto valIt = stepBoundedX.begin(); - auto valIte = stepBoundedX.end(); - auto probIt = stepBoundedStayProbs.begin(); - for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { - ValueType currentBound = *valIt / (storm::utility::one() - *probIt); - if (primaryBoundIsDecisionValue) { - ValueType currentImprovedBound = *valIt + primaryBound * (*probIt); - if (better(currentImprovedBound, improvedPrimaryBound)) { - primaryIndex = index; - improvedPrimaryBound = std::move(currentImprovedBound); - } - if (better(secondaryBound, currentBound)) { - secondaryIndex = index; - secondaryBound = std::move(currentBound); - } - } else { - if (currentBound < currentLowerBound) { - minIndex = index; - currentLowerBound = std::move(currentBound); - } else if (currentBound > currentUpperBound) { - maxIndex = index; - currentUpperBound = std::move(currentBound); - } + // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). + if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { + getPrimaryBound() = decisionValue; + decisionValueBlocks = true; + } + + // Check whether the desired precision is reached + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); } - } - if (primaryBoundIsDecisionValue) { - hasImprovedPrimaryBound = true; - } - // If the old bounds where tighter, use them instead. - if (hasCurrentLowerBound && oldLowerBound > currentLowerBound) { - currentLowerBound = oldLowerBound; - } - if (hasCurrentUpperBound && oldUpperBound < currentUpperBound) { - currentUpperBound = oldUpperBound; - } - // Potentially correct the primary bound so that scheduler choices remain valid - if (!primaryBoundIsDecisionValue && hasDecisionValue && better(decisionValue, primaryBound)) { - primaryBound = decisionValue; - primaryBoundIsDecisionValue = true; - } - hasCurrentUpperBound = true; - hasCurrentLowerBound = true; - // Check whether the desired precision is reached - ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound); - if (absoluteError <= maxAllowedError) { - // The current index satisfies the desired bound. We now move to the next index that violates it - while (true) { - ++firstIndexViolatingConvergence; - if (this->hasRelevantValues()) { - firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); - } - if (firstIndexViolatingConvergence == stepBoundedStayProbs.size()) { - status = SolverStatus::Converged; + if (firstIndexViolatingConvergence == x.size()) { + // Converged! + return true; + } else { + if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // not converged yet break; - } else { - absoluteError = stepBoundedStayProbs[firstIndexViolatingConvergence] * (currentUpperBound - currentLowerBound); - maxAllowedError = relative ? (precision * stepBoundedX[firstIndexViolatingConvergence]) : precision; - if (absoluteError > maxAllowedError) { - // not converged yet - break; - } } } } - // Check whether we should restart - if (primaryBoundIsDecisionValue && hasImprovedPrimaryBound && iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound)) { - STORM_LOG_INFO("Restarting QVI after " << iterations << " iterations. Improved bound from " << primaryBound << " to " << improvedPrimaryBound << "."); - stepBoundedStayProbs.assign(this->A->getRowGroupCount(), storm::utility::one()); - stepBoundedX.assign(this->A->getRowGroupCount(), storm::utility::zero()); - primaryBound = improvedPrimaryBound; - hasDecisionValue = false; - primaryBoundIsDecisionValue = false; - firstStayProb1Index = 0; - firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; - } + } + // Check whether we should restart + if (computedImprovedPrimaryBound && checkRestartCriterion()) { + STORM_LOG_INFO("Restarting QVI after " << iterations << " iterations. Improved bound from " << getPrimaryBound() << " to " << improvedPrimaryBound << "."); + getPrimaryBound() = improvedPrimaryBound; + restart(); } } + return false; + } + + void setSolutionVector() { + STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); + + ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); + STORM_LOG_INFO("Quick Value Iteration terminated with lower value bound " + << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") + << " and upper value bound " + << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") + << ". Decision value is " + << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") + << "."); + + } + + private: + + bool checkConvergencePhase1() { + // Return true if y ('the probability to stay within the matrix') is < 1 at every entry + for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { + return false; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { + return false; + } + } + } + convergencePhase1 = false; + return true; + } + + std::vector& x; + std::vector& y; + std::vector xTmp, yTmp; + + ValueType lowerBound, upperBound, decisionValue; + bool hasLowerBound, hasUpperBound, hasDecisionValue; + uint64_t minIndex, maxIndex; + bool convergencePhase1; + bool decisionValueBlocks; + uint64_t firstIndexViolatingConvergence; + + bool relative; + ValueType precision; + }; + + template + bool IterativeMinMaxLinearEquationSolver::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + + // Prepare the solution vectors. + assert(x.size() == this->A->getRowGroupCount()); + if (!this->auxiliaryRowGroupVector) { + this->auxiliaryRowGroupVector = std::make_unique>(); + } + + QuickValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + + // Get the precision + uint64_t restartMaxIterations = env.solver().minMax().getQviRestartMaxIterations(); + ValueType restartThreshold = storm::utility::convertNumber(env.solver().minMax().getQviRestartThreshold()); + + + // Prepare initial bounds for the solution (if given) + if (this->hasLowerBound(AbstractEquationSolver::BoundType::Global)) { + helper.setLowerBound(this->getLowerBound()); + } else if (this->hasLowerBound(AbstractEquationSolver::BoundType::Local)) { + helper.setLowerBound(*std::min_element(this->getLowerBounds().begin(), this->getLowerBounds().end())); + } + if (this->hasUpperBound(AbstractEquationSolver::BoundType::Global)) { + helper.setUpperBound(this->getUpperBound()); + } else if (this->hasUpperBound(AbstractEquationSolver::BoundType::Local)) { + helper.setUpperBound(*std::max_element(this->getUpperBounds().begin(), this->getUpperBounds().end())); + } + + //STORM_LOG_INFO_COND(!hasCurrentLowerBound, "Initial lower bound on the result is " << currentLowerBound); + //STORM_LOG_INFO_COND(!hasCurrentUpperBound, "Initial upper bound on the result is " << currentUpperBound); + + storm::storage::BitVector const* relevantValuesPtr = nullptr; + if (this->hasRelevantValues()) { + relevantValuesPtr = &this->getRelevantValues(); + } + + SolverStatus status = SolverStatus::InProgress; + this->startMeasureProgress(); + uint64_t iterations = 0; + + while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { + if (minimize(dir)) { + helper.template performIterationStep(*this->A, b); + if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { + status = SolverStatus::Converged; + } + } else { + assert(maximize(dir)); + helper.template performIterationStep(*this->A, b); + if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { + status = SolverStatus::Converged; + } + } + // Update environment variables. ++iterations; // TODO: Implement custom termination criterion. We would need to add our errors to the stepBoundedX values (only if in second phase) - status = updateStatusIfNotConverged(status, stepBoundedX, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); + status = updateStatusIfNotConverged(status, x, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); // Potentially show progress. this->showProgressIterative(iterations); } - - reportStatus(status, iterations); - - STORM_LOG_WARN_COND(hasCurrentLowerBound && hasCurrentUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); - - // Finally set up the solution vector - ValueType meanBound = (currentUpperBound + currentLowerBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(stepBoundedX, stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + helper.setSolutionVector(); // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); + this->A->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); } - STORM_LOG_INFO("Quick Value Iteration terminated with lower value bound " - << (hasCurrentLowerBound ? currentLowerBound : storm::utility::zero()) << (hasCurrentLowerBound ? "" : "(none)") - << " and upper value bound " - << (hasCurrentUpperBound ? currentUpperBound : storm::utility::zero()) << (hasCurrentUpperBound ? "" : "(none)") - << ". Decision value is " - << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") - << "."); + + reportStatus(status, iterations); + if (!this->isCachingEnabled()) { clearCache(); } From fa7f74f0f1cffa5caf9f2eb52cbdf6746b37a12e Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 5 Jan 2018 14:53:24 +0100 Subject: [PATCH 068/647] quicker iterations when the decision value blocks the bound --- .../IterativeMinMaxLinearEquationSolver.cpp | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index af83589ae..71f29a0c0 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -674,6 +674,49 @@ namespace storm { template void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { + if (!decisionValueBlocks) { + performIterationStepUpdateDecisionValue(A, b); + } else { + assert(decisionValue == getPrimaryBound()); + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (currentValue == bestValue && yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + xBest = std::move(xi); + yBest = std::move(yi); + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + } + + template + void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, std::vector const& b) { auto xIt = x.rbegin(); auto yIt = y.rbegin(); auto groupStartIt = A.getRowGroupIndices().rbegin(); From 0d1de8aba9e929e0b6dc71270066e9cff72db018 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 6 Jan 2018 13:23:20 +0100 Subject: [PATCH 069/647] restructured code, SCC missing --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 303 +++++------------- .../helper/SparseMarkovAutomatonCslHelper.h | 28 +- 2 files changed, 76 insertions(+), 255 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 4b419d92e..ad95dee20 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -158,70 +158,13 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } - template::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::printTransitions(const uint64_t N, ValueType const diff, - storm::storage::SparseMatrix const &fullTransitionMatrix, - std::vector const &exitRateVector, storm::storage::BitVector const &markovianStates, - storm::storage::BitVector const &psiStates, std::vector> relReachability, - const storage::BitVector &cycleStates, const storage::BitVector &cycleGoalStates, - std::vector>> &unifVectors, std::ofstream& logfile) { - - auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); - - //Transition Matrix - logfile << "number of states = num of row group count " << numberOfStates << "\n"; - for (uint_fast64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { - logfile << " from node " << i << " "; - auto from = rowGroupIndices[i]; - auto to = rowGroupIndices[i+1]; - for (auto j = from ; j < to; j++){ - for (auto &v : fullTransitionMatrix.getRow(j)) { - if (markovianStates[i]){ - logfile << v.getValue() *exitRateVector[i] << " -> "<< v.getColumn() << "\t"; - } else { - logfile << v.getValue() << " -> "<< v.getColumn() << "\t"; - } - } - logfile << "\n"; - } - } - logfile << "\n"; - - logfile << "probStates\tmarkovianStates\tgoalStates\tcycleStates\tcycleGoalStates\n"; - for (int i =0 ; i< markovianStates.size() ; i++){ - logfile << (~markovianStates)[i] << "\t\t" << markovianStates[i] << "\t\t" << psiStates[i] << "\t\t" << cycleStates[i] << "\t\t" << cycleGoalStates[i] << "\n"; - } - - logfile << "Iteration for N = " << N << " maximal difference was " << diff << "\n"; - - logfile << "vd: \n"; - for (uint64_t i =0 ; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson){ + void SparseMarkovAutomatonCslHelper::calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, + uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, + std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, + storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, + std::unique_ptr> const& solver, std::ofstream& logfile, + storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); @@ -229,7 +172,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson); + calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson, cycleFree); //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); } if (i>=poisson.left && i<=poisson.right){ @@ -250,7 +193,8 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson) { + std::unique_ptr> const &solver, std::ofstream& logfile, + storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree) { if (unifVectors[kind][k][node]!=-1){ @@ -300,7 +244,7 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (unifVectors[kind][k+1][to]==-1){ - calculateUnifPlusVector(env, k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); + calculateUnifPlusVector(env, k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson, cycleFree); } res+=element.getValue()*unifVectors[kind][k+1][to]; } @@ -310,164 +254,80 @@ namespace storm { } //probabilistic non-goal State - res = -1; - uint64_t rowStart = rowGroupIndices[node]; - uint64_t rowEnd = rowGroupIndices[node+1]; - for (uint64_t i = rowStart; i< rowEnd; i++){ - auto line = fullTransitionMatrix.getRow(i); - ValueType between = 0; - for (auto& element: line){ - uint64_t to = element.getColumn(); - if (to==node){ - continue; - } - if (unifVectors[kind][k][to]==-1){ - calculateUnifPlusVector(env, k,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson); - } - between+=element.getValue()*unifVectors[kind][k][to]; - } - if (maximize(dir)){ - res = std::max(res,between); - } else { - if (res!=-1){ - res = std::min(res,between); - } else { - res = between; - } - } - } - unifVectors[kind][k][node]=res; - //logfile << print << "probabilistic state: "<< " res = " << unifVectors[kind][k][node] << " but calculated more \n"; - - //end probabilistic states - } - - - template ::SupportsExponential, int>::type> - uint64_t SparseMarkovAutomatonCslHelper::trajans(storm::storage::SparseMatrix const& transitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t* counter) { - auto const& rowGroupIndice = transitionMatrix.getRowGroupIndices(); - - disc[node] = *counter; - finish[node] = *counter; - (*counter)+=1; - - auto from = rowGroupIndice[node]; - auto to = rowGroupIndice[node+1]; - - for(uint64_t i =from; i::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::identify( - storm::storage::SparseMatrix const &fullTransitionMatrix, - storm::storage::BitVector const &markovianStates, storm::storage::BitVector const& psiStates) { - auto indices = fullTransitionMatrix.getRowGroupIndices(); - bool realProb = false; - bool NDM = false; - bool Alternating = true; - bool probStates = false; - bool markStates = false; - - for (uint64_t i=0; i::SupportsExponential, int>::type> - storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates) { - - storm::storage::BitVector goalStates(cycleStates.size(), false); - auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); - - for (uint64_t i = 0 ; i < transitionMatrix.getRowGroupCount() ; i++){ - if (!cycleStates[i]){ + //not cycle free - use solver technique, calling SVI per default + //solving all sub-MDP's in one iteration + std::vector b(probSize, 0), x(numberOfProbStates,0); + //calculate b + uint64_t lineCounter=0; + for (int i =0; i::SupportsExponential, int>::type> - storm::storage::BitVector SparseMarkovAutomatonCslHelper::identifyProbCycles(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates){ - - storm::storage::BitVector const& probabilisticStates = ~markovianStates; - storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates; - - storm::storage::SparseMatrix const& probMatrix = transitionMatrix.getSubmatrix(true, probabilisticNonGoalStates, probabilisticNonGoalStates); - uint64_t probSize = probMatrix.getRowGroupCount(); - std::vector disc(probSize, 0), finish(probSize, 0); - - uint64_t counter =1; - - for (uint64_t i =0; isolveEquations(env, dir, x, b); - storm::storage::BitVector cycleStates(markovianStates.size(), false); - for (int i = 0 ; i< finish.size() ; i++){ - auto f = finish[i]; - for (int j =i+1; j::SupportsExponential, int>::type> void SparseMarkovAutomatonCslHelper::deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates){ auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); @@ -512,6 +372,7 @@ namespace storm { storm::solver::MinMaxLinearEquationSolverFactory const &minMaxLinearEquationSolverFactory) { STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + bool cycleFree; std::ofstream logfile("U+logfile.txt", std::ios::app); //logfile << "Using U+\n"; @@ -571,7 +432,6 @@ namespace storm { //calculate relative reachability - /* for (uint64_t i = 0; i < numberOfStates; i++) { if (markovianStates[i]) { continue; @@ -593,15 +453,14 @@ namespace storm { requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - */ std::unique_ptr> solver; - /*if (probSize != 0) { + if (probSize != 0) { solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); solver->setHasUniqueSolution(); solver->setBounds(storm::utility::zero(), storm::utility::one()); solver->setRequirementsChecked(); solver->setCachingEnabled(true); - } */ + } // while not close enough to precision: do { //logfile << "starting iteration\n"; @@ -661,15 +520,13 @@ namespace storm { for (uint64_t k = N; k <= N; k--) { calculateUnifPlusVector(env, k, i, 0, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult); + foxGlynnResult, cycleFree); calculateUnifPlusVector(env, k, i, 2, lambda, probSize, relReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult); + foxGlynnResult, cycleFree); calculateVu(env, relReachability, dir, k, i, 1, lambda, probSize, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, logfile, - foxGlynnResult); - //also use iteration to keep maxNorm of vd and vup to date, so the loop-condition is easy to prove - //ValueType diff = std::abs(unifVectors[0][k][i] - unifVectors[1][k][i]); + foxGlynnResult, cycleFree); } } @@ -678,23 +535,11 @@ namespace storm { ValueType diff = std::abs(unifVectors[0][0][i]-unifVectors[1][0][i]); maxNorm = std::max(maxNorm, diff); } - //printTransitions(N, maxNorm, fullTransitionMatrix, exitRate, markovianStates, psiStates, - // relReachability, psiStates, psiStates, unifVectors, logfile); //TODO remove - // (6) double lambda lambda = 2 * lambda; - // (7) escape if not coming closer to solution - if (oldDiff != -1) { - if (oldDiff == maxNorm) { - std::cout << "Not coming closer to solution as " << maxNorm << "\n"; - break; - } - } - oldDiff = maxNorm; - std::cout << "Finished Iteration for N = " << N << " with difference " << maxNorm << "\n"; - } while (maxNorm > epsilon /* * (1 - kappa)*/); + } while (maxNorm > epsilon*(1 - kappa)); logfile.close(); return unifVectors[0][0]; diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index ac005ce38..82492aa6e 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -60,10 +60,7 @@ namespace storm { private: template ::SupportsExponential, int>::type=0> - static void identify(storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates,storm::storage::BitVector const& psiStates); - - template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson); + static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); @@ -80,28 +77,12 @@ namespace storm { return id-1; } - template ::SupportsExponential, int>::type=0> - static storm::storage::BitVector identifyProbCyclesGoalStates(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& cycleStates); - - - template ::SupportsExponential, int>::type=0> - static storm::storage::BitVector identifyProbCycles(storm::storage::SparseMatrix const& TransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - - //TODO: move this - - - template ::SupportsExponential, int>::type=0> - static uint64_t trajans(storm::storage::SparseMatrix const& TransitionMatrix, uint64_t node, std::vector& disc, std::vector& finish, uint64_t * counter); - /* * Computes vu vector according to UnifPlus * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson); - - - + static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile @@ -109,11 +90,6 @@ namespace storm { * */ - template ::SupportsExponential, int>::type=0> - static void printTransitions(const uint64_t N, ValueType const diff, storm::storage::SparseMatrix const& fullTransitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, - storm::storage::BitVector const& psiStates, std::vector> relReachability, - storm::storage::BitVector const& cycleStates , storm::storage::BitVector const& cycleGoalStates ,std::vector>>& unifVectors, std::ofstream& logfile); - template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From 2ea911f86570090b0291dd4f8cb308ad415cd565 Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 6 Jan 2018 17:09:02 +0100 Subject: [PATCH 070/647] finished version of implementation --- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index ad95dee20..6fee0321e 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -372,19 +372,19 @@ namespace storm { storm::solver::MinMaxLinearEquationSolverFactory const &minMaxLinearEquationSolverFactory) { STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - bool cycleFree; + std::ofstream logfile("U+logfile.txt", std::ios::app); //logfile << "Using U+\n"; ValueType maxNorm = storm::utility::zero(); - ValueType oldDiff = -storm::utility::zero(); //bitvectors to identify different kind of states storm::storage::BitVector markovianStates = markovStates; storm::storage::BitVector allStates(markovianStates.size(), true); storm::storage::BitVector probabilisticStates = ~markovianStates; - + storm::storage::StronglyConnectedComponentDecomposition sccList(transitionMatrix, probabilisticStates, true, false); + bool cycleFree = sccList.size() == 0; //vectors to save calculation std::vector>> unifVectors{}; From 6a52a953c23bfc3683580c16b24d055077a0fddb Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 6 Jan 2018 17:56:47 +0100 Subject: [PATCH 071/647] clean up code --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 114 +++++++++--------- .../helper/SparseMarkovAutomatonCslHelper.h | 23 ++-- 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 6fee0321e..283814633 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -163,7 +163,7 @@ namespace storm { uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, - std::unique_ptr> const& solver, std::ofstream& logfile, + std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree){ if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. uint64_t N = unifVectors[1].size()-1; @@ -172,8 +172,7 @@ namespace storm { ValueType res =0; for (uint64_t i = k ; i < N ; i++ ){ if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, logfile, poisson, cycleFree); - //old: relativeReachability, dir, (N-1-(i-k)),node,lambda,wu,fullTransitionMatrix,markovianStates,psiStates, solver); + calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, poisson, cycleFree); } if (i>=poisson.left && i<=poisson.right){ res+=poisson.weights[i-poisson.left]*unifVectors[2][N-1-(i-k)][node]; @@ -193,15 +192,13 @@ namespace storm { storm::storage::SparseMatrix const &fullTransitionMatrix, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, - std::unique_ptr> const &solver, std::ofstream& logfile, + std::unique_ptr> const &solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree) { if (unifVectors[kind][k][node]!=-1){ - //logfile << "already calculated for k = " << k << " node = " << node << "\n"; - return; + return; //already calculated } - std::string print = std::string("calculating vector ") + std::to_string(kind) + " for k = " + std::to_string(k) + " node " + std::to_string(node) +" \t"; auto numberOfStates=fullTransitionMatrix.getRowGroupCount(); auto numberOfProbStates = numberOfStates - markovianStates.getNumberOfSetBits(); @@ -211,12 +208,11 @@ namespace storm { // First Case, k==N, independent from kind of state if (k==N){ - //logfile << print << "k == N! res = 0\n"; unifVectors[kind][k][node]=0; return; } - //goal state + //goal state, independent from kind of state if (psiStates[node]){ if (kind==0){ // Vd @@ -232,9 +228,7 @@ namespace storm { // WU unifVectors[kind][k][node]=1; } - //logfile << print << "goal state node " << node << " res = " << res << "\n"; return; - } //markovian non-goal State @@ -244,12 +238,11 @@ namespace storm { for (auto &element : line){ uint64_t to = element.getColumn(); if (unifVectors[kind][k+1][to]==-1){ - calculateUnifPlusVector(env, k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, logfile, poisson, cycleFree); + calculateUnifPlusVector(env, k+1,to,kind,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix,markovianStates,psiStates,solver, poisson, cycleFree); } res+=element.getValue()*unifVectors[kind][k+1][to]; } unifVectors[kind][k][node]=res; - //logfile << print << "markovian state: " << " res = " << res << "\n"; return; } @@ -270,7 +263,7 @@ namespace storm { if (unifVectors[kind][k][to] == -1) { calculateUnifPlusVector(env, k, to, kind, lambda, probSize, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, - solver, logfile, poisson, cycleFree); + solver, poisson, cycleFree); } between += element.getValue() * unifVectors[kind][k][to]; } @@ -310,7 +303,7 @@ namespace storm { if (unifVectors[kind][k][to] == -1) { calculateUnifPlusVector(env, k, to, kind, lambda, probSize, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, - psiStates, solver, logfile, poisson, cycleFree); + psiStates, solver, poisson, cycleFree); } res = res + relativeReachability[j][stateCount] * unifVectors[kind][k][to]; stateCount++; @@ -372,17 +365,12 @@ namespace storm { storm::solver::MinMaxLinearEquationSolverFactory const &minMaxLinearEquationSolverFactory) { STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); - - - std::ofstream logfile("U+logfile.txt", std::ios::app); - //logfile << "Using U+\n"; - ValueType maxNorm = storm::utility::zero(); - //bitvectors to identify different kind of states storm::storage::BitVector markovianStates = markovStates; storm::storage::BitVector allStates(markovianStates.size(), true); storm::storage::BitVector probabilisticStates = ~markovianStates; + //searching for SCC on Underlying MDP to decide which algorhitm is applied storm::storage::StronglyConnectedComponentDecomposition sccList(transitionMatrix, probabilisticStates, true, false); bool cycleFree = sccList.size() == 0; //vectors to save calculation @@ -390,6 +378,7 @@ namespace storm { //transitions from goalStates will be ignored. still: they are not allowed to be probabilistic! + // to make sure we apply our formula and NOT the MDP algorithm for (uint64_t i = 0; i < psiStates.size(); i++) { if (psiStates[i]) { markovianStates.set(i, true); @@ -397,12 +386,15 @@ namespace storm { } } - //transition matrix with diagonal entries. The values can be changed during uniformisation + //transition matrix with extended with diagonal entries. Therefore, the values can be changed during uniformisation + // exitRateVector with changeable exit Rates std::vector exitRate{exitRateVector}; typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix( true, allStates, allStates, true); - // delete diagonals - deleteProbDiagonals(fullTransitionMatrix, markovianStates); //for now leaving this out + + + // delete diagonals - needed for VI, not vor SVI + deleteProbDiagonals(fullTransitionMatrix, markovianStates); typename storm::storage::SparseMatrix probMatrix{}; uint64_t probSize = 0; if (probabilisticStates.getNumberOfSetBits() != 0) { //work around in case there are no prob states @@ -411,10 +403,12 @@ namespace storm { probSize = probMatrix.getRowCount(); } + // indices for transition martrix auto &rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); - //(1) define horizon, epsilon, kappa , N, lambda, + + //(1) define/declare horizon, epsilon, kappa , N, lambda, maxNorm uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); double T = boundsPair.second; ValueType kappa = storm::utility::one() / 10; // would be better as option-parameter @@ -424,47 +418,50 @@ namespace storm { lambda = std::max(act, lambda); } uint64_t N; + ValueType maxNorm = storm::utility::zero(); - //calculate relative ReachabilityVectors + //calculate relative ReachabilityVectors and create solver - just needed for cycles std::vector in{}; std::vector> relReachability(transitionMatrix.getRowCount(), in); + std::unique_ptr> solver; - - - //calculate relative reachability - for (uint64_t i = 0; i < numberOfStates; i++) { - if (markovianStates[i]) { - continue; - } - auto from = rowGroupIndices[i]; - auto to = rowGroupIndices[i + 1]; - for (auto j = from; j < to; j++) { - for (auto& element: fullTransitionMatrix.getRow(j)) { - if (markovianStates[element.getColumn()]) { - relReachability[j].push_back(element.getValue()); + if (!cycleFree) { + //calculate relative reachability + for (uint64_t i = 0; i < numberOfStates; i++) { + if (markovianStates[i]) { + continue; + } + auto from = rowGroupIndices[i]; + auto to = rowGroupIndices[i + 1]; + for (auto j = from; j < to; j++) { + for (auto &element: fullTransitionMatrix.getRow(j)) { + if (markovianStates[element.getColumn()]) { + relReachability[j].push_back(element.getValue()); + } } } } - } - //create equitation solver - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); - - requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, - "Cannot establish requirements for solver."); - std::unique_ptr> solver; - if (probSize != 0) { - solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); - solver->setHasUniqueSolution(); - solver->setBounds(storm::utility::zero(), storm::utility::one()); - solver->setRequirementsChecked(); - solver->setCachingEnabled(true); + //create equitation solver + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements( + env, true, dir); + + requirements.clearBounds(); + STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, + "Cannot establish requirements for solver."); + if (probSize != 0) { + solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); + solver->setHasUniqueSolution(); + solver->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + } } + // while not close enough to precision: do { - //logfile << "starting iteration\n"; maxNorm = storm::utility::zero(); + // (2) update parameter N = ceil(lambda * T * exp(2) - log(kappa * epsilon)); @@ -519,13 +516,13 @@ namespace storm { for (uint64_t i = 0; i < numberOfStates; i++) { for (uint64_t k = N; k <= N; k--) { calculateUnifPlusVector(env, k, i, 0, lambda, probSize, relReachability, dir, unifVectors, - fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + fullTransitionMatrix, markovianStates, psiStates, solver, foxGlynnResult, cycleFree); calculateUnifPlusVector(env, k, i, 2, lambda, probSize, relReachability, dir, unifVectors, - fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + fullTransitionMatrix, markovianStates, psiStates, solver, foxGlynnResult, cycleFree); calculateVu(env, relReachability, dir, k, i, 1, lambda, probSize, unifVectors, - fullTransitionMatrix, markovianStates, psiStates, solver, logfile, + fullTransitionMatrix, markovianStates, psiStates, solver, foxGlynnResult, cycleFree); } } @@ -535,13 +532,12 @@ namespace storm { ValueType diff = std::abs(unifVectors[0][0][i]-unifVectors[1][0][i]); maxNorm = std::max(maxNorm, diff); } - // (6) double lambda + // (6) double lambda lambda = 2 * lambda; } while (maxNorm > epsilon*(1 - kappa)); - logfile.close(); return unifVectors[0][0]; } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 82492aa6e..527af3a0a 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -19,13 +19,7 @@ namespace storm { public: /*! - * Computes TBU according to the UnifPlus algorithm - * - * @param boundsPair With precondition that the first component is 0, the second one gives the time bound - * @param exitRateVector the exit-rates of the given MA - * @param transitionMatrix the transitions of the given MA - * @param markovianStates bitvector refering to the markovian states - * @param psiStates bitvector refering to the goal states + * Computes time-bounded reachability according to the UnifPlus algorithm * * @return the probability vector * @@ -59,12 +53,21 @@ namespace storm { static std::vector computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: + /* + * calculating the unifVectors uv, ow according to Unif+ for MA + */ template ::SupportsExponential, int>::type=0> - static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); + static void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector> const& relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); + /* + * deleting the probabilistic Diagonals + */ template ::SupportsExponential, int>::type=0> static void deleteProbDiagonals(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates); + /* + * with having only a subset of the originalMatrix/vector, we need to transform indice + */ static uint64_t transformIndice(storm::storage::BitVector const& subset, uint64_t fakeId){ uint64_t id =0; uint64_t counter =0; @@ -78,11 +81,11 @@ namespace storm { } /* - * Computes vu vector according to UnifPlus + * Computes vu vector according to Unif+ for MA * */ template ::SupportsExponential, int>::type=0> - static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, std::ofstream& logfile, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); + static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); /*! * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile From 4a321aab28bc1dd8faff27f981fc658d2a6023dd Mon Sep 17 00:00:00 2001 From: Timo Philipp Gros Date: Sat, 6 Jan 2018 18:55:00 +0100 Subject: [PATCH 072/647] delete comment --- .../csl/helper/SparseMarkovAutomatonCslHelper.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 527af3a0a..0125b2feb 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -87,12 +87,6 @@ namespace storm { template ::SupportsExponential, int>::type=0> static void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree); - /*! - * Prints the TransitionMatrix and the vectors vd, vu, wu to the logfile - * TODO: delete when development is finished - * - */ - template ::SupportsExponential, int>::type = 0> static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); From fc422af5571a9e372b4fb969d6d4d183dd29e7de Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 11 Jan 2018 21:48:47 +0100 Subject: [PATCH 073/647] making things compile again in debug mode --- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 71f29a0c0..25e6e037d 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -677,7 +677,7 @@ namespace storm { if (!decisionValueBlocks) { performIterationStepUpdateDecisionValue(A, b); } else { - assert(decisionValue == getPrimaryBound()); + assert(decisionValue == getPrimaryBound()); auto xIt = x.rbegin(); auto yIt = y.rbegin(); auto groupStartIt = A.getRowGroupIndices().rbegin(); From 78cfb10c7e75f2945dbd6199012b1d2d7d004c48 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 16 Jan 2018 15:20:43 +0100 Subject: [PATCH 074/647] fixed qvi with negative rewards --- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 25e6e037d..71708a86c 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -626,11 +626,13 @@ namespace storm { void setLowerBound(ValueType const& value) { hasLowerBound = true; lowerBound = value; + // std::cout << "Lower bound set to " << lowerBound << std::endl; } void setUpperBound(ValueType const& value) { hasUpperBound = true; upperBound = value; + // std::cout << "Upper bound set to " << upperBound << std::endl; } template @@ -800,7 +802,7 @@ namespace storm { } bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { - return yi * (ub - lb) <= (relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0))); + return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); } template @@ -808,6 +810,7 @@ namespace storm { if (convergencePhase1) { if (checkConvergencePhase1()) { + STORM_LOG_INFO("Quick Value Iteration took " << iterations << " iterations for first convergence phase."); firstIndexViolatingConvergence = 0; if (relevantValues != nullptr) { firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); From 96845e26690ecfd370b41fac931c55deb11422a0 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 09:52:47 +0100 Subject: [PATCH 075/647] restructured quick power iterations a little --- .../solver/NativeLinearEquationSolver.cpp | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 0199857d1..3abef13d7 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -606,8 +606,8 @@ namespace storm { bool terminate = false; ValueType minValueBound, maxValueBound; uint64_t minIndex(0), maxIndex(0); - uint64_t firstStayProb1Index = 0; - uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; + bool convergencePhase1 = true; + uint64_t firstIndexViolatingConvergence = 0; this->startMeasureProgress(); while (!converged && !terminate && iterations < maxIter) { @@ -622,29 +622,29 @@ namespace storm { std::swap(tmp, stepBoundedStayProbs); } - //std::cout << "Iteration " << iterations << std::endl; - //std::cout << "x: " << storm::utility::vector::toString(*stepBoundedX) << std::endl; - //std::cout << "y: " << storm::utility::vector::toString(*stepBoundedStayProbs) << std::endl; - // Check for convergence - // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state - for (; firstStayProb1Index != stepBoundedStayProbs->size(); ++firstStayProb1Index) { - static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); - if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbs->at(firstStayProb1Index))) { - break; - } - } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstStayProb1Index)))) { - break; - // std::cout << "In Phase 1" << std::endl; + if (convergencePhase1) { + // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state + for (; firstIndexViolatingConvergence != stepBoundedStayProbs->size(); ++firstIndexViolatingConvergence) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(stepBoundedStayProbs->at(firstIndexViolatingConvergence))) { + break; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstIndexViolatingConvergence)))) { + break; + } } } + if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { + STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + convergencePhase1 = false; + firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; + } } - if (firstStayProb1Index == stepBoundedStayProbs->size()) { - STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + if (!convergencePhase1) { // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value - // std::cout << "In Phase 2" << std::endl; // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. minValueBound = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); maxValueBound = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); From 8c3991fb2f01a74feb13142e7961f01bfccef9f4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 10:38:59 +0100 Subject: [PATCH 076/647] respecting lower/upper bounds from preprocessing in quick sound power method --- src/storm/solver/AbstractEquationSolver.cpp | 24 ++++++++++++ src/storm/solver/AbstractEquationSolver.h | 14 +++++++ .../IterativeMinMaxLinearEquationSolver.cpp | 15 ++----- .../solver/NativeLinearEquationSolver.cpp | 39 +++++++++++++++---- 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/storm/solver/AbstractEquationSolver.cpp b/src/storm/solver/AbstractEquationSolver.cpp index d17a9041d..5b16cd096 100644 --- a/src/storm/solver/AbstractEquationSolver.cpp +++ b/src/storm/solver/AbstractEquationSolver.cpp @@ -9,6 +9,7 @@ #include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/exceptions/UnmetRequirementException.h" +#include "storm/exceptions/InvalidOperationException.h" namespace storm { namespace solver { @@ -119,10 +120,33 @@ namespace storm { return lowerBound.get(); } + template + ValueType AbstractEquationSolver::getLowerBound(bool convertLocalBounds) const { + if (lowerBound) { + return lowerBound.get(); + } else if (convertLocalBounds) { + return *std::min_element(lowerBounds->begin(), lowerBounds->end()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "No lower bound available but some was requested."); + return ValueType(); + } + template ValueType const& AbstractEquationSolver::getUpperBound() const { return upperBound.get(); } + + template + ValueType AbstractEquationSolver::getUpperBound(bool convertLocalBounds) const { + if (upperBound) { + return upperBound.get(); + } else if (convertLocalBounds) { + return *std::max_element(upperBounds->begin(), upperBounds->end()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "No upper bound available but some was requested."); + return ValueType(); + } + template std::vector const& AbstractEquationSolver::getLowerBounds() const { diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index d5000f8c7..476399bfa 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -97,11 +97,25 @@ namespace storm { */ ValueType const& getLowerBound() const; + /*! + * Retrieves the lower bound (if there is any). + * If the given flag is true and if there are only local bounds, + * the minimum of the local bounds is returned. + */ + ValueType getLowerBound(bool convertLocalBounds) const; + /*! * Retrieves the upper bound (if there is any). */ ValueType const& getUpperBound() const; + /*! + * Retrieves the upper bound (if there is any). + * If the given flag is true and if there are only local bounds, + * the maximum of the local bounds is returned. + */ + ValueType getUpperBound(bool convertLocalBounds) const; + /*! * Retrieves a vector containing the lower bounds (if there are any). */ diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 71708a86c..d79ed2f35 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -984,20 +984,13 @@ namespace storm { // Prepare initial bounds for the solution (if given) - if (this->hasLowerBound(AbstractEquationSolver::BoundType::Global)) { - helper.setLowerBound(this->getLowerBound()); - } else if (this->hasLowerBound(AbstractEquationSolver::BoundType::Local)) { - helper.setLowerBound(*std::min_element(this->getLowerBounds().begin(), this->getLowerBounds().end())); + if (this->hasLowerBound()) { + helper.setLowerBound(this->getLowerBound(true)); } - if (this->hasUpperBound(AbstractEquationSolver::BoundType::Global)) { - helper.setUpperBound(this->getUpperBound()); - } else if (this->hasUpperBound(AbstractEquationSolver::BoundType::Local)) { - helper.setUpperBound(*std::max_element(this->getUpperBounds().begin(), this->getUpperBounds().end())); + if (this->hasUpperBound()) { + helper.setUpperBound(this->getUpperBound(true)); } - //STORM_LOG_INFO_COND(!hasCurrentLowerBound, "Initial lower bound on the result is " << currentLowerBound); - //STORM_LOG_INFO_COND(!hasCurrentUpperBound, "Initial upper bound on the result is " << currentUpperBound); - storm::storage::BitVector const* relevantValuesPtr = nullptr; if (this->hasRelevantValues()) { relevantValuesPtr = &this->getRelevantValues(); diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 3abef13d7..56498f06e 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -604,8 +604,19 @@ namespace storm { uint64_t iterations = 0; bool converged = false; bool terminate = false; - ValueType minValueBound, maxValueBound; uint64_t minIndex(0), maxIndex(0); + ValueType minValueBound, maxValueBound; + bool hasMinValueBound, hasMaxValueBound; + // Prepare initial bounds for the solution (if given) + if (this->hasLowerBound()) { + minValueBound = this->getLowerBound(true); + hasMinValueBound = true; + } + if (this->hasUpperBound()) { + maxValueBound = this->getUpperBound(true); + hasMaxValueBound = true; + } + bool convergencePhase1 = true; uint64_t firstIndexViolatingConvergence = 0; this->startMeasureProgress(); @@ -646,11 +657,17 @@ namespace storm { if (!convergencePhase1) { // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - minValueBound = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); - maxValueBound = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); + ValueType minValueBoundCandidate = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); + ValueType maxValueBoundCandidate = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); + if (hasMinValueBound && minValueBound > minValueBoundCandidate) { + minValueBoundCandidate = minValueBound; + } + if (hasMaxValueBound && maxValueBound < maxValueBoundCandidate) { + maxValueBoundCandidate = maxValueBound; + } ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence); // The error made in this iteration - ValueType absoluteError = stayProb * (maxValueBound - minValueBound); + ValueType absoluteError = stayProb * (maxValueBoundCandidate - minValueBoundCandidate); // The maximal allowed error (possibly respecting relative precision) // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; @@ -661,14 +678,20 @@ namespace storm { auto probIt = stepBoundedStayProbs->begin(); for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { ValueType currentBound = *valIt / (storm::utility::one() - *probIt); - if (currentBound < minValueBound) { + if (currentBound < minValueBoundCandidate) { minIndex = index; - minValueBound = std::move(currentBound); - } else if (currentBound > maxValueBound) { + minValueBoundCandidate = std::move(currentBound); + } else if (currentBound > maxValueBoundCandidate) { maxIndex = index; - maxValueBound = std::move(currentBound); + maxValueBoundCandidate = std::move(currentBound); } } + if (!hasMinValueBound || minValueBoundCandidate > minValueBound) { + minValueBound = minValueBoundCandidate; + } + if (!hasMaxValueBound || maxValueBoundCandidate < maxValueBound) { + maxValueBound = maxValueBoundCandidate; + } absoluteError = stayProb * (maxValueBound - minValueBound); if (absoluteError <= maxAllowedError) { // The current index satisfies the desired bound. We now move to the next index that violates it From 3b394a965e4d7bec11f60778f1838b4b52470f15 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 11:43:16 +0100 Subject: [PATCH 077/647] some qvi optimizations --- .../IterativeMinMaxLinearEquationSolver.cpp | 55 ++++++++++--------- src/storm/storage/SparseMatrix.cpp | 14 +++++ src/storm/storage/SparseMatrix.h | 6 ++ 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index d79ed2f35..5e7600feb 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -610,7 +610,10 @@ namespace storm { template class QuickValueIterationHelper { public: - QuickValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + QuickValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision, uint64_t sizeOfLargestRowGroup) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + xTmp.resize(sizeOfLargestRowGroup); + yTmp.resize(sizeOfLargestRowGroup); + restart(); } @@ -623,45 +626,43 @@ namespace storm { firstIndexViolatingConvergence = 0; } - void setLowerBound(ValueType const& value) { + inline void setLowerBound(ValueType const& value) { hasLowerBound = true; lowerBound = value; - // std::cout << "Lower bound set to " << lowerBound << std::endl; } - void setUpperBound(ValueType const& value) { + inline void setUpperBound(ValueType const& value) { hasUpperBound = true; upperBound = value; - // std::cout << "Upper bound set to " << upperBound << std::endl; } template - bool better(ValueType const& val1, ValueType const& val2) { + inline bool better(ValueType const& val1, ValueType const& val2) { return maximize(dir) ? val1 > val2 : val1 < val2; } template - ValueType& getPrimaryBound() { + inline ValueType& getPrimaryBound() { return maximize(dir) ? upperBound : lowerBound; } template - bool& hasPrimaryBound() { + inline bool& hasPrimaryBound() { return maximize(dir) ? hasUpperBound : hasLowerBound; } template - ValueType& getSecondaryBound() { + inline ValueType& getSecondaryBound() { return maximize(dir) ? lowerBound : upperBound; } template - uint64_t& getPrimaryIndex() { + inline uint64_t& getPrimaryIndex() { return maximize(dir) ? maxIndex : minIndex; } template - uint64_t& getSecondaryIndex() { + inline uint64_t& getSecondaryIndex() { return maximize(dir) ? minIndex : maxIndex; } @@ -732,9 +733,8 @@ namespace storm { ++row; // Only do more work if there are still rows in this row group if (row != groupEnd) { - xTmp.clear(); - yTmp.clear(); ValueType xi, yi; + uint64_t xyTmpIndex = 0; if (hasPrimaryBound()) { ValueType bestValue = xBest + yBest * getPrimaryBound(); for (;row < groupEnd; ++row) { @@ -745,8 +745,9 @@ namespace storm { if (better(currentValue, bestValue)) { if (yBest < yi) { // We need to store the 'old' best value as it might be relevant for the decision value - xTmp.push_back(std::move(xBest)); - yTmp.push_back(std::move(yBest)); + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; } xBest = std::move(xi); yBest = std::move(yi); @@ -757,8 +758,9 @@ namespace storm { xBest = std::move(xi); yBest = std::move(yi); } else { - xTmp.push_back(std::move(xi)); - yTmp.push_back(std::move(yi)); + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; } } } @@ -767,24 +769,25 @@ namespace storm { multiplyRow(row, A, b[row], xi, yi); // Update the best choice if (yi > yBest || (yi == yBest && better(xi, xBest))) { - xTmp.push_back(std::move(xBest)); - yTmp.push_back(std::move(yBest)); + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; xBest = std::move(xi); yBest = std::move(yi); } else { - xTmp.push_back(std::move(xi)); - yTmp.push_back(std::move(yi)); + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; } } } // Update the decision value - for (auto xTmpIt = xTmp.begin(), yTmpIt = yTmp.begin(); xTmpIt != xTmp.end(); ++xTmpIt, ++yTmpIt) { - ValueType deltaY = yBest - (*yTmpIt); + for (uint64_t i = 0; i < xyTmpIndex; ++i) { + ValueType deltaY = yBest - yTmp[i]; if (deltaY > storm::utility::zero()) { - ValueType newDecisionValue = (*xTmpIt - xBest) / deltaY; + ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { - // std::cout << "Updating decision value in Iteration " << iterations << " to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl; decisionValue = std::move(newDecisionValue); hasDecisionValue = true; } @@ -976,7 +979,7 @@ namespace storm { this->auxiliaryRowGroupVector = std::make_unique>(); } - QuickValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + QuickValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); // Get the precision uint64_t restartMaxIterations = env.solver().minMax().getQviRestartMaxIterations(); diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 36dd5724e..729b85b46 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -579,6 +579,20 @@ namespace storm { return this->getRowGroupIndices()[group + 1] - this->getRowGroupIndices()[group]; } + template + typename SparseMatrix::index_type SparseMatrix::getSizeOfLargestRowGroup() const { + if (this->hasTrivialRowGrouping()) { + return 1; + } + index_type res = 0; + index_type previousGroupStart = 0; + for (auto const& i : rowGroupIndices.get()) { + res = std::max(res, i - previousGroupStart); + previousGroupStart = i; + } + return res; + } + template std::vector::index_type> const& SparseMatrix::getRowGroupIndices() const { // If there is no current row grouping, we need to create it. diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index e07389e5a..e115db443 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -567,6 +567,11 @@ namespace storm { */ index_type getRowGroupSize(index_type group) const; + /*! + * Returns the size of the largest row group of the matrix + */ + index_type getSizeOfLargestRowGroup() const; + /*! * Returns the grouping of rows of this matrix. * @@ -574,6 +579,7 @@ namespace storm { */ std::vector const& getRowGroupIndices() const; + /*! * Sets the row grouping to the given one. * @note It is assumed that the new row grouping is non-trivial. From 4ab47671f5561034268fc65047c590d43eae6450 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 11:57:13 +0100 Subject: [PATCH 078/647] Renamed TopologicalMinMaxLinearEquationSolver -> TopologicalCudaMinMaxLinearEquationSolver --- .../solver/MinMaxLinearEquationSolver.cpp | 5 +- src/storm/solver/SolverSelectionOptions.cpp | 2 + src/storm/solver/SolverSelectionOptions.h | 2 +- ...ologicalCudaMinMaxLinearEquationSolver.cpp | 485 ++++++++++++++++++ ...opologicalCudaMinMaxLinearEquationSolver.h | 154 ++++++ .../TopologicalMinMaxLinearEquationSolver.cpp | 485 ------------------ .../TopologicalMinMaxLinearEquationSolver.h | 154 ------ .../solver/MinMaxLinearEquationSolverTest.cpp | 12 + 8 files changed, 657 insertions(+), 642 deletions(-) create mode 100644 src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp create mode 100644 src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index c250c17a0..4a5066079 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -5,6 +5,7 @@ #include "storm/solver/LinearEquationSolver.h" #include "storm/solver/IterativeMinMaxLinearEquationSolver.h" #include "storm/solver/TopologicalMinMaxLinearEquationSolver.h" +#include "storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h" #include "storm/solver/LpMinMaxLinearEquationSolver.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" @@ -198,8 +199,8 @@ namespace storm { auto method = env.solver().minMax().getMethod(); if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { result = std::make_unique>(std::make_unique>()); - } else if (method == MinMaxMethod::Topological) { - result = std::make_unique>(); + } else if (method == MinMaxMethod::TopologicalCuda) { + result = std::make_unique>(); } else if (method == MinMaxMethod::LinearProgramming) { result = std::make_unique>(std::make_unique>(), std::make_unique>()); } else { diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 3461f2bc6..f2537f1a4 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -16,6 +16,8 @@ namespace storm { return "ratsearch"; case MinMaxMethod::QuickValueIteration: return "QuickValueIteration"; + case MinMaxMethod::TopologicalCuda: + return "topologicalcuda"; } return "invalid"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index fc9750611..e2ffdb5dd 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -6,7 +6,7 @@ namespace storm { namespace solver { - ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, QuickValueIteration) + ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, QuickValueIteration, TopologicalCuda) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp new file mode 100644 index 000000000..083e2581f --- /dev/null +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp @@ -0,0 +1,485 @@ +#include "storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h" + +#include "storm/utility/vector.h" +#include "storm/utility/graph.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/exceptions/IllegalArgumentException.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidEnvironmentException.h" + +#include "storm/environment/solver/MinMaxSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + +#include "storm/utility/macros.h" +#include "storm-config.h" +#ifdef STORM_HAVE_CUDA +# include "cudaForStorm.h" +#endif + +namespace storm { + namespace solver { + + template + TopologicalCudaMinMaxLinearEquationSolver::TopologicalCudaMinMaxLinearEquationSolver() { + // Get the settings object to customize solving. + this->enableCuda = storm::settings::getModule().isUseCudaSet(); +#ifdef STORM_HAVE_CUDA + STORM_LOG_INFO_COND(this->enableCuda, "Option CUDA was not set, but the topological value iteration solver will use it anyways."); +#endif + } + + template + TopologicalCudaMinMaxLinearEquationSolver::TopologicalCudaMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : TopologicalCudaMinMaxLinearEquationSolver() { + this->setMatrix(A); + } + + template + void TopologicalCudaMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { + this->localA = nullptr; + this->A = &matrix; + } + + template + void TopologicalCudaMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { + this->localA = std::make_unique>(std::move(matrix)); + this->A = this->localA.get(); + } + + template + bool TopologicalCudaMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); + + ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + uint64_t maxIters = env.solver().minMax().getMaximalNumberOfIterations(); + bool relative = env.solver().minMax().getMaximalNumberOfIterations(); + +#ifdef GPU_USE_FLOAT +#define __FORCE_FLOAT_CALCULATION true +#else +#define __FORCE_FLOAT_CALCULATION false +#endif + if (__FORCE_FLOAT_CALCULATION && std::is_same::value) { + // FIXME: This actually allocates quite some storage, because of this conversion, is it really necessary? + storm::storage::SparseMatrix newA = this->A->template toValueType(); + + TopologicalCudaMinMaxLinearEquationSolver newSolver(newA); + + std::vector new_x = storm::utility::vector::toValueType(x); + std::vector const new_b = storm::utility::vector::toValueType(b); + + bool callConverged = newSolver.solveEquations(env, dir, new_x, new_b); + + for (size_t i = 0, size = new_x.size(); i < size; ++i) { + x.at(i) = new_x.at(i); + } + return callConverged; + } + + // For testing only + if (sizeof(ValueType) == sizeof(double)) { + //std::cout << "<<< Using CUDA-DOUBLE Kernels >>>" << std::endl; + STORM_LOG_INFO("<<< Using CUDA-DOUBLE Kernels >>>"); + } else { + //std::cout << "<<< Using CUDA-FLOAT Kernels >>>" << std::endl; + STORM_LOG_INFO("<<< Using CUDA-FLOAT Kernels >>>"); + } + + // Now, we need to determine the SCCs of the MDP and perform a topological sort. + std::vector const& nondeterministicChoiceIndices = this->A->getRowGroupIndices(); + + // Check if the decomposition is necessary +#ifdef STORM_HAVE_CUDA +#define __USE_CUDAFORSTORM_OPT true + size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(A->getRowCount()), nondeterministicChoiceIndices.size(), static_cast(A->getEntryCount())); + size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); +#else +#define __USE_CUDAFORSTORM_OPT false + size_t const gpuSizeOfCompleteSystem = 0; + size_t const cudaFreeMemory = 0; +#endif + std::vector> sccDecomposition; + if (__USE_CUDAFORSTORM_OPT && (gpuSizeOfCompleteSystem < cudaFreeMemory)) { + // Dummy output for SCC Times + //std::cout << "Computing the SCC Decomposition took 0ms" << std::endl; + +#ifdef STORM_HAVE_CUDA + STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA Equation Solver."); + + bool result = false; + size_t globalIterations = 0; + if (dir == OptimizationDirection::Minimize) { + result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); + } else { + result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); + } + STORM_LOG_INFO("Executed " << globalIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); + + bool converged = false; + if (!result) { + converged = false; + STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); + throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; + } else { + converged = true; + } + + // Check if the solver converged and issue a warning otherwise. + if (converged) { + STORM_LOG_INFO("Iterative solver converged after " << globalIterations << " iterations."); + } else { + STORM_LOG_WARN("Iterative solver did not converged after " << globalIterations << " iterations."); + } +#else + STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); + throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; +#endif + } else { + storm::storage::BitVector fullSystem(this->A->getRowGroupCount(), true); + storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(*this->A, fullSystem, false, false); + + STORM_LOG_THROW(sccDecomposition.size() > 0, storm::exceptions::IllegalArgumentException, "Can not solve given equation system as the SCC decomposition returned no SCCs."); + + storm::storage::SparseMatrix stronglyConnectedComponentsDependencyGraph = sccDecomposition.extractPartitionDependencyGraph(*this->A); + std::vector topologicalSort = storm::utility::graph::getTopologicalSort(stronglyConnectedComponentsDependencyGraph); + + // Calculate the optimal distribution of sccs + std::vector> optimalSccs = this->getOptimalGroupingFromTopologicalSccDecomposition(sccDecomposition, topologicalSort, *this->A); + STORM_LOG_INFO("Optimized SCC Decomposition, originally " << topologicalSort.size() << " SCCs, optimized to " << optimalSccs.size() << " SCCs."); + + std::vector* currentX = nullptr; + std::vector* swap = nullptr; + size_t currentMaxLocalIterations = 0; + size_t localIterations = 0; + size_t globalIterations = 0; + bool converged = true; + + // Iterate over all SCCs of the MDP as specified by the topological sort. This guarantees that an SCC is only + // solved after all SCCs it depends on have been solved. + for (auto sccIndexIt = optimalSccs.cbegin(); sccIndexIt != optimalSccs.cend() && converged; ++sccIndexIt) { + bool const useGpu = sccIndexIt->first; + storm::storage::StateBlock const& scc = sccIndexIt->second; + + // Generate a sub matrix + storm::storage::BitVector subMatrixIndices(this->A->getColumnCount(), scc.cbegin(), scc.cend()); + storm::storage::SparseMatrix sccSubmatrix = this->A->getSubmatrix(true, subMatrixIndices, subMatrixIndices); + std::vector sccSubB(sccSubmatrix.getRowCount()); + storm::utility::vector::selectVectorValues(sccSubB, subMatrixIndices, nondeterministicChoiceIndices, b); + std::vector sccSubX(sccSubmatrix.getColumnCount()); + std::vector sccSubXSwap(sccSubmatrix.getColumnCount()); + std::vector sccMultiplyResult(sccSubmatrix.getRowCount()); + + // Prepare the pointers for swapping in the calculation + currentX = &sccSubX; + swap = &sccSubXSwap; + + storm::utility::vector::selectVectorValues(sccSubX, subMatrixIndices, x); // x is getCols() large, where as b and multiplyResult are getRows() (nondet. choices times states) + std::vector sccSubNondeterministicChoiceIndices(sccSubmatrix.getColumnCount() + 1); + sccSubNondeterministicChoiceIndices.at(0) = 0; + + // Pre-process all dependent states + // Remove outgoing transitions and create the ChoiceIndices + uint_fast64_t innerIndex = 0; + uint_fast64_t outerIndex = 0; + for (uint_fast64_t state : scc) { + // Choice Indices + sccSubNondeterministicChoiceIndices.at(outerIndex + 1) = sccSubNondeterministicChoiceIndices.at(outerIndex) + (nondeterministicChoiceIndices[state + 1] - nondeterministicChoiceIndices[state]); + + for (auto rowGroupIt = nondeterministicChoiceIndices[state]; rowGroupIt != nondeterministicChoiceIndices[state + 1]; ++rowGroupIt) { + typename storm::storage::SparseMatrix::const_rows row = this->A->getRow(rowGroupIt); + for (auto rowIt = row.begin(); rowIt != row.end(); ++rowIt) { + if (!subMatrixIndices.get(rowIt->getColumn())) { + // This is an outgoing transition of a state in the SCC to a state not included in the SCC + // Subtracting Pr(tau) * x_other from b fixes that + sccSubB.at(innerIndex) = sccSubB.at(innerIndex) + (rowIt->getValue() * x.at(rowIt->getColumn())); + } + } + ++innerIndex; + } + ++outerIndex; + } + + // For the current SCC, we need to perform value iteration until convergence. + if (useGpu) { +#ifdef STORM_HAVE_CUDA + STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA-based equation solver."); + + //STORM_LOG_INFO("Device has " << getTotalCudaMemory() << " Bytes of Memory with " << getFreeCudaMemory() << "Bytes free (" << (static_cast(getFreeCudaMemory()) / static_cast(getTotalCudaMemory())) * 100 << "%)."); + //STORM_LOG_INFO("We will allocate " << (sizeof(uint_fast64_t)* sccSubmatrix.rowIndications.size() + sizeof(uint_fast64_t)* sccSubmatrix.columnsAndValues.size() * 2 + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubB.size() + sizeof(double)* sccSubB.size() + sizeof(uint_fast64_t)* sccSubNondeterministicChoiceIndices.size()) << " Bytes."); + //STORM_LOG_INFO("The CUDA Runtime Version is " << getRuntimeCudaVersion()); + + bool result = false; + localIterations = 0; + if (dir == OptimizationDirection::Minimum) { + result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); + } else { + result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); + } + STORM_LOG_INFO("Executed " << localIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); + + if (!result) { + converged = false; + STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); + throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; + } else { + converged = true; + } + + // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep + // track of the maximum. + if (localIterations > currentMaxLocalIterations) { + currentMaxLocalIterations = localIterations; + } + globalIterations += localIterations; +#else + STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); + throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; +#endif + } else { + //std::cout << "WARNING: Using CPU based TopoSolver! (double)" << std::endl; + STORM_LOG_INFO("Performance Warning: Using CPU based TopoSolver! (double)"); + localIterations = 0; + converged = false; + while (!converged && localIterations < maxIters) { + // Compute x' = A*x + b. + sccSubmatrix.multiplyWithVector(*currentX, sccMultiplyResult); + storm::utility::vector::addVectors(sccMultiplyResult, sccSubB, sccMultiplyResult); + + //A.multiplyWithVector(scc, nondeterministicChoiceIndices, *currentX, multiplyResult); + //storm::utility::addVectors(scc, nondeterministicChoiceIndices, multiplyResult, b); + + /* + Versus: + A.multiplyWithVector(*currentX, *multiplyResult); + storm::utility::vector::addVectorsInPlace(*multiplyResult, b); + */ + + // Reduce the vector x' by applying min/max for all non-deterministic choices. + storm::utility::vector::reduceVectorMinOrMax(dir,sccMultiplyResult, *swap, sccSubNondeterministicChoiceIndices); + + // Determine whether the method converged. + // TODO: It seems that the equalModuloPrecision call that compares all values should have a higher + // running time. In fact, it is faster. This has to be investigated. + // converged = storm::utility::equalModuloPrecision(*currentX, *newX, scc, precision, relative); + converged = storm::utility::vector::equalModuloPrecision(*currentX, *swap, precision, relative); + + // Update environment variables. + std::swap(currentX, swap); + + ++localIterations; + ++globalIterations; + } + STORM_LOG_INFO("Executed " << localIterations << " of max. " << maxIters << " Iterations."); + } + + + // The Result of this SCC has to be taken back into the main result vector + innerIndex = 0; + for (uint_fast64_t state : scc) { + x.at(state) = currentX->at(innerIndex); + ++innerIndex; + } + + // Since the pointers for swapping in the calculation point to temps they should not be valid anymore + currentX = nullptr; + swap = nullptr; + + // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep + // track of the maximum. + if (localIterations > currentMaxLocalIterations) { + currentMaxLocalIterations = localIterations; + } + } + + //std::cout << "Used a total of " << globalIterations << " iterations with a maximum of " << localIterations << " iterations in a single block." << std::endl; + + // Check if the solver converged and issue a warning otherwise. + if (converged) { + STORM_LOG_INFO("Iterative solver converged after " << currentMaxLocalIterations << " iterations."); + } else { + STORM_LOG_WARN("Iterative solver did not converged after " << currentMaxLocalIterations << " iterations."); + } + + return converged; + } + } + + template + std::vector> + TopologicalCudaMinMaxLinearEquationSolver::getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const { + + (void)matrix; + + std::vector> result; + +#ifdef STORM_HAVE_CUDA + // 95% to have a bit of padding + size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); + size_t lastResultIndex = 0; + + std::vector const& rowGroupIndices = matrix.getRowGroupIndices(); + + size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(matrix.getRowCount()), rowGroupIndices.size(), static_cast(matrix.getEntryCount())); + size_t const gpuSizePerRowGroup = std::max(static_cast(gpuSizeOfCompleteSystem / rowGroupIndices.size()), static_cast(1)); + size_t const maxRowGroupsPerMemory = cudaFreeMemory / gpuSizePerRowGroup; + + size_t currentSize = 0; + size_t neededReserveSize = 0; + size_t startIndex = 0; + for (size_t i = 0; i < topologicalSort.size(); ++i) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[i]]; + size_t const currentSccSize = scc.size(); + + uint_fast64_t rowCount = 0; + uint_fast64_t entryCount = 0; + + for (auto sccIt = scc.cbegin(); sccIt != scc.cend(); ++sccIt) { + rowCount += matrix.getRowGroupSize(*sccIt); + entryCount += matrix.getRowGroupEntryCount(*sccIt); + } + + size_t sccSize = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(rowCount), scc.size(), static_cast(entryCount)); + + if ((currentSize + sccSize) <= cudaFreeMemory) { + // There is enough space left in the current group + neededReserveSize += currentSccSize; + currentSize += sccSize; + } else { + // This would make the last open group to big for the GPU + + if (startIndex < i) { + if ((startIndex + 1) < i) { + // More than one component + std::vector tempGroups; + tempGroups.reserve(neededReserveSize); + + // Copy the first group to make inplace_merge possible + storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; + tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); + + if (((startIndex + 1) + 80) >= i) { + size_t lastSize = 0; + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + lastSize = tempGroups.size(); + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + std::vector::iterator middleIterator = tempGroups.begin(); + std::advance(middleIterator, lastSize); + std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); + } + } else { + // Use std::sort + for (size_t j = startIndex + 1; j < i; ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + } + std::sort(tempGroups.begin(), tempGroups.end()); + } + result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); + } else { + // Only one group, copy construct. + result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); + } + ++lastResultIndex; + } + + if (sccSize <= cudaFreeMemory) { + currentSize = sccSize; + neededReserveSize = currentSccSize; + startIndex = i; + } else { + // This group is too big to fit into the CUDA Memory by itself + result.push_back(std::make_pair(false, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[i]])))); + ++lastResultIndex; + + currentSize = 0; + neededReserveSize = 0; + startIndex = i + 1; + } + } + } + + size_t const topologicalSortSize = topologicalSort.size(); + if (startIndex < topologicalSortSize) { + if ((startIndex + 1) < topologicalSortSize) { + // More than one component + std::vector tempGroups; + tempGroups.reserve(neededReserveSize); + + // Copy the first group to make inplace_merge possible. + storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; + tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); + + // For set counts <= 80, in-place merge is faster. + if (((startIndex + 1) + 80) >= topologicalSortSize) { + size_t lastSize = 0; + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + lastSize = tempGroups.size(); + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + std::vector::iterator middleIterator = tempGroups.begin(); + std::advance(middleIterator, lastSize); + std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); + } + } else { + // Use std::sort + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + } + std::sort(tempGroups.begin(), tempGroups.end()); + } + result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); + } + else { + // Only one group, copy construct. + result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); + } + ++lastResultIndex; + } +#else + for (auto sccIndexIt = topologicalSort.cbegin(); sccIndexIt != topologicalSort.cend(); ++sccIndexIt) { + storm::storage::StateBlock const& scc = sccDecomposition[*sccIndexIt]; + result.push_back(std::make_pair(false, scc)); + } +#endif + return result; + } + + template + void TopologicalCudaMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { + std::unique_ptr> multiplyResult = std::make_unique>(this->A->getRowCount()); + + // Now perform matrix-vector multiplication as long as we meet the bound of the formula. + for (uint_fast64_t i = 0; i < n; ++i) { + this->A->multiplyWithVector(x, *multiplyResult); + + // Add b if it is non-null. + if (b != nullptr) { + storm::utility::vector::addVectors(*multiplyResult, *b, *multiplyResult); + } + + // Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost + // element of the min/max operator stack. + storm::utility::vector::reduceVectorMinOrMax(dir, *multiplyResult, x, this->A->getRowGroupIndices()); + } + } + + template + TopologicalCudaMinMaxLinearEquationSolverFactory::TopologicalCudaMinMaxLinearEquationSolverFactory(bool trackScheduler) { + // Intentionally left empty. + } + + template + std::unique_ptr> TopologicalCudaMinMaxLinearEquationSolverFactory::create(Environment const& env) const { + STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); + return std::make_unique>(); + } + + // Explicitly instantiate the solver. + template class TopologicalCudaMinMaxLinearEquationSolver; + + template class TopologicalCudaMinMaxLinearEquationSolverFactory; + } // namespace solver +} // namespace storm diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h new file mode 100644 index 000000000..e302028a5 --- /dev/null +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h @@ -0,0 +1,154 @@ +#ifndef STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ +#define STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ + +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/NotSupportedException.h" + +#include +#include + +#include "storm-config.h" +#ifdef STORM_HAVE_CUDA +#include "cudaForStorm.h" +#endif + +namespace storm { + namespace solver { + + /*! + * A class that uses SCC Decompositions to solve a min/max linear equation system. + */ + template + class TopologicalCudaMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { + public: + TopologicalCudaMinMaxLinearEquationSolver(); + + /*! + * Constructs a min-max linear equation solver with parameters being set according to the settings + * object. + * + * @param A The matrix defining the coefficients of the linear equation system. + */ + TopologicalCudaMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); + + virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; + virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; + + virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; + + virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; + + private: + storm::storage::SparseMatrix const* A; + std::unique_ptr> localA; + + bool enableCuda; + /*! + * Given a topological sort of a SCC Decomposition, this will calculate the optimal grouping of SCCs with respect to the size of the GPU memory. + */ + std::vector> getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const; + }; + + template + bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector& x, std::vector const&, std::vector const&, size_t&) { + // + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); + } + template <> + inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_double_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + template <> + inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_float_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + + template + bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector&, std::vector const&, std::vector const&, size_t&) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); + } + template <> + inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_double_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + template <> + inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_float_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + + template + class TopologicalCudaMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { + public: + TopologicalCudaMinMaxLinearEquationSolverFactory(bool trackScheduler = false); + + protected: + virtual std::unique_ptr> create(Environment const& env) const override; + }; + + } // namespace solver +} // namespace storm + +#endif /* STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ */ diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 9e33a4c9e..e69de29bb 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -1,485 +0,0 @@ -#include "storm/solver/TopologicalMinMaxLinearEquationSolver.h" - -#include "storm/utility/vector.h" -#include "storm/utility/graph.h" -#include "storm/storage/StronglyConnectedComponentDecomposition.h" -#include "storm/exceptions/IllegalArgumentException.h" -#include "storm/exceptions/InvalidStateException.h" -#include "storm/exceptions/InvalidEnvironmentException.h" - -#include "storm/environment/solver/MinMaxSolverEnvironment.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/CoreSettings.h" - -#include "storm/utility/macros.h" -#include "storm-config.h" -#ifdef STORM_HAVE_CUDA -# include "cudaForStorm.h" -#endif - -namespace storm { - namespace solver { - - template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { - // Get the settings object to customize solving. - this->enableCuda = storm::settings::getModule().isUseCudaSet(); -#ifdef STORM_HAVE_CUDA - STORM_LOG_INFO_COND(this->enableCuda, "Option CUDA was not set, but the topological value iteration solver will use it anyways."); -#endif - } - - template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : TopologicalMinMaxLinearEquationSolver() { - this->setMatrix(A); - } - - template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { - this->localA = nullptr; - this->A = &matrix; - } - - template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { - this->localA = std::make_unique>(std::move(matrix)); - this->A = this->localA.get(); - } - - template - bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - - ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - uint64_t maxIters = env.solver().minMax().getMaximalNumberOfIterations(); - bool relative = env.solver().minMax().getMaximalNumberOfIterations(); - -#ifdef GPU_USE_FLOAT -#define __FORCE_FLOAT_CALCULATION true -#else -#define __FORCE_FLOAT_CALCULATION false -#endif - if (__FORCE_FLOAT_CALCULATION && std::is_same::value) { - // FIXME: This actually allocates quite some storage, because of this conversion, is it really necessary? - storm::storage::SparseMatrix newA = this->A->template toValueType(); - - TopologicalMinMaxLinearEquationSolver newSolver(newA); - - std::vector new_x = storm::utility::vector::toValueType(x); - std::vector const new_b = storm::utility::vector::toValueType(b); - - bool callConverged = newSolver.solveEquations(env, dir, new_x, new_b); - - for (size_t i = 0, size = new_x.size(); i < size; ++i) { - x.at(i) = new_x.at(i); - } - return callConverged; - } - - // For testing only - if (sizeof(ValueType) == sizeof(double)) { - //std::cout << "<<< Using CUDA-DOUBLE Kernels >>>" << std::endl; - STORM_LOG_INFO("<<< Using CUDA-DOUBLE Kernels >>>"); - } else { - //std::cout << "<<< Using CUDA-FLOAT Kernels >>>" << std::endl; - STORM_LOG_INFO("<<< Using CUDA-FLOAT Kernels >>>"); - } - - // Now, we need to determine the SCCs of the MDP and perform a topological sort. - std::vector const& nondeterministicChoiceIndices = this->A->getRowGroupIndices(); - - // Check if the decomposition is necessary -#ifdef STORM_HAVE_CUDA -#define __USE_CUDAFORSTORM_OPT true - size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(A->getRowCount()), nondeterministicChoiceIndices.size(), static_cast(A->getEntryCount())); - size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); -#else -#define __USE_CUDAFORSTORM_OPT false - size_t const gpuSizeOfCompleteSystem = 0; - size_t const cudaFreeMemory = 0; -#endif - std::vector> sccDecomposition; - if (__USE_CUDAFORSTORM_OPT && (gpuSizeOfCompleteSystem < cudaFreeMemory)) { - // Dummy output for SCC Times - //std::cout << "Computing the SCC Decomposition took 0ms" << std::endl; - -#ifdef STORM_HAVE_CUDA - STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA Equation Solver."); - - bool result = false; - size_t globalIterations = 0; - if (dir == OptimizationDirection::Minimize) { - result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); - } else { - result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); - } - STORM_LOG_INFO("Executed " << globalIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); - - bool converged = false; - if (!result) { - converged = false; - STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); - throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; - } else { - converged = true; - } - - // Check if the solver converged and issue a warning otherwise. - if (converged) { - STORM_LOG_INFO("Iterative solver converged after " << globalIterations << " iterations."); - } else { - STORM_LOG_WARN("Iterative solver did not converged after " << globalIterations << " iterations."); - } -#else - STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); - throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; -#endif - } else { - storm::storage::BitVector fullSystem(this->A->getRowGroupCount(), true); - storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(*this->A, fullSystem, false, false); - - STORM_LOG_THROW(sccDecomposition.size() > 0, storm::exceptions::IllegalArgumentException, "Can not solve given equation system as the SCC decomposition returned no SCCs."); - - storm::storage::SparseMatrix stronglyConnectedComponentsDependencyGraph = sccDecomposition.extractPartitionDependencyGraph(*this->A); - std::vector topologicalSort = storm::utility::graph::getTopologicalSort(stronglyConnectedComponentsDependencyGraph); - - // Calculate the optimal distribution of sccs - std::vector> optimalSccs = this->getOptimalGroupingFromTopologicalSccDecomposition(sccDecomposition, topologicalSort, *this->A); - STORM_LOG_INFO("Optimized SCC Decomposition, originally " << topologicalSort.size() << " SCCs, optimized to " << optimalSccs.size() << " SCCs."); - - std::vector* currentX = nullptr; - std::vector* swap = nullptr; - size_t currentMaxLocalIterations = 0; - size_t localIterations = 0; - size_t globalIterations = 0; - bool converged = true; - - // Iterate over all SCCs of the MDP as specified by the topological sort. This guarantees that an SCC is only - // solved after all SCCs it depends on have been solved. - for (auto sccIndexIt = optimalSccs.cbegin(); sccIndexIt != optimalSccs.cend() && converged; ++sccIndexIt) { - bool const useGpu = sccIndexIt->first; - storm::storage::StateBlock const& scc = sccIndexIt->second; - - // Generate a sub matrix - storm::storage::BitVector subMatrixIndices(this->A->getColumnCount(), scc.cbegin(), scc.cend()); - storm::storage::SparseMatrix sccSubmatrix = this->A->getSubmatrix(true, subMatrixIndices, subMatrixIndices); - std::vector sccSubB(sccSubmatrix.getRowCount()); - storm::utility::vector::selectVectorValues(sccSubB, subMatrixIndices, nondeterministicChoiceIndices, b); - std::vector sccSubX(sccSubmatrix.getColumnCount()); - std::vector sccSubXSwap(sccSubmatrix.getColumnCount()); - std::vector sccMultiplyResult(sccSubmatrix.getRowCount()); - - // Prepare the pointers for swapping in the calculation - currentX = &sccSubX; - swap = &sccSubXSwap; - - storm::utility::vector::selectVectorValues(sccSubX, subMatrixIndices, x); // x is getCols() large, where as b and multiplyResult are getRows() (nondet. choices times states) - std::vector sccSubNondeterministicChoiceIndices(sccSubmatrix.getColumnCount() + 1); - sccSubNondeterministicChoiceIndices.at(0) = 0; - - // Pre-process all dependent states - // Remove outgoing transitions and create the ChoiceIndices - uint_fast64_t innerIndex = 0; - uint_fast64_t outerIndex = 0; - for (uint_fast64_t state : scc) { - // Choice Indices - sccSubNondeterministicChoiceIndices.at(outerIndex + 1) = sccSubNondeterministicChoiceIndices.at(outerIndex) + (nondeterministicChoiceIndices[state + 1] - nondeterministicChoiceIndices[state]); - - for (auto rowGroupIt = nondeterministicChoiceIndices[state]; rowGroupIt != nondeterministicChoiceIndices[state + 1]; ++rowGroupIt) { - typename storm::storage::SparseMatrix::const_rows row = this->A->getRow(rowGroupIt); - for (auto rowIt = row.begin(); rowIt != row.end(); ++rowIt) { - if (!subMatrixIndices.get(rowIt->getColumn())) { - // This is an outgoing transition of a state in the SCC to a state not included in the SCC - // Subtracting Pr(tau) * x_other from b fixes that - sccSubB.at(innerIndex) = sccSubB.at(innerIndex) + (rowIt->getValue() * x.at(rowIt->getColumn())); - } - } - ++innerIndex; - } - ++outerIndex; - } - - // For the current SCC, we need to perform value iteration until convergence. - if (useGpu) { -#ifdef STORM_HAVE_CUDA - STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA-based equation solver."); - - //STORM_LOG_INFO("Device has " << getTotalCudaMemory() << " Bytes of Memory with " << getFreeCudaMemory() << "Bytes free (" << (static_cast(getFreeCudaMemory()) / static_cast(getTotalCudaMemory())) * 100 << "%)."); - //STORM_LOG_INFO("We will allocate " << (sizeof(uint_fast64_t)* sccSubmatrix.rowIndications.size() + sizeof(uint_fast64_t)* sccSubmatrix.columnsAndValues.size() * 2 + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubB.size() + sizeof(double)* sccSubB.size() + sizeof(uint_fast64_t)* sccSubNondeterministicChoiceIndices.size()) << " Bytes."); - //STORM_LOG_INFO("The CUDA Runtime Version is " << getRuntimeCudaVersion()); - - bool result = false; - localIterations = 0; - if (dir == OptimizationDirection::Minimum) { - result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); - } else { - result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); - } - STORM_LOG_INFO("Executed " << localIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); - - if (!result) { - converged = false; - STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); - throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; - } else { - converged = true; - } - - // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep - // track of the maximum. - if (localIterations > currentMaxLocalIterations) { - currentMaxLocalIterations = localIterations; - } - globalIterations += localIterations; -#else - STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); - throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; -#endif - } else { - //std::cout << "WARNING: Using CPU based TopoSolver! (double)" << std::endl; - STORM_LOG_INFO("Performance Warning: Using CPU based TopoSolver! (double)"); - localIterations = 0; - converged = false; - while (!converged && localIterations < maxIters) { - // Compute x' = A*x + b. - sccSubmatrix.multiplyWithVector(*currentX, sccMultiplyResult); - storm::utility::vector::addVectors(sccMultiplyResult, sccSubB, sccMultiplyResult); - - //A.multiplyWithVector(scc, nondeterministicChoiceIndices, *currentX, multiplyResult); - //storm::utility::addVectors(scc, nondeterministicChoiceIndices, multiplyResult, b); - - /* - Versus: - A.multiplyWithVector(*currentX, *multiplyResult); - storm::utility::vector::addVectorsInPlace(*multiplyResult, b); - */ - - // Reduce the vector x' by applying min/max for all non-deterministic choices. - storm::utility::vector::reduceVectorMinOrMax(dir,sccMultiplyResult, *swap, sccSubNondeterministicChoiceIndices); - - // Determine whether the method converged. - // TODO: It seems that the equalModuloPrecision call that compares all values should have a higher - // running time. In fact, it is faster. This has to be investigated. - // converged = storm::utility::equalModuloPrecision(*currentX, *newX, scc, precision, relative); - converged = storm::utility::vector::equalModuloPrecision(*currentX, *swap, precision, relative); - - // Update environment variables. - std::swap(currentX, swap); - - ++localIterations; - ++globalIterations; - } - STORM_LOG_INFO("Executed " << localIterations << " of max. " << maxIters << " Iterations."); - } - - - // The Result of this SCC has to be taken back into the main result vector - innerIndex = 0; - for (uint_fast64_t state : scc) { - x.at(state) = currentX->at(innerIndex); - ++innerIndex; - } - - // Since the pointers for swapping in the calculation point to temps they should not be valid anymore - currentX = nullptr; - swap = nullptr; - - // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep - // track of the maximum. - if (localIterations > currentMaxLocalIterations) { - currentMaxLocalIterations = localIterations; - } - } - - //std::cout << "Used a total of " << globalIterations << " iterations with a maximum of " << localIterations << " iterations in a single block." << std::endl; - - // Check if the solver converged and issue a warning otherwise. - if (converged) { - STORM_LOG_INFO("Iterative solver converged after " << currentMaxLocalIterations << " iterations."); - } else { - STORM_LOG_WARN("Iterative solver did not converged after " << currentMaxLocalIterations << " iterations."); - } - - return converged; - } - } - - template - std::vector> - TopologicalMinMaxLinearEquationSolver::getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const { - - (void)matrix; - - std::vector> result; - -#ifdef STORM_HAVE_CUDA - // 95% to have a bit of padding - size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); - size_t lastResultIndex = 0; - - std::vector const& rowGroupIndices = matrix.getRowGroupIndices(); - - size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(matrix.getRowCount()), rowGroupIndices.size(), static_cast(matrix.getEntryCount())); - size_t const gpuSizePerRowGroup = std::max(static_cast(gpuSizeOfCompleteSystem / rowGroupIndices.size()), static_cast(1)); - size_t const maxRowGroupsPerMemory = cudaFreeMemory / gpuSizePerRowGroup; - - size_t currentSize = 0; - size_t neededReserveSize = 0; - size_t startIndex = 0; - for (size_t i = 0; i < topologicalSort.size(); ++i) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[i]]; - size_t const currentSccSize = scc.size(); - - uint_fast64_t rowCount = 0; - uint_fast64_t entryCount = 0; - - for (auto sccIt = scc.cbegin(); sccIt != scc.cend(); ++sccIt) { - rowCount += matrix.getRowGroupSize(*sccIt); - entryCount += matrix.getRowGroupEntryCount(*sccIt); - } - - size_t sccSize = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(rowCount), scc.size(), static_cast(entryCount)); - - if ((currentSize + sccSize) <= cudaFreeMemory) { - // There is enough space left in the current group - neededReserveSize += currentSccSize; - currentSize += sccSize; - } else { - // This would make the last open group to big for the GPU - - if (startIndex < i) { - if ((startIndex + 1) < i) { - // More than one component - std::vector tempGroups; - tempGroups.reserve(neededReserveSize); - - // Copy the first group to make inplace_merge possible - storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; - tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); - - if (((startIndex + 1) + 80) >= i) { - size_t lastSize = 0; - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - lastSize = tempGroups.size(); - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - std::vector::iterator middleIterator = tempGroups.begin(); - std::advance(middleIterator, lastSize); - std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); - } - } else { - // Use std::sort - for (size_t j = startIndex + 1; j < i; ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - } - std::sort(tempGroups.begin(), tempGroups.end()); - } - result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); - } else { - // Only one group, copy construct. - result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); - } - ++lastResultIndex; - } - - if (sccSize <= cudaFreeMemory) { - currentSize = sccSize; - neededReserveSize = currentSccSize; - startIndex = i; - } else { - // This group is too big to fit into the CUDA Memory by itself - result.push_back(std::make_pair(false, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[i]])))); - ++lastResultIndex; - - currentSize = 0; - neededReserveSize = 0; - startIndex = i + 1; - } - } - } - - size_t const topologicalSortSize = topologicalSort.size(); - if (startIndex < topologicalSortSize) { - if ((startIndex + 1) < topologicalSortSize) { - // More than one component - std::vector tempGroups; - tempGroups.reserve(neededReserveSize); - - // Copy the first group to make inplace_merge possible. - storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; - tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); - - // For set counts <= 80, in-place merge is faster. - if (((startIndex + 1) + 80) >= topologicalSortSize) { - size_t lastSize = 0; - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - lastSize = tempGroups.size(); - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - std::vector::iterator middleIterator = tempGroups.begin(); - std::advance(middleIterator, lastSize); - std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); - } - } else { - // Use std::sort - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - } - std::sort(tempGroups.begin(), tempGroups.end()); - } - result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); - } - else { - // Only one group, copy construct. - result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); - } - ++lastResultIndex; - } -#else - for (auto sccIndexIt = topologicalSort.cbegin(); sccIndexIt != topologicalSort.cend(); ++sccIndexIt) { - storm::storage::StateBlock const& scc = sccDecomposition[*sccIndexIt]; - result.push_back(std::make_pair(false, scc)); - } -#endif - return result; - } - - template - void TopologicalMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - std::unique_ptr> multiplyResult = std::make_unique>(this->A->getRowCount()); - - // Now perform matrix-vector multiplication as long as we meet the bound of the formula. - for (uint_fast64_t i = 0; i < n; ++i) { - this->A->multiplyWithVector(x, *multiplyResult); - - // Add b if it is non-null. - if (b != nullptr) { - storm::utility::vector::addVectors(*multiplyResult, *b, *multiplyResult); - } - - // Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost - // element of the min/max operator stack. - storm::utility::vector::reduceVectorMinOrMax(dir, *multiplyResult, x, this->A->getRowGroupIndices()); - } - } - - template - TopologicalMinMaxLinearEquationSolverFactory::TopologicalMinMaxLinearEquationSolverFactory(bool trackScheduler) { - // Intentionally left empty. - } - - template - std::unique_ptr> TopologicalMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - return std::make_unique>(); - } - - // Explicitly instantiate the solver. - template class TopologicalMinMaxLinearEquationSolver; - - template class TopologicalMinMaxLinearEquationSolverFactory; - } // namespace solver -} // namespace storm diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index 7bf35c2d2..e69de29bb 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -1,154 +0,0 @@ -#ifndef STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ -#define STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ - -#include "storm/solver/MinMaxLinearEquationSolver.h" -#include "storm/storage/StronglyConnectedComponentDecomposition.h" -#include "storm/storage/SparseMatrix.h" -#include "storm/exceptions/NotImplementedException.h" -#include "storm/exceptions/NotSupportedException.h" - -#include -#include - -#include "storm-config.h" -#ifdef STORM_HAVE_CUDA -#include "cudaForStorm.h" -#endif - -namespace storm { - namespace solver { - - /*! - * A class that uses SCC Decompositions to solve a min/max linear equation system. - */ - template - class TopologicalMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { - public: - TopologicalMinMaxLinearEquationSolver(); - - /*! - * Constructs a min-max linear equation solver with parameters being set according to the settings - * object. - * - * @param A The matrix defining the coefficients of the linear equation system. - */ - TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); - - virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; - virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; - - virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; - - virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; - - private: - storm::storage::SparseMatrix const* A; - std::unique_ptr> localA; - - bool enableCuda; - /*! - * Given a topological sort of a SCC Decomposition, this will calculate the optimal grouping of SCCs with respect to the size of the GPU memory. - */ - std::vector> getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const; - }; - - template - bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector& x, std::vector const&, std::vector const&, size_t&) { - // - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); - } - template <> - inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_double_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - template <> - inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_float_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - - template - bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector&, std::vector const&, std::vector const&, size_t&) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); - } - template <> - inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_double_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - template <> - inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_float_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - - template - class TopologicalMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { - public: - TopologicalMinMaxLinearEquationSolverFactory(bool trackScheduler = false); - - protected: - virtual std::unique_ptr> create(Environment const& env) const override; - }; - - } // namespace solver -} // namespace storm - -#endif /* STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ */ diff --git a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp index 5da2067e5..3caf14699 100644 --- a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp +++ b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp @@ -45,6 +45,17 @@ namespace { return env; } }; + class DoubleTopologicalCudaViEnvironment { + public: + typedef double ValueType; + static const bool isExact = false; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::TopologicalCuda); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-8)); + return env; + } + }; class DoublePIEnvironment { public: typedef double ValueType; @@ -96,6 +107,7 @@ namespace { DoubleViEnvironment, DoubleSoundViEnvironment, DoubleTopologicalViEnvironment, + DoubleTopologicalCudaViEnvironment, DoublePIEnvironment, RationalPIEnvironment, RationalRationalSearchEnvironment From 2d910b79ed9d6b508b1333c8f1133f67cead9982 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 16:33:47 +0100 Subject: [PATCH 079/647] Introduced new topological min max solver --- src/storm/environment/SubEnvironment.cpp | 4 +- .../solver/MinMaxSolverEnvironment.cpp | 4 +- .../solver/MinMaxSolverEnvironment.h | 2 +- .../environment/solver/SolverEnvironment.cpp | 12 +- .../environment/solver/SolverEnvironment.h | 10 +- ...logicalLinearEquationSolverEnvironment.cpp | 37 -- ...pologicalLinearEquationSolverEnvironment.h | 24 - .../solver/TopologicalSolverEnvironment.cpp | 56 +++ .../solver/TopologicalSolverEnvironment.h | 31 ++ .../solver/MinMaxLinearEquationSolver.cpp | 2 + .../TopologicalLinearEquationSolver.cpp | 38 +- .../TopologicalMinMaxLinearEquationSolver.cpp | 434 ++++++++++++++++++ .../TopologicalMinMaxLinearEquationSolver.h | 73 +++ .../DtmcPrctlModelCheckerTest.cpp | 4 +- .../modelchecker/MdpPrctlModelCheckerTest.cpp | 39 ++ .../storm/solver/LinearEquationSolverTest.cpp | 4 +- .../solver/MinMaxLinearEquationSolverTest.cpp | 4 + 17 files changed, 676 insertions(+), 102 deletions(-) delete mode 100644 src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp delete mode 100644 src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h create mode 100644 src/storm/environment/solver/TopologicalSolverEnvironment.cpp create mode 100644 src/storm/environment/solver/TopologicalSolverEnvironment.h diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index 6227548e5..45c833110 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -5,7 +5,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" namespace storm { @@ -41,7 +41,7 @@ namespace storm { template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; - template class SubEnvironment; + template class SubEnvironment; } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index d44eac259..83ff18826 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -34,8 +34,8 @@ namespace storm { return methodSetFromDefault; } - void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value) { - methodSetFromDefault = false; + void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault) { + methodSetFromDefault = isSetFromDefault; minMaxMethod = value; } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.h b/src/storm/environment/solver/MinMaxSolverEnvironment.h index 999ed18bd..f7e0a24b1 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.h +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.h @@ -16,7 +16,7 @@ namespace storm { storm::solver::MinMaxMethod const& getMethod() const; bool const& isMethodSetFromDefault() const; - void setMethod(storm::solver::MinMaxMethod value); + void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault = false); uint64_t const& getMaximalNumberOfIterations() const; void setMaximalNumberOfIterations(uint64_t value); storm::RationalNumber const& getPrecision() const; diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index b9635757c..5fc371072 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -5,7 +5,7 @@ #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" @@ -68,11 +68,11 @@ namespace storm { return gameSolverEnvironment.get(); } - TopologicalLinearEquationSolverEnvironment& SolverEnvironment::topological() { + TopologicalSolverEnvironment& SolverEnvironment::topological() { return topologicalSolverEnvironment.get(); } - TopologicalLinearEquationSolverEnvironment const& SolverEnvironment::topological() const { + TopologicalSolverEnvironment const& SolverEnvironment::topological() const { return topologicalSolverEnvironment.get(); } @@ -88,8 +88,8 @@ namespace storm { return linearEquationSolverType; } - void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault) { - linearEquationSolverTypeSetFromDefault = assumeSetFromDefault; + void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault) { + linearEquationSolverTypeSetFromDefault = isSetFromDefault; linearEquationSolverType = value; } @@ -113,7 +113,7 @@ namespace storm { case storm::solver::EquationSolverType::Elimination: break; case storm::solver::EquationSolverType::Topological: - result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingSolverType()); + result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingEquationSolverType()); break; default: STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "The selected solver type is unknown."); diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index 614fd1d02..32c3cb648 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -16,7 +16,7 @@ namespace storm { class NativeSolverEnvironment; class MinMaxSolverEnvironment; class GameSolverEnvironment; - class TopologicalLinearEquationSolverEnvironment; + class TopologicalSolverEnvironment; class SolverEnvironment { public: @@ -34,14 +34,14 @@ namespace storm { MinMaxSolverEnvironment const& minMax() const; GameSolverEnvironment& game(); GameSolverEnvironment const& game() const; - TopologicalLinearEquationSolverEnvironment& topological(); - TopologicalLinearEquationSolverEnvironment const& topological() const; + TopologicalSolverEnvironment& topological(); + TopologicalSolverEnvironment const& topological() const; bool isForceSoundness() const; void setForceSoundness(bool value); storm::solver::EquationSolverType const& getLinearEquationSolverType() const; - void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool assumeSetFromDefault = false); + void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault = false); bool isLinearEquationSolverTypeSetFromDefaultValue() const; std::pair, boost::optional> getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const; @@ -52,7 +52,7 @@ namespace storm { SubEnvironment gmmxxSolverEnvironment; SubEnvironment nativeSolverEnvironment; SubEnvironment gameSolverEnvironment; - SubEnvironment topologicalSolverEnvironment; + SubEnvironment topologicalSolverEnvironment; SubEnvironment minMaxSolverEnvironment; storm::solver::EquationSolverType linearEquationSolverType; diff --git a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp deleted file mode 100644 index a0f3ac030..000000000 --- a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/TopologicalEquationSolverSettings.h" -#include "storm/utility/macros.h" - -#include "storm/exceptions/InvalidArgumentException.h" - -namespace storm { - - TopologicalLinearEquationSolverEnvironment::TopologicalLinearEquationSolverEnvironment() { - auto const& topologicalSettings = storm::settings::getModule(); - underlyingSolverType = topologicalSettings.getUnderlyingEquationSolverType(); - underlyingSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); - } - - TopologicalLinearEquationSolverEnvironment::~TopologicalLinearEquationSolverEnvironment() { - // Intentionally left empty - } - - storm::solver::EquationSolverType const& TopologicalLinearEquationSolverEnvironment::getUnderlyingSolverType() const { - return underlyingSolverType; - } - - bool const& TopologicalLinearEquationSolverEnvironment::isUnderlyingSolverTypeSetFromDefault() const { - return underlyingSolverTypeSetFromDefault; - } - - void TopologicalLinearEquationSolverEnvironment::setUnderlyingSolverType(storm::solver::EquationSolverType value) { - STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); - underlyingSolverTypeSetFromDefault = false; - underlyingSolverType = value; - } - - - -} diff --git a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h b/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h deleted file mode 100644 index b79ed66a9..000000000 --- a/src/storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "storm/environment/solver/SolverEnvironment.h" - -#include "storm/solver/SolverSelectionOptions.h" - -namespace storm { - - class TopologicalLinearEquationSolverEnvironment { - public: - - TopologicalLinearEquationSolverEnvironment(); - ~TopologicalLinearEquationSolverEnvironment(); - - storm::solver::EquationSolverType const& getUnderlyingSolverType() const; - bool const& isUnderlyingSolverTypeSetFromDefault() const; - void setUnderlyingSolverType(storm::solver::EquationSolverType value); - - private: - storm::solver::EquationSolverType underlyingSolverType; - bool underlyingSolverTypeSetFromDefault; - }; -} - diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp new file mode 100644 index 000000000..244adc1fa --- /dev/null +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp @@ -0,0 +1,56 @@ +#include "storm/environment/solver/TopologicalSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + + TopologicalSolverEnvironment::TopologicalSolverEnvironment() { + auto const& topologicalSettings = storm::settings::getModule(); + underlyingEquationSolverType = topologicalSettings.getUnderlyingEquationSolverType(); + underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); + + std::cout << "Get topo env minmax from settings!!" << std::endl; + underlyingMinMaxMethod = storm::solver::MinMaxMethod::ValueIteration; + underlyingEquationSolverTypeSetFromDefault = false; + + } + + TopologicalSolverEnvironment::~TopologicalSolverEnvironment() { + // Intentionally left empty + } + + storm::solver::EquationSolverType const& TopologicalSolverEnvironment::getUnderlyingEquationSolverType() const { + return underlyingEquationSolverType; + } + + bool const& TopologicalSolverEnvironment::isUnderlyingEquationSolverTypeSetFromDefault() const { + return underlyingEquationSolverTypeSetFromDefault; + } + + void TopologicalSolverEnvironment::setUnderlyingEquationSolverType(storm::solver::EquationSolverType value) { + STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); + underlyingEquationSolverTypeSetFromDefault = false; + underlyingEquationSolverType = value; + } + + storm::solver::MinMaxMethod const& TopologicalSolverEnvironment::getUnderlyingMinMaxMethod() const { + return underlyingMinMaxMethod; + } + + bool const& TopologicalSolverEnvironment::isUnderlyingMinMaxMethodSetFromDefault() const { + return underlyingMinMaxMethodSetFromDefault; + } + + void TopologicalSolverEnvironment::setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value) { + STORM_LOG_THROW(value != storm::solver::MinMaxMethod::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); + underlyingMinMaxMethodSetFromDefault = false; + underlyingMinMaxMethod = value; + } + + + +} diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.h b/src/storm/environment/solver/TopologicalSolverEnvironment.h new file mode 100644 index 000000000..594dd3d86 --- /dev/null +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.h @@ -0,0 +1,31 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class TopologicalSolverEnvironment { + public: + + TopologicalSolverEnvironment(); + ~TopologicalSolverEnvironment(); + + storm::solver::EquationSolverType const& getUnderlyingEquationSolverType() const; + bool const& isUnderlyingEquationSolverTypeSetFromDefault() const; + void setUnderlyingEquationSolverType(storm::solver::EquationSolverType value); + + storm::solver::MinMaxMethod const& getUnderlyingMinMaxMethod() const; + bool const& isUnderlyingMinMaxMethodSetFromDefault() const; + void setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value); + + private: + storm::solver::EquationSolverType underlyingEquationSolverType; + bool underlyingEquationSolverTypeSetFromDefault; + + storm::solver::MinMaxMethod underlyingMinMaxMethod; + bool underlyingMinMaxMethodSetFromDefault; + }; +} + diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index 4a5066079..3c76d2f9e 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -199,6 +199,8 @@ namespace storm { auto method = env.solver().minMax().getMethod(); if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { result = std::make_unique>(std::make_unique>()); + } else if (method == MinMaxMethod::Topological) { + result = std::make_unique>(); } else if (method == MinMaxMethod::TopologicalCuda) { result = std::make_unique>(); } else if (method == MinMaxMethod::LinearProgramming) { diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 9f6dcdebf..83825d562 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -1,6 +1,6 @@ #include "storm/solver/TopologicalLinearEquationSolver.h" -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" @@ -43,7 +43,7 @@ namespace storm { template storm::Environment TopologicalLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const { storm::Environment subEnv(env); - subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingSolverType(), env.solver().topological().isUnderlyingSolverTypeSetFromDefault()); + subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingEquationSolverType(), env.solver().topological().isUnderlyingEquationSolverTypeSetFromDefault()); if (adaptPrecision) { STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed."); auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType()); @@ -54,14 +54,9 @@ namespace storm { template bool TopologicalLinearEquationSolver::internalSolveEquations(Environment const& env, std::vector& x, std::vector const& b) const { - //std::cout << "Solving equation system with fixpoint characterization " << std::endl; - //std::cout << *this->A << std::endl; - //std::cout << storm::utility::vector::toString(b) << std::endl; - //std::cout << "Initial solution vector: " << std::endl; - //std::cout << storm::utility::vector::toString(x) << std::endl; // For sound computations we need to increase the precision in each SCC - bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingSolverType()).first.is_initialized(); + bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingEquationSolverType()).first.is_initialized(); if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) { STORM_LOG_TRACE("Creating SCC decomposition."); @@ -88,21 +83,21 @@ namespace storm { } // Handle the case where there is just one large SCC - if (this->sortedSccDecomposition->size() == 1) { - return solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b); - } - - storm::storage::BitVector sccAsBitVector(x.size(), false); bool returnValue = true; - for (auto const& scc : *this->sortedSccDecomposition) { - if (scc.isTrivial()) { - returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; - } else { - sccAsBitVector.clear(); - for (auto const& state : scc) { - sccAsBitVector.set(state, true); + if (this->sortedSccDecomposition->size() == 1) { + returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b); + } else { + storm::storage::BitVector sccAsBitVector(x.size(), false); + for (auto const& scc : *this->sortedSccDecomposition) { + if (scc.isTrivial()) { + returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; + } else { + sccAsBitVector.clear(); + for (auto const& state : scc) { + sccAsBitVector.set(state, true); + } + returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue; } - returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue; } } @@ -373,6 +368,7 @@ namespace storm { template void TopologicalLinearEquationSolver::clearCache() const { sortedSccDecomposition.reset(); + longestSccChainSize = boost::none; sccSolver.reset(); LinearEquationSolver::clearCache(); } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index e69de29bb..0e285c82e 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -0,0 +1,434 @@ +#include "storm/solver/TopologicalMinMaxLinearEquationSolver.h" + +#include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" + +#include "storm/utility/constants.h" +#include "storm/utility/vector.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/UnmetRequirementException.h" + +namespace storm { + namespace solver { + + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() : localA(nullptr), A(nullptr) { + // Intentionally left empty. + } + + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(nullptr) { + this->setMatrix(A); + } + + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(nullptr), A(nullptr) { + this->setMatrix(std::move(A)); + } + + template + void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& A) { + localA.reset(); + this->A = &A; + clearCache(); + } + + template + void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& A) { + localA = std::make_unique>(std::move(A)); + this->A = localA.get(); + clearCache(); + } + + template + storm::Environment TopologicalMinMaxLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const { + storm::Environment subEnv(env); + subEnv.solver().minMax().setMethod(env.solver().topological().getUnderlyingMinMaxMethod(), env.solver().topological().isUnderlyingMinMaxMethodSetFromDefault()); + if (adaptPrecision) { + STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed."); + storm::RationalNumber subEnvPrec = subEnv.solver().minMax().getPrecision() / storm::utility::convertNumber(this->longestSccChainSize.get()); + subEnv.solver().minMax().setPrecision(subEnvPrec); + } + return subEnv; + } + + template + bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(), "Provided x-vector has invalid size."); + STORM_LOG_ASSERT(b.size() == this->A->getRowCount(), "Provided b-vector has invalid size."); + + //std::cout << "Solving equation system with fixpoint characterization " << std::endl; + //std::cout << *this->A << std::endl; + //std::cout << storm::utility::vector::toString(b) << std::endl; + //std::cout << "Initial solution vector: " << std::endl; + //std::cout << storm::utility::vector::toString(x) << std::endl; + + // For sound computations we need to increase the precision in each SCC + bool needAdaptPrecision = env.solver().isForceSoundness(); + + if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) { + STORM_LOG_TRACE("Creating SCC decomposition."); + createSortedSccDecomposition(needAdaptPrecision); + } + + //std::cout << "Sorted SCC decomposition: " << std::endl; + //for (auto const& scc : *this->sortedSccDecomposition) { + //std::cout << "SCC: "; + // for (auto const& row : scc) { + //std::cout << row << " "; + // } + //std::cout << std::endl; + //} + + // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) + needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->A->getRowGroupCount()); + + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); + + std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->A->getRowGroupCount()) / static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + if (this->longestSccChainSize) { + std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl; + } + + bool returnValue = true; + if (this->sortedSccDecomposition->size() == 1) { + // Handle the case where there is just one large SCC + returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, dir, x, b); + } else { + if (this->isTrackSchedulerSet()) { + if (this->schedulerChoices) { + this->schedulerChoices.get().resize(x.size()); + } else { + this->schedulerChoices = std::vector(x.size()); + } + } + storm::storage::BitVector sccRowGroupsAsBitVector(x.size(), false); + storm::storage::BitVector sccRowsAsBitVector(b.size(), false); + for (auto const& scc : *this->sortedSccDecomposition) { + if (scc.isTrivial()) { + returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; + } else { + sccRowGroupsAsBitVector.clear(); + sccRowsAsBitVector.clear(); + for (auto const& group : scc) { + sccRowGroupsAsBitVector.set(group, true); + for (uint64_t row = this->A->getRowGroupIndices()[group]; row < this->A->getRowGroupIndices()[group + 1]; ++row) { + sccRowsAsBitVector.set(row, true); + } + } + returnValue = solveScc(sccSolverEnvironment, dir, sccRowGroupsAsBitVector, sccRowsAsBitVector, x, b) && returnValue; + } + } + + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + if (!auxiliaryRowGroupVector) { + auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); + } + this->schedulerChoices = std::vector(this->A->getRowGroupCount()); + this->A->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); + } + } + + if (!this->isCachingEnabled()) { + clearCache(); + } + + return returnValue; + } + + template + void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { + // Obtain the scc decomposition + auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*this->A); + + // Get a mapping from matrix row to the corresponding scc + STORM_LOG_THROW(sccDecomposition.size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); + std::vector sccIndices(this->A->getRowCount(), std::numeric_limits::max()); + uint32_t sccIndex = 0; + for (auto const& scc : sccDecomposition) { + for (auto const& row : scc) { + sccIndices[row] = sccIndex; + } + ++sccIndex; + } + + // Prepare the resulting set of sorted sccs + this->sortedSccDecomposition = std::make_unique>(); + std::vector& sortedSCCs = *this->sortedSccDecomposition; + sortedSCCs.reserve(sccDecomposition.size()); + + // Find a topological sort via DFS. + storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); + std::vector sccStack, chainSizes; + if (needLongestChainSize) { + chainSizes.resize(sccDecomposition.size(), 1u); + } + uint32_t longestChainSize = 0; + uint32_t const token = std::numeric_limits::max(); + std::set successorSCCs; + + for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { + + sccStack.push_back(firstUnsortedScc); + while (!sccStack.empty()) { + uint32_t currentSccIndex = sccStack.back(); + if (currentSccIndex != token) { + // Check whether the SCC is still unprocessed + if (unsortedSCCs.get(currentSccIndex)) { + // Explore the successors of the scc. + storm::storage::StronglyConnectedComponent const& currentScc = sccDecomposition.getBlock(currentSccIndex); + // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. + sccStack.push_back(token); + // Now add all successors that are not already sorted. + // Successors should only be added once, so we first prepare a set of them and add them afterwards. + successorSCCs.clear(); + for (auto const& row : currentScc) { + for (auto const& entry : this->A->getRow(row)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { + successorSCCs.insert(successorSCC); + } + } + } + sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); + + } + } else { + // all successors of the current scc have already been explored. + sccStack.pop_back(); // pop the token + + currentSccIndex = sccStack.back(); + storm::storage::StronglyConnectedComponent& scc = sccDecomposition.getBlock(currentSccIndex); + + // Compute the longest chain size for this scc + if (needLongestChainSize) { + uint32_t& currentChainSize = chainSizes[currentSccIndex]; + for (auto const& row : scc) { + for (auto const& entry : this->A->getRow(row)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex) { + currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); + } + } + } + longestChainSize = std::max(longestChainSize, currentChainSize); + } + + unsortedSCCs.set(currentSccIndex, false); + sccStack.pop_back(); // pop the current scc index + sortedSCCs.push_back(std::move(scc)); + } + } + } + + if (longestChainSize > 0) { + this->longestSccChainSize = longestChainSize; + } + } + + template + bool TopologicalMinMaxLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, OptimizationDirection dir, std::vector& globalX, std::vector const& globalB) const { + ValueType& xi = globalX[sccState]; + bool firstRow = true; + uint64_t bestRow; + + for (uint64_t row = this->A->getRowGroupIndices()[sccState]; row < this->A->getRowGroupIndices()[sccState + 1]; ++row) { + ValueType rowValue = globalB[sccState]; + bool hasDiagonalEntry = false; + ValueType denominator; + for (auto const& entry : this->A->getRow(sccState)) { + if (entry.getColumn() == sccState) { + STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1."); + hasDiagonalEntry = true; + denominator = storm::utility::one() - entry.getValue(); + } else { + rowValue += entry.getValue() * globalX[entry.getColumn()]; + } + } + if (hasDiagonalEntry) { + rowValue /= denominator; + } + if (firstRow) { + xi = std::move(rowValue); + bestRow = row; + firstRow = false; + } else { + if (minimize(dir)) { + if (rowValue < xi) { + xi = std::move(rowValue); + bestRow = row; + } + } else { + if (rowValue > xi) { + xi = std::move(rowValue); + bestRow = row; + } + } + } + } + if (this->isTrackSchedulerSet()) { + this->schedulerChoices.get()[sccState] = bestRow - this->A->getRowGroupIndices()[sccState]; + } + //std::cout << "Solved trivial scc " << sccState << " with result " << globalX[sccState] << std::endl; + return true; + } + + template + bool TopologicalMinMaxLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + if (!this->sccSolver) { + this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + this->sccSolver->setMatrix(*this->A); + this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution()); + this->sccSolver->setBoundsFromOtherSolver(*this); + this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet()); + if (this->hasInitialScheduler()) { + auto choices = this->getInitialScheduler(); + this->sccSolver->setInitialScheduler(std::move(choices)); + } + auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); + if (req.requiresUpperBounds() && this->hasUpperBound()) { + req.clearUpperBounds(); + } + if (req.requiresLowerBounds() && this->hasLowerBound()) { + req.clearLowerBounds(); + } + STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + + bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, x, b); + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = this->sccSolver->getSchedulerChoices(); + } + return res; + } + + template + bool TopologicalMinMaxLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector& globalX, std::vector const& globalB) const { + + // Set up the SCC solver + if (!this->sccSolver) { + this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution()); + this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet()); + + // Requirements + auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); + if (req.requiresUpperBounds() && this->hasUpperBound()) { + req.clearUpperBounds(); + } + if (req.requiresLowerBounds() && this->hasLowerBound()) { + req.clearLowerBounds(); + } + if (req.requiresValidInitialScheduler() && this->hasInitialScheduler()) { + req.clearValidInitialScheduler(); + } + STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + + // SCC Matrix + storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, sccRowGroups, sccRowGroups); + this->sccSolver->setMatrix(std::move(sccA)); + + // x Vector + auto sccX = storm::utility::vector::filterVector(globalX, sccRowGroups); + + // b Vector + std::vector sccB; + sccB.reserve(sccRows.getNumberOfSetBits()); + for (auto const& row : sccRows) { + ValueType bi = globalB[row]; + for (auto const& entry : this->A->getRow(row)) { + if (!sccRowGroups.get(entry.getColumn())) { + bi += entry.getValue() * globalX[entry.getColumn()]; + } + } + sccB.push_back(std::move(bi)); + } + + // initial scheduler + if (this->hasInitialScheduler()) { + auto sccInitChoices = storm::utility::vector::filterVector(this->getInitialScheduler(), sccRowGroups); + this->sccSolver->setInitialScheduler(std::move(sccInitChoices)); + } + + // lower/upper bounds + if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setLowerBound(this->getLowerBound()); + } else if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setLowerBounds(storm::utility::vector::filterVector(this->getLowerBounds(), sccRowGroups)); + } + if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setUpperBound(this->getUpperBound()); + } else if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), sccRowGroups)); + } + + // Invoke scc solver + bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, sccX, sccB); + //std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl; + //std::cout << "x is " << storm::utility::vector::toString(sccX) << std::endl; + + // Set Scheduler choices + if (this->isTrackSchedulerSet()) { + storm::utility::vector::setVectorValues(this->schedulerChoices.get(), sccRowGroups, this->sccSolver->getSchedulerChoices()); + } + + // Set solution + storm::utility::vector::setVectorValues(globalX, sccRowGroups, sccX); + + return res; + } + + template + void TopologicalMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n) const { + + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env); + + // Set up the SCC solver + if (!this->sccSolver) { + this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + this->sccSolver->setMatrix(*this->A); + this->sccSolver->repeatedMultiply(sccSolverEnvironment, d, x, b, n); + + if (!this->isCachingEnabled()) { + clearCache(); + } + } + + template + MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + // Return the requirements of the underlying solver + return GeneralMinMaxLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, assumeNoInitialScheduler); + } + + template + void TopologicalMinMaxLinearEquationSolver::clearCache() const { + sortedSccDecomposition.reset(); + longestSccChainSize = boost::none; + sccSolver.reset(); + auxiliaryRowGroupVector.reset(); + MinMaxLinearEquationSolver::clearCache(); + } + + template + std::unique_ptr> TopologicalMinMaxLinearEquationSolverFactory::create(Environment const& env) const { + return std::make_unique>(); + } + + // Explicitly instantiate the min max linear equation solver. + template class TopologicalMinMaxLinearEquationSolver; + template class TopologicalMinMaxLinearEquationSolverFactory; + +#ifdef STORM_HAVE_CARL + template class TopologicalMinMaxLinearEquationSolver; + template class TopologicalMinMaxLinearEquationSolverFactory; +#endif + } +} diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index e69de29bb..d1ad36e4a 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -0,0 +1,73 @@ +#pragma once + +#include "storm/solver/MinMaxLinearEquationSolver.h" + +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" + +namespace storm { + + class Environment; + + namespace solver { + + template + class TopologicalMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { + public: + TopologicalMinMaxLinearEquationSolver(); + TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); + TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); + + virtual void setMatrix(storm::storage::SparseMatrix const& A) override; + virtual void setMatrix(storm::storage::SparseMatrix&& A) override; + + + virtual void clearCache() const override; + + virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override ; + + protected: + + virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const override; + + private: + storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const; + + // Creates an SCC decomposition and sorts the SCCs according to a topological sort. + void createSortedSccDecomposition(bool needLongestChainSize) const; + + // Solves the SCC with the given index + // ... for the case that the SCC is trivial + bool solveTrivialScc(uint64_t const& sccState, OptimizationDirection d, std::vector& globalX, std::vector const& globalB) const; + // ... for the case that there is just one large SCC + bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, std::vector& x, std::vector const& b) const; + // ... for the remaining cases (1 < scc.size() < x.size()) + bool solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector& globalX, std::vector const& globalB) const; + + // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted + // when the solver is destructed. + std::unique_ptr> localA; + + // A pointer to the original sparse matrix given to this solver. If the solver takes posession of the matrix + // the pointer refers to localA. + storm::storage::SparseMatrix const* A; + + // cached auxiliary data + mutable std::unique_ptr> sortedSccDecomposition; + mutable boost::optional longestSccChainSize; + mutable std::unique_ptr> sccSolver; + mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries + }; + + template + class TopologicalMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { + public: + using MinMaxLinearEquationSolverFactory::create; + + virtual std::unique_ptr> create(Environment const& env) const override; + + }; + + } +} diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index 0040dd81f..bb569e5a5 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -25,7 +25,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" namespace { @@ -266,7 +266,7 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological); - env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen); + env.solver().topological().setUnderlyingEquationSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); return env; } diff --git a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp index 99cf434f6..668a94796 100644 --- a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp @@ -19,6 +19,7 @@ #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/QualitativeCheckResult.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/logic/Formulas.h" #include "storm/storage/jani/Property.h" @@ -71,6 +72,42 @@ namespace { return env; } }; + + class SparseDoubleTopologicalValueIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::Mdp ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological); + env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-8)); + env.solver().minMax().setRelativeTerminationCriterion(false); + return env; + } + }; + + class SparseDoubleTopologicalSoundValueIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::Mdp ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setForceSoundness(true); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological); + env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); + env.solver().minMax().setRelativeTerminationCriterion(false); + return env; + } + }; + class SparseRationalPolicyIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models @@ -300,6 +337,8 @@ namespace { SparseDoubleValueIterationEnvironment, SparseDoubleSoundValueIterationEnvironment, SparseDoubleQuickValueIterationEnvironment, + SparseDoubleTopologicalValueIterationEnvironment, + SparseDoubleTopologicalSoundValueIterationEnvironment, SparseRationalPolicyIterationEnvironment, SparseRationalRationalSearchEnvironment, HybridCuddDoubleValueIterationEnvironment, diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index 0ab4c1a55..f1ef97220 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -6,7 +6,7 @@ #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" -#include "storm/environment/solver/TopologicalLinearEquationSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/utility/vector.h" namespace { @@ -273,7 +273,7 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Topological); - env.solver().topological().setUnderlyingSolverType(storm::solver::EquationSolverType::Eigen); + env.solver().topological().setUnderlyingEquationSolverType(storm::solver::EquationSolverType::Eigen); env.solver().eigen().setMethod(storm::solver::EigenLinearEquationSolverMethod::SparseLU); return env; } diff --git a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp index 3caf14699..e34cf6a31 100644 --- a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp +++ b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp @@ -6,6 +6,7 @@ #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/solver/SolverSelectionOptions.h" #include "storm/storage/SparseMatrix.h" @@ -34,6 +35,7 @@ namespace { return env; } }; + class DoubleTopologicalViEnvironment { public: typedef double ValueType; @@ -41,10 +43,12 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological); + env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-8)); return env; } }; + class DoubleTopologicalCudaViEnvironment { public: typedef double ValueType; From 7eab8589bd217a285b9be7d837e96c513c13d691 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 16:34:21 +0100 Subject: [PATCH 080/647] Fixed issue in qpower --- src/storm/solver/NativeLinearEquationSolver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 56498f06e..76e261961 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -606,7 +606,7 @@ namespace storm { bool terminate = false; uint64_t minIndex(0), maxIndex(0); ValueType minValueBound, maxValueBound; - bool hasMinValueBound, hasMaxValueBound; + bool hasMinValueBound(false), hasMaxValueBound(false); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { minValueBound = this->getLowerBound(true); @@ -688,9 +688,11 @@ namespace storm { } if (!hasMinValueBound || minValueBoundCandidate > minValueBound) { minValueBound = minValueBoundCandidate; + hasMinValueBound = true; } if (!hasMaxValueBound || maxValueBoundCandidate < maxValueBound) { maxValueBound = maxValueBoundCandidate; + hasMaxValueBound = true; } absoluteError = stayProb * (maxValueBound - minValueBound); if (absoluteError <= maxAllowedError) { @@ -724,6 +726,7 @@ namespace storm { } + // Finally set up the solution vector ValueType meanBound = (maxValueBound + minValueBound) / storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); @@ -733,6 +736,7 @@ namespace storm { } this->logIterations(converged, terminate, iterations); + STORM_LOG_WARN_COND(hasMinValueBound && hasMaxValueBound, "Could not compute lower or upper bound within the given number of iterations."); STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); return converged; From 6b3a02d7324b38c5dc3b768380703b3ef500fae6 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 16:58:15 +0100 Subject: [PATCH 081/647] Fixing topological cuda --- src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp index 083e2581f..839c9417f 100644 --- a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp @@ -49,7 +49,7 @@ namespace storm { template bool TopologicalCudaMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); + STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::TopologicalCuda, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); uint64_t maxIters = env.solver().minMax().getMaximalNumberOfIterations(); From a2bd1e0026d37c02dca004ed6ecf28facd4872a4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 17:32:03 +0100 Subject: [PATCH 082/647] renamed argument from getRequirements so that it is easier to understand --- ...SparseDtmcParameterLiftingModelChecker.cpp | 4 +-- .../helper/SparseMarkovAutomatonCslHelper.cpp | 6 ++-- .../StandardMaPcaaWeightVectorChecker.cpp | 2 +- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 2 +- .../prctl/helper/HybridMdpPrctlHelper.cpp | 4 +-- .../prctl/helper/SparseMdpPrctlHelper.cpp | 4 +-- .../IterativeMinMaxLinearEquationSolver.cpp | 4 +-- .../IterativeMinMaxLinearEquationSolver.h | 2 +- .../solver/LpMinMaxLinearEquationSolver.cpp | 2 +- .../solver/LpMinMaxLinearEquationSolver.h | 2 +- .../solver/MinMaxLinearEquationSolver.cpp | 6 ++-- src/storm/solver/MinMaxLinearEquationSolver.h | 4 +-- .../TopologicalMinMaxLinearEquationSolver.cpp | 30 +++++++++---------- .../TopologicalMinMaxLinearEquationSolver.h | 2 +- 14 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp index 9c009ccee..c8cb685e5 100644 --- a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -150,7 +150,7 @@ namespace storm { upperResultBound = storm::utility::one(); // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). - auto req = solverFactory->getRequirements(env, true); + auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearBounds(); STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement."); solverFactory->setRequirementsChecked(true); @@ -189,7 +189,7 @@ namespace storm { lowerResultBound = storm::utility::zero(); // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). - auto req = solverFactory->getRequirements(env, true); + auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearLowerBounds(); if (req.requiresUpperBounds()) { solvingRequiresUpperRewardBounds = true; diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index ad3db92f0..62672023b 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -104,7 +104,7 @@ namespace storm { // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -403,7 +403,7 @@ namespace storm { std::vector x(numberOfSspStates); // Check for requirements of the solver. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -616,7 +616,7 @@ namespace storm { // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearLowerBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp index 8505ab035..211a12cc4 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp @@ -303,7 +303,7 @@ namespace storm { result->solver->setHasUniqueSolution(true); result->solver->setTrackScheduler(true); result->solver->setCachingEnabled(true); - auto req = result->solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, true); + auto req = result->solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, false); boost::optional lowerBound = this->computeWeightedResultBound(true, weightVector, storm::storage::BitVector(weightVector.size(), true)); if (lowerBound) { result->solver->setLowerBound(lowerBound.get()); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index bd93a44ef..068d08b63 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -179,7 +179,7 @@ namespace storm { solver->setTrackScheduler(true); solver->setHasUniqueSolution(true); solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); - auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, true); + auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize); setBoundsToSolver(*solver, req.requiresLowerBounds(), req.requiresUpperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix, ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues); if (solver->hasLowerBound()) { req.clearLowerBounds(); diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index ad1903d1c..2e14497d5 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -146,7 +146,7 @@ namespace storm { // If we minimize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Minimize; // Check for requirements of the solver early so we can adjust the maybe state computation accordingly. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir, true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; SolverRequirementsData solverRequirementsData; bool extendMaybeStates = false; @@ -517,7 +517,7 @@ namespace storm { // If we maximize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Maximize; // Check for requirements of the solver this early so we can adapt the maybe states accordingly. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir, true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; bool extendMaybeStates = false; if (!clearedRequirements.empty()) { diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 10311c2a2..91ff99c8a 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -433,7 +433,7 @@ namespace storm { // Check for requirements of the solver. bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().hasSchedulerHint(); - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, !hasSchedulerHint); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, hasSchedulerHint); if (!requirements.empty()) { // If the solver still requires no end-components, we have to eliminate them later. @@ -1298,7 +1298,7 @@ namespace storm { storm::storage::SparseMatrix sspMatrix = sspMatrixBuilder.build(currentChoice, numberOfSspStates, numberOfSspStates); // Check for requirements of the solver. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction(), true); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction()); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 5e7600feb..bb4886094 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -212,12 +212,12 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { auto method = getMethod(env, storm::NumberTraits::IsExact); // Start by getting the requirements of the linear equation solver. LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && assumeNoInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { linEqTask = LinearEquationSolverTask::Multiply; } MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index fac4555fc..f8943a57a 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -26,7 +26,7 @@ namespace storm { virtual void clearCache() const override; - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override; private: diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp index 2067c7949..3add9ad41 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp @@ -111,7 +111,7 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, LinearEquationSolverTask::Multiply)); diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.h b/src/storm/solver/LpMinMaxLinearEquationSolver.h index df20e120f..e8a531e67 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.h +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.h @@ -21,7 +21,7 @@ namespace storm { virtual void clearCache() const override; - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override; private: std::unique_ptr> lpSolverFactory; diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index 3c76d2f9e..433e02c11 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -137,7 +137,7 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements(Environment const&, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements(Environment const&, boost::optional const& direction, bool const& hasInitialScheduler) const { return MinMaxLinearEquationSolverRequirements(); } @@ -167,11 +167,11 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements(Environment const& env, bool hasUniqueSolution, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements(Environment const& env, bool hasUniqueSolution, boost::optional const& direction, bool const& hasInitialScheduler) const { // Create dummy solver and ask it for requirements. std::unique_ptr> solver = this->create(env); solver->setHasUniqueSolution(hasUniqueSolution); - return solver->getRequirements(env, direction, assumeNoInitialScheduler); + return solver->getRequirements(env, direction, hasInitialScheduler); } template diff --git a/src/storm/solver/MinMaxLinearEquationSolver.h b/src/storm/solver/MinMaxLinearEquationSolver.h index cb442e0f4..159b3e46e 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.h +++ b/src/storm/solver/MinMaxLinearEquationSolver.h @@ -167,7 +167,7 @@ namespace storm { * Retrieves the requirements of this solver for solving equations with the current settings. The requirements * are guaranteed to be ordered according to their appearance in the SolverRequirement type. */ - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const; /*! * Notifies the solver that the requirements for solving equations have been checked. If this has not been @@ -220,7 +220,7 @@ namespace storm { * Retrieves the requirements of the solver that would be created when calling create() right now. The * requirements are guaranteed to be ordered according to their appearance in the SolverRequirement type. */ - MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, bool hasUniqueSolution = false, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const; + MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, bool hasUniqueSolution = false, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const; void setRequirementsChecked(bool value = true); bool isRequirementsCheckedSet() const; diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 0e285c82e..c90dec99b 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -317,19 +317,6 @@ namespace storm { this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution()); this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet()); - // Requirements - auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); - if (req.requiresUpperBounds() && this->hasUpperBound()) { - req.clearUpperBounds(); - } - if (req.requiresLowerBounds() && this->hasLowerBound()) { - req.clearLowerBounds(); - } - if (req.requiresValidInitialScheduler() && this->hasInitialScheduler()) { - req.clearValidInitialScheduler(); - } - STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); - // SCC Matrix storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, sccRowGroups, sccRowGroups); this->sccSolver->setMatrix(std::move(sccA)); @@ -368,6 +355,19 @@ namespace storm { this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), sccRowGroups)); } + // Requirements + auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); + if (req.requiresUpperBounds() && this->hasUpperBound()) { + req.clearUpperBounds(); + } + if (req.requiresLowerBounds() && this->hasLowerBound()) { + req.clearLowerBounds(); + } + if (req.requiresValidInitialScheduler() && this->hasInitialScheduler()) { + req.clearValidInitialScheduler(); + } + STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + // Invoke scc solver bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, sccX, sccB); //std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl; @@ -403,9 +403,9 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { // Return the requirements of the underlying solver - return GeneralMinMaxLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, assumeNoInitialScheduler); + return GeneralMinMaxLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, hasInitialScheduler); } template diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index d1ad36e4a..3ac93955d 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -25,7 +25,7 @@ namespace storm { virtual void clearCache() const override; virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override ; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override ; protected: From 29b40899bfe3ee81cbb3c6b68dd33b3f66ea49f2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 17:50:44 +0100 Subject: [PATCH 083/647] Removed settings of old topologicalvalueiteration solver --- src/storm-pars/settings/ParsSettings.cpp | 3 +- src/storm/settings/SettingsManager.cpp | 2 - ...alValueIterationEquationSolverSettings.cpp | 61 ------------- ...icalValueIterationEquationSolverSettings.h | 85 ------------------- 4 files changed, 1 insertion(+), 150 deletions(-) delete mode 100644 src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp delete mode 100644 src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index e36793b04..4b182760b 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -18,7 +18,6 @@ #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GameSolverSettings.h" #include "storm/settings/modules/BisimulationSettings.h" -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" @@ -48,7 +47,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 80cfbb58b..2d99b739c 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -30,7 +30,6 @@ #include "storm/settings/modules/GlpkSettings.h" #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" #include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" @@ -527,7 +526,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp deleted file mode 100644 index ead40d320..000000000 --- a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" - -#include "storm/settings/Option.h" -#include "storm/settings/OptionBuilder.h" -#include "storm/settings/ArgumentBuilder.h" -#include "storm/settings/Argument.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/GeneralSettings.h" -#include "storm/solver/SolverSelectionOptions.h" - -namespace storm { - namespace settings { - namespace modules { - - const std::string TopologicalValueIterationEquationSolverSettings::moduleName = "topologicalValueIteration"; - const std::string TopologicalValueIterationEquationSolverSettings::maximalIterationsOptionName = "maxiter"; - const std::string TopologicalValueIterationEquationSolverSettings::maximalIterationsOptionShortName = "i"; - const std::string TopologicalValueIterationEquationSolverSettings::precisionOptionName = "precision"; - const std::string TopologicalValueIterationEquationSolverSettings::absoluteOptionName = "absolute"; - - TopologicalValueIterationEquationSolverSettings::TopologicalValueIterationEquationSolverSettings() : ModuleSettings(moduleName) { - - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); - - this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); - - this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").build()); - } - - bool TopologicalValueIterationEquationSolverSettings::isMaximalIterationCountSet() const { - return this->getOption(maximalIterationsOptionName).getHasOptionBeenSet(); - } - - uint_fast64_t TopologicalValueIterationEquationSolverSettings::getMaximalIterationCount() const { - return this->getOption(maximalIterationsOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); - } - - bool TopologicalValueIterationEquationSolverSettings::isPrecisionSet() const { - return this->getOption(precisionOptionName).getHasOptionBeenSet(); - } - - double TopologicalValueIterationEquationSolverSettings::getPrecision() const { - return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); - } - - bool TopologicalValueIterationEquationSolverSettings::isConvergenceCriterionSet() const { - return this->getOption(absoluteOptionName).getHasOptionBeenSet(); - } - - TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion TopologicalValueIterationEquationSolverSettings::getConvergenceCriterion() const { - return this->getOption(absoluteOptionName).getHasOptionBeenSet() ? TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion::Absolute : TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion::Relative; - } - - bool TopologicalValueIterationEquationSolverSettings::check() const { - return true; - } - - } // namespace modules - } // namespace settings -} // namespace storm diff --git a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h b/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h deleted file mode 100644 index 21006c3bd..000000000 --- a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ -#define STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ - -#include "storm/settings/modules/ModuleSettings.h" - -namespace storm { - namespace settings { - namespace modules { - - /*! - * This class represents the settings for topological value iteration. - */ - class TopologicalValueIterationEquationSolverSettings : public ModuleSettings { - public: - - // An enumeration of all available convergence criteria. - enum class ConvergenceCriterion { Absolute, Relative }; - - /*! - * Creates a new set of topological value iteration settings. - */ - TopologicalValueIterationEquationSolverSettings(); - - - /*! - * Retrieves whether the maximal iteration count has been set. - * - * @return True iff the maximal iteration count has been set. - */ - bool isMaximalIterationCountSet() const; - - /*! - * Retrieves the maximal number of iterations to perform until giving up on converging. - * - * @return The maximal iteration count. - */ - uint_fast64_t getMaximalIterationCount() const; - - /*! - * Retrieves whether the precision has been set. - * - * @return True iff the precision has been set. - */ - bool isPrecisionSet() const; - - /*! - * Retrieves the precision that is used for detecting convergence. - * - * @return The precision to use for detecting convergence. - */ - double getPrecision() const; - - /*! - * Retrieves whether the convergence criterion has been set. - * - * @return True iff the convergence criterion has been set. - */ - bool isConvergenceCriterionSet() const; - - /*! - * Retrieves the selected convergence criterion. - * - * @return The selected convergence criterion. - */ - ConvergenceCriterion getConvergenceCriterion() const; - - bool check() const override; - - // The name of the module. - static const std::string moduleName; - - private: - // Define the string names of the options as constants. - static const std::string techniqueOptionName; - static const std::string maximalIterationsOptionName; - static const std::string maximalIterationsOptionShortName; - static const std::string precisionOptionName; - static const std::string absoluteOptionName; - }; - - } // namespace modules - } // namespace settings -} // namespace storm - -#endif /* STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ */ From b69543802d21ada49ff5e36c826213c8e0998dc5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 17:51:31 +0100 Subject: [PATCH 084/647] completed the renaming from topologicalValueIterationMinMaxSolver to TopologicalCudaMinMax... --- src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h | 2 +- src/storm/storage/SparseMatrix.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h index e302028a5..f20f37b09 100644 --- a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h @@ -151,4 +151,4 @@ namespace storm { } // namespace solver } // namespace storm -#endif /* STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ */ +#endif /* STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ */ diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index e115db443..4013a7cbf 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -27,7 +27,7 @@ namespace storm { } namespace solver { template - class TopologicalValueIterationMinMaxLinearEquationSolver; + class TopologicalCudaValueIterationMinMaxLinearEquationSolver; } } @@ -327,7 +327,7 @@ namespace storm { friend class storm::adapters::GmmxxAdapter; friend class storm::adapters::EigenAdapter; friend class storm::adapters::StormAdapter; - friend class storm::solver::TopologicalValueIterationMinMaxLinearEquationSolver; + friend class storm::solver::TopologicalCudaValueIterationMinMaxLinearEquationSolver; friend class SparseMatrixBuilder; typedef SparseMatrixIndexType index_type; From 25260c7602105d1f9c683f69b416884a27e93532 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 17:53:06 +0100 Subject: [PATCH 085/647] added settings for the new topological min max solver --- .../solver/TopologicalSolverEnvironment.cpp | 6 ++-- .../modules/MinMaxEquationSolverSettings.cpp | 4 ++- .../TopologicalEquationSolverSettings.cpp | 31 +++++++++++++++++++ .../TopologicalEquationSolverSettings.h | 22 +++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp index 244adc1fa..678c6cb6c 100644 --- a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp @@ -13,10 +13,8 @@ namespace storm { underlyingEquationSolverType = topologicalSettings.getUnderlyingEquationSolverType(); underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); - std::cout << "Get topo env minmax from settings!!" << std::endl; - underlyingMinMaxMethod = storm::solver::MinMaxMethod::ValueIteration; - underlyingEquationSolverTypeSetFromDefault = false; - + underlyingMinMaxMethod = topologicalSettings.getUnderlyingMinMaxMethod(); + underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingMinMaxMethodSetFromDefaultValue(); } TopologicalSolverEnvironment::~TopologicalSolverEnvironment() { diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 35145e829..c0728c579 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -23,7 +23,7 @@ namespace storm { const std::string MinMaxEquationSolverSettings::quickValueIterationRestartOptionName = "qvirestart"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); @@ -60,6 +60,8 @@ namespace storm { return storm::solver::MinMaxMethod::RationalSearch; } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { return storm::solver::MinMaxMethod::QuickValueIteration; + } else if (minMaxEquationSolvingTechnique == "topological") { + return storm::solver::MinMaxMethod::Topological; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown min/max equation solving technique '" << minMaxEquationSolvingTechnique << "'."); } diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index c5f74a124..ec551fae1 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -28,6 +28,9 @@ namespace storm { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, true, "Sets which solver is considered for solving the underlying equation systems.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; + this->addOption(storm::settings::OptionBuilder(moduleName, underlyingMinMaxMethodOptionName, true, "Sets which minmax method is considered for solving the underlying minmax equation systems.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used min max method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("value-iteration").build()).build()); } bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSet() const { @@ -52,11 +55,39 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << equationSolverName << "'."); } + bool TopologicalEquationSolverSettings::isUnderlyingMinMaxMethodSet() const { + return this->getOption(underlyingMinMaxMethodOptionName).getHasOptionBeenSet(); + } + + bool TopologicalEquationSolverSettings::isUnderlyingMinMaxMethodSetFromDefaultValue() const { + return !this->getOption(underlyingMinMaxMethodOptionName).getHasOptionBeenSet() || this->getOption(underlyingMinMaxMethodOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + + storm::solver::MinMaxMethod TopologicalEquationSolverSettings::getUnderlyingMinMaxMethod() const { + std::string minMaxEquationSolvingTechnique = this->getOption(underlyingMinMaxMethodOptionName).getArgumentByName("name").getValueAsString(); + if (minMaxEquationSolvingTechnique == "value-iteration" || minMaxEquationSolvingTechnique == "vi") { + return storm::solver::MinMaxMethod::ValueIteration; + } else if (minMaxEquationSolvingTechnique == "policy-iteration" || minMaxEquationSolvingTechnique == "pi") { + return storm::solver::MinMaxMethod::PolicyIteration; + } else if (minMaxEquationSolvingTechnique == "linear-programming" || minMaxEquationSolvingTechnique == "lp") { + return storm::solver::MinMaxMethod::LinearProgramming; + } else if (minMaxEquationSolvingTechnique == "ratsearch") { + return storm::solver::MinMaxMethod::RationalSearch; + } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { + return storm::solver::MinMaxMethod::QuickValueIteration; + } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << equationSolverName << "'."); + } + bool TopologicalEquationSolverSettings::check() const { if (this->isUnderlyingEquationSolverTypeSet() && getUnderlyingEquationSolverType() == storm::solver::EquationSolverType::Topological) { STORM_LOG_WARN("Underlying solver type of the topological solver can not be the topological solver."); return false; } + if (this->isUnderlyingMinMaxMethodSet() && getUnderlyingMinMaxMethod() == storm::solver::MinMaxMethod::Topological) { + STORM_LOG_WARN("Underlying minmax method of the topological solver can not be topological."); + return false; + } return true; } diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.h b/src/storm/settings/modules/TopologicalEquationSolverSettings.h index 45014db32..f9ddefd78 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.h +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.h @@ -40,6 +40,27 @@ namespace storm { */ storm::solver::EquationSolverType getUnderlyingEquationSolverType() const; + /*! + * Retrieves whether the underlying equation solver type has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isUnderlyingMinMaxMethodSet() const; + + /*! + * Retrieves whether the underlying minmax method is set from its default value. + * + * @return True iff it was set from its default value. + */ + bool isUnderlyingMinMaxMethodSetFromDefaultValue() const; + + /*! + * Retrieves the method that is to be used for solving systems of linear equations. + * + * @return The method to use. + */ + storm::solver::MinMaxMethod getUnderlyingMinMaxMethod() const; + bool check() const override; // The name of the module. @@ -48,6 +69,7 @@ namespace storm { private: // Define the string names of the options as constants. static const std::string underlyingEquationSolverOptionName; + static const std::string underlyingMinMaxMethodOptionName; }; } // namespace modules From 7bdecad4adec6d1c69141b2c1b9c71a8eb5e281d Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 18:00:55 +0100 Subject: [PATCH 086/647] fixed compiling --- .../settings/modules/TopologicalEquationSolverSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index ec551fae1..86e344f9c 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -76,7 +76,7 @@ namespace storm { } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { return storm::solver::MinMaxMethod::QuickValueIteration; } - STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << equationSolverName << "'."); + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << minMaxEquationSolvingTechnique << "'."); } bool TopologicalEquationSolverSettings::check() const { From 5f831d156f6b35753b110bedfaec4df90216cd30 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 18:01:41 +0100 Subject: [PATCH 087/647] forceBounds option for native solver --- .../environment/solver/NativeSolverEnvironment.cpp | 10 ++++++++++ src/storm/environment/solver/NativeSolverEnvironment.h | 3 +++ .../settings/modules/NativeEquationSolverSettings.cpp | 8 ++++++++ .../settings/modules/NativeEquationSolverSettings.h | 7 +++++++ src/storm/solver/NativeLinearEquationSolver.cpp | 4 ++++ 5 files changed, 32 insertions(+) diff --git a/src/storm/environment/solver/NativeSolverEnvironment.cpp b/src/storm/environment/solver/NativeSolverEnvironment.cpp index 3a3d0cb08..b11b906df 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.cpp +++ b/src/storm/environment/solver/NativeSolverEnvironment.cpp @@ -18,6 +18,7 @@ namespace storm { STORM_LOG_ASSERT(considerRelativeTerminationCriterion || nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); powerMethodMultiplicationStyle = nativeSettings.getPowerMethodMultiplicationStyle(); sorOmega = storm::utility::convertNumber(nativeSettings.getOmega()); + forceBounds = nativeSettings.isForceBoundsSet(); } NativeSolverEnvironment::~NativeSolverEnvironment() { @@ -77,4 +78,13 @@ namespace storm { sorOmega = value; } + bool NativeSolverEnvironment::isForceBoundsSet() const { + return forceBounds; + } + + void NativeSolverEnvironment::setForceBounds(bool value) { + forceBounds = value; + } + + } diff --git a/src/storm/environment/solver/NativeSolverEnvironment.h b/src/storm/environment/solver/NativeSolverEnvironment.h index 51b96f613..675b553b0 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.h +++ b/src/storm/environment/solver/NativeSolverEnvironment.h @@ -27,6 +27,8 @@ namespace storm { void setPowerMethodMultiplicationStyle(storm::solver::MultiplicationStyle value); storm::RationalNumber const& getSorOmega() const; void setSorOmega(storm::RationalNumber const& value); + bool isForceBoundsSet() const; + void setForceBounds(bool value); private: storm::solver::NativeLinearEquationSolverMethod method; @@ -36,6 +38,7 @@ namespace storm { bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle powerMethodMultiplicationStyle; storm::RationalNumber sorOmega; + bool forceBounds; }; } diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 628e0bd75..a34679ae8 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -23,6 +23,7 @@ namespace storm { const std::string NativeEquationSolverSettings::precisionOptionName = "precision"; const std::string NativeEquationSolverSettings::absoluteOptionName = "absolute"; const std::string NativeEquationSolverSettings::powerMethodMultiplicationStyleOptionName = "powmult"; + const std::string NativeEquationSolverSettings::forceBoundsOptionName = "forcebounds"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch", "qpower" }; @@ -39,6 +40,9 @@ namespace storm { std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, powerMethodMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for the power method.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, the equation solver always require that a priori bounds for the solution are computed.").build()); + } bool NativeEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { @@ -107,6 +111,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool NativeEquationSolverSettings::isForceBoundsSet() const { + return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); + } + bool NativeEquationSolverSettings::check() const { // This list does not include the precision, because this option is shared with other modules. bool optionSet = isLinearEquationSystemTechniqueSet() || isMaximalIterationCountSet() || isConvergenceCriterionSet(); diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.h b/src/storm/settings/modules/NativeEquationSolverSettings.h index 32d3caed1..67d68cb2d 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.h +++ b/src/storm/settings/modules/NativeEquationSolverSettings.h @@ -100,6 +100,11 @@ namespace storm { */ storm::solver::MultiplicationStyle getPowerMethodMultiplicationStyle() const; + /*! + * Retrieves whether the force bounds option has been set. + */ + bool isForceBoundsSet() const; + bool check() const override; // The name of the module. @@ -114,6 +119,8 @@ namespace storm { static const std::string precisionOptionName; static const std::string absoluteOptionName; static const std::string powerMethodMultiplicationStyleOptionName; + static const std::string forceBoundsOptionName; + }; } // namespace modules diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 76e261961..06e9efebb 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -1128,6 +1128,10 @@ namespace storm { LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { LinearEquationSolverRequirements requirements; if (task != LinearEquationSolverTask::Multiply) { + if (env.solver().native().isForceBoundsSet()) { + requirements.requiresLowerBounds(); + requirements.requiresUpperBounds(); + } auto method = getMethod(env, storm::NumberTraits::IsExact); if (method == NativeLinearEquationSolverMethod::Power && env.solver().isForceSoundness()) { requirements.requireBounds(); From 5d5159c43777a3e8561e0384abc682de1fae3828 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 18:23:53 +0100 Subject: [PATCH 088/647] fixed compiling --- src/storm/settings/modules/TopologicalEquationSolverSettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index 86e344f9c..fd22757ac 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -23,6 +23,7 @@ namespace storm { const std::string TopologicalEquationSolverSettings::moduleName = "topological"; const std::string TopologicalEquationSolverSettings::underlyingEquationSolverOptionName = "eqsolver"; + const std::string TopologicalEquationSolverSettings::underlyingMinMaxMethodOptionName = "minmax"; TopologicalEquationSolverSettings::TopologicalEquationSolverSettings() : ModuleSettings(moduleName) { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; From aabbea11b8379010af96f811e9e51fa9e4756758 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 19:23:59 +0100 Subject: [PATCH 089/647] various fixes for topological min max solver --- .../modules/TopologicalEquationSolverSettings.cpp | 2 +- src/storm/solver/StandardMinMaxLinearEquationSolver.cpp | 2 ++ .../solver/TopologicalMinMaxLinearEquationSolver.cpp | 9 +++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index fd22757ac..d088b2879 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -31,7 +31,7 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; this->addOption(storm::settings::OptionBuilder(moduleName, underlyingMinMaxMethodOptionName, true, "Sets which minmax method is considered for solving the underlying minmax equation systems.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used min max method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("value-iteration").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used min max method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("value-iteration").build()).build()); } bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSet() const { diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index 853f84cf3..a377689e4 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -36,12 +36,14 @@ namespace storm { void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { this->localA = nullptr; this->A = &matrix; + clearCache(); } template void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { this->localA = std::make_unique>(std::move(matrix)); this->A = this->localA.get(); + clearCache(); } template diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index c90dec99b..573f18f3a 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -185,8 +185,8 @@ namespace storm { // Now add all successors that are not already sorted. // Successors should only be added once, so we first prepare a set of them and add them afterwards. successorSCCs.clear(); - for (auto const& row : currentScc) { - for (auto const& entry : this->A->getRow(row)) { + for (auto const& group : currentScc) { + for (auto const& entry : this->A->getRowGroup(group)) { auto const& successorSCC = sccIndices[entry.getColumn()]; if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { successorSCCs.insert(successorSCC); @@ -236,10 +236,10 @@ namespace storm { uint64_t bestRow; for (uint64_t row = this->A->getRowGroupIndices()[sccState]; row < this->A->getRowGroupIndices()[sccState + 1]; ++row) { - ValueType rowValue = globalB[sccState]; + ValueType rowValue = globalB[row]; bool hasDiagonalEntry = false; ValueType denominator; - for (auto const& entry : this->A->getRow(sccState)) { + for (auto const& entry : this->A->getRow(row)) { if (entry.getColumn() == sccState) { STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1."); hasDiagonalEntry = true; @@ -319,6 +319,7 @@ namespace storm { // SCC Matrix storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, sccRowGroups, sccRowGroups); + //std::cout << "Matrix is " << sccA << std::endl; this->sccSolver->setMatrix(std::move(sccA)); // x Vector From 7d705240ce5dce541b1ac0abf28f38d0ee380e7a Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 19:39:30 +0100 Subject: [PATCH 090/647] introduced model checker settings --- src/storm-dft/settings/DftSettings.cpp | 2 ++ src/storm-pars/settings/ParsSettings.cpp | 5 ++- .../prctl/helper/SparseDtmcPrctlHelper.cpp | 1 + src/storm/settings/SettingsManager.cpp | 2 ++ .../settings/modules/ModelCheckerSettings.cpp | 28 +++++++++++++++ .../settings/modules/ModelCheckerSettings.h | 36 +++++++++++++++++++ 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 src/storm/settings/modules/ModelCheckerSettings.cpp create mode 100644 src/storm/settings/modules/ModelCheckerSettings.h diff --git a/src/storm-dft/settings/DftSettings.cpp b/src/storm-dft/settings/DftSettings.cpp index b80afa2ce..845ba6aa9 100644 --- a/src/storm-dft/settings/DftSettings.cpp +++ b/src/storm-dft/settings/DftSettings.cpp @@ -9,6 +9,7 @@ #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/EigenEquationSolverSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/GmmxxEquationSolverSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" #include "storm/settings/modules/EliminationSettings.h" @@ -33,6 +34,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index 4b182760b..f7eb39604 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -9,6 +9,7 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/BuildSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/SylvanSettings.h" #include "storm/settings/modules/EigenEquationSolverSettings.h" @@ -36,8 +37,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - - + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); @@ -47,7 +47,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 6f63bd94a..fd4ca4ff1 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -23,6 +23,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/ProgressMeasurement.h" diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 2d99b739c..a97fc9ea3 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -15,6 +15,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/ModelcheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/modules/CuddSettings.h" @@ -513,6 +514,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/settings/modules/ModelCheckerSettings.cpp b/src/storm/settings/modules/ModelCheckerSettings.cpp new file mode 100644 index 000000000..ec5ec7921 --- /dev/null +++ b/src/storm/settings/modules/ModelCheckerSettings.cpp @@ -0,0 +1,28 @@ +#include "storm/settings/modules/ModelCheckerSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/SettingMemento.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + + +namespace storm { + namespace settings { + namespace modules { + + const std::string GeneralSettings::moduleName = "modelchecker"; + const std::string GeneralSettings::filterRewZeroOptionName = "filterrewzero"; + + ModelCheckerSettings::ModelCheckerSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, filterRewZeroOptionName, false, "If set, states with reward zero are filtered out, potentially reducing the size of the equation system").build()); + } + + bool ModelCheckerSettings::isFilterRewZeroSet() const { + return this->getOption(filterRewZeroOptionName).getHasOptionBeenSet(); + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm/settings/modules/ModelCheckerSettings.h b/src/storm/settings/modules/ModelCheckerSettings.h new file mode 100644 index 000000000..4c6a1dfd6 --- /dev/null +++ b/src/storm/settings/modules/ModelCheckerSettings.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/builder/ExplorationOrder.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the general settings. + */ + class ModelCheckerSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of general settings. + */ + ModelCheckerSettings(); + + bool isFilterRewZeroSet() const; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string filterRewZeroOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm + From a9f72198a075459db7dd5d95567be3ec314a223b Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 20:10:27 +0100 Subject: [PATCH 091/647] made filtering states with reward zero a setting --- .../prctl/helper/SparseDtmcPrctlHelper.cpp | 49 ++++++++++++------- .../prctl/helper/SparseDtmcPrctlHelper.h | 2 +- .../settings/modules/ModelCheckerSettings.cpp | 4 +- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index fd4ca4ff1..f10e1155e 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -382,29 +382,32 @@ namespace storm { template std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { - // Extend the set of target states such that states for which target is reached without collecting any reward are included - // TODO - storm::storage::BitVector extendedTargetStates = storm::utility::graph::performProb1(backwardTransitions, rewardModel.getStatesWithZeroReward(transitionMatrix), targetStates); - STORM_LOG_INFO("Extended the set of target states from " << targetStates.getNumberOfSetBits() << " states to " << extendedTargetStates.getNumberOfSetBits() << " states."); - std::cout << "TODO: make target state extension a setting." << std::endl; - return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); }, extendedTargetStates, qualitative, linearEquationSolverFactory, hint); + + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, + [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { + return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); + }, + targetStates, qualitative, linearEquationSolverFactory, + [&] () { + return rewardModel.getStatesWithZeroReward(transitionMatrix); + }, + hint); } template std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { - // TODO - storm::storage::BitVector extendedTargetStates = storm::utility::graph::performProb1(backwardTransitions, storm::utility::vector::filterZero(totalStateRewardVector), targetStates); - STORM_LOG_INFO("Extended the set of target states from " << targetStates.getNumberOfSetBits() << " states to " << extendedTargetStates.getNumberOfSetBits() << " states."); - std::cout << "TODO: make target state extension a setting" << std::endl; - return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const& maybeStates) { std::vector result(numberOfRows); storm::utility::vector::selectVectorValues(result, maybeStates, totalStateRewardVector); return result; }, - targetStates, qualitative, linearEquationSolverFactory, hint); + targetStates, qualitative, linearEquationSolverFactory, + [&] () { + return storm::utility::vector::filterZero(totalStateRewardVector); + }, + hint); } // This function computes an upper bound on the reachability rewards (see Baier et al, CAV'17). @@ -421,24 +424,32 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); + // Determine which states have reward zero + storm::storage::BitVector rew0States; + if (storm::settings::getModule().isFilterRewZeroSet()) { + rew0States = storm::utility::graph::performProb1(backwardTransitions, zeroRewardStatesGetter(), targetStates); + } else { + rew0States = targetStates; + } + // Determine which states have a reward that is less than infinity. storm::storage::BitVector maybeStates; if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().getComputeOnlyMaybeStates()) { maybeStates = hint.template asExplicitModelCheckerHint().getMaybeStates(); - storm::utility::vector::setVectorValues(result, ~(maybeStates | targetStates), storm::utility::infinity()); + storm::utility::vector::setVectorValues(result, ~(maybeStates | rew0States), storm::utility::infinity()); - STORM_LOG_INFO("Preprocessing: " << targetStates.getNumberOfSetBits() << " target states (" << maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << rew0States.getNumberOfSetBits() << " States with reward zero (" << maybeStates.getNumberOfSetBits() << " states remaining)."); } else { storm::storage::BitVector trueStates(transitionMatrix.getRowCount(), true); - storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, targetStates); + storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, rew0States); infinityStates.complement(); - maybeStates = ~(targetStates | infinityStates); + maybeStates = ~(rew0States | infinityStates); - STORM_LOG_INFO("Preprocessing: " << infinityStates.getNumberOfSetBits() << " states with reward infinity, " << targetStates.getNumberOfSetBits() << " target states (" << maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << infinityStates.getNumberOfSetBits() << " states with reward infinity, " << rew0States.getNumberOfSetBits() << " states with reward zero (" << maybeStates.getNumberOfSetBits() << " states remaining)."); storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity()); } @@ -473,7 +484,7 @@ namespace storm { boost::optional> upperRewardBounds; requirements.clearLowerBounds(); if (requirements.requiresUpperBounds()) { - upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, targetStates)); + upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, rew0States)); requirements.clearUpperBounds(); } STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "There are unchecked requirements of the solver."); diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index ead15de74..e9b4f939f 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -57,7 +57,7 @@ namespace storm { static std::vector computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); private: - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); struct BaierTransformedModel { BaierTransformedModel() : noTargetStates(false) { diff --git a/src/storm/settings/modules/ModelCheckerSettings.cpp b/src/storm/settings/modules/ModelCheckerSettings.cpp index ec5ec7921..9d7646327 100644 --- a/src/storm/settings/modules/ModelCheckerSettings.cpp +++ b/src/storm/settings/modules/ModelCheckerSettings.cpp @@ -12,8 +12,8 @@ namespace storm { namespace settings { namespace modules { - const std::string GeneralSettings::moduleName = "modelchecker"; - const std::string GeneralSettings::filterRewZeroOptionName = "filterrewzero"; + const std::string ModelCheckerSettings::moduleName = "modelchecker"; + const std::string ModelCheckerSettings::filterRewZeroOptionName = "filterrewzero"; ModelCheckerSettings::ModelCheckerSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, filterRewZeroOptionName, false, "If set, states with reward zero are filtered out, potentially reducing the size of the equation system").build()); From a1c10cac37a3ac97fd32a2a49656ef4a79c76509 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 21:51:27 +0100 Subject: [PATCH 092/647] filtering reward zero states for MDPs --- .../prctl/helper/SparseMdpPrctlHelper.cpp | 98 +++++++++++++------ .../prctl/helper/SparseMdpPrctlHelper.h | 2 +- .../models/sparse/StandardRewardModel.cpp | 36 +++++-- src/storm/models/sparse/StandardRewardModel.h | 16 ++- src/storm/utility/graph.cpp | 88 +++++++++-------- src/storm/utility/graph.h | 6 +- 6 files changed, 162 insertions(+), 84 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 91ff99c8a..adaed4627 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -24,6 +24,7 @@ #include "storm/solver/LpSolver.h" #include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -845,7 +846,14 @@ namespace storm { [&rewardModel] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(rowCount, transitionMatrix, maybeStates); }, - targetStates, qualitative, produceScheduler, minMaxLinearEquationSolverFactory, hint); + targetStates, qualitative, produceScheduler, minMaxLinearEquationSolverFactory, + [&] () { + return rewardModel.getStatesWithZeroReward(transitionMatrix); + }, + [&] () { + return rewardModel.getChoicesWithZeroReward(transitionMatrix); + }, + hint); } #ifdef STORM_HAVE_CARL @@ -862,8 +870,14 @@ namespace storm { result.push_back(lowerBoundOfIntervals ? interval.lower() : interval.upper()); } return result; - }, \ - targetStates, qualitative, false, minMaxLinearEquationSolverFactory).values; + }, + targetStates, qualitative, false, minMaxLinearEquationSolverFactory, + [&] () { + return intervalRewardModel.getStatesWithFilter(transitionMatrix, [&](storm::Interval const& i) {return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());}); + }, + [&] () { + return intervalRewardModel.getChoicesWithFilter(transitionMatrix, [&](storm::Interval const& i) {return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());}); + }).values; } template<> @@ -875,18 +889,32 @@ namespace storm { struct QualitativeStateSetsReachabilityRewards { storm::storage::BitVector maybeStates; storm::storage::BitVector infinityStates; + storm::storage::BitVector rewardZeroStates; }; template QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewardsFromHint(ModelCheckerHint const& hint, storm::storage::BitVector const& targetStates) { QualitativeStateSetsReachabilityRewards result; result.maybeStates = hint.template asExplicitModelCheckerHint().getMaybeStates(); - result.infinityStates = ~(result.maybeStates | targetStates); + + // Treat the states with reward zero/infinity. + std::vector const& resultsForNonMaybeStates = hint.template asExplicitModelCheckerHint().getResultHint(); + result.infinityStates = storm::storage::BitVector(result.maybeStates.size()); + result.rewardZeroStates = storm::storage::BitVector(result.maybeStates.size()); + storm::storage::BitVector nonMaybeStates = ~result.maybeStates; + for (auto const& state : nonMaybeStates) { + if (storm::utility::isZero(resultsForNonMaybeStates[state])) { + result.rewardZeroStates.set(state, true); + } else { + STORM_LOG_THROW(storm::utility::isInfinity(resultsForNonMaybeStates[state]), storm::exceptions::IllegalArgumentException, "Expected that the result hint specifies probabilities in {0,infinity} for non-maybe states"); + result.infinityStates.set(state, true); + } + } return result; } template - QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates) { + QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter) { QualitativeStateSetsReachabilityRewards result; storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true); if (goal.minimize()) { @@ -895,33 +923,43 @@ namespace storm { result.infinityStates = storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates); } result.infinityStates.complement(); - result.maybeStates = ~(targetStates | result.infinityStates); + + if (storm::settings::getModule().isFilterRewZeroSet()) { + if (goal.minimize()) { + result.rewardZeroStates = storm::utility::graph::performProb1E(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates, zeroRewardChoicesGetter()); + } else { + result.rewardZeroStates = storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, zeroRewardStatesGetter(), targetStates); + } + } else { + result.rewardZeroStates = targetStates; + } + result.maybeStates = ~(result.rewardZeroStates | result.infinityStates); return result; } template - QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint) { + QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter) { if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().getComputeOnlyMaybeStates()) { return getQualitativeStateSetsReachabilityRewardsFromHint(hint, targetStates); } else { - return computeQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates); + return computeQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, zeroRewardStatesGetter, zeroRewardChoicesGetter); } } template - void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& targetStates) { + void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardChoicesGetter) { // Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for - // the states with reward infinity. Moreover, we have to set some arbitrary choice for the remaining states - // to obtain a fully defined scheduler. - if (!goal.minimize()) { - storm::utility::graph::computeSchedulerProb0E(qualitativeStateSets.infinityStates, transitionMatrix, scheduler); - } else { + // the states with reward zero/infinity. + if (goal.minimize()) { + storm::utility::graph::computeSchedulerProb1E(qualitativeStateSets.rewardZeroStates, transitionMatrix, backwardTransitions, qualitativeStateSets.rewardZeroStates, targetStates, scheduler, zeroRewardChoicesGetter()); for (auto const& state : qualitativeStateSets.infinityStates) { scheduler.setChoice(0, state); } - } - for (auto const& state : targetStates) { - scheduler.setChoice(0, state); + } else { + storm::utility::graph::computeSchedulerProb0E(qualitativeStateSets.infinityStates, transitionMatrix, scheduler); + for (auto const& state : qualitativeStateSets.rewardZeroStates) { + scheduler.setChoice(0, state); + } } } @@ -949,21 +987,21 @@ namespace storm { } template - void computeFixedPointSystemReachabilityRewards(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, std::vector* oneStepTargetProbabilities = nullptr) { + void computeFixedPointSystemReachabilityRewards(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, std::vector* oneStepTargetProbabilities = nullptr) { // Remove rows and columns from the original transition probability matrix for states whose reward values are already known. // If there are infinity states, we additionally have to remove choices of maybeState that lead to infinity. if (qualitativeStateSets.infinityStates.empty()) { submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false); b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, qualitativeStateSets.maybeStates); if (oneStepTargetProbabilities) { - (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, targetStates); + (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.rewardZeroStates); } } else { submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, qualitativeStateSets.maybeStates, false); b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true)); storm::utility::vector::filterVectorInPlace(b, *selectedChoices); if (oneStepTargetProbabilities) { - (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, targetStates); + (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, qualitativeStateSets.rewardZeroStates); } } @@ -972,7 +1010,7 @@ namespace storm { } template - boost::optional> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, boost::optional>& oneStepTargetProbabilities) { + boost::optional> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, boost::optional>& oneStepTargetProbabilities) { // Start by computing the choices with reward 0, as we only want ECs within this fragment. storm::storage::BitVector zeroRewardChoices(transitionMatrix.getRowCount()); @@ -1019,7 +1057,7 @@ namespace storm { // Only do more work if there are actually end-components. if (doDecomposition && !endComponentDecomposition.empty()) { STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " ECs."); - SparseMdpEndComponentInformation result = SparseMdpEndComponentInformation::eliminateEndComponents(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, oneStepTargetProbabilities ? &targetStates : nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector, submatrix, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr, &b); + SparseMdpEndComponentInformation result = SparseMdpEndComponentInformation::eliminateEndComponents(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, oneStepTargetProbabilities ? &qualitativeStateSets.rewardZeroStates : nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector, submatrix, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr, &b); // If the solve goal has relevant values, we need to adjust them. if (goal.hasRelevantValues()) { @@ -1037,7 +1075,7 @@ namespace storm { return result; } else { STORM_LOG_DEBUG("Not eliminating ECs as there are none."); - computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); + computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); return boost::none; } } @@ -1056,15 +1094,15 @@ namespace storm { } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint) { // Prepare resulting vector. std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // Determine which states have a reward that is infinity or less than infinity. - QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, hint); + QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, hint, zeroRewardStatesGetter, zeroRewardChoicesGetter); - STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.infinityStates.getNumberOfSetBits() << " states with reward infinity, " << targetStates.getNumberOfSetBits() << " target states (" << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.infinityStates.getNumberOfSetBits() << " states with reward infinity, " << qualitativeStateSets.rewardZeroStates.getNumberOfSetBits() << " states with reward zero (" << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining)."); storm::utility::vector::setVectorValues(result, qualitativeStateSets.infinityStates, storm::utility::infinity()); @@ -1091,7 +1129,7 @@ namespace storm { } // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices); + SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, minMaxLinearEquationSolverFactory, selectedChoices); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -1107,13 +1145,13 @@ namespace storm { // If the hint information tells us that we have to eliminate MECs, we do so now. boost::optional> ecInformation; if (hintInformation.getEliminateEndComponents()) { - ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents(goal, transitionMatrix, backwardTransitions, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities); + ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents(goal, transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities); // Make sure we are not supposed to produce a scheduler if we actually eliminate end components. STORM_LOG_THROW(!ecInformation || !ecInformation.get().getEliminatedEndComponents() || !produceScheduler, storm::exceptions::NotSupportedException, "Producing schedulers is not supported if end-components need to be eliminated for the solver."); } else { // Otherwise, we compute the standard equations. - computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); + computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); } // If we need to compute upper bounds, do so now. @@ -1141,7 +1179,7 @@ namespace storm { // Extend scheduler with choices for the states in the qualitative state sets. if (produceScheduler) { - extendScheduler(*scheduler, goal, qualitativeStateSets, transitionMatrix, targetStates); + extendScheduler(*scheduler, goal, qualitativeStateSets, transitionMatrix, backwardTransitions, targetStates, zeroRewardChoicesGetter); } // Sanity check for created scheduler. diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index b06b14192..5a6f5ae2b 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -71,7 +71,7 @@ namespace storm { static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); private: - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); template static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); diff --git a/src/storm/models/sparse/StandardRewardModel.cpp b/src/storm/models/sparse/StandardRewardModel.cpp index ccf9b5d71..e37de0562 100644 --- a/src/storm/models/sparse/StandardRewardModel.cpp +++ b/src/storm/models/sparse/StandardRewardModel.cpp @@ -270,11 +270,17 @@ namespace storm { template template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const { - storm::storage::BitVector result = this->hasStateRewards() ? storm::utility::vector::filterZero(this->getStateRewardVector()) : storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true); + return getStatesWithFilter(transitionMatrix, storm::utility::isZero); + } + + template + template + storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const { + storm::storage::BitVector result = this->hasStateRewards() ? storm::utility::vector::filter(this->getStateRewardVector(), filter) : storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true); if (this->hasStateActionRewards()) { for (uint_fast64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { for (uint_fast64_t row = transitionMatrix.getRowGroupIndices()[state]; row < transitionMatrix.getRowGroupIndices()[state+1]; ++row) { - if(!storm::utility::isZero(this->getStateActionRewardVector()[row])) { + if(!filter(this->getStateActionRewardVector()[row])) { result.set(state, false); break; } @@ -284,7 +290,7 @@ namespace storm { if (this->hasTransitionRewards()) { for (uint_fast64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { for (auto const& rewardMatrixEntry : this->getTransitionRewardMatrix().getRowGroup(state)) { - if(!storm::utility::isZero(rewardMatrixEntry.getValue())) { + if(!filter(rewardMatrixEntry.getValue())) { result.set(state, false); break; } @@ -293,19 +299,25 @@ namespace storm { } return result; } - + template template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const { + return getChoicesWithFilter(transitionMatrix, storm::utility::isZero); + } + + template + template + storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const { storm::storage::BitVector result; if (this->hasStateActionRewards()) { - result = storm::utility::vector::filterZero(this->getStateActionRewardVector()); + result = storm::utility::vector::filter(this->getStateActionRewardVector(), filter); if (this->hasStateRewards()) { - result &= transitionMatrix.getRowFilter(storm::utility::vector::filterZero(this->getStateRewardVector())); + result &= transitionMatrix.getRowFilter(storm::utility::vector::filter(this->getStateRewardVector(), filter)); } } else { if (this->hasStateRewards()) { - result = transitionMatrix.getRowFilter(storm::utility::vector::filterZero(this->getStateRewardVector())); + result = transitionMatrix.getRowFilter(storm::utility::vector::filter(this->getStateRewardVector(), filter)); } else { result = storm::storage::BitVector(transitionMatrix.getRowCount(), true); } @@ -313,7 +325,7 @@ namespace storm { if (this->hasTransitionRewards()) { for (uint_fast64_t row = 0; row < transitionMatrix.getRowCount(); ++row) { for (auto const& rewardMatrixEntry : this->getTransitionRewardMatrix().getRow(row)) { - if(!storm::utility::isZero(rewardMatrixEntry.getValue())) { + if(!filter(rewardMatrixEntry.getValue())) { result.set(row, false); break; } @@ -396,7 +408,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template double StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, double const& stateRewardWeight, double const& actionRewardWeight) const; template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, bool reduceToStateRewards, std::vector const* weights); @@ -421,7 +435,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::RationalNumber StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, storm::RationalNumber const& stateRewardWeight, storm::RationalNumber const& actionRewardWeight) const; template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, bool reduceToStateRewards, std::vector const* weights); template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, storm::RationalNumber const & newValue); @@ -433,7 +449,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix) const; template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::RationalFunction StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, storm::RationalFunction const& stateRewardWeight, storm::RationalFunction const& actionRewardWeight) const; @@ -447,6 +465,8 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix) const; template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, double const & newValue); template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, storm::Interval const & newValue); template void StandardRewardModel::setStateReward(uint_fast64_t state, double const & newValue); diff --git a/src/storm/models/sparse/StandardRewardModel.h b/src/storm/models/sparse/StandardRewardModel.h index 33303f380..cdfce6038 100644 --- a/src/storm/models/sparse/StandardRewardModel.h +++ b/src/storm/models/sparse/StandardRewardModel.h @@ -253,6 +253,13 @@ namespace storm { template storm::storage::BitVector getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + /*! + * Returns the set of states for which all associated rewards (state, action or transition rewards) satisfy the given filter. + * @param transitionMatrix the transition matrix of the model (used to determine the actions and transitions that belong to a state) + */ + template + storm::storage::BitVector getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + /*! * Returns the set of choices at which all rewards (state-, action- and transition-rewards) are zero. * @@ -261,7 +268,14 @@ namespace storm { */ template storm::storage::BitVector getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; - + + /*! + * Returns the set of choices for which all associated rewards (state, action or transition rewards) satisfy the given filter. + * @param transitionMatrix the transition matrix of the model (used to determine the actions and transitions that belong to a state) + */ + template + storm::storage::BitVector getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + /*! * Sets the given value in the state-action reward vector at the given row. This assumes that the reward * model has state-action rewards. diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index a2716ba8d..5bb8cc758 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -479,9 +479,9 @@ namespace storm { } template - void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler) { + void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter) { - // set an arbitrary choice for the psi states. + // set an arbitrary (valid) choice for the psi states. for (auto const& psiState : psiStates) { for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) { scheduler.setChoice(0, psiState, memState); @@ -504,27 +504,29 @@ namespace storm { // Check whether the predecessor has only successors in the prob1E state set for one of the // nondeterminstic choices. for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]; row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) { - bool allSuccessorsInProb1EStates = true; - bool hasSuccessorInCurrentStates = false; - for (typename storm::storage::SparseMatrix::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { - if (!prob1EStates.get(successorEntryIt->getColumn())) { - allSuccessorsInProb1EStates = false; + if (!rowFilter || rowFilter.get().get(row)) { + bool allSuccessorsInProb1EStates = true; + bool hasSuccessorInCurrentStates = false; + for (typename storm::storage::SparseMatrix::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { + if (!prob1EStates.get(successorEntryIt->getColumn())) { + allSuccessorsInProb1EStates = false; + break; + } else if (currentStates.get(successorEntryIt->getColumn())) { + hasSuccessorInCurrentStates = true; + } + } + + // If all successors for a given nondeterministic choice are in the prob1E state set, we + // perform a backward search from that state. + if (allSuccessorsInProb1EStates && hasSuccessorInCurrentStates) { + for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) { + scheduler.setChoice(row - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()], predecessorEntryIt->getColumn(), memState); + } + currentStates.set(predecessorEntryIt->getColumn(), true); + stack.push_back(predecessorEntryIt->getColumn()); break; - } else if (currentStates.get(successorEntryIt->getColumn())) { - hasSuccessorInCurrentStates = true; } } - - // If all successors for a given nondeterministic choice are in the prob1E state set, we - // perform a backward search from that state. - if (allSuccessorsInProb1EStates && hasSuccessorInCurrentStates) { - for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) { - scheduler.setChoice(row - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()], predecessorEntryIt->getColumn(), memState); - } - currentStates.set(predecessorEntryIt->getColumn(), true); - stack.push_back(predecessorEntryIt->getColumn()); - break; - } } } } @@ -595,7 +597,7 @@ namespace storm { } template - storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { + storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& choiceConstraint) { size_t numberOfStates = phiStates.size(); // Initialize the environment for the iterative algorithm. @@ -620,25 +622,27 @@ namespace storm { // Check whether the predecessor has only successors in the current state set for one of the // nondeterminstic choices. for (uint_fast64_t row = nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]; row < nondeterministicChoiceIndices[predecessorEntryIt->getColumn() + 1]; ++row) { - bool allSuccessorsInCurrentStates = true; - bool hasNextStateSuccessor = false; - for (typename storm::storage::SparseMatrix::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { - if (!currentStates.get(successorEntryIt->getColumn())) { - allSuccessorsInCurrentStates = false; + if (!choiceConstraint || choiceConstraint.get().get(row)) { + bool allSuccessorsInCurrentStates = true; + bool hasNextStateSuccessor = false; + for (typename storm::storage::SparseMatrix::const_iterator successorEntryIt = transitionMatrix.begin(row), successorEntryIte = transitionMatrix.end(row); successorEntryIt != successorEntryIte; ++successorEntryIt) { + if (!currentStates.get(successorEntryIt->getColumn())) { + allSuccessorsInCurrentStates = false; + break; + } else if (nextStates.get(successorEntryIt->getColumn())) { + hasNextStateSuccessor = true; + } + } + + // If all successors for a given nondeterministic choice are in the current state set, we + // add it to the set of states for the next iteration and perform a backward search from + // that state. + if (allSuccessorsInCurrentStates && hasNextStateSuccessor) { + nextStates.set(predecessorEntryIt->getColumn(), true); + stack.push_back(predecessorEntryIt->getColumn()); break; - } else if (nextStates.get(successorEntryIt->getColumn())) { - hasNextStateSuccessor = true; } } - - // If all successors for a given nondeterministic choice are in the current state set, we - // add it to the set of states for the next iteration and perform a backward search from - // that state. - if (allSuccessorsInCurrentStates && hasNextStateSuccessor) { - nextStates.set(predecessorEntryIt->getColumn(), true); - stack.push_back(predecessorEntryIt->getColumn()); - break; - } } } } @@ -1381,13 +1385,13 @@ namespace storm { template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::Scheduler& scheduler); - template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler); + template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); template storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool useStepBound = false, uint_fast64_t maximalSteps = 0) ; template storm::storage::BitVector performProb0A(storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); - template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& choiceConstraint = boost::none); template storm::storage::BitVector performProb1E(storm::models::sparse::NondeterministicModel> const& model, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); @@ -1446,13 +1450,13 @@ namespace storm { template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::Scheduler& scheduler); - template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler); + template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); template storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool useStepBound = false, uint_fast64_t maximalSteps = 0) ; template storm::storage::BitVector performProb0A(storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); - template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& choiceConstraint = boost::none); template storm::storage::BitVector performProb1E(storm::models::sparse::NondeterministicModel const& model, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); @@ -1503,7 +1507,7 @@ namespace storm { template storm::storage::BitVector performProb0A(storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); - template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + template storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& choiceConstraint = boost::none); template storm::storage::BitVector performProb1E(storm::models::sparse::NondeterministicModel const& model, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index 0f9b3c66e..79103700b 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -297,9 +297,10 @@ namespace storm { * @param phiStates The set of states satisfying phi. * @param psiStates The set of states satisfying psi. * @param scheduler The resulting scheduler for the prob1EStates. The scheduler is not set at the remaining states. + * @param rowFilter If given, only scheduler choices within this filter are taken. This filter is ignored for the psiStates. */ template - void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler); + void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler& scheduler, boost::optional const& rowFilter = boost::none); /*! * Computes the sets of states that have probability greater 0 of satisfying phi until psi under at least @@ -330,10 +331,11 @@ namespace storm { * @param backwardTransitions The reversed transition relation of the model. * @param phiStates The set of all states satisfying phi. * @param psiStates The set of all states satisfying psi. + * @param choiceConstraint If given, only the selected choices are considered. * @return A bit vector that represents all states with probability 1. */ template - storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + storm::storage::BitVector performProb1E(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& nondeterministicChoiceIndices, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& choiceConstraint = boost::none); /*! * Computes the sets of states that have probability 1 of satisfying phi until psi under at least From 52979dcbc152684703e52d45ec9902b36f264a66 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 22:31:12 +0100 Subject: [PATCH 093/647] setting the 'requirementsChecked' flag in topo min max solver --- src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 573f18f3a..1ba0c7467 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -298,6 +298,7 @@ namespace storm { req.clearLowerBounds(); } STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + this->sccSolver->setRequirementsChecked(true); bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, x, b); if (this->isTrackSchedulerSet()) { @@ -368,6 +369,7 @@ namespace storm { req.clearValidInitialScheduler(); } STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + this->sccSolver->setRequirementsChecked(true); // Invoke scc solver bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, sccX, sccB); From 5c911c6bc4c448490dfd9ffcd124da0e212fa546 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 18 Jan 2018 22:40:14 +0100 Subject: [PATCH 094/647] fixed capitalization --- src/storm/settings/SettingsManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index a97fc9ea3..a0f6bf568 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -15,7 +15,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" -#include "storm/settings/modules/ModelcheckerSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/modules/CuddSettings.h" From b5399d05962be0409a01bc66fd64f104953062b8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 19 Jan 2018 09:55:40 +0100 Subject: [PATCH 095/647] Printing the number of performed iterations --- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 5 ++++- .../pcaa/StandardPcaaWeightVectorChecker.h | 8 +++++++- src/storm/solver/AbstractEquationSolver.h | 11 ++++++++++- .../solver/IterativeMinMaxLinearEquationSolver.cpp | 5 ++++- src/storm/solver/NativeLinearEquationSolver.cpp | 6 ++++-- src/storm/solver/TopologicalLinearEquationSolver.cpp | 8 ++++++++ .../solver/TopologicalMinMaxLinearEquationSolver.cpp | 7 +++++++ 7 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index 068d08b63..e3c734bf0 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -194,7 +194,8 @@ namespace storm { std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero()); solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues); - + this->overallPerformedIterations += solver->overallPerformedIterations; + solver->overallPerformedIterations = 0; this->weightedResult = std::vector(transitionMatrix.getRowGroupCount()); transformReducedSolutionToOriginalModel(ecQuotient->matrix, ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecQuotient->ecqToOriginalChoiceMapping, ecQuotient->originalToEcqStateMapping, this->weightedResult, this->optimalChoices); @@ -277,6 +278,8 @@ namespace storm { STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); solver->solveEquations(env, x, b); + this->overallPerformedIterations += solver->overallPerformedIterations; + solver->overallPerformedIterations = 0; // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h index 2f0a27f33..10cba6fbc 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h @@ -37,7 +37,13 @@ namespace storm { StandardPcaaWeightVectorChecker(SparseMultiObjectivePreprocessorResult const& preprocessorResult); - virtual ~StandardPcaaWeightVectorChecker() = default; + virtual ~StandardPcaaWeightVectorChecker() { + if (overallPerformedIterations != 0) { + std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; + } + } + + mutable uint64_t overallPerformedIterations = 0; /*! * - computes the optimal expected reward w.r.t. the weighted sum of the rewards of the individual objectives diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index 476399bfa..7d9013566 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -3,7 +3,7 @@ #include #include - +#include #include #include "storm/solver/TerminationCondition.h" @@ -17,6 +17,15 @@ namespace storm { public: AbstractEquationSolver(); + virtual ~AbstractEquationSolver() { + if (overallPerformedIterations != 0) { + std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; + } + } + + mutable uint64_t overallPerformedIterations = 0; + + /*! * Sets a custom termination condition that is used together with the regular termination condition of the * solver. diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index bb4886094..fcb715819 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -582,7 +582,8 @@ namespace storm { } reportStatus(status, iterations); - + this->overallPerformedIterations += iterations; + // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); @@ -1035,6 +1036,8 @@ namespace storm { reportStatus(status, iterations); + this->overallPerformedIterations += iterations; + if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 06e9efebb..ba0032b08 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -549,7 +549,8 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - + this->overallPerformedIterations += iterations; + this->logIterations(converged, terminate, iterations); return converged; @@ -734,7 +735,8 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - + this->overallPerformedIterations += iterations; + this->logIterations(converged, terminate, iterations); STORM_LOG_WARN_COND(hasMinValueBound && hasMaxValueBound, "Could not compute lower or upper bound within the given number of iterations."); STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 83825d562..35994357b 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -91,6 +91,7 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; + ++this->overallPerformedIterations; } else { sccAsBitVector.clear(); for (auto const& state : scc) { @@ -101,9 +102,16 @@ namespace storm { } } + if (this->sccSolver) { + this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; + this->sccSolver->overallPerformedIterations = 0; + } if (!this->isCachingEnabled()) { clearCache(); } + + + return returnValue; } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 1ba0c7467..92d909189 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -109,6 +109,7 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; + ++this->overallPerformedIterations; } else { sccRowGroupsAsBitVector.clear(); sccRowsAsBitVector.clear(); @@ -132,6 +133,12 @@ namespace storm { } } + if (this->sccSolver) { + this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; + this->sccSolver->overallPerformedIterations = 0; + } + + if (!this->isCachingEnabled()) { clearCache(); } From 26362ed36f02b5222875b25c7dfbdf933fbe4172 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 19 Jan 2018 15:58:15 +0100 Subject: [PATCH 096/647] trying an alternative implementation of qvi --- .../IterativeMinMaxLinearEquationSolver.cpp | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index fcb715819..38313a57f 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -679,7 +679,7 @@ namespace storm { template void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValue(A, b); + performIterationStepUpdateDecisionValue2(A, b); } else { assert(decisionValue == getPrimaryBound()); auto xIt = x.rbegin(); @@ -800,6 +800,86 @@ namespace storm { } } + template + void performIterationStepUpdateDecisionValue2(storm::storage::SparseMatrix const& A, std::vector const& b) { + auto const& groupIndices = A.getRowGroupIndices(); + uint64_t group = groupIndices.size(); + while (group != 0) { + uint64_t const& groupEnd = groupIndices[group]; + --group; + uint64_t row = groupIndices[group]; + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); + ++row; + + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + uint64_t xyTmpIndex = 0; + if (hasPrimaryBound()) { + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + if (yBest < yi) { + // We need to store the 'old' best value as it might be relevant for the decision value + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + } + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + if (currentValue == bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + } else { + for (;row < groupEnd; ++row) { + multiplyRow(row, A, b[row], xi, yi); + // Update the best choice + if (yi > yBest || (yi == yBest && better(xi, xBest))) { + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + + // Update the decision value + for (uint64_t i = 0; i < xyTmpIndex; ++i) { + ValueType deltaY = yBest - yTmp[i]; + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; + } + } + } + } + x[group] = std::move(xBest); + y[group] = std::move(yBest); + } + } + bool checkRestartCriterion() { return false; // iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound From cebf29ef23282acb31219647c4fb9c619d8f5d91 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 19 Jan 2018 16:44:45 +0100 Subject: [PATCH 097/647] trying something else --- .../IterativeMinMaxLinearEquationSolver.cpp | 204 ++++++++++++++++-- 1 file changed, 184 insertions(+), 20 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 38313a57f..d45f1478e 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -679,7 +679,7 @@ namespace storm { template void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValue2(A, b); + performIterationStepUpdateDecisionValue(A, b); } else { assert(decisionValue == getPrimaryBound()); auto xIt = x.rbegin(); @@ -719,6 +719,90 @@ namespace storm { } } + void performIterationStepMax(storm::storage::SparseMatrix const& A, std::vector const& b) { + if (!decisionValueBlocks) { + performIterationStepUpdateDecisionValueMax(A, b); + } else { + assert(decisionValue == upperBound); + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + ValueType bestValue = xBest + yBest * upperBound; + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * upperBound; + // Check if the current row is better then the previously found one + if (currentValue > bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (currentValue == bestValue && yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + xBest = std::move(xi); + yBest = std::move(yi); + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + } + + void performIterationStepMin(storm::storage::SparseMatrix const& A, std::vector const& b) { + if (!decisionValueBlocks) { + performIterationStepUpdateDecisionValueMin(A, b); + } else { + assert(decisionValue == lowerBound); + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + ValueType bestValue = xBest + yBest * lowerBound; + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * lowerBound; + // Check if the current row is better then the previously found one + if (currentValue < bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (currentValue == bestValue && yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + xBest = std::move(xi); + yBest = std::move(yi); + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + } + template void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, std::vector const& b) { auto xIt = x.rbegin(); @@ -800,30 +884,30 @@ namespace storm { } } - template - void performIterationStepUpdateDecisionValue2(storm::storage::SparseMatrix const& A, std::vector const& b) { - auto const& groupIndices = A.getRowGroupIndices(); - uint64_t group = groupIndices.size(); - while (group != 0) { - uint64_t const& groupEnd = groupIndices[group]; - --group; - uint64_t row = groupIndices[group]; + void performIterationStepUpdateDecisionValueMax(storm::storage::SparseMatrix const& A, std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; ValueType xBest, yBest; multiplyRow(row, A, b[row], xBest, yBest); ++row; - // Only do more work if there are still rows in this row group if (row != groupEnd) { ValueType xi, yi; uint64_t xyTmpIndex = 0; - if (hasPrimaryBound()) { - ValueType bestValue = xBest + yBest * getPrimaryBound(); + if (hasUpperBound) { + ValueType bestValue = xBest + yBest * upperBound; for (;row < groupEnd; ++row) { // Get the multiplication results multiplyRow(row, A, b[row], xi, yi); - ValueType currentValue = xi + yi * getPrimaryBound(); + ValueType currentValue = xi + yi * upperBound; // Check if the current row is better then the previously found one - if (better(currentValue, bestValue)) { + if (currentValue > bestValue) { if (yBest < yi) { // We need to store the 'old' best value as it might be relevant for the decision value xTmp[xyTmpIndex] = std::move(xBest); @@ -849,7 +933,7 @@ namespace storm { for (;row < groupEnd; ++row) { multiplyRow(row, A, b[row], xi, yi); // Update the best choice - if (yi > yBest || (yi == yBest && better(xi, xBest))) { + if (yi > yBest || (yi == yBest && xi > xBest)) { xTmp[xyTmpIndex] = std::move(xBest); yTmp[xyTmpIndex] = std::move(yBest); ++xyTmpIndex; @@ -868,15 +952,95 @@ namespace storm { ValueType deltaY = yBest - yTmp[i]; if (deltaY > storm::utility::zero()) { ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; - if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + if (!hasDecisionValue || newDecisionValue > decisionValue) { decisionValue = std::move(newDecisionValue); hasDecisionValue = true; } } } } - x[group] = std::move(xBest); - y[group] = std::move(yBest); + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + + void performIterationStepUpdateDecisionValueMin(storm::storage::SparseMatrix const& A, std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = A.getRowGroupIndices().rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, A, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + uint64_t xyTmpIndex = 0; + if (hasLowerBound) { + ValueType bestValue = xBest + yBest * lowerBound; + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, A, b[row], xi, yi); + ValueType currentValue = xi + yi * lowerBound; + // Check if the current row is better then the previously found one + if (currentValue < bestValue) { + if (yBest < yi) { + // We need to store the 'old' best value as it might be relevant for the decision value + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + } + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + if (currentValue == bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + } else { + for (;row < groupEnd; ++row) { + multiplyRow(row, A, b[row], xi, yi); + // Update the best choice + if (yi > yBest || (yi == yBest && xi < xBest)) { + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + + // Update the decision value + for (uint64_t i = 0; i < xyTmpIndex; ++i) { + ValueType deltaY = yBest - yTmp[i]; + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; + if (!hasDecisionValue || newDecisionValue < decisionValue) { + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; + } + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); } } @@ -1086,13 +1250,13 @@ namespace storm { while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { if (minimize(dir)) { - helper.template performIterationStep(*this->A, b); + helper.template performIterationStepMin(*this->A, b); if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { status = SolverStatus::Converged; } } else { assert(maximize(dir)); - helper.template performIterationStep(*this->A, b); + helper.template performIterationStepMax(*this->A, b); if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { status = SolverStatus::Converged; } From 13184aefcfc81928e2bb1d76891ad9d9d5ef0210 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 19 Jan 2018 17:32:49 +0100 Subject: [PATCH 098/647] Printing the number of performed iterations (reverted from commit b5399d05962be0409a01bc66fd64f104953062b8) --- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 5 +---- .../pcaa/StandardPcaaWeightVectorChecker.h | 8 +------- src/storm/solver/AbstractEquationSolver.h | 11 +---------- .../solver/IterativeMinMaxLinearEquationSolver.cpp | 5 +---- src/storm/solver/NativeLinearEquationSolver.cpp | 6 ++---- src/storm/solver/TopologicalLinearEquationSolver.cpp | 8 -------- .../solver/TopologicalMinMaxLinearEquationSolver.cpp | 7 ------- 7 files changed, 6 insertions(+), 44 deletions(-) diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index e3c734bf0..068d08b63 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -194,8 +194,7 @@ namespace storm { std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero()); solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues); - this->overallPerformedIterations += solver->overallPerformedIterations; - solver->overallPerformedIterations = 0; + this->weightedResult = std::vector(transitionMatrix.getRowGroupCount()); transformReducedSolutionToOriginalModel(ecQuotient->matrix, ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecQuotient->ecqToOriginalChoiceMapping, ecQuotient->originalToEcqStateMapping, this->weightedResult, this->optimalChoices); @@ -278,8 +277,6 @@ namespace storm { STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); solver->solveEquations(env, x, b); - this->overallPerformedIterations += solver->overallPerformedIterations; - solver->overallPerformedIterations = 0; // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h index 10cba6fbc..2f0a27f33 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h @@ -37,13 +37,7 @@ namespace storm { StandardPcaaWeightVectorChecker(SparseMultiObjectivePreprocessorResult const& preprocessorResult); - virtual ~StandardPcaaWeightVectorChecker() { - if (overallPerformedIterations != 0) { - std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; - } - } - - mutable uint64_t overallPerformedIterations = 0; + virtual ~StandardPcaaWeightVectorChecker() = default; /*! * - computes the optimal expected reward w.r.t. the weighted sum of the rewards of the individual objectives diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index 7d9013566..476399bfa 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -3,7 +3,7 @@ #include #include -#include + #include #include "storm/solver/TerminationCondition.h" @@ -17,15 +17,6 @@ namespace storm { public: AbstractEquationSolver(); - virtual ~AbstractEquationSolver() { - if (overallPerformedIterations != 0) { - std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; - } - } - - mutable uint64_t overallPerformedIterations = 0; - - /*! * Sets a custom termination condition that is used together with the regular termination condition of the * solver. diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index d45f1478e..927c57d46 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -582,8 +582,7 @@ namespace storm { } reportStatus(status, iterations); - this->overallPerformedIterations += iterations; - + // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); @@ -1280,8 +1279,6 @@ namespace storm { reportStatus(status, iterations); - this->overallPerformedIterations += iterations; - if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index ba0032b08..06e9efebb 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -549,8 +549,7 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - this->overallPerformedIterations += iterations; - + this->logIterations(converged, terminate, iterations); return converged; @@ -735,8 +734,7 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - this->overallPerformedIterations += iterations; - + this->logIterations(converged, terminate, iterations); STORM_LOG_WARN_COND(hasMinValueBound && hasMaxValueBound, "Could not compute lower or upper bound within the given number of iterations."); STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 35994357b..83825d562 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -91,7 +91,6 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; - ++this->overallPerformedIterations; } else { sccAsBitVector.clear(); for (auto const& state : scc) { @@ -102,16 +101,9 @@ namespace storm { } } - if (this->sccSolver) { - this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; - this->sccSolver->overallPerformedIterations = 0; - } if (!this->isCachingEnabled()) { clearCache(); } - - - return returnValue; } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 92d909189..1ba0c7467 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -109,7 +109,6 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; - ++this->overallPerformedIterations; } else { sccRowGroupsAsBitVector.clear(); sccRowsAsBitVector.clear(); @@ -133,12 +132,6 @@ namespace storm { } } - if (this->sccSolver) { - this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; - this->sccSolver->overallPerformedIterations = 0; - } - - if (!this->isCachingEnabled()) { clearCache(); } From ef893abca6076a708e1ef5c88bed6e352a8a6cb1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 23 Jan 2018 21:47:22 +0100 Subject: [PATCH 099/647] fixed a case for topologicalMinMaxSolver with exact arithmetic --- src/storm/solver/MinMaxLinearEquationSolver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index 433e02c11..b543925e8 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -220,6 +220,8 @@ namespace storm { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::LinearProgramming) { result = std::make_unique>(std::make_unique>(), std::make_unique>()); + } else if (method == MinMaxMethod::Topological) { + result = std::make_unique>(); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } From ca1bcebc713c6bb83bfb0d0f2c692628819d5af3 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 23 Jan 2018 22:15:25 +0100 Subject: [PATCH 100/647] Added an option that enforces updating both bounds in interval iteration --- src/storm/environment/solver/MinMaxSolverEnvironment.cpp | 9 +++++++++ src/storm/environment/solver/MinMaxSolverEnvironment.h | 3 +++ src/storm/environment/solver/NativeSolverEnvironment.cpp | 9 +++++++++ src/storm/environment/solver/NativeSolverEnvironment.h | 3 +++ .../settings/modules/MinMaxEquationSolverSettings.cpp | 7 +++++++ .../settings/modules/MinMaxEquationSolverSettings.h | 6 ++++++ .../settings/modules/NativeEquationSolverSettings.cpp | 6 ++++++ .../settings/modules/NativeEquationSolverSettings.h | 6 ++++++ src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 2 +- src/storm/solver/NativeLinearEquationSolver.cpp | 2 +- 10 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index 83ff18826..d9e43c2e2 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -18,6 +18,7 @@ namespace storm { STORM_LOG_ASSERT(considerRelativeTerminationCriterion || minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); multiplicationStyle = minMaxSettings.getValueIterationMultiplicationStyle(); forceBounds = minMaxSettings.isForceBoundsSet(); + symmetricUpdates = minMaxSettings.isForceIntervalIterationSymmetricUpdatesSet(); qviRestartThreshold = minMaxSettings.getQviRestartThreshold(); qviRestartMaxIterations = minMaxSettings.getQviRestartMaxIterations(); } @@ -78,6 +79,14 @@ namespace storm { void MinMaxSolverEnvironment::setForceBounds(bool value) { forceBounds = value; } + + bool MinMaxSolverEnvironment::isSymmetricUpdatesSet() const { + return symmetricUpdates; + } + + void MinMaxSolverEnvironment::setSymmetricUpdates(bool value) { + symmetricUpdates = value; + } storm::RationalNumber MinMaxSolverEnvironment::getQviRestartThreshold() const { return qviRestartThreshold; diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.h b/src/storm/environment/solver/MinMaxSolverEnvironment.h index f7e0a24b1..6196942a1 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.h +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.h @@ -27,6 +27,8 @@ namespace storm { void setMultiplicationStyle(storm::solver::MultiplicationStyle value); bool isForceBoundsSet() const; void setForceBounds(bool value); + bool isSymmetricUpdatesSet() const; + void setSymmetricUpdates(bool value); storm::RationalNumber getQviRestartThreshold() const; void setQviRestartThreshold(storm::RationalNumber value); uint64_t getQviRestartMaxIterations() const; @@ -40,6 +42,7 @@ namespace storm { bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle multiplicationStyle; bool forceBounds; + bool symmetricUpdates; storm::RationalNumber qviRestartThreshold; uint64_t qviRestartMaxIterations; }; diff --git a/src/storm/environment/solver/NativeSolverEnvironment.cpp b/src/storm/environment/solver/NativeSolverEnvironment.cpp index b11b906df..722fed3d1 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.cpp +++ b/src/storm/environment/solver/NativeSolverEnvironment.cpp @@ -19,6 +19,8 @@ namespace storm { powerMethodMultiplicationStyle = nativeSettings.getPowerMethodMultiplicationStyle(); sorOmega = storm::utility::convertNumber(nativeSettings.getOmega()); forceBounds = nativeSettings.isForceBoundsSet(); + symmetricUpdates = nativeSettings.isForcePowerMethodSymmetricUpdatesSet(); + } NativeSolverEnvironment::~NativeSolverEnvironment() { @@ -86,5 +88,12 @@ namespace storm { forceBounds = value; } + bool NativeSolverEnvironment::isSymmetricUpdatesSet() const { + return symmetricUpdates; + } + void NativeSolverEnvironment::setSymmetricUpdates(bool value) { + symmetricUpdates = value; + } + } diff --git a/src/storm/environment/solver/NativeSolverEnvironment.h b/src/storm/environment/solver/NativeSolverEnvironment.h index 675b553b0..b3c9ce457 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.h +++ b/src/storm/environment/solver/NativeSolverEnvironment.h @@ -29,6 +29,8 @@ namespace storm { void setSorOmega(storm::RationalNumber const& value); bool isForceBoundsSet() const; void setForceBounds(bool value); + bool isSymmetricUpdatesSet() const; + void setSymmetricUpdates(bool value); private: storm::solver::NativeLinearEquationSolverMethod method; @@ -39,6 +41,7 @@ namespace storm { storm::solver::MultiplicationStyle powerMethodMultiplicationStyle; storm::RationalNumber sorOmega; bool forceBounds; + bool symmetricUpdates; }; } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index c0728c579..f918fe112 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string MinMaxEquationSolverSettings::absoluteOptionName = "absolute"; const std::string MinMaxEquationSolverSettings::lraMethodOptionName = "lramethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; + const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; const std::string MinMaxEquationSolverSettings::quickValueIterationRestartOptionName = "qvirestart"; @@ -41,6 +42,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, intervalIterationSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, minmax solver always require that a priori bounds for the solution are computed.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, quickValueIterationRestartOptionName, false, "Controls when a restart of quick value iteration is triggered.") @@ -118,6 +121,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool MinMaxEquationSolverSettings::isForceIntervalIterationSymmetricUpdatesSet() const { + return this->getOption(intervalIterationSymmetricUpdatesOptionName).getHasOptionBeenSet(); + } + bool MinMaxEquationSolverSettings::isForceBoundsSet() const { return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index eeb60be4e..02be37d00 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -97,6 +97,11 @@ namespace storm { */ storm::solver::MultiplicationStyle getValueIterationMultiplicationStyle() const; + /*! + * Retrievew whether updates in interval iteration have to be made symmetrically + */ + bool isForceIntervalIterationSymmetricUpdatesSet() const; + /*! * Retrieves whether the force bounds option has been set. */ @@ -123,6 +128,7 @@ namespace storm { static const std::string absoluteOptionName; static const std::string lraMethodOptionName; static const std::string valueIterationMultiplicationStyleOptionName; + static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string forceBoundsOptionName; static const std::string quickValueIterationRestartOptionName; }; diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index a34679ae8..c07d56dff 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -24,6 +24,7 @@ namespace storm { const std::string NativeEquationSolverSettings::absoluteOptionName = "absolute"; const std::string NativeEquationSolverSettings::powerMethodMultiplicationStyleOptionName = "powmult"; const std::string NativeEquationSolverSettings::forceBoundsOptionName = "forcebounds"; + const std::string NativeEquationSolverSettings::powerMethodSymmetricUpdatesOptionName = "symmetricupdates"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch", "qpower" }; @@ -43,6 +44,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, the equation solver always require that a priori bounds for the solution are computed.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, powerMethodSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); } bool NativeEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { @@ -111,6 +113,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool NativeEquationSolverSettings::isForcePowerMethodSymmetricUpdatesSet() const { + return this->getOption(powerMethodSymmetricUpdatesOptionName).getHasOptionBeenSet(); + } + bool NativeEquationSolverSettings::isForceBoundsSet() const { return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); } diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.h b/src/storm/settings/modules/NativeEquationSolverSettings.h index 67d68cb2d..1562a89c2 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.h +++ b/src/storm/settings/modules/NativeEquationSolverSettings.h @@ -93,6 +93,11 @@ namespace storm { */ ConvergenceCriterion getConvergenceCriterion() const; + /*! + * Retrievew whether updates in power method have to be made symmetrically + */ + bool isForcePowerMethodSymmetricUpdatesSet() const; + /*! * Retrieves the multiplication style to use in the power method. * @@ -118,6 +123,7 @@ namespace storm { static const std::string maximalIterationsOptionShortName; static const std::string precisionOptionName; static const std::string absoluteOptionName; + static const std::string powerMethodSymmetricUpdatesOptionName; static const std::string powerMethodMultiplicationStyleOptionName; static const std::string forceBoundsOptionName; diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 927c57d46..0acb770fe 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -465,7 +465,7 @@ namespace storm { SolverStatus status = SolverStatus::InProgress; bool doConvergenceCheck = true; - bool useDiffs = this->hasRelevantValues(); + bool useDiffs = this->hasRelevantValues() && !env.solver().minMax().isSymmetricUpdatesSet(); std::vector oldValues; if (useGaussSeidelMultiplication && useDiffs) { oldValues.resize(this->getRelevantValues().getNumberOfSetBits()); diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 06e9efebb..b82737803 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -417,7 +417,7 @@ namespace storm { bool terminate = false; uint64_t iterations = 0; bool doConvergenceCheck = true; - bool useDiffs = this->hasRelevantValues(); + bool useDiffs = this->hasRelevantValues() && !env.solver().native().isSymmetricUpdatesSet(); std::vector oldValues; if (useGaussSeidelMultiplication && useDiffs) { oldValues.resize(this->getRelevantValues().getNumberOfSetBits()); From 674a30c154f41d9f2e4df4e3be013f9b193870df Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 23 Jan 2018 22:30:35 +0100 Subject: [PATCH 101/647] removed some 'experimental' code and introduced the #iteration output again --- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 5 +- .../pcaa/StandardPcaaWeightVectorChecker.h | 8 +- src/storm/solver/AbstractEquationSolver.h | 11 +- .../IterativeMinMaxLinearEquationSolver.cpp | 253 +----------------- .../solver/NativeLinearEquationSolver.cpp | 6 +- .../TopologicalLinearEquationSolver.cpp | 8 + .../TopologicalMinMaxLinearEquationSolver.cpp | 7 + 7 files changed, 46 insertions(+), 252 deletions(-) diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index 068d08b63..e3c734bf0 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -194,7 +194,8 @@ namespace storm { std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero()); solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues); - + this->overallPerformedIterations += solver->overallPerformedIterations; + solver->overallPerformedIterations = 0; this->weightedResult = std::vector(transitionMatrix.getRowGroupCount()); transformReducedSolutionToOriginalModel(ecQuotient->matrix, ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecQuotient->ecqToOriginalChoiceMapping, ecQuotient->originalToEcqStateMapping, this->weightedResult, this->optimalChoices); @@ -277,6 +278,8 @@ namespace storm { STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); solver->solveEquations(env, x, b); + this->overallPerformedIterations += solver->overallPerformedIterations; + solver->overallPerformedIterations = 0; // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h index 2f0a27f33..10cba6fbc 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h @@ -37,7 +37,13 @@ namespace storm { StandardPcaaWeightVectorChecker(SparseMultiObjectivePreprocessorResult const& preprocessorResult); - virtual ~StandardPcaaWeightVectorChecker() = default; + virtual ~StandardPcaaWeightVectorChecker() { + if (overallPerformedIterations != 0) { + std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; + } + } + + mutable uint64_t overallPerformedIterations = 0; /*! * - computes the optimal expected reward w.r.t. the weighted sum of the rewards of the individual objectives diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index 476399bfa..7d9013566 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -3,7 +3,7 @@ #include #include - +#include #include #include "storm/solver/TerminationCondition.h" @@ -17,6 +17,15 @@ namespace storm { public: AbstractEquationSolver(); + virtual ~AbstractEquationSolver() { + if (overallPerformedIterations != 0) { + std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; + } + } + + mutable uint64_t overallPerformedIterations = 0; + + /*! * Sets a custom termination condition that is used together with the regular termination condition of the * solver. diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 0acb770fe..78faa6a8a 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -582,7 +582,8 @@ namespace storm { } reportStatus(status, iterations); - + this->overallPerformedIterations += iterations; + // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); @@ -718,90 +719,6 @@ namespace storm { } } - void performIterationStepMax(storm::storage::SparseMatrix const& A, std::vector const& b) { - if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValueMax(A, b); - } else { - assert(decisionValue == upperBound); - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - ValueType bestValue = xBest + yBest * upperBound; - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); - ValueType currentValue = xi + yi * upperBound; - // Check if the current row is better then the previously found one - if (currentValue > bestValue) { - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (currentValue == bestValue && yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - xBest = std::move(xi); - yBest = std::move(yi); - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - } - - void performIterationStepMin(storm::storage::SparseMatrix const& A, std::vector const& b) { - if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValueMin(A, b); - } else { - assert(decisionValue == lowerBound); - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - ValueType bestValue = xBest + yBest * lowerBound; - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); - ValueType currentValue = xi + yi * lowerBound; - // Check if the current row is better then the previously found one - if (currentValue < bestValue) { - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (currentValue == bestValue && yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - xBest = std::move(xi); - yBest = std::move(yi); - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - } - template void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, std::vector const& b) { auto xIt = x.rbegin(); @@ -883,166 +800,6 @@ namespace storm { } } - void performIterationStepUpdateDecisionValueMax(storm::storage::SparseMatrix const& A, std::vector const& b) { - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - uint64_t xyTmpIndex = 0; - if (hasUpperBound) { - ValueType bestValue = xBest + yBest * upperBound; - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); - ValueType currentValue = xi + yi * upperBound; - // Check if the current row is better then the previously found one - if (currentValue > bestValue) { - if (yBest < yi) { - // We need to store the 'old' best value as it might be relevant for the decision value - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - } - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - if (currentValue == bestValue) { - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - } else { - for (;row < groupEnd; ++row) { - multiplyRow(row, A, b[row], xi, yi); - // Update the best choice - if (yi > yBest || (yi == yBest && xi > xBest)) { - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - - // Update the decision value - for (uint64_t i = 0; i < xyTmpIndex; ++i) { - ValueType deltaY = yBest - yTmp[i]; - if (deltaY > storm::utility::zero()) { - ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; - if (!hasDecisionValue || newDecisionValue > decisionValue) { - decisionValue = std::move(newDecisionValue); - hasDecisionValue = true; - } - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - - void performIterationStepUpdateDecisionValueMin(storm::storage::SparseMatrix const& A, std::vector const& b) { - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - uint64_t xyTmpIndex = 0; - if (hasLowerBound) { - ValueType bestValue = xBest + yBest * lowerBound; - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); - ValueType currentValue = xi + yi * lowerBound; - // Check if the current row is better then the previously found one - if (currentValue < bestValue) { - if (yBest < yi) { - // We need to store the 'old' best value as it might be relevant for the decision value - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - } - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - if (currentValue == bestValue) { - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - } else { - for (;row < groupEnd; ++row) { - multiplyRow(row, A, b[row], xi, yi); - // Update the best choice - if (yi > yBest || (yi == yBest && xi < xBest)) { - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - - // Update the decision value - for (uint64_t i = 0; i < xyTmpIndex; ++i) { - ValueType deltaY = yBest - yTmp[i]; - if (deltaY > storm::utility::zero()) { - ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; - if (!hasDecisionValue || newDecisionValue < decisionValue) { - decisionValue = std::move(newDecisionValue); - hasDecisionValue = true; - } - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - bool checkRestartCriterion() { return false; // iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound @@ -1249,13 +1006,13 @@ namespace storm { while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { if (minimize(dir)) { - helper.template performIterationStepMin(*this->A, b); + helper.template performIterationStep(*this->A, b); if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { status = SolverStatus::Converged; } } else { assert(maximize(dir)); - helper.template performIterationStepMax(*this->A, b); + helper.template performIterationStep(*this->A, b); if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { status = SolverStatus::Converged; } @@ -1279,6 +1036,8 @@ namespace storm { reportStatus(status, iterations); + this->overallPerformedIterations += iterations; + if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index b82737803..ad1c9136c 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -549,7 +549,8 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - + this->overallPerformedIterations += iterations; + this->logIterations(converged, terminate, iterations); return converged; @@ -734,7 +735,8 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - + this->overallPerformedIterations += iterations; + this->logIterations(converged, terminate, iterations); STORM_LOG_WARN_COND(hasMinValueBound && hasMaxValueBound, "Could not compute lower or upper bound within the given number of iterations."); STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 83825d562..35994357b 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -91,6 +91,7 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; + ++this->overallPerformedIterations; } else { sccAsBitVector.clear(); for (auto const& state : scc) { @@ -101,9 +102,16 @@ namespace storm { } } + if (this->sccSolver) { + this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; + this->sccSolver->overallPerformedIterations = 0; + } if (!this->isCachingEnabled()) { clearCache(); } + + + return returnValue; } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 1ba0c7467..92d909189 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -109,6 +109,7 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; + ++this->overallPerformedIterations; } else { sccRowGroupsAsBitVector.clear(); sccRowsAsBitVector.clear(); @@ -132,6 +133,12 @@ namespace storm { } } + if (this->sccSolver) { + this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; + this->sccSolver->overallPerformedIterations = 0; + } + + if (!this->isCachingEnabled()) { clearCache(); } From 7660a6c9f8ef637bc759499961f835cc7d738a7a Mon Sep 17 00:00:00 2001 From: sjunges Date: Sat, 27 Jan 2018 14:33:00 +0100 Subject: [PATCH 102/647] dont check != 0 in templated code --- src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 10311c2a2..dce686091 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -1244,7 +1244,7 @@ namespace storm { // Now insert all (cumulative) probability values that target an MEC. for (uint_fast64_t mecIndex = 0; mecIndex < auxiliaryStateToProbabilityMap.size(); ++mecIndex) { - if (auxiliaryStateToProbabilityMap[mecIndex] != 0) { + if (!storm::utility::isZero(auxiliaryStateToProbabilityMap[mecIndex])) { sspMatrixBuilder.addNextValue(currentChoice, firstAuxiliaryStateIndex + mecIndex, auxiliaryStateToProbabilityMap[mecIndex]); } } @@ -1279,7 +1279,7 @@ namespace storm { // Now insert all (cumulative) probability values that target an MEC. for (uint_fast64_t targetMecIndex = 0; targetMecIndex < auxiliaryStateToProbabilityMap.size(); ++targetMecIndex) { - if (auxiliaryStateToProbabilityMap[targetMecIndex] != 0) { + if (!storm::utility::isZero(auxiliaryStateToProbabilityMap[targetMecIndex])) { sspMatrixBuilder.addNextValue(currentChoice, firstAuxiliaryStateIndex + targetMecIndex, auxiliaryStateToProbabilityMap[targetMecIndex]); } } @@ -1659,7 +1659,6 @@ namespace storm { template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - #endif } } From c0481ab72d7a28992adb96cf968f93c3aae07d00 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 13 Feb 2018 18:02:02 +0100 Subject: [PATCH 103/647] Moved ValueParser to separate file --- src/storm/parser/DirectEncodingParser.cpp | 30 +------------ src/storm/parser/DirectEncodingParser.h | 41 +----------------- src/storm/parser/ValueParser.cpp | 39 +++++++++++++++++ src/storm/parser/ValueParser.h | 53 +++++++++++++++++++++++ 4 files changed, 94 insertions(+), 69 deletions(-) create mode 100644 src/storm/parser/ValueParser.cpp create mode 100644 src/storm/parser/ValueParser.h diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm/parser/DirectEncodingParser.cpp index 45768f908..68530a5a7 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm/parser/DirectEncodingParser.cpp @@ -25,32 +25,6 @@ namespace storm { namespace parser { - template - void ValueParser::addParameter(std::string const& parameter) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); - } - - template<> - void ValueParser::addParameter(std::string const& parameter) { - //STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); - } - - template<> - double ValueParser::parseValue(std::string const& value) const { - return boost::lexical_cast(value); - } - - template<> - storm::RationalFunction ValueParser::parseValue(std::string const& value) const { - storm::RationalFunction rationalFunction = evaluator.asRational(parser.parseFromString(value)); - STORM_LOG_TRACE("Parsed expression: " << rationalFunction); - return rationalFunction; - } - template std::shared_ptr> DirectEncodingParser::parseModel(std::string const& filename) { @@ -253,9 +227,7 @@ namespace storm { // Template instantiations. template class DirectEncodingParser; - -#ifdef STORM_HAVE_CARL template class DirectEncodingParser; -#endif + } // namespace parser } // namespace storm diff --git a/src/storm/parser/DirectEncodingParser.h b/src/storm/parser/DirectEncodingParser.h index db1bac12e..456445e1c 100644 --- a/src/storm/parser/DirectEncodingParser.h +++ b/src/storm/parser/DirectEncodingParser.h @@ -1,53 +1,14 @@ #ifndef STORM_PARSER_DIRECTENCODINGPARSER_H_ #define STORM_PARSER_DIRECTENCODINGPARSER_H_ +#include "storm/parser/ValueParser.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" -#include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm/storage/sparse/ModelComponents.h" namespace storm { namespace parser { - /*! - * Parser for values according to their ValueType. - */ - template - class ValueParser { - public: - - ValueParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { - } - - /*! - * Parse ValueType from string. - * - * @param value String containing the value. - * - * @return ValueType - */ - ValueType parseValue(std::string const& value) const; - - /*! - * Add declaration of parameter. - * - * @param parameter New parameter. - */ - void addParameter(std::string const& parameter); - - private: - - std::shared_ptr manager; - - storm::parser::ExpressionParser parser; - - storm::expressions::ExpressionEvaluator evaluator; - - std::unordered_map identifierMapping; - }; - /*! * Parser for models in the DRN format with explicit encoding. */ diff --git a/src/storm/parser/ValueParser.cpp b/src/storm/parser/ValueParser.cpp new file mode 100644 index 000000000..90ccd4aff --- /dev/null +++ b/src/storm/parser/ValueParser.cpp @@ -0,0 +1,39 @@ +#include "storm/parser/ValueParser.h" + +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace parser { + + template + void ValueParser::addParameter(std::string const& parameter) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); + } + + template<> + void ValueParser::addParameter(std::string const& parameter) { + //STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); + storm::expressions::Variable var = manager->declareRationalVariable(parameter); + identifierMapping.emplace(var.getName(), var); + parser.setIdentifierMapping(identifierMapping); + STORM_LOG_TRACE("Added parameter: " << var.getName()); + } + + template<> + double ValueParser::parseValue(std::string const& value) const { + return boost::lexical_cast(value); + } + + template<> + storm::RationalFunction ValueParser::parseValue(std::string const& value) const { + storm::RationalFunction rationalFunction = evaluator.asRational(parser.parseFromString(value)); + STORM_LOG_TRACE("Parsed expression: " << rationalFunction); + return rationalFunction; + } + + // Template instantiations. + template class ValueParser; + template class ValueParser; + + } // namespace parser +} // namespace storm diff --git a/src/storm/parser/ValueParser.h b/src/storm/parser/ValueParser.h new file mode 100644 index 000000000..ab2e741b6 --- /dev/null +++ b/src/storm/parser/ValueParser.h @@ -0,0 +1,53 @@ +#ifndef STORM_PARSER_VALUEPARSER_H_ +#define STORM_PARSER_VALUEPARSER_H_ + +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/parser/ExpressionParser.h" +#include "storm/storage/expressions/ExpressionEvaluator.h" + +namespace storm { + namespace parser { + /*! + * Parser for values according to their ValueType. + */ + template + class ValueParser { + public: + + /*! + * Constructor. + */ + ValueParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { + } + + /*! + * Parse ValueType from string. + * + * @param value String containing the value. + * + * @return ValueType + */ + ValueType parseValue(std::string const& value) const; + + /*! + * Add declaration of parameter. + * + * @param parameter New parameter. + */ + void addParameter(std::string const& parameter); + + private: + + std::shared_ptr manager; + + storm::parser::ExpressionParser parser; + + storm::expressions::ExpressionEvaluator evaluator; + + std::unordered_map identifierMapping; + }; + + } // namespace parser +} // namespace storm + +#endif /* STORM_PARSER_VALUEPARSER_H_ */ From 821300e7775f180f7b174c3ef06f00bd90cc6fa1 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 13 Feb 2018 18:12:12 +0100 Subject: [PATCH 104/647] Use ValueParser in GalileoParser --- src/storm-dft/parser/DFTGalileoParser.cpp | 45 +++++------------------ src/storm-dft/parser/DFTGalileoParser.h | 22 +++++------ 2 files changed, 18 insertions(+), 49 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index c81c2767a..fafd4e256 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -2,12 +2,14 @@ #include #include + #include #include #include #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/parser/ValueParser.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -52,6 +54,8 @@ namespace storm { storm::utility::openFile(filename, file); std::string line; + ValueParser valueParser; + while (std::getline(file, line)) { bool success = true; STORM_LOG_TRACE("Parsing: " << line); @@ -69,16 +73,9 @@ namespace storm { toplevelId = stripQuotsFromName(line.substr(toplevelToken.size() + 1)); } else if (boost::starts_with(line, parametricToken)) { -#ifdef STORM_HAVE_CARL STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); std::string parameter = stripQuotsFromName(line.substr(parametricToken.size() + 1)); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); -#endif + valueParser.addParameter(parameter); } else { std::vector tokens; boost::split(tokens, line, boost::is_any_of(" ")); @@ -119,11 +116,11 @@ namespace storm { } else if (tokens[1] == "fdep") { success = builder.addDepElement(name, childNames, storm::utility::one()); } else if (boost::starts_with(tokens[1], "pdep=")) { - ValueType probability = parseRationalExpression(tokens[1].substr(5)); + ValueType probability = valueParser.parseValue(tokens[1].substr(5)); success = builder.addDepElement(name, childNames, probability); } else if (boost::starts_with(tokens[1], "lambda=")) { - ValueType failureRate = parseRationalExpression(tokens[1].substr(7)); - ValueType dormancyFactor = parseRationalExpression(tokens[2].substr(5)); + ValueType failureRate = valueParser.parseValue(tokens[1].substr(7)); + ValueType dormancyFactor = valueParser.parseValue(tokens[2].substr(5)); success = builder.addBasicElement(name, failureRate, dormancyFactor, false); // TODO set transient BEs } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << tokens[1] << " not recognized."); @@ -138,33 +135,9 @@ namespace storm { storm::utility::closeFile(file); } - template - ValueType DFTGalileoParser::parseRationalExpression(std::string const& expr) { - STORM_LOG_ASSERT(false, "Specialized method should be called."); - return 0; - } - - template<> - double DFTGalileoParser::parseRationalExpression(std::string const& expr) { - return boost::lexical_cast(expr); - } - // Explicitly instantiate the class. template class DFTGalileoParser; - -#ifdef STORM_HAVE_CARL - template<> - storm::RationalFunction DFTGalileoParser::parseRationalExpression(std::string const& expr) { - STORM_LOG_TRACE("Translating expression: " << expr); - storm::expressions::Expression expression = parser.parseFromString(expr); - STORM_LOG_TRACE("Expression: " << expression); - storm::RationalFunction rationalFunction = evaluator.asRational(expression); - STORM_LOG_TRACE("Parsed expression: " << rationalFunction); - return rationalFunction; - } - template class DFTGalileoParser; -#endif - + } } diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index c2a35bc50..039314069 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -15,18 +15,15 @@ namespace storm { template class DFTGalileoParser { - storm::storage::DFTBuilder builder; - - std::shared_ptr manager; - - storm::parser::ExpressionParser parser; - - storm::expressions::ExpressionEvaluator evaluator; - - std::unordered_map identifierMapping; - public: - DFTGalileoParser(bool defaultInclusive = true, bool binaryDependencies = true) : builder(defaultInclusive, binaryDependencies), manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { + + /*! + * Constructor. + * + * @param defaultInclusive Flag indicating if priority gates are inclusive by default. + * @param binaryDependencies Flag indicating if dependencies should be converted to binary dependencies. + */ + DFTGalileoParser(bool defaultInclusive = true, bool binaryDependencies = true) : builder(defaultInclusive, binaryDependencies) { } storm::storage::DFT parseDFT(std::string const& filename); @@ -37,8 +34,7 @@ namespace storm { std::string stripQuotsFromName(std::string const& name); std::string parseNodeIdentifier(std::string const& name); - ValueType parseRationalExpression(std::string const& expr); - + storm::storage::DFTBuilder builder; bool defaultInclusive; }; } From 8eb16634c14e7c85c61383c1e3283878bfbeb0a9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 14 Feb 2018 22:53:39 +0100 Subject: [PATCH 105/647] Better error message in ValueParser --- src/storm/parser/ValueParser.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/storm/parser/ValueParser.cpp b/src/storm/parser/ValueParser.cpp index 90ccd4aff..96ed0015b 100644 --- a/src/storm/parser/ValueParser.cpp +++ b/src/storm/parser/ValueParser.cpp @@ -1,6 +1,7 @@ #include "storm/parser/ValueParser.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/WrongFormatException.h" namespace storm { namespace parser { @@ -12,7 +13,6 @@ namespace storm { template<> void ValueParser::addParameter(std::string const& parameter) { - //STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); storm::expressions::Variable var = manager->declareRationalVariable(parameter); identifierMapping.emplace(var.getName(), var); parser.setIdentifierMapping(identifierMapping); @@ -21,7 +21,12 @@ namespace storm { template<> double ValueParser::parseValue(std::string const& value) const { - return boost::lexical_cast(value); + try { + return boost::lexical_cast(value); + } + catch(boost::bad_lexical_cast &) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "'."); + } } template<> From f37bd143f1ecbad29bea4f64c584304d6ebaeb95 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 14 Feb 2018 23:01:13 +0100 Subject: [PATCH 106/647] Better handling of comments in GalileoParser --- src/storm-dft-cli/storm-dft.cpp | 3 +- src/storm-dft/parser/DFTGalileoParser.cpp | 161 +++++++++++++--------- src/storm-dft/parser/DFTGalileoParser.h | 21 ++- 3 files changed, 110 insertions(+), 75 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 21f3cfecc..cef8717b2 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -32,9 +32,8 @@ std::shared_ptr> loadDFT() { STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); dft = std::make_shared>(parser.parseJson(dftIOSettings.getDftJsonFilename())); } else { - storm::parser::DFTGalileoParser parser; STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); - dft = std::make_shared>(parser.parseDFT(dftIOSettings.getDftFilename())); + dft = std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(dftIOSettings.getDftFilename())); } if (dftIOSettings.isDisplayStatsSet()) { diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index fafd4e256..c5d1b9c36 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -9,6 +10,7 @@ #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/WrongFormatException.h" #include "storm/parser/ValueParser.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -16,15 +18,6 @@ namespace storm { namespace parser { - template - storm::storage::DFT DFTGalileoParser::parseDFT(const std::string& filename) { - readFile(filename); - storm::storage::DFT dft = builder.build(); - STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); - STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); - return dft; - } - template std::string DFTGalileoParser::stripQuotsFromName(std::string const& name) { size_t firstQuots = name.find("\""); @@ -44,95 +37,139 @@ namespace storm { } template - void DFTGalileoParser::readFile(const std::string& filename) { - // constants - std::string toplevelToken = "toplevel"; - std::string toplevelId; - std::string parametricToken = "param"; + storm::storage::DFT DFTGalileoParser::parseDFT(const std::string& filename, bool defaultInclusive, bool binaryDependencies) { + storm::storage::DFTBuilder builder(defaultInclusive, binaryDependencies); + ValueParser valueParser; + // Regular expression to detect comments + // taken from: https://stackoverflow.com/questions/9449887/removing-c-c-style-comments-using-boostregex + const std::regex commentRegex("(/\\*([^*]|(\\*+[^*/]))*\\*+/)|(//.*)"); std::ifstream file; storm::utility::openFile(filename, file); - std::string line; - ValueParser valueParser; + std::string line; + size_t lineNo = 0; + std::string toplevelId = ""; + bool comment = false; // Indicates whether the current line is part of a multiline comment while (std::getline(file, line)) { - bool success = true; - STORM_LOG_TRACE("Parsing: " << line); - size_t commentstarts = line.find("//"); - line = line.substr(0, commentstarts); - size_t firstsemicolon = line.find(";"); - line = line.substr(0, firstsemicolon); - if (line.find_first_not_of(' ') == std::string::npos) { - // Only whitespace - continue; + ++lineNo; + // First consider comments + if (comment) { + // Line is part of multiline comment -> search for end of this comment + size_t commentEnd = line.find("*/"); + if (commentEnd == std::string::npos) { + continue; + } else { + // Remove comment + line = line.substr(commentEnd + 2); + comment = false; + } + } + // Remove comments + line = std::regex_replace(line, commentRegex, ""); + // Check if multiline comment starts + size_t commentStart = line.find("/*"); + if (commentStart != std::string::npos) { + // Remove comment + line = line.substr(0, commentStart); + comment = true; } - // Top level indicator. - if(boost::starts_with(line, toplevelToken)) { - toplevelId = stripQuotsFromName(line.substr(toplevelToken.size() + 1)); + boost::trim(line); + if (line.empty()) { + // Empty line + continue; } - else if (boost::starts_with(line, parametricToken)) { + + // Remove semicolon + STORM_LOG_THROW(line.back() == ';', storm::exceptions::WrongFormatException, "Semicolon expected at the end of line " << lineNo << "."); + line.pop_back(); + + // Split line into tokens + boost::trim(line); + std::vector tokens; + boost::split(tokens, line, boost::is_any_of(" \t"), boost::token_compress_on); + + if (tokens[0] == "toplevel") { + // Top level indicator + STORM_LOG_THROW(toplevelId == "", storm::exceptions::WrongFormatException, "Toplevel element already defined."); + STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected element id after 'toplevel' in line " << lineNo << "."); + toplevelId = stripQuotsFromName(tokens[1]); + } else if (tokens[0] == "param") { + // Parameters + STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected parameter name after 'param' in line " << lineNo << "."); STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - std::string parameter = stripQuotsFromName(line.substr(parametricToken.size() + 1)); - valueParser.addParameter(parameter); + valueParser.addParameter(stripQuotsFromName(tokens[1])); } else { - std::vector tokens; - boost::split(tokens, line, boost::is_any_of(" ")); - std::string name(parseNodeIdentifier(stripQuotsFromName(tokens[0]))); + // DFT element + std::string name = parseNodeIdentifier(stripQuotsFromName(tokens[0])); std::vector childNames; for(unsigned i = 2; i < tokens.size(); ++i) { childNames.push_back(parseNodeIdentifier(stripQuotsFromName(tokens[i]))); } - if(tokens[1] == "and") { + bool success = true; + + // Add element according to type + std::string type = tokens[1]; + if (type == "and") { success = builder.addAndElement(name, childNames); - } else if (tokens[1] == "or") { + } else if (type == "or") { success = builder.addOrElement(name, childNames); - } else if (boost::starts_with(tokens[1], "vot")) { - success = builder.addVotElement(name, boost::lexical_cast(tokens[1].substr(3)), childNames); - } else if (tokens[1].find("of") != std::string::npos) { - size_t pos = tokens[1].find("of"); - unsigned threshold = boost::lexical_cast(tokens[1].substr(0, pos)); - unsigned count = boost::lexical_cast(tokens[1].substr(pos + 2)); - STORM_LOG_THROW(count == childNames.size(), storm::exceptions::FileIoException, "Voting gate does not correspond to number of children."); + } else if (boost::starts_with(type, "vot")) { + unsigned threshold = boost::lexical_cast(type.substr(3)); success = builder.addVotElement(name, threshold, childNames); - } else if (tokens[1] == "pand") { - success = builder.addPandElement(name, childNames); - } else if (tokens[1] == "pand-inc") { + } else if (type.find("of") != std::string::npos) { + size_t pos = type.find("of"); + unsigned threshold = boost::lexical_cast(type.substr(0, pos)); + unsigned count = boost::lexical_cast(type.substr(pos + 2)); + STORM_LOG_THROW(count == childNames.size(), storm::exceptions::WrongFormatException, "Voting gate number " << count << " does not correspond to number of children " << childNames.size() << "in line " << lineNo << "."); + success = builder.addVotElement(name, threshold, childNames); + } else if (type == "pand") { + success = builder.addPandElement(name, childNames, defaultInclusive); + } else if (type == "pand-inc") { success = builder.addPandElement(name, childNames, true); - } else if (tokens[1] == "pand-ex") { + } else if (type == "pand-ex") { success = builder.addPandElement(name, childNames, false); - } else if (tokens[1] == "por") { - success = builder.addPorElement(name, childNames); - } else if (tokens[1] == "por-ex") { + } else if (type == "por") { + success = builder.addPorElement(name, childNames, defaultInclusive); + } else if (type == "por-ex") { success = builder.addPorElement(name, childNames, false); - } else if (tokens[1] == "por-inc") { + } else if (type == "por-inc") { success = builder.addPorElement(name, childNames, true); - } else if (tokens[1] == "wsp" || tokens[1] == "csp") { + } else if (type == "wsp" || type == "csp" || type == "hsp") { success = builder.addSpareElement(name, childNames); - } else if (tokens[1] == "seq") { + } else if (type == "seq") { success = builder.addSequenceEnforcer(name, childNames); - } else if (tokens[1] == "fdep") { + } else if (type == "fdep") { + STORM_LOG_THROW(childNames.size() >= 2, storm::exceptions::WrongFormatException, "FDEP gate needs at least two children in line " << lineNo << "."); success = builder.addDepElement(name, childNames, storm::utility::one()); - } else if (boost::starts_with(tokens[1], "pdep=")) { - ValueType probability = valueParser.parseValue(tokens[1].substr(5)); + } else if (boost::starts_with(type, "pdep=")) { + ValueType probability = valueParser.parseValue(type.substr(5)); success = builder.addDepElement(name, childNames, probability); - } else if (boost::starts_with(tokens[1], "lambda=")) { - ValueType failureRate = valueParser.parseValue(tokens[1].substr(7)); + } else if (boost::starts_with(type, "lambda=")) { + ValueType failureRate = valueParser.parseValue(type.substr(7)); ValueType dormancyFactor = valueParser.parseValue(tokens[2].substr(5)); success = builder.addBasicElement(name, failureRate, dormancyFactor, false); // TODO set transient BEs } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << tokens[1] << " not recognized."); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " in line " << lineNo << " not recognized."); success = false; } - STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << name << "' of line '" << line << "'."); + STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << name << "' in line " << lineNo << "."); } } - if(!builder.setTopLevel(toplevelId)) { - STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown."); + + if (!builder.setTopLevel(toplevelId)) { + STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id '" << toplevelId << "' unknown."); } storm::utility::closeFile(file); + + // Build DFT + storm::storage::DFT dft = builder.build(); + STORM_LOG_DEBUG("DFT Elements:" << std::endl << dft.getElementsString()); + STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); + return dft; } // Explicitly instantiate the class. diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index 039314069..f12e0d2fb 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -13,29 +13,28 @@ namespace storm { namespace parser { + /*! + * Parser for DFT in the Galileo format. + */ template class DFTGalileoParser { public: /*! - * Constructor. + * Parse DFT in Galileo format and build DFT. * + * @param filename File. * @param defaultInclusive Flag indicating if priority gates are inclusive by default. * @param binaryDependencies Flag indicating if dependencies should be converted to binary dependencies. + * + * @return DFT. */ - DFTGalileoParser(bool defaultInclusive = true, bool binaryDependencies = true) : builder(defaultInclusive, binaryDependencies) { - } - - storm::storage::DFT parseDFT(std::string const& filename); + static storm::storage::DFT parseDFT(std::string const& filename, bool defaultInclusive = true, bool binaryDependencies = true); private: - void readFile(std::string const& filename); - - std::string stripQuotsFromName(std::string const& name); - std::string parseNodeIdentifier(std::string const& name); + static std::string stripQuotsFromName(std::string const& name); - storm::storage::DFTBuilder builder; - bool defaultInclusive; + static std::string parseNodeIdentifier(std::string const& name); }; } } From 32b958518412ca0a8d295343e82717c86fd46e87 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 14 Feb 2018 23:11:38 +0100 Subject: [PATCH 107/647] Method for parsing node name --- src/storm-dft/parser/DFTGalileoParser.cpp | 25 ++++++++++------------- src/storm-dft/parser/DFTGalileoParser.h | 4 +--- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index c5d1b9c36..ac9687da2 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -19,21 +19,18 @@ namespace storm { namespace parser { template - std::string DFTGalileoParser::stripQuotsFromName(std::string const& name) { + std::string DFTGalileoParser::parseName(std::string const& name) { size_t firstQuots = name.find("\""); size_t secondQuots = name.find("\"", firstQuots+1); + std::string parsedName; - if(firstQuots == std::string::npos) { - return name; + if (firstQuots == std::string::npos) { + parsedName = name; } else { - STORM_LOG_THROW(secondQuots != std::string::npos, storm::exceptions::FileIoException, "No ending quotation mark found in " << name); - return name.substr(firstQuots+1,secondQuots-1); + STORM_LOG_THROW(secondQuots != std::string::npos, storm::exceptions::WrongFormatException, "No ending quotation mark found in " << name); + parsedName = name.substr(firstQuots+1,secondQuots-1); } - } - - template - std::string DFTGalileoParser::parseNodeIdentifier(std::string const& name) { - return boost::replace_all_copy(name, "'", "__prime__"); + return boost::replace_all_copy(parsedName, "'", "__prime__"); } template @@ -95,19 +92,19 @@ namespace storm { // Top level indicator STORM_LOG_THROW(toplevelId == "", storm::exceptions::WrongFormatException, "Toplevel element already defined."); STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected element id after 'toplevel' in line " << lineNo << "."); - toplevelId = stripQuotsFromName(tokens[1]); + toplevelId = parseName(tokens[1]); } else if (tokens[0] == "param") { // Parameters STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected parameter name after 'param' in line " << lineNo << "."); STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - valueParser.addParameter(stripQuotsFromName(tokens[1])); + valueParser.addParameter(parseName(tokens[1])); } else { // DFT element - std::string name = parseNodeIdentifier(stripQuotsFromName(tokens[0])); + std::string name = parseName(tokens[0]); std::vector childNames; for(unsigned i = 2; i < tokens.size(); ++i) { - childNames.push_back(parseNodeIdentifier(stripQuotsFromName(tokens[i]))); + childNames.push_back(parseName(tokens[i])); } bool success = true; diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index f12e0d2fb..6402c1969 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -32,9 +32,7 @@ namespace storm { static storm::storage::DFT parseDFT(std::string const& filename, bool defaultInclusive = true, bool binaryDependencies = true); private: - static std::string stripQuotsFromName(std::string const& name); - - static std::string parseNodeIdentifier(std::string const& name); + static std::string parseName(std::string const& name); }; } } From 8d845fad95342f2c37d2932644a6d873098d9f44 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 14 Feb 2018 23:51:49 +0100 Subject: [PATCH 108/647] Throw exceptions for all unsupported Galileo distributions --- src/storm-dft/parser/DFTGalileoParser.cpp | 49 ++++++++++++++++++++--- src/storm-dft/parser/DFTGalileoParser.h | 19 +++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index ac9687da2..8a02ce1fe 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -11,7 +11,6 @@ #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/WrongFormatException.h" -#include "storm/parser/ValueParser.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -145,10 +144,8 @@ namespace storm { } else if (boost::starts_with(type, "pdep=")) { ValueType probability = valueParser.parseValue(type.substr(5)); success = builder.addDepElement(name, childNames, probability); - } else if (boost::starts_with(type, "lambda=")) { - ValueType failureRate = valueParser.parseValue(type.substr(7)); - ValueType dormancyFactor = valueParser.parseValue(tokens[2].substr(5)); - success = builder.addBasicElement(name, failureRate, dormancyFactor, false); // TODO set transient BEs + } else if (type.find("=") != std::string::npos) { + success = parseBasicElement(tokens, builder, valueParser); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " in line " << lineNo << " not recognized."); success = false; @@ -169,6 +166,48 @@ namespace storm { return dft; } + template + bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser) { + std::string name = parseName(tokens[0]); + + // Default values + ValueType lambda = storm::utility::zero(); + ValueType dormancyFactor = storm::utility::one(); + bool exponential = false; + + for (size_t i = 1; i < tokens.size(); ++i) { + std::string token = tokens[i]; + if (boost::starts_with(token, "prob=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); + } else if (boost::starts_with(token, "lambda=")) { + lambda = valueParser.parseValue(token.substr(7)); + exponential = true; + } else if (boost::starts_with(token, "rate=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + } else if (boost::starts_with(token, "shape=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + } else if (boost::starts_with(token, "mean=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + } else if (boost::starts_with(token, "stddev=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + } else if (boost::starts_with(token, "cov=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Coverage is not supported."); + } else if (boost::starts_with(token, "res=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Restoration is not supported."); + } else if (boost::starts_with(token, "repl=")) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Replication is not supported."); + } else if (boost::starts_with(token, "dorm=")) { + dormancyFactor = valueParser.parseValue(token.substr(5)); + } + } + + if (exponential) { + return builder.addBasicElement(name, lambda, dormancyFactor, false); // TODO set transient BEs + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "No distribution for basic element defined."); + } + } + // Explicitly instantiate the class. template class DFTGalileoParser; template class DFTGalileoParser; diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index 6402c1969..6bdb66ee2 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -8,6 +8,7 @@ #include "storm-dft/storage/dft/DFT.h" #include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm/parser/ValueParser.h" namespace storm { @@ -32,7 +33,25 @@ namespace storm { static storm::storage::DFT parseDFT(std::string const& filename, bool defaultInclusive = true, bool binaryDependencies = true); private: + /*! + * Parse element name (strip quotation marks, etc.). + * + * @param name Element name. + * + * @return Name. + */ static std::string parseName(std::string const& name); + + /*! + * Parse basic element and add it to builder. + * + * @param tokens Tokens defining the basic element. + * @param builder DFTBuilder. + * @param valueParser ValueParser. + * + * @return True iff the parsing and creation was successful. + */ + static bool parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser); }; } } From f168df139dc2574b02874ecb582246aecf4192ff Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 15 Feb 2018 12:11:10 +0100 Subject: [PATCH 109/647] made qvi code more readable --- .../IterativeMinMaxLinearEquationSolver.cpp | 201 +++++++++--------- 1 file changed, 96 insertions(+), 105 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 78faa6a8a..cd6810a14 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -799,22 +799,12 @@ namespace storm { *yIt = std::move(yBest); } } - - bool checkRestartCriterion() { - return false; - // iterations <= restartMaxIterations && (minimize(dir) ? restartThreshold * improvedPrimaryBound > primaryBound : restartThreshold * primaryBound > improvedPrimaryBound - } - bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { - return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); - } - template - bool checkConvergenceUpdateBounds(uint64_t const& iterations, storm::storage::BitVector const* relevantValues = nullptr) { + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr) { if (convergencePhase1) { if (checkConvergencePhase1()) { - STORM_LOG_INFO("Quick Value Iteration took " << iterations << " iterations for first convergence phase."); firstIndexViolatingConvergence = 0; if (relevantValues != nullptr) { firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); @@ -829,93 +819,11 @@ namespace storm { // The difference between lower and upper bound has to be < precision at every (relevant) value // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds - - ValueType lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); - ValueType upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); - // Make sure that these candidates are at least as tight as the already known bounds - if (hasLowerBound && lowerBoundCandidate < lowerBound) { - lowerBoundCandidate = lowerBound; - } - if (hasUpperBound && upperBoundCandidate > upperBound) { - upperBoundCandidate = upperBound; - } - bool computeActualBounds = isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate); - if (!computeActualBounds) { - if (decisionValueBlocks) { - ValueType improvedPrimaryBound = x[getPrimaryIndex()] + getPrimaryBound() * y[getPrimaryIndex()]; - assert(better(getPrimaryBound(), improvedPrimaryBound)); - computeActualBounds = checkRestartCriterion(); - } else { - computeActualBounds = hasDecisionValue && better(decisionValue, getPrimaryBound()); - } - } - if (computeActualBounds) { - auto xIt = x.begin(); - auto xIte = x.end(); - auto yIt = y.begin(); - ValueType improvedPrimaryBound; - bool computedImprovedPrimaryBound = false; - for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { - ValueType currentBound = *xIt / (storm::utility::one() - *yIt); - if (decisionValueBlocks) { - ValueType currentImprovedBound = *xIt + getPrimaryBound() * (*yIt); - if (!computedImprovedPrimaryBound || better(currentImprovedBound, improvedPrimaryBound)) { - computedImprovedPrimaryBound = true; - getPrimaryIndex() = index; - improvedPrimaryBound = std::move(currentImprovedBound); - } - if (better(getSecondaryBound(), currentBound)) { - getSecondaryIndex() = index; - getSecondaryBound() = std::move(currentBound); - } - } else { - if (currentBound < lowerBoundCandidate) { - minIndex = index; - lowerBoundCandidate = std::move(currentBound); - } else if (currentBound > upperBoundCandidate) { - maxIndex = index; - upperBoundCandidate = std::move(currentBound); - } - } - } - if ((maximize(dir) || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { - setLowerBound(lowerBoundCandidate); - } - if ((minimize(dir) || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { - setUpperBound(upperBoundCandidate); - } - - // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). - if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { - getPrimaryBound() = decisionValue; - decisionValueBlocks = true; - } - - // Check whether the desired precision is reached - if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // The current index satisfies the desired bound. We now move to the next index that violates it - while (true) { - ++firstIndexViolatingConvergence; - if (relevantValues != nullptr) { - firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); - } - if (firstIndexViolatingConvergence == x.size()) { - // Converged! - return true; - } else { - if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // not converged yet - break; - } - } - } - } - // Check whether we should restart - if (computedImprovedPrimaryBound && checkRestartCriterion()) { - STORM_LOG_INFO("Restarting QVI after " << iterations << " iterations. Improved bound from " << getPrimaryBound() << " to " << improvedPrimaryBound << "."); - getPrimaryBound() = improvedPrimaryBound; - restart(); - } + ValueType lowerBoundCandidate, upperBoundCandidate; + if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { + updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); + checkIfDecisionValueBlocks(); + return checkConvergencePhase2(relevantValues); } return false; } @@ -956,6 +864,94 @@ namespace storm { return true; } + + bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { + return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); + } + + template + bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); + upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); + // Make sure that these candidates are at least as tight as the already known bounds + if (hasLowerBound && lowerBoundCandidate < lowerBound) { + lowerBoundCandidate = lowerBound; + } + if (hasUpperBound && upperBoundCandidate > upperBound) { + upperBoundCandidate = upperBound; + } + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { + return true; + } + if (!decisionValueBlocks) { + return hasDecisionValue && better(decisionValue, getPrimaryBound()); + } + return false; + } + + template + void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + auto xIt = x.begin(); + auto xIte = x.end(); + auto yIt = y.begin(); + for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { + ValueType currentBound = *xIt / (storm::utility::one() - *yIt); + if (decisionValueBlocks) { + if (better(getSecondaryBound(), currentBound)) { + getSecondaryIndex() = index; + getSecondaryBound() = std::move(currentBound); + } + } else { + if (currentBound < lowerBoundCandidate) { + minIndex = index; + lowerBoundCandidate = std::move(currentBound); + } else if (currentBound > upperBoundCandidate) { + maxIndex = index; + upperBoundCandidate = std::move(currentBound); + } + } + } + if ((maximize(dir) || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { + setLowerBound(lowerBoundCandidate); + } + if ((minimize(dir) || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { + setUpperBound(upperBoundCandidate); + } + } + + template + void checkIfDecisionValueBlocks() { + // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). + if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { + getPrimaryBound() = decisionValue; + decisionValueBlocks = true; + } + } + + template + bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr) { + // Check whether the desired precision is reached + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); + } + if (firstIndexViolatingConvergence == x.size()) { + // Converged! + return true; + } else { + if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // not converged yet + return false; + } + } + } + } + return false; + } + std::vector& x; std::vector& y; std::vector xTmp, yTmp; @@ -982,11 +978,6 @@ namespace storm { QuickValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); - // Get the precision - uint64_t restartMaxIterations = env.solver().minMax().getQviRestartMaxIterations(); - ValueType restartThreshold = storm::utility::convertNumber(env.solver().minMax().getQviRestartThreshold()); - - // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { helper.setLowerBound(this->getLowerBound(true)); @@ -1007,13 +998,13 @@ namespace storm { while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { if (minimize(dir)) { helper.template performIterationStep(*this->A, b); - if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { + if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } } else { assert(maximize(dir)); helper.template performIterationStep(*this->A, b); - if (helper.template checkConvergenceUpdateBounds(iterations, relevantValuesPtr)) { + if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } } From f2289a3b87bbb75a23d1c36cdb7b7b3249bd2d09 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 15 Feb 2018 12:24:41 +0100 Subject: [PATCH 110/647] removed unused option --- .../solver/MinMaxSolverEnvironment.cpp | 20 ------------------- .../solver/MinMaxSolverEnvironment.h | 6 ------ .../modules/MinMaxEquationSolverSettings.cpp | 13 ------------ .../modules/MinMaxEquationSolverSettings.h | 10 ---------- 4 files changed, 49 deletions(-) diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index d9e43c2e2..ada4cc5da 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -19,8 +19,6 @@ namespace storm { multiplicationStyle = minMaxSettings.getValueIterationMultiplicationStyle(); forceBounds = minMaxSettings.isForceBoundsSet(); symmetricUpdates = minMaxSettings.isForceIntervalIterationSymmetricUpdatesSet(); - qviRestartThreshold = minMaxSettings.getQviRestartThreshold(); - qviRestartMaxIterations = minMaxSettings.getQviRestartMaxIterations(); } MinMaxSolverEnvironment::~MinMaxSolverEnvironment() { @@ -88,22 +86,4 @@ namespace storm { symmetricUpdates = value; } - storm::RationalNumber MinMaxSolverEnvironment::getQviRestartThreshold() const { - return qviRestartThreshold; - } - - void MinMaxSolverEnvironment::setQviRestartThreshold(storm::RationalNumber value) { - qviRestartThreshold = value; - } - - uint64_t MinMaxSolverEnvironment::getQviRestartMaxIterations() const { - return qviRestartMaxIterations; - } - - void MinMaxSolverEnvironment::setQviRestartMaxIterations(uint64_t value) { - qviRestartMaxIterations = value; - } - - - } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.h b/src/storm/environment/solver/MinMaxSolverEnvironment.h index 6196942a1..3f54f0fa9 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.h +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.h @@ -29,10 +29,6 @@ namespace storm { void setForceBounds(bool value); bool isSymmetricUpdatesSet() const; void setSymmetricUpdates(bool value); - storm::RationalNumber getQviRestartThreshold() const; - void setQviRestartThreshold(storm::RationalNumber value); - uint64_t getQviRestartMaxIterations() const; - void setQviRestartMaxIterations(uint64_t value); private: storm::solver::MinMaxMethod minMaxMethod; @@ -43,8 +39,6 @@ namespace storm { storm::solver::MultiplicationStyle multiplicationStyle; bool forceBounds; bool symmetricUpdates; - storm::RationalNumber qviRestartThreshold; - uint64_t qviRestartMaxIterations; }; } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index f918fe112..7612f16ec 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -21,7 +21,6 @@ namespace storm { const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; - const std::string MinMaxEquationSolverSettings::quickValueIterationRestartOptionName = "qvirestart"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration", "topological"}; @@ -46,9 +45,6 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, minmax solver always require that a priori bounds for the solution are computed.").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, quickValueIterationRestartOptionName, false, "Controls when a restart of quick value iteration is triggered.") - .addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("threshold", "The minimal (relative) bound improvement that triggers a restart").addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorIncluding(0.0, 1.0)).setDefaultValueDouble(0.5).build()) - .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("maxiters", "The maximal number of iterations within which a restart can be triggered.").setDefaultValueUnsignedInteger(300).build()).build()); } storm::solver::MinMaxMethod MinMaxEquationSolverSettings::getMinMaxEquationSolvingMethod() const { @@ -128,15 +124,6 @@ namespace storm { bool MinMaxEquationSolverSettings::isForceBoundsSet() const { return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); } - - double MinMaxEquationSolverSettings::getQviRestartThreshold() const { - return this->getOption(quickValueIterationRestartOptionName).getArgumentByName("threshold").getValueAsDouble(); - } - - uint_fast64_t MinMaxEquationSolverSettings::getQviRestartMaxIterations() const { - return this->getOption(quickValueIterationRestartOptionName).getArgumentByName("maxiters").getValueAsUnsignedInteger(); - } - } } } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index 02be37d00..fc5add0c4 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -107,16 +107,6 @@ namespace storm { */ bool isForceBoundsSet() const; - /*! - * Retrieves the restart threshold for quick value iteration - */ - double getQviRestartThreshold() const; - - /*! - * Retrieves the maximal number of iterations within which a restart of quick value iteration can be triggered. - */ - uint_fast64_t getQviRestartMaxIterations() const; - // The name of the module. static const std::string moduleName; From ea25c8fd2ee1e584fcc258ec4a7bd001d3b9d205 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 15 Feb 2018 12:43:35 +0100 Subject: [PATCH 111/647] renamed 'sound value iteration' to 'interval iteration' and 'quick sound value iteration' to 'sound value iteration' --- .../modules/MinMaxEquationSolverSettings.cpp | 11 +++-- .../TopologicalEquationSolverSettings.cpp | 16 +++++-- .../IterativeMinMaxLinearEquationSolver.cpp | 48 ++++++++++--------- .../IterativeMinMaxLinearEquationSolver.h | 2 +- .../solver/MinMaxLinearEquationSolver.cpp | 4 +- src/storm/solver/SolverSelectionOptions.cpp | 6 ++- src/storm/solver/SolverSelectionOptions.h | 2 +- .../StandardMinMaxLinearEquationSolver.cpp | 2 +- .../modelchecker/MdpPrctlModelCheckerTest.cpp | 14 +++--- 9 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 7612f16ec..add033af0 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -23,7 +23,7 @@ namespace storm { const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration", "topological"}; + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); @@ -55,13 +55,16 @@ namespace storm { return storm::solver::MinMaxMethod::PolicyIteration; } else if (minMaxEquationSolvingTechnique == "linear-programming" || minMaxEquationSolvingTechnique == "lp") { return storm::solver::MinMaxMethod::LinearProgramming; - } else if (minMaxEquationSolvingTechnique == "ratsearch") { + } else if (minMaxEquationSolvingTechnique == "ratsearch" || minMaxEquationSolvingTechnique == "rs") { return storm::solver::MinMaxMethod::RationalSearch; - } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { - return storm::solver::MinMaxMethod::QuickValueIteration; + } else if (minMaxEquationSolvingTechnique == "interval-iteration" || minMaxEquationSolvingTechnique == "ii") { + return storm::solver::MinMaxMethod::IntervalIteration; + } else if (minMaxEquationSolvingTechnique == "sound-value-iteration" || minMaxEquationSolvingTechnique == "svi") { + return storm::solver::MinMaxMethod::SoundValueIteration; } else if (minMaxEquationSolvingTechnique == "topological") { return storm::solver::MinMaxMethod::Topological; } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown min/max equation solving technique '" << minMaxEquationSolvingTechnique << "'."); } diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp index d088b2879..88a0c48fd 100644 --- a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -29,7 +29,7 @@ namespace storm { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, true, "Sets which solver is considered for solving the underlying equation systems.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); - std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"}; + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration"}; this->addOption(storm::settings::OptionBuilder(moduleName, underlyingMinMaxMethodOptionName, true, "Sets which minmax method is considered for solving the underlying minmax equation systems.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used min max method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("value-iteration").build()).build()); } @@ -66,17 +66,23 @@ namespace storm { storm::solver::MinMaxMethod TopologicalEquationSolverSettings::getUnderlyingMinMaxMethod() const { std::string minMaxEquationSolvingTechnique = this->getOption(underlyingMinMaxMethodOptionName).getArgumentByName("name").getValueAsString(); - if (minMaxEquationSolvingTechnique == "value-iteration" || minMaxEquationSolvingTechnique == "vi") { + if (minMaxEquationSolvingTechnique == "value-iteration" || minMaxEquationSolvingTechnique == "vi") { return storm::solver::MinMaxMethod::ValueIteration; } else if (minMaxEquationSolvingTechnique == "policy-iteration" || minMaxEquationSolvingTechnique == "pi") { return storm::solver::MinMaxMethod::PolicyIteration; } else if (minMaxEquationSolvingTechnique == "linear-programming" || minMaxEquationSolvingTechnique == "lp") { return storm::solver::MinMaxMethod::LinearProgramming; - } else if (minMaxEquationSolvingTechnique == "ratsearch") { + } else if (minMaxEquationSolvingTechnique == "ratsearch" || minMaxEquationSolvingTechnique == "rs") { return storm::solver::MinMaxMethod::RationalSearch; - } else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") { - return storm::solver::MinMaxMethod::QuickValueIteration; + } else if (minMaxEquationSolvingTechnique == "interval-iteration" || minMaxEquationSolvingTechnique == "ii") { + return storm::solver::MinMaxMethod::IntervalIteration; + } else if (minMaxEquationSolvingTechnique == "sound-value-iteration" || minMaxEquationSolvingTechnique == "svi") { + return storm::solver::MinMaxMethod::SoundValueIteration; } + + + + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << minMaxEquationSolvingTechnique << "'."); } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index cd6810a14..2aa60ded3 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -38,7 +38,7 @@ namespace storm { template MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environment const& env, bool isExactMode) const { - // Adjust the method if none was specified and we are using rational numbers. + // Adjust the method if none was specified and we want exact or sound computations. auto method = env.solver().minMax().getMethod(); if (isExactMode && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { @@ -48,8 +48,15 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } + } else if (env.solver().isForceSoundness() && method != MinMaxMethod::SoundValueIteration && method != MinMaxMethod::IntervalIteration && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { + if (env.solver().minMax().isMethodSetFromDefault()) { + STORM_LOG_INFO("Selecting 'sound value iteration' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); + method = MinMaxMethod::SoundValueIteration; + } else { + STORM_LOG_WARN("The selected solution method does not guarantee sound results."); + } } - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); return method; } @@ -58,11 +65,7 @@ namespace storm { bool result = false; switch (getMethod(env, storm::NumberTraits::IsExact)) { case MinMaxMethod::ValueIteration: - if (env.solver().isForceSoundness()) { - result = solveEquationsSoundValueIteration(env, dir, x, b); - } else { - result = solveEquationsValueIteration(env, dir, x, b); - } + result = solveEquationsValueIteration(env, dir, x, b); break; case MinMaxMethod::PolicyIteration: result = solveEquationsPolicyIteration(env, dir, x, b); @@ -70,8 +73,11 @@ namespace storm { case MinMaxMethod::RationalSearch: result = solveEquationsRationalSearch(env, dir, x, b); break; - case MinMaxMethod::QuickValueIteration: - result = solveEquationsQuickSoundValueIteration(env, dir, x, b); + case MinMaxMethod::IntervalIteration: + result = solveEquationsIntervalIteration(env, dir, x, b); + break; + case MinMaxMethod::SoundValueIteration: + result = solveEquationsSoundValueIteration(env, dir, x, b); break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); @@ -217,7 +223,7 @@ namespace storm { // Start by getting the requirements of the linear equation solver. LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration) { linEqTask = LinearEquationSolverTask::Multiply; } MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); @@ -254,7 +260,7 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireValidInitialScheduler(); } - } else if (method == MinMaxMethod::QuickValueIteration) { + } else if (method == MinMaxMethod::SoundValueIteration) { if (!this->hasUniqueSolution()) { requirements.requireNoEndComponents(); } @@ -434,7 +440,7 @@ namespace storm { * Model Checker: Interval Iteration for Markov Decision Processes, CAV 2017). */ template - bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + bool IterativeMinMaxLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { STORM_LOG_THROW(this->hasUpperBound(), storm::exceptions::UnmetRequirementException, "Solver requires upper bound, but none was given."); if (!this->linEqSolverA) { @@ -609,16 +615,11 @@ namespace storm { } template - class QuickValueIterationHelper { + class SoundValueIterationHelper { public: - QuickValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision, uint64_t sizeOfLargestRowGroup) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + SoundValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision, uint64_t sizeOfLargestRowGroup) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { xTmp.resize(sizeOfLargestRowGroup); yTmp.resize(sizeOfLargestRowGroup); - - restart(); - } - - void restart() { x.assign(x.size(), storm::utility::zero()); y.assign(x.size(), storm::utility::one()); hasDecisionValue = false; @@ -627,6 +628,7 @@ namespace storm { firstIndexViolatingConvergence = 0; } + inline void setLowerBound(ValueType const& value) { hasLowerBound = true; lowerBound = value; @@ -834,7 +836,7 @@ namespace storm { ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); - STORM_LOG_INFO("Quick Value Iteration terminated with lower value bound " + STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") << " and upper value bound " << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") @@ -968,7 +970,7 @@ namespace storm { }; template - bool IterativeMinMaxLinearEquationSolver::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Prepare the solution vectors. assert(x.size() == this->A->getRowGroupCount()); @@ -976,7 +978,7 @@ namespace storm { this->auxiliaryRowGroupVector = std::make_unique>(); } - QuickValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); + SoundValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { @@ -1394,7 +1396,7 @@ namespace storm { STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); auto method = env.solver().minMax().getMethod(); - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone()); result->setRequirementsChecked(this->isRequirementsCheckedSet()); diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index f8943a57a..5806ec4a2 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -37,8 +37,8 @@ namespace storm { bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; - bool solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index b543925e8..20194ec6b 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -197,7 +197,7 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::Topological) { result = std::make_unique>(); @@ -216,7 +216,7 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::LinearProgramming) { result = std::make_unique>(std::make_unique>(), std::make_unique>()); diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index f2537f1a4..7344dde0a 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -14,8 +14,10 @@ namespace storm { return "topological"; case MinMaxMethod::RationalSearch: return "ratsearch"; - case MinMaxMethod::QuickValueIteration: - return "QuickValueIteration"; + case MinMaxMethod::IntervalIteration: + return "intervaliteration"; + case MinMaxMethod::SoundValueIteration: + return "soundvalueiteration"; case MinMaxMethod::TopologicalCuda: return "topologicalcuda"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index e2ffdb5dd..a4bc6d614 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -6,7 +6,7 @@ namespace storm { namespace solver { - ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, QuickValueIteration, TopologicalCuda) + ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, IntervalIteration, SoundValueIteration, TopologicalCuda) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index a377689e4..57120ef77 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -113,7 +113,7 @@ namespace storm { std::unique_ptr> StandardMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(this->linearEquationSolverFactory->clone()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The selected min max method is not supported by this solver."); diff --git a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp index 668a94796..0538fa081 100644 --- a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp @@ -40,7 +40,7 @@ namespace { return env; } }; - class SparseDoubleSoundValueIterationEnvironment { + class SparseDoubleIntervalIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; @@ -50,13 +50,13 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::IntervalIteration); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); env.solver().minMax().setRelativeTerminationCriterion(false); return env; } }; - class SparseDoubleQuickValueIterationEnvironment { + class SparseDoubleSoundValueIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; @@ -66,7 +66,7 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::QuickValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::SoundValueIteration); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); env.solver().minMax().setRelativeTerminationCriterion(false); return env; @@ -101,7 +101,7 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Topological); - env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().topological().setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod::SoundValueIteration); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); env.solver().minMax().setRelativeTerminationCriterion(false); return env; @@ -172,7 +172,7 @@ namespace { static storm::Environment createEnvironment() { storm::Environment env; env.solver().setForceSoundness(true); - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::SoundValueIteration); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); env.solver().minMax().setRelativeTerminationCriterion(false); return env; @@ -335,8 +335,8 @@ namespace { typedef ::testing::Types< SparseDoubleValueIterationEnvironment, + SparseDoubleIntervalIterationEnvironment, SparseDoubleSoundValueIterationEnvironment, - SparseDoubleQuickValueIterationEnvironment, SparseDoubleTopologicalValueIterationEnvironment, SparseDoubleTopologicalSoundValueIterationEnvironment, SparseRationalPolicyIterationEnvironment, From a6c61187332b059da9b3e9788ab578656c7df8a0 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 15 Feb 2018 13:18:52 +0100 Subject: [PATCH 112/647] Renamed 'sound power' to interval iteration and 'quick sound power' to 'sound power' --- .../modules/NativeEquationSolverSettings.cpp | 6 ++-- .../solver/NativeLinearEquationSolver.cpp | 36 ++++++++----------- src/storm/solver/NativeLinearEquationSolver.h | 2 +- src/storm/solver/SolverSelectionOptions.cpp | 8 +++-- src/storm/solver/SolverSelectionOptions.h | 2 +- .../DtmcPrctlModelCheckerTest.cpp | 8 ++--- 6 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index c07d56dff..ce92cef82 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -67,10 +67,12 @@ namespace storm { return storm::solver::NativeLinearEquationSolverMethod::WalkerChae; } else if (linearEquationSystemTechniqueAsString == "power") { return storm::solver::NativeLinearEquationSolverMethod::Power; + } else if (linearEquationSystemTechniqueAsString == "soundpower") { + return storm::solver::NativeLinearEquationSolverMethod::SoundPower; + } else if (linearEquationSystemTechniqueAsString == "interval-iteration") { + return storm::solver::NativeLinearEquationSolverMethod::IntervalIteration; } else if (linearEquationSystemTechniqueAsString == "ratsearch") { return storm::solver::NativeLinearEquationSolverMethod::RationalSearch; - } else if (linearEquationSystemTechniqueAsString == "qpower") { - return storm::solver::NativeLinearEquationSolverMethod::QuickPower; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown solution technique '" << linearEquationSystemTechniqueAsString << "' selected."); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index ad1c9136c..360acb2b8 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -396,10 +396,10 @@ namespace storm { } template - bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + bool NativeLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_THROW(this->hasLowerBound(), storm::exceptions::UnmetRequirementException, "Solver requires lower bound, but none was given."); STORM_LOG_THROW(this->hasUpperBound(), storm::exceptions::UnmetRequirementException, "Solver requires upper bound, but none was given."); - STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (SoundPower)"); + STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (IntervalIteration)"); std::vector* lowerX = &x; this->createLowerBoundsVector(*lowerX); @@ -557,8 +557,8 @@ namespace storm { } template - bool NativeLinearEquationSolver::solveEquationsQuickSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { - STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (QuickPower)"); + bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (SoundPower)"); bool useGaussSeidelMultiplication = env.solver().native().getPowerMethodMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; // Prepare the solution vectors. @@ -597,11 +597,6 @@ namespace storm { } uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); - //std::cout << *this->A << std::endl; - //std::cout << storm::utility::vector::toString(b) << std::endl; - - //std::cout << "solving eq sys.. " << std::endl; - uint64_t iterations = 0; bool converged = false; bool terminate = false; @@ -1018,9 +1013,9 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } - } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::Power && method != NativeLinearEquationSolverMethod::RationalSearch && method != NativeLinearEquationSolverMethod::QuickPower) { + } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::SoundPower && method != NativeLinearEquationSolverMethod::IntervalIteration && method != NativeLinearEquationSolverMethod::RationalSearch) { if (env.solver().native().isMethodSetFromDefault()) { - method = NativeLinearEquationSolverMethod::Power; + method = NativeLinearEquationSolverMethod::SoundPower; STORM_LOG_INFO("Selecting '" + toString(method) + "' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); } else { STORM_LOG_WARN("The selected solution method does not guarantee sound results."); @@ -1042,13 +1037,11 @@ namespace storm { case NativeLinearEquationSolverMethod::WalkerChae: return this->solveEquationsWalkerChae(env, x, b); case NativeLinearEquationSolverMethod::Power: - if (env.solver().isForceSoundness()) { - return this->solveEquationsSoundPower(env, x, b); - } else { - return this->solveEquationsPower(env, x, b); - } - case NativeLinearEquationSolverMethod::QuickPower: - return this->solveEquationsQuickSoundPower(env, x, b); + return this->solveEquationsPower(env, x, b); + case NativeLinearEquationSolverMethod::SoundPower: + return this->solveEquationsSoundPower(env, x, b); + case NativeLinearEquationSolverMethod::IntervalIteration: + return this->solveEquationsIntervalIteration(env, x, b); case NativeLinearEquationSolverMethod::RationalSearch: return this->solveEquationsRationalSearch(env, x, b); } @@ -1119,7 +1112,7 @@ namespace storm { template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::QuickPower) { + if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::SoundPower || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::IntervalIteration) { return LinearEquationSolverProblemFormat::FixedPointSystem; } else { return LinearEquationSolverProblemFormat::EquationSystem; @@ -1131,11 +1124,10 @@ namespace storm { LinearEquationSolverRequirements requirements; if (task != LinearEquationSolverTask::Multiply) { if (env.solver().native().isForceBoundsSet()) { - requirements.requiresLowerBounds(); - requirements.requiresUpperBounds(); + requirements.requireBounds(); } auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power && env.solver().isForceSoundness()) { + if (method == NativeLinearEquationSolverMethod::IntervalIteration) { requirements.requireBounds(); } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { requirements.requireLowerBounds(); diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index fbb5d4357..795f5ef19 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -72,7 +72,7 @@ namespace storm { virtual bool solveEquationsWalkerChae(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; - virtual bool solveEquationsQuickSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; + virtual bool solveEquationsIntervalIteration(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsRationalSearch(storm::Environment const& env, std::vector& x, std::vector const& b) const; template diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 7344dde0a..21693781a 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -73,7 +73,7 @@ namespace storm { } std::string toString(NativeLinearEquationSolverMethod t) { - switch( t) { + switch(t) { case NativeLinearEquationSolverMethod::Jacobi: return "Jacobi"; case NativeLinearEquationSolverMethod::GaussSeidel: @@ -84,10 +84,12 @@ namespace storm { return "WalkerChae"; case NativeLinearEquationSolverMethod::Power: return "Power"; + case NativeLinearEquationSolverMethod::SoundPower: + return "SoundPower"; + case NativeLinearEquationSolverMethod::IntervalIteration: + return "IntervalIteration"; case NativeLinearEquationSolverMethod::RationalSearch: return "RationalSearch"; - case NativeLinearEquationSolverMethod::QuickPower: - return "QuickPower"; } return "invalid"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index a4bc6d614..e92c0ee0e 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -14,7 +14,7 @@ namespace storm { ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination, Topological) ExtendEnumsWithSelectionField(SmtSolverType, Z3, Mathsat) - ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, RationalSearch, QuickPower) + ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, SoundPower, IntervalIteration, RationalSearch) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverMethod, Bicgstab, Qmr, Gmres) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverPreconditioner, Ilu, Diagonal, None) ExtendEnumsWithSelectionField(EigenLinearEquationSolverMethod, SparseLU, Bicgstab, DGmres, Gmres) diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index bb569e5a5..4ba411f18 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -217,13 +217,13 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundPower); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; } }; - class SparseNativeQuickSoundPowerEnvironment { + class SparseNativeIntervalIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; @@ -234,7 +234,7 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::QuickPower); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::IntervalIteration); env.solver().native().setRelativeTerminationCriterion(false); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; @@ -482,7 +482,7 @@ namespace { SparseNativeSorEnvironment, SparseNativePowerEnvironment, SparseNativeSoundPowerEnvironment, - SparseNativeQuickSoundPowerEnvironment, + SparseNativeIntervalIterationEnvironment, SparseNativeRationalSearchEnvironment, SparseTopologicalEigenLUEnvironment, HybridSylvanGmmxxGmresEnvironment, From 09bcaa8db82cf211add9bf6bfa6caa5ce6b4de18 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 15 Feb 2018 13:37:07 +0100 Subject: [PATCH 113/647] fixed correct requirements in minmaxsolver --- .../IterativeMinMaxLinearEquationSolver.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 2aa60ded3..2c8eb5481 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -223,19 +223,13 @@ namespace storm { // Start by getting the requirements of the linear equation solver. LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration) { + if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration) { linEqTask = LinearEquationSolverTask::Multiply; } MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); if (method == MinMaxMethod::ValueIteration) { - if (env.solver().isForceSoundness()) { - // Interval iteration requires a unique solution and lower+upper bounds - if (!this->hasUniqueSolution()) { - requirements.requireNoEndComponents(); - } - requirements.requireBounds(); - } else if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique. + if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique. // Computing a scheduler is only possible if the solution is unique if (this->isTrackSchedulerSet()) { requirements.requireNoEndComponents(); @@ -249,6 +243,12 @@ namespace storm { } } } + } else if (method == MinMaxMethod::IntervalIteration) { + // Interval iteration requires a unique solution and lower+upper bounds + if (!this->hasUniqueSolution()) { + requirements.requireNoEndComponents(); + } + requirements.requireBounds(); } else if (method == MinMaxMethod::RationalSearch) { // Rational search needs to approach the solution from below. requirements.requireLowerBounds(); From f81b6d49172bbf0185291dfa57b9dbe1c1b52084 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 15 Feb 2018 16:10:00 +0100 Subject: [PATCH 114/647] Added NumberParser --- src/storm-dft/parser/DFTGalileoParser.cpp | 7 +++---- src/storm/parser/DirectEncodingParser.cpp | 8 ++++---- src/storm/parser/ValueParser.cpp | 8 +------- src/storm/parser/ValueParser.h | 24 ++++++++++++++++++++--- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index 8a02ce1fe..b2d145277 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/FileIoException.h" @@ -114,12 +113,12 @@ namespace storm { } else if (type == "or") { success = builder.addOrElement(name, childNames); } else if (boost::starts_with(type, "vot")) { - unsigned threshold = boost::lexical_cast(type.substr(3)); + unsigned threshold = NumberParser::parse(type.substr(3)); success = builder.addVotElement(name, threshold, childNames); } else if (type.find("of") != std::string::npos) { size_t pos = type.find("of"); - unsigned threshold = boost::lexical_cast(type.substr(0, pos)); - unsigned count = boost::lexical_cast(type.substr(pos + 2)); + unsigned threshold = NumberParser::parse(type.substr(0, pos)); + unsigned count = NumberParser::parse(type.substr(pos + 2)); STORM_LOG_THROW(count == childNames.size(), storm::exceptions::WrongFormatException, "Voting gate number " << count << " does not correspond to number of children " << childNames.size() << "in line " << lineNo << "."); success = builder.addVotElement(name, threshold, childNames); } else if (type == "pand") { diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm/parser/DirectEncodingParser.cpp index 68530a5a7..288eda7e5 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm/parser/DirectEncodingParser.cpp @@ -79,7 +79,7 @@ namespace storm { if(line == "@nr_states") { STORM_LOG_THROW(nrStates == 0, storm::exceptions::WrongFormatException, "Number states declared twice"); std::getline(file, line); - nrStates = boost::lexical_cast(line); + nrStates = NumberParser::parse(line); } if(line == "@model") { @@ -132,7 +132,7 @@ namespace storm { size_t parsedId; size_t posId = line.find(" "); if (posId != std::string::npos) { - parsedId = boost::lexical_cast(line.substr(0, posId)); + parsedId = NumberParser::parse(line.substr(0, posId)); // Parse rewards and labels line = line.substr(posId+1); @@ -167,7 +167,7 @@ namespace storm { } } else { // Only state id given - parsedId = boost::lexical_cast(line); + parsedId = NumberParser::parse(line); } STORM_LOG_TRACE("New state " << state); STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); @@ -201,7 +201,7 @@ namespace storm { // New transition size_t posColon = line.find(":"); STORM_LOG_ASSERT(posColon != std::string::npos, "':' not found."); - size_t target = boost::lexical_cast(line.substr(2, posColon-3)); + size_t target = NumberParser::parse(line.substr(2, posColon-3)); std::string valueStr = line.substr(posColon+2); ValueType value = valueParser.parseValue(valueStr); STORM_LOG_TRACE("Transition " << row << " -> " << target << ": " << value); diff --git a/src/storm/parser/ValueParser.cpp b/src/storm/parser/ValueParser.cpp index 96ed0015b..17495b0d9 100644 --- a/src/storm/parser/ValueParser.cpp +++ b/src/storm/parser/ValueParser.cpp @@ -1,7 +1,6 @@ #include "storm/parser/ValueParser.h" #include "storm/exceptions/NotSupportedException.h" -#include "storm/exceptions/WrongFormatException.h" namespace storm { namespace parser { @@ -21,12 +20,7 @@ namespace storm { template<> double ValueParser::parseValue(std::string const& value) const { - try { - return boost::lexical_cast(value); - } - catch(boost::bad_lexical_cast &) { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "'."); - } + return NumberParser::parse(value); } template<> diff --git a/src/storm/parser/ValueParser.h b/src/storm/parser/ValueParser.h index ab2e741b6..db948b75e 100644 --- a/src/storm/parser/ValueParser.h +++ b/src/storm/parser/ValueParser.h @@ -4,6 +4,7 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" +#include "storm/exceptions/WrongFormatException.h" namespace storm { namespace parser { @@ -39,14 +40,31 @@ namespace storm { private: std::shared_ptr manager; - storm::parser::ExpressionParser parser; - storm::expressions::ExpressionEvaluator evaluator; - std::unordered_map identifierMapping; }; + template + class NumberParser { + public: + /*! + * Parse number from string. + * + * @param value String containing the value. + * + * @return NumberType. + */ + static NumberType parse(std::string const& value) { + try { + return boost::lexical_cast(value); + } + catch(boost::bad_lexical_cast &) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "' into " << typeid(NumberType).name() << "."); + } + } + }; + } // namespace parser } // namespace storm From 6355619c090cedca5a57dca7cc0549f84ce938a0 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 15 Feb 2018 17:49:10 +0100 Subject: [PATCH 115/647] Refactored BE parsing --- src/storm-dft/parser/DFTGalileoParser.cpp | 64 +++++++++++++++++------ src/storm-dft/parser/DFTGalileoParser.h | 2 + 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index b2d145277..ca56f25da 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -167,44 +167,74 @@ namespace storm { template bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser) { - std::string name = parseName(tokens[0]); - // Default values - ValueType lambda = storm::utility::zero(); + Distribution distribution = Distribution::None; + ValueType firstValDistribution = storm::utility::zero(); + ValueType secondValDistribution = storm::utility::zero(); ValueType dormancyFactor = storm::utility::one(); - bool exponential = false; + size_t replication = 1; + // Parse properties and determine distribution for (size_t i = 1; i < tokens.size(); ++i) { std::string token = tokens[i]; if (boost::starts_with(token, "prob=")) { + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::Constant; STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); } else if (boost::starts_with(token, "lambda=")) { - lambda = valueParser.parseValue(token.substr(7)); - exponential = true; + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(7)); + distribution = Distribution::Exponential; } else if (boost::starts_with(token, "rate=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::Weibull; } else if (boost::starts_with(token, "shape=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = valueParser.parseValue(token.substr(6)); + distribution = Distribution::Weibull; } else if (boost::starts_with(token, "mean=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::LogNormal; } else if (boost::starts_with(token, "stddev=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = valueParser.parseValue(token.substr(7)); + distribution = Distribution::LogNormal; } else if (boost::starts_with(token, "cov=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Coverage is not supported."); + STORM_LOG_WARN("Coverage is not supported and will be ignored."); } else if (boost::starts_with(token, "res=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Restoration is not supported."); + STORM_LOG_WARN("Restoration is not supported and will be ignored."); } else if (boost::starts_with(token, "repl=")) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Replication is not supported."); + replication = NumberParser::parse(token.substr(5)); + STORM_LOG_THROW(replication == 1, storm::exceptions::NotSupportedException, "Replication > 1 is not supported."); } else if (boost::starts_with(token, "dorm=")) { dormancyFactor = valueParser.parseValue(token.substr(5)); } } - if (exponential) { - return builder.addBasicElement(name, lambda, dormancyFactor, false); // TODO set transient BEs - } else { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "No distribution for basic element defined."); + switch (distribution) { + case Constant: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); + break; + case Exponential: + return builder.addBasicElement(parseName(tokens[0]), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + break; + case Weibull: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + break; + case LogNormal: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + break; + case None: + // go-through + default: + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "No distribution for basic element defined."); + break; } + return false; + } // Explicitly instantiate the class. diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index 6bdb66ee2..e8e78244f 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -52,6 +52,8 @@ namespace storm { * @return True iff the parsing and creation was successful. */ static bool parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser); + + enum Distribution { None, Constant, Exponential, Weibull, LogNormal }; }; } } From 63a9f3a5ca2bc2049436cf99856b233ec7c15881 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Feb 2018 11:06:21 +0100 Subject: [PATCH 116/647] Fixed assertion by incorporating precision --- src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 10311c2a2..517868946 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -546,7 +546,7 @@ namespace storm { if (solver->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { auto resultIt = x.begin(); for (auto const& entry : solver->getUpperBounds()) { - STORM_LOG_ASSERT(*resultIt <= entry, "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); + STORM_LOG_ASSERT(*resultIt <= entry + env.solver().minMax().getPrecision(), "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); ++resultIt; } } From b00e65adf98ab7fe66c96a8733616feccd846466 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Feb 2018 17:41:15 +0100 Subject: [PATCH 117/647] Created API for storm-dft --- src/storm-dft-cli/storm-dft.cpp | 192 ++++++++------------------------ src/storm-dft/api/storm-dft.h | 159 ++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 146 deletions(-) create mode 100644 src/storm-dft/api/storm-dft.h diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index cef8717b2..2d2e24b8e 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -1,163 +1,65 @@ -#include "storm-dft/settings/DftSettings.h" +#include "storm-dft/api/storm-dft.h" +#include "storm-dft/settings/DftSettings.h" #include "storm-dft/settings/modules/DftIOSettings.h" #include "storm-dft/settings/modules/FaultTreeSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/utility/initialize.h" -#include "storm/api/storm.h" #include "storm-cli-utilities/cli.h" -#include "storm-dft/parser/DFTGalileoParser.h" -#include "storm-dft/parser/DFTJsonParser.h" -#include "storm-dft/modelchecker/dft/DFTModelChecker.h" -#include "storm-dft/modelchecker/dft/DFTASFChecker.h" -#include "storm-dft/transformations/DftToGspnTransformator.h" -#include "storm-dft/storage/dft/DftJsonExporter.h" - -#include "storm-gspn/storage/gspn/GSPN.h" -#include "storm-gspn/storm-gspn.h" - -#include -#include - -template -std::shared_ptr> loadDFT() { - storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule(); - std::shared_ptr> dft; - // Build DFT from given file. - if (dftIOSettings.isDftJsonFileSet()) { - storm::parser::DFTJsonParser parser; - STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); - dft = std::make_shared>(parser.parseJson(dftIOSettings.getDftJsonFilename())); - } else { - STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); - dft = std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(dftIOSettings.getDftFilename())); - } - - if (dftIOSettings.isDisplayStatsSet()) { - std::cout << "=============DFT Statistics==============" << std::endl; - dft->writeStatsToStream(std::cout); - std::cout << "=========================================" << std::endl; - } - return dft; -} - -/*! - * Analyse the given DFT according to the given properties. - * We first load the DFT from the given file, then build the corresponding model and last check against the given properties. - * - * @param properties PCTL formulas capturing the properties to check. - * @param symred Flag whether symmetry reduction should be used. - * @param allowModularisation Flag whether modularisation should be applied if possible. - * @param enableDC Flag whether Don't Care propagation should be used. - * @param approximationError Allowed approximation error. - */ -template -void analyzeDFT(std::vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { - std::shared_ptr> dft = loadDFT(); - - // Build properties - std::string propString = properties[0]; - for (size_t i = 1; i < properties.size(); ++i) { - propString += ";" + properties[i]; - } - std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); - STORM_LOG_ASSERT(props.size() > 0, "No properties found."); - - // Check model - storm::modelchecker::DFTModelChecker modelChecker; - modelChecker.check(*dft, props, symred, allowModularisation, enableDC, approximationError); - modelChecker.printTimings(); - modelChecker.printResults(); -} - /*! - * Analyze the DFT with use of SMT solving. - * - * @param filename Path to DFT file in Galileo format. + * Process commandline options and start computations. */ template -void analyzeWithSMT(std::shared_ptr> dft) { - STORM_LOG_DEBUG("Running DFT analysis with use of SMT"); - storm::modelchecker::DFTASFChecker asfChecker(*dft); - asfChecker.convert(); - asfChecker.toFile("test.smt2"); - //bool sat = dftSmtBuilder.check(); - //std::cout << "SMT result: " << sat << std::endl; -} - void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) storm::cli::setUrgentOptions(); storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule(); storm::settings::modules::FaultTreeSettings const& faultTreeSettings = storm::settings::getModule(); - storm::settings::modules::GeneralSettings const& generalSettings = storm::settings::getModule(); storm::settings::modules::IOSettings const& ioSettings = storm::settings::getModule(); + if (!dftIOSettings.isDftFileSet() && !dftIOSettings.isDftJsonFileSet()) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model."); } + // Build DFT from given file + std::shared_ptr> dft; + if (dftIOSettings.isDftJsonFileSet()) { + STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); + dft = storm::api::loadDFTJson(dftIOSettings.getDftJsonFilename()); + } else { + STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); + dft = storm::api::loadDFTGalileo(dftIOSettings.getDftFilename()); + } + + if (dftIOSettings.isDisplayStatsSet()) { + std::cout << "=============DFT Statistics==============" << std::endl; + dft->writeStatsToStream(std::cout); + std::cout << "=========================================" << std::endl; + } + if (dftIOSettings.isExportToJson()) { - STORM_LOG_THROW(dftIOSettings.isDftFileSet(), storm::exceptions::InvalidSettingsException, "No input model in Galileo format given."); - std::shared_ptr> dft = loadDFT(); // Export to json - storm::storage::DftJsonExporter::toFile(*dft, dftIOSettings.getExportJsonFilename()); + storm::api::exportDFTToJson(*dft, dftIOSettings.getExportJsonFilename()); return; } - if (dftIOSettings.isTransformToGspn()) { - std::shared_ptr> dft = loadDFT(); // Transform to GSPN - storm::transformations::dft::DftToGspnTransformator gspnTransformator(*dft); - bool smart = true; - gspnTransformator.transform(smart); - storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); - uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - - storm::handleGSPNExportSettings(*gspn); - - std::shared_ptr const& exprManager = gspn->getExpressionManager(); - storm::builder::JaniGSPNBuilder builder(*gspn); - storm::jani::Model* model = builder.build(); - storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); - - storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); - auto evtlFormula = std::make_shared(targetExpression); - auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - auto tbUntil = std::make_shared(tbFormula); - - auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); - auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - - storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); - if (janiSettings.isJaniFileSet()) { - storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); - } - - delete model; - delete gspn; + storm::api::transformToGSPN(*dft); return; } - bool parametric = false; -#ifdef STORM_HAVE_CARL - parametric = generalSettings.isParametricSet(); -#endif - + #ifdef STORM_HAVE_Z3 if (faultTreeSettings.solveWithSMT()) { // Solve with SMT - if (parametric) { - // std::shared_ptr> dft = loadDFT(); - // analyzeWithSMT(dftSettings.getDftFilename()); - } else { - std::shared_ptr> dft = loadDFT(); - analyzeWithSMT(dft); - } + STORM_LOG_DEBUG("Running DFT analysis with use of SMT"); + storm::api::exportDFTToSMT(*dft, "test.smt2"); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only exported to SMT file 'test.smt2' but analysis is not supported."); return; } #endif @@ -169,9 +71,8 @@ void processOptions() { optimizationDirection = "max"; } - // Construct properties to check for + // Construct properties to analyse std::vector properties; - if (ioSettings.isPropertySet()) { properties.push_back(ioSettings.getProperty()); } @@ -194,38 +95,32 @@ void processOptions() { } } - if (properties.empty()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No property given."); - } - // Set possible approximation error double approximationError = 0.0; if (faultTreeSettings.isApproximationErrorSet()) { approximationError = faultTreeSettings.getApproximationError(); } - // From this point on we are ready to carry out the actual computations. - if (parametric) { -#ifdef STORM_HAVE_CARL - analyzeDFT(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); -#endif - } else { - analyzeDFT(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); + // Build properties + STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidSettingsException, "No property given."); + std::string propString = properties[0]; + for (size_t i = 1; i < properties.size(); ++i) { + propString += ";" + properties[i]; } + std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); + STORM_LOG_ASSERT(props.size() > 0, "No properties found."); + + // Carry out the actual analysis + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); } /*! - * Entry point for the DyFTeE backend. + * Entry point for Storm-DFT. * * @param argc The argc argument of main(). * @param argv The argv argument of main(). * @return Return code, 0 if successfull, not 0 otherwise. */ -/*! - * Main entry point of the executable storm-pars. - */ int main(const int argc, const char** argv) { try { storm::utility::setUp(); @@ -237,7 +132,12 @@ int main(const int argc, const char** argv) { return -1; } - processOptions(); + storm::settings::modules::GeneralSettings const& generalSettings = storm::settings::getModule(); + if (generalSettings.isParametricSet()) { + processOptions(); + } else { + processOptions(); + } totalTimer.stop(); if (storm::settings::getModule().isPrintTimeAndMemorySet()) { @@ -248,10 +148,10 @@ int main(const int argc, const char** argv) { storm::utility::cleanUp(); return 0; } catch (storm::exceptions::BaseException const& exception) { - STORM_LOG_ERROR("An exception caused Storm-DyFTeE to terminate. The message of the exception is: " << exception.what()); + STORM_LOG_ERROR("An exception caused Storm-DFT to terminate. The message of the exception is: " << exception.what()); return 1; } catch (std::exception const& exception) { - STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-DyFTeE to terminate. The message of this exception is: " << exception.what()); + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-DFT to terminate. The message of this exception is: " << exception.what()); return 2; } } diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h new file mode 100644 index 000000000..fc88fe792 --- /dev/null +++ b/src/storm-dft/api/storm-dft.h @@ -0,0 +1,159 @@ +#pragma once + +#include + +#include "storm-dft/parser/DFTGalileoParser.h" +#include "storm-dft/parser/DFTJsonParser.h" +#include "storm-dft/storage/dft/DftJsonExporter.h" + +#include "storm-dft/modelchecker/dft/DFTModelChecker.h" +#include "storm-dft/modelchecker/dft/DFTASFChecker.h" + +#include "storm-dft/transformations/DftToGspnTransformator.h" +#include "storm-gspn/storage/gspn/GSPN.h" +#include "storm-gspn/storm-gspn.h" + +namespace storm { + namespace api { + + /*! + * Load DFT from Galileo file. + * + * @param file File containing DFT description in Galileo format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTGalileo(std::string const& file) { + return std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(file)); + } + + /*! + * Load DFT from JSON file. + * + * @param file File containing DFT description in JSON format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTJson(std::string const& file) { + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJson(file)); + } + + /*! + * Analyse the given DFT according to the given properties. + * First the Markov model is built from the DFT and then this model is checked against the given properties. + * + * @param dft DFT. + * @param properties PCTL formulas capturing the properties to check. + * @param symred Flag whether symmetry reduction should be used. + * @param allowModularisation Flag whether modularisation should be applied if possible. + * @param enableDC Flag whether Don't Care propagation should be used. + * @param approximationError Allowed approximation error, 0 indicates no approximation. + */ + template + void analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + storm::modelchecker::DFTModelChecker modelChecker; + modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError); + modelChecker.printTimings(); + modelChecker.printResults(); + } + + + /*! + * Export DFT to JSON file. + * + * @param dft DFT. + * @param file File. + */ + template + typename std::enable_if::value, void>::type exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + storm::storage::DftJsonExporter::toFile(dft, file); + } + + /*! + * Export DFT to JSON file. + * + * @param dft DFT. + * @param file File. + */ + template + typename std::enable_if::value, void>::type exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); + } + + /*! + * Export DFT to SMT encoding. + * + * @param dft DFT. + * @param file File. + */ + template + typename std::enable_if::value, void>::type exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + storm::modelchecker::DFTASFChecker asfChecker(dft); + asfChecker.convert(); + asfChecker.toFile(file); + } + + /*! + * Export DFT to SMT encoding. + * + * @param dft DFT. + * @param file File. + */ + template + typename std::enable_if::value, void>::type exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to SMT does not support this data type."); + } + + /*! + * Transform DFT to GSPN. + * + * @param dft DFT. + */ + template + typename std::enable_if::value, void>::type transformToGSPN(storm::storage::DFT const& dft) { + // Transform to GSPN + storm::transformations::dft::DftToGspnTransformator gspnTransformator(dft); + bool smart = true; + gspnTransformator.transform(smart); + storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); + uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); + + storm::handleGSPNExportSettings(*gspn); + + std::shared_ptr const& exprManager = gspn->getExpressionManager(); + storm::builder::JaniGSPNBuilder builder(*gspn); + storm::jani::Model* model = builder.build(); + storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); + + storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); + auto evtlFormula = std::make_shared(targetExpression); + auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); + auto tbUntil = std::make_shared(tbFormula); + + auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); + auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); + + storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); + if (janiSettings.isJaniFileSet()) { + storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); + } + + delete model; + delete gspn; + } + + /*! + * Transform DFT to GSPN. + * + * @param dft DFT. + */ + template + typename std::enable_if::value, void>::type transformToGSPN(storm::storage::DFT const& dft) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation to GSPN not supported for this data type."); + } + + } +} From ed7efc0268b46b31f4fe1ce06b76bab6878847b9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Feb 2018 18:15:19 +0100 Subject: [PATCH 118/647] Moved DFTBuilder to builder dir --- .../{storage/dft => builder}/DFTBuilder.cpp | 118 +++++++++--------- .../{storage/dft => builder}/DFTBuilder.h | 50 ++++---- src/storm-dft/parser/DFTGalileoParser.cpp | 4 +- src/storm-dft/parser/DFTGalileoParser.h | 4 +- src/storm-dft/parser/DFTJsonParser.h | 4 +- src/storm-dft/storage/dft/DFT.cpp | 6 +- src/storm-dft/storage/dft/DFT.h | 12 +- 7 files changed, 101 insertions(+), 97 deletions(-) rename src/storm-dft/{storage/dft => builder}/DFTBuilder.cpp (73%) rename src/storm-dft/{storage/dft => builder}/DFTBuilder.h (81%) diff --git a/src/storm-dft/storage/dft/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp similarity index 73% rename from src/storm-dft/storage/dft/DFTBuilder.cpp rename to src/storm-dft/builder/DFTBuilder.cpp index 88abc9665..a333c3cd6 100644 --- a/src/storm-dft/storage/dft/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -11,15 +11,15 @@ namespace storm { - namespace storage { + namespace builder { template std::size_t DFTBuilder::mUniqueOffset = 0; template - DFT DFTBuilder::build() { + storm::storage::DFT DFTBuilder::build() { for(auto& elem : mChildNames) { - DFTGatePointer gate = std::static_pointer_cast>(elem.first); + DFTGatePointer gate = std::static_pointer_cast>(elem.first); for(auto const& child : elem.second) { auto itFind = mElements.find(child); if (itFind != mElements.end()) { @@ -54,16 +54,16 @@ namespace storm { for(auto& elem : mDependencyChildNames) { bool first = true; - std::vector>> dependencies; + std::vector>> dependencies; for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << childName << "' not found"); DFTElementPointer childElement = itFind->second; if (!first) { STORM_LOG_ASSERT(childElement->isBasicElement(), "Child '" << childName << "' of dependency '" << elem.first->name() << "' must be BE."); - dependencies.push_back(std::static_pointer_cast>(childElement)); + dependencies.push_back(std::static_pointer_cast>(childElement)); } else { - elem.first->setTriggerElement(std::static_pointer_cast>(childElement)); + elem.first->setTriggerElement(std::static_pointer_cast>(childElement)); childElement->addOutgoingDependency(elem.first); } first = false; @@ -92,7 +92,7 @@ namespace storm { } STORM_LOG_ASSERT(!mTopLevelIdentifier.empty(), "No top level element."); - DFT dft(elems, mElements[mTopLevelIdentifier]); + storm::storage::DFT dft(elems, mElements[mTopLevelIdentifier]); // Set layout info for (auto& elem : mElements) { @@ -113,7 +113,7 @@ namespace storm { if(elem->nrChildren() == 0 || elem->isDependency()) { elem->setRank(0); } else { - DFTGatePointer gate = std::static_pointer_cast>(elem); + DFTGatePointer gate = std::static_pointer_cast>(elem); unsigned maxrnk = 0; unsigned newrnk = 0; @@ -131,7 +131,7 @@ namespace storm { } template - bool DFTBuilder::addRestriction(std::string const& name, std::vector const& children, DFTElementType tp) { + bool DFTBuilder::addRestriction(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp) { if (children.size() <= 1) { STORM_LOG_ERROR("Sequence enforcers require at least two children"); } @@ -140,10 +140,10 @@ namespace storm { } DFTRestrictionPointer restr; switch (tp) { - case DFTElementType::SEQ: - restr = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::SEQ: + restr = std::make_shared>(mNextId++, name); break; - case DFTElementType::MUTEX: + case storm::storage::DFTElementType::MUTEX: // TODO notice that mutex state generation support is lacking anyway, as DONT CARE propagation would be broken for this. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); break; @@ -159,7 +159,7 @@ namespace storm { } template - bool DFTBuilder::addStandardGate(std::string const& name, std::vector const& children, DFTElementType tp) { + bool DFTBuilder::addStandardGate(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp) { STORM_LOG_ASSERT(children.size() > 0, "No child for " << name); if(mElements.count(name) != 0) { // Element with that name already exists. @@ -167,28 +167,28 @@ namespace storm { } DFTElementPointer element; switch(tp) { - case DFTElementType::AND: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::AND: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::OR: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::OR: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::PAND: - element = std::make_shared>(mNextId++, name, pandDefaultInclusive); + case storm::storage::DFTElementType::PAND: + element = std::make_shared>(mNextId++, name, pandDefaultInclusive); break; - case DFTElementType::POR: - element = std::make_shared>(mNextId++, name, porDefaultInclusive); + case storm::storage::DFTElementType::POR: + element = std::make_shared>(mNextId++, name, porDefaultInclusive); break; - case DFTElementType::SPARE: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::SPARE: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::BE: - case DFTElementType::VOT: - case DFTElementType::PDEP: + case storm::storage::DFTElementType::BE: + case storm::storage::DFTElementType::VOT: + case storm::storage::DFTElementType::PDEP: // Handled separately STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type handled separately."); - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case storm::storage::DFTElementType::CONSTF: + case storm::storage::DFTElementType::CONSTS: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not known."); @@ -199,29 +199,29 @@ namespace storm { } template - void DFTBuilder::topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L) { + void DFTBuilder::topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L) { if(visited[n] == topoSortColour::GREY) { throw storm::exceptions::WrongFormatException("DFT is cyclic"); } else if(visited[n] == topoSortColour::WHITE) { if(n->isGate()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { topoVisit(c, visited, L); } } // TODO restrictions and dependencies have no parents, so this can be done more efficiently. if(n->isRestriction()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { topoVisit(c, visited, L); } } if(n->isDependency()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->dependentEvents()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->dependentEvents()) { topoVisit(c, visited, L); } - topoVisit(std::static_pointer_cast>(n)->triggerEvent(), visited, L); + topoVisit(std::static_pointer_cast>(n)->triggerEvent(), visited, L); } visited[n] = topoSortColour::BLACK; L.push_back(n); @@ -229,8 +229,8 @@ namespace storm { } template - std::vector>> DFTBuilder::topoSort() { - std::map> visited; + std::vector>> DFTBuilder::topoSort() { + std::map> visited; for(auto const& e : mElements) { visited.insert(std::make_pair(e.second, topoSortColour::WHITE)); } @@ -252,22 +252,22 @@ namespace storm { void DFTBuilder::copyElement(DFTElementPointer element) { std::vector children; switch (element->type()) { - case DFTElementType::AND: - case DFTElementType::OR: - case DFTElementType::PAND: - case DFTElementType::POR: - case DFTElementType::SPARE: - case DFTElementType::VOT: + case storm::storage::DFTElementType::AND: + case storm::storage::DFTElementType::OR: + case storm::storage::DFTElementType::PAND: + case storm::storage::DFTElementType::POR: + case storm::storage::DFTElementType::SPARE: + case storm::storage::DFTElementType::VOT: { - for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { + for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { children.push_back(elem->name()); } - copyGate(std::static_pointer_cast>(element), children); + copyGate(std::static_pointer_cast>(element), children); break; } - case DFTElementType::BE: + case storm::storage::DFTElementType::BE: { - std::shared_ptr> be = std::static_pointer_cast>(element); + std::shared_ptr> be = std::static_pointer_cast>(element); ValueType dormancyFactor = storm::utility::zero(); if (be->canFail()) { dormancyFactor = be->passiveFailureRate() / be->activeFailureRate(); @@ -275,14 +275,14 @@ namespace storm { addBasicElement(be->name(), be->activeFailureRate(), dormancyFactor, be->isTransient()); break; } - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case storm::storage::DFTElementType::CONSTF: + case storm::storage::DFTElementType::CONSTS: // TODO STORM_LOG_ASSERT(false, "Const elements not supported."); break; - case DFTElementType::PDEP: + case storm::storage::DFTElementType::PDEP: { - DFTDependencyPointer dependency = std::static_pointer_cast>(element); + DFTDependencyPointer dependency = std::static_pointer_cast>(element); children.push_back(dependency->triggerEvent()->name()); for(auto const& depEv : dependency->dependentEvents()) { children.push_back(depEv->name()); @@ -290,10 +290,10 @@ namespace storm { addDepElement(element->name(), children, dependency->probability()); break; } - case DFTElementType::SEQ: - case DFTElementType::MUTEX: + case storm::storage::DFTElementType::SEQ: + case storm::storage::DFTElementType::MUTEX: { - for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { + for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { children.push_back(elem->name()); } addRestriction(element->name(), children, element->type()); @@ -308,15 +308,15 @@ namespace storm { template void DFTBuilder::copyGate(DFTGatePointer gate, std::vector const& children) { switch (gate->type()) { - case DFTElementType::AND: - case DFTElementType::OR: - case DFTElementType::PAND: - case DFTElementType::POR: - case DFTElementType::SPARE: + case storm::storage::DFTElementType::AND: + case storm::storage::DFTElementType::OR: + case storm::storage::DFTElementType::PAND: + case storm::storage::DFTElementType::POR: + case storm::storage::DFTElementType::SPARE: addStandardGate(gate->name(), children, gate->type()); break; - case DFTElementType::VOT: - addVotElement(gate->name(), std::static_pointer_cast>(gate)->threshold(), children); + case storm::storage::DFTElementType::VOT: + addVotElement(gate->name(), std::static_pointer_cast>(gate)->threshold(), children); break; default: STORM_LOG_ASSERT(false, "Dft type not known."); diff --git a/src/storm-dft/storage/dft/DFTBuilder.h b/src/storm-dft/builder/DFTBuilder.h similarity index 81% rename from src/storm-dft/storage/dft/DFTBuilder.h rename to src/storm-dft/builder/DFTBuilder.h index 42713e601..625355371 100644 --- a/src/storm-dft/storage/dft/DFTBuilder.h +++ b/src/storm-dft/builder/DFTBuilder.h @@ -11,18 +11,22 @@ namespace storm { namespace storage { + // Forward declaration template class DFT; + } + + namespace builder { template class DFTBuilder { - using DFTElementPointer = std::shared_ptr>; + using DFTElementPointer = std::shared_ptr>; using DFTElementVector = std::vector; - using DFTGatePointer = std::shared_ptr>; + using DFTGatePointer = std::shared_ptr>; using DFTGateVector = std::vector; - using DFTDependencyPointer = std::shared_ptr>; - using DFTRestrictionPointer = std::shared_ptr>; + using DFTDependencyPointer = std::shared_ptr>; + using DFTRestrictionPointer = std::shared_ptr>; private: std::size_t mNextId = 0; @@ -34,7 +38,7 @@ namespace storm { std::unordered_map> mDependencyChildNames; std::vector mDependencies; std::vector mRestrictions; - std::unordered_map mLayoutInfo; + std::unordered_map mLayoutInfo; public: DFTBuilder(bool defaultInclusive = true, bool binaryDependencies = true) : pandDefaultInclusive(defaultInclusive), porDefaultInclusive(defaultInclusive), binaryDependencies(binaryDependencies) { @@ -42,47 +46,47 @@ namespace storm { } bool addAndElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::AND); + return addStandardGate(name, children, storm::storage::DFTElementType::AND); } bool addOrElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::OR); + return addStandardGate(name, children, storm::storage::DFTElementType::OR); } bool addPandElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::PAND); + return addStandardGate(name, children, storm::storage::DFTElementType::PAND); } bool addPandElement(std::string const& name, std::vector const& children, bool inclusive) { bool tmpDefault = pandDefaultInclusive; pandDefaultInclusive = inclusive; - bool result = addStandardGate(name, children, DFTElementType::PAND); + bool result = addStandardGate(name, children, storm::storage::DFTElementType::PAND); pandDefaultInclusive = tmpDefault; return result; } bool addPorElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::POR); + return addStandardGate(name, children, storm::storage::DFTElementType::POR); } bool addPorElement(std::string const& name, std::vector const& children, bool inclusive) { bool tmpDefault = porDefaultInclusive; porDefaultInclusive = inclusive; - bool result = addStandardGate(name, children, DFTElementType::POR); + bool result = addStandardGate(name, children, storm::storage::DFTElementType::POR); pandDefaultInclusive = tmpDefault; return result; } bool addSpareElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::SPARE); + return addStandardGate(name, children, storm::storage::DFTElementType::SPARE); } bool addSequenceEnforcer(std::string const& name, std::vector const& children) { - return addRestriction(name, children, DFTElementType::SEQ); + return addRestriction(name, children, storm::storage::DFTElementType::SEQ); } bool addMutex(std::string const& name, std::vector const& children) { - return addRestriction(name, children, DFTElementType::MUTEX); + return addRestriction(name, children, storm::storage::DFTElementType::MUTEX); } bool addDepElement(std::string const& name, std::vector const& children, ValueType probability) { @@ -125,15 +129,13 @@ namespace storm { } STORM_LOG_ASSERT(storm::utility::isOne(probability) || children.size() == 2, "PDep with multiple children supported."); - DFTDependencyPointer element = std::make_shared>(mNextId++, - nameDep, - probability); + DFTDependencyPointer element = std::make_shared>(mNextId++, nameDep, probability); mElements[element->name()] = element; mDependencyChildNames[element] = {trigger, children[i]}; mDependencies.push_back(element); } } else { - DFTDependencyPointer element = std::make_shared>(mNextId++, name, probability); + DFTDependencyPointer element = std::make_shared>(mNextId++, name, probability); mElements[element->name()] = element; mDependencyChildNames[element] = children; mDependencies.push_back(element); @@ -161,7 +163,7 @@ namespace storm { STORM_LOG_ERROR("Voting gates with threshold higher than the number of children is not supported."); return false; } - DFTElementPointer element = std::make_shared>(mNextId++, name, threshold); + DFTElementPointer element = std::make_shared>(mNextId++, name, threshold); mElements[name] = element; mChildNames[element] = children; @@ -173,7 +175,7 @@ namespace storm { //failureRate > 0 //0 <= dormancyFactor <= 1 - mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); + mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); return true; } @@ -189,7 +191,7 @@ namespace storm { std::string getUniqueName(std::string name); - DFT build(); + storm::storage::DFT build(); /** * Copy element and insert it again in the builder. @@ -211,13 +213,13 @@ namespace storm { unsigned computeRank(DFTElementPointer const& elem); - bool addStandardGate(std::string const& name, std::vector const& children, DFTElementType tp); + bool addStandardGate(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp); - bool addRestriction(std::string const& name, std::vector const& children, DFTElementType tp); + bool addRestriction(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp); enum class topoSortColour {WHITE, BLACK, GREY}; - void topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L); + void topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L); DFTElementVector topoSort(); diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index ca56f25da..94ef80c67 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -33,7 +33,7 @@ namespace storm { template storm::storage::DFT DFTGalileoParser::parseDFT(const std::string& filename, bool defaultInclusive, bool binaryDependencies) { - storm::storage::DFTBuilder builder(defaultInclusive, binaryDependencies); + storm::builder::DFTBuilder builder(defaultInclusive, binaryDependencies); ValueParser valueParser; // Regular expression to detect comments // taken from: https://stackoverflow.com/questions/9449887/removing-c-c-style-comments-using-boostregex @@ -166,7 +166,7 @@ namespace storm { } template - bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser) { + bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser) { // Default values Distribution distribution = Distribution::None; ValueType firstValDistribution = storm::utility::zero(); diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index e8e78244f..c56540edd 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -7,7 +7,7 @@ #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" #include "storm/parser/ValueParser.h" @@ -51,7 +51,7 @@ namespace storm { * * @return True iff the parsing and creation was successful. */ - static bool parseBasicElement(std::vector const& tokens, storm::storage::DFTBuilder& builder, ValueParser& valueParser); + static bool parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser); enum Distribution { None, Constant, Exponential, Weibull, LogNormal }; }; diff --git a/src/storm-dft/parser/DFTJsonParser.h b/src/storm-dft/parser/DFTJsonParser.h index d23baf58e..5517d85e1 100644 --- a/src/storm-dft/parser/DFTJsonParser.h +++ b/src/storm-dft/parser/DFTJsonParser.h @@ -7,7 +7,7 @@ #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" // JSON parser #include "json.hpp" @@ -19,7 +19,7 @@ namespace storm { template class DFTJsonParser { - storm::storage::DFTBuilder builder; + storm::builder::DFTBuilder builder; std::shared_ptr manager; diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 6f5db6a44..81784ea96 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -7,7 +7,7 @@ #include "storm/utility/iota_n.h" #include "storm/utility/vector.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" #include "storm-dft/storage/dft/DFTIsomorphism.h" @@ -271,7 +271,7 @@ namespace storm { std::vector> res; for(auto const& subdft : subdfts) { - DFTBuilder builder; + storm::builder::DFTBuilder builder; for(size_t id : subdft.second) { builder.copyElement(mElements[id]); @@ -307,7 +307,7 @@ namespace storm { std::vector> rewriteIds; rewriteIds.push_back(modIdea); - DFTBuilder builder; + storm::builder::DFTBuilder builder; // Accumulate elements which must be rewritten std::set rewriteSet; diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index 20c42fdb8..c373c8199 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -18,6 +18,11 @@ #include "storm-dft/storage/dft/DFTLayoutInfo.h" namespace storm { + namespace builder { + // Forward declaration + template class DFTBuilder; + } + namespace storage { template @@ -32,11 +37,8 @@ namespace storm { }; - // Forward declarations + // Forward declaration template class DFTColouring; - - template class DFTBuilder; - /** * Represents a Dynamic Fault Tree @@ -76,7 +78,7 @@ namespace storm { DFT optimize() const; - void copyElements(std::vector elements, DFTBuilder builder) const; + void copyElements(std::vector elements, storm::builder::DFTBuilder builder) const; size_t stateVectorSize() const { return mStateVectorSize; From e76a77abc97accf5511bf0b491089a5fc17353f8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 22 Feb 2018 16:09:07 +0100 Subject: [PATCH 119/647] improved code for sound power iteration --- .../solver/NativeLinearEquationSolver.cpp | 356 ++++++++++-------- 1 file changed, 204 insertions(+), 152 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 360acb2b8..aa3c6b894 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -557,187 +557,239 @@ namespace storm { } template - bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { - STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (SoundPower)"); - bool useGaussSeidelMultiplication = env.solver().native().getPowerMethodMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; - - // Prepare the solution vectors. - assert(x.size() == getMatrixRowCount()); - std::vector *stepBoundedX, *stepBoundedStayProbs, *tmp; - if (useGaussSeidelMultiplication) { - stepBoundedX = &x; - stepBoundedX->assign(getMatrixRowCount(), storm::utility::zero()); - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::one()); - } else { - this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::one()); - } - stepBoundedStayProbs = this->cachedRowVector.get(); - tmp = nullptr; - } else { - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount(), storm::utility::zero()); - } else { - this->cachedRowVector->assign(getMatrixRowCount(), storm::utility::zero()); - } - stepBoundedX = this->cachedRowVector.get(); - if (!this->cachedRowVector2) { - this->cachedRowVector2 = std::make_unique>(getMatrixRowCount(), storm::utility::one()); - } else { - this->cachedRowVector2->assign(getMatrixRowCount(), storm::utility::one()); - } - stepBoundedStayProbs = this->cachedRowVector2.get(); - tmp = &x; + class SoundPowerHelper { + public: + SoundPowerHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + convergencePhase1 = true; + firstIndexViolatingConvergence = 0; } - - ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); - bool relative = env.solver().native().getRelativeTerminationCriterion(); - if (!relative) { - precision *= storm::utility::convertNumber(2.0); + + inline void setLowerBound(ValueType const& value) { + hasLowerBound = true; + lowerBound = value; } - uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); - - uint64_t iterations = 0; - bool converged = false; - bool terminate = false; - uint64_t minIndex(0), maxIndex(0); - ValueType minValueBound, maxValueBound; - bool hasMinValueBound(false), hasMaxValueBound(false); - // Prepare initial bounds for the solution (if given) - if (this->hasLowerBound()) { - minValueBound = this->getLowerBound(true); - hasMinValueBound = true; + + inline void setUpperBound(ValueType const& value) { + hasUpperBound = true; + upperBound = value; } - if (this->hasUpperBound()) { - maxValueBound = this->getUpperBound(true); - hasMaxValueBound = true; + + void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, ValueType const& bi, ValueType& xi, ValueType& yi) { + xi = bi; + yi = storm::utility::zero(); + for (auto const& entry : A.getRow(row)) { + xi += entry.getValue() * x[entry.getColumn()]; + yi += entry.getValue() * y[entry.getColumn()]; + } } - bool convergencePhase1 = true; - uint64_t firstIndexViolatingConvergence = 0; - this->startMeasureProgress(); - while (!converged && !terminate && iterations < maxIter) { - - // Apply step - if (useGaussSeidelMultiplication) { - this->multiplier.multAddGaussSeidelBackward(*this->A, *stepBoundedX, &b); - this->multiplier.multAddGaussSeidelBackward(*this->A, *stepBoundedStayProbs, nullptr); - } else { - this->multiplier.multAdd(*this->A, *stepBoundedX, &b, *tmp); - std::swap(tmp, stepBoundedX); - this->multiplier.multAdd(*this->A, *stepBoundedStayProbs, nullptr, *tmp); - std::swap(tmp, stepBoundedStayProbs); + void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + uint64_t row = A.getRowCount(); + while (row > 0) { + --row; + multiplyRow(row, A, b[row], *xIt, *yIt); + ++xIt; + ++yIt; } + } + + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr) { - // Check for convergence if (convergencePhase1) { - // Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state - for (; firstIndexViolatingConvergence != stepBoundedStayProbs->size(); ++firstIndexViolatingConvergence) { - static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); - if (NumberTraits::IsExact) { - if (storm::utility::isOne(stepBoundedStayProbs->at(firstIndexViolatingConvergence))) { - break; - } - } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(stepBoundedStayProbs->at(firstIndexViolatingConvergence)))) { - break; - } + if (checkConvergencePhase1()) { + firstIndexViolatingConvergence = 0; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); } - } - if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { - STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); - convergencePhase1 = false; - firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0; + } else { + return false; } } - if (!convergencePhase1) { - // Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value - // First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes. - ValueType minValueBoundCandidate = stepBoundedX->at(minIndex) / (storm::utility::one() - stepBoundedStayProbs->at(minIndex)); - ValueType maxValueBoundCandidate = stepBoundedX->at(maxIndex) / (storm::utility::one() - stepBoundedStayProbs->at(maxIndex)); - if (hasMinValueBound && minValueBound > minValueBoundCandidate) { - minValueBoundCandidate = minValueBound; - } - if (hasMaxValueBound && maxValueBound < maxValueBoundCandidate) { - maxValueBoundCandidate = maxValueBound; - } - ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence); - // The error made in this iteration - ValueType absoluteError = stayProb * (maxValueBoundCandidate - minValueBoundCandidate); - // The maximal allowed error (possibly respecting relative precision) - // Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero. - ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; - if (absoluteError <= maxAllowedError) { - // Compute the actual bounds now - auto valIt = stepBoundedX->begin(); - auto valIte = stepBoundedX->end(); - auto probIt = stepBoundedStayProbs->begin(); - for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) { - ValueType currentBound = *valIt / (storm::utility::one() - *probIt); - if (currentBound < minValueBoundCandidate) { - minIndex = index; - minValueBoundCandidate = std::move(currentBound); - } else if (currentBound > maxValueBoundCandidate) { - maxIndex = index; - maxValueBoundCandidate = std::move(currentBound); - } + STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + + // Reaching this point means that we are in Phase 2: + // The difference between lower and upper bound has to be < precision at every (relevant) value + + // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds + ValueType lowerBoundCandidate, upperBoundCandidate; + if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { + updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); + return checkConvergencePhase2(relevantValues); + } + return false; + } + + void setSolutionVector() { + STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); + + ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); + + STORM_LOG_INFO("Sound Power Iteration terminated with lower value bound " + << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") + << " and upper value bound " + << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") + << "."); + } + + private: + + bool checkConvergencePhase1() { + // Return true if y ('the probability to stay within the 'maybestates') is < 1 at every entry + for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { + return false; } - if (!hasMinValueBound || minValueBoundCandidate > minValueBound) { - minValueBound = minValueBoundCandidate; - hasMinValueBound = true; + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { + return false; } - if (!hasMaxValueBound || maxValueBoundCandidate < maxValueBound) { - maxValueBound = maxValueBoundCandidate; - hasMaxValueBound = true; + } + } + convergencePhase1 = false; + return true; + } + + + bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { + return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); + } + + bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); + upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); + // Make sure that these candidates are at least as tight as the already known bounds + if (hasLowerBound && lowerBoundCandidate < lowerBound) { + lowerBoundCandidate = lowerBound; + } + if (hasUpperBound && upperBoundCandidate > upperBound) { + upperBoundCandidate = upperBound; + } + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { + return true; + } + return false; + } + + void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + auto xIt = x.begin(); + auto xIte = x.end(); + auto yIt = y.begin(); + for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { + ValueType currentBound = *xIt / (storm::utility::one() - *yIt); + if (currentBound < lowerBoundCandidate) { + minIndex = index; + lowerBoundCandidate = std::move(currentBound); + } else if (currentBound > upperBoundCandidate) { + maxIndex = index; + upperBoundCandidate = std::move(currentBound); + } + } + if (!hasLowerBound || lowerBoundCandidate > lowerBound) { + setLowerBound(lowerBoundCandidate); + } + if (!hasUpperBound || upperBoundCandidate < upperBound) { + setUpperBound(upperBoundCandidate); + } + } + + bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr) { + // Check whether the desired precision is reached + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); } - absoluteError = stayProb * (maxValueBound - minValueBound); - if (absoluteError <= maxAllowedError) { - // The current index satisfies the desired bound. We now move to the next index that violates it - while (true) { - ++firstIndexViolatingConvergence; - if (this->hasRelevantValues()) { - firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence); - } - if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) { - converged = true; - break; - } else { - absoluteError = stepBoundedStayProbs->at(firstIndexViolatingConvergence) * (maxValueBound - minValueBound); - maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision; - if (absoluteError > maxAllowedError) { - // not converged yet - break; - } - } + if (firstIndexViolatingConvergence == x.size()) { + // Converged! + return true; + } else { + if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // not converged yet + return false; } } } } + return false; + } + + std::vector& x; + std::vector& y; + + ValueType lowerBound, upperBound, decisionValue; + bool hasLowerBound, hasUpperBound, hasDecisionValue; + uint64_t minIndex, maxIndex; + bool convergencePhase1; + uint64_t firstIndexViolatingConvergence; + + bool relative; + ValueType precision; + }; + + template + bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + + // Prepare the solution vectors. + assert(x.size() == this->A->getRowCount()); + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(); + } + + SoundPowerHelper helper(x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + + // Prepare initial bounds for the solution (if given) + if (this->hasLowerBound()) { + helper.setLowerBound(this->getLowerBound(true)); + } + if (this->hasUpperBound()) { + helper.setUpperBound(this->getUpperBound(true)); + } + + storm::storage::BitVector const* relevantValuesPtr = nullptr; + if (this->hasRelevantValues()) { + relevantValuesPtr = &this->getRelevantValues(); + } + + bool converged = false; + bool terminate = false; + this->startMeasureProgress(); + uint64_t iterations = 0; + + while (!converged && iterations < env.solver().native().getMaximalNumberOfIterations()) { + helper.performIterationStep(*this->A, b); + if (helper.checkConvergenceUpdateBounds(relevantValuesPtr)) { + converged = true; + } + + // todo: custom termination check + // terminate = .... + + // Update environment variables. + ++iterations; // Potentially show progress. this->showProgressIterative(iterations); - - // Set up next iteration. - ++iterations; - } + helper.setSolutionVector(); + this->logIterations(converged, terminate, iterations); - // Finally set up the solution vector - ValueType meanBound = (maxValueBound + minValueBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; }); + this->overallPerformedIterations += iterations; if (!this->isCachingEnabled()) { clearCache(); } - this->overallPerformedIterations += iterations; - - this->logIterations(converged, terminate, iterations); - STORM_LOG_WARN_COND(hasMinValueBound && hasMaxValueBound, "Could not compute lower or upper bound within the given number of iterations."); - STORM_LOG_INFO("Quick Power Iteration terminated with lower value bound " << minValueBound << " and upper value bound " << maxValueBound << "."); - + return converged; - } template From 537a8152d3c4ec38ea32b176f9b72adf1c762895 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 22 Feb 2018 17:34:54 +0100 Subject: [PATCH 120/647] Removed Duplicated code --- .../TopologicalLinearEquationSolver.cpp | 97 +------------------ .../solver/TopologicalLinearEquationSolver.h | 2 +- .../TopologicalMinMaxLinearEquationSolver.cpp | 97 +------------------ .../TopologicalMinMaxLinearEquationSolver.h | 3 +- ...tronglyConnectedComponentDecomposition.cpp | 88 +++++++++++++++++ .../StronglyConnectedComponentDecomposition.h | 8 ++ 6 files changed, 108 insertions(+), 187 deletions(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 35994357b..6778970c9 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -63,15 +63,6 @@ namespace storm { createSortedSccDecomposition(needAdaptPrecision); } - //std::cout << "Sorted SCC decomposition: " << std::endl; - //for (auto const& scc : *this->sortedSccDecomposition) { - //std::cout << "SCC: "; - // for (auto const& row : scc) { - //std::cout << row << " "; - // } - //std::cout << std::endl; - //} - // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->getMatrixRowCount()); @@ -119,90 +110,12 @@ namespace storm { template void TopologicalLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { // Obtain the scc decomposition - auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*this->A); - - // Get a mapping from matrix row to the corresponding scc - STORM_LOG_THROW(sccDecomposition.size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); - std::vector sccIndices(this->A->getRowCount(), std::numeric_limits::max()); - uint32_t sccIndex = 0; - for (auto const& scc : sccDecomposition) { - for (auto const& row : scc) { - sccIndices[row] = sccIndex; - } - ++sccIndex; - } - - // Prepare the resulting set of sorted sccs - this->sortedSccDecomposition = std::make_unique>(); - std::vector& sortedSCCs = *this->sortedSccDecomposition; - sortedSCCs.reserve(sccDecomposition.size()); - - // Find a topological sort via DFS. - storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); - std::vector sccStack, chainSizes; + this->sortedSccDecomposition = std::make_unique>(*this->A); if (needLongestChainSize) { - chainSizes.resize(sccDecomposition.size(), 1u); - } - uint32_t longestChainSize = 0; - uint32_t const token = std::numeric_limits::max(); - std::set successorSCCs; - - for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { - - sccStack.push_back(firstUnsortedScc); - while (!sccStack.empty()) { - uint32_t currentSccIndex = sccStack.back(); - if (currentSccIndex != token) { - // Check whether the SCC is still unprocessed - if (unsortedSCCs.get(currentSccIndex)) { - // Explore the successors of the scc. - storm::storage::StronglyConnectedComponent const& currentScc = sccDecomposition.getBlock(currentSccIndex); - // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. - sccStack.push_back(token); - // Now add all successors that are not already sorted. - // Successors should only be added once, so we first prepare a set of them and add them afterwards. - successorSCCs.clear(); - for (auto const& row : currentScc) { - for (auto const& entry : this->A->getRow(row)) { - auto const& successorSCC = sccIndices[entry.getColumn()]; - if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { - successorSCCs.insert(successorSCC); - } - } - } - sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); - - } - } else { - // all successors of the current scc have already been explored. - sccStack.pop_back(); // pop the token - - currentSccIndex = sccStack.back(); - storm::storage::StronglyConnectedComponent& scc = sccDecomposition.getBlock(currentSccIndex); - - // Compute the longest chain size for this scc - if (needLongestChainSize) { - uint32_t& currentChainSize = chainSizes[currentSccIndex]; - for (auto const& row : scc) { - for (auto const& entry : this->A->getRow(row)) { - auto const& successorSCC = sccIndices[entry.getColumn()]; - if (successorSCC != currentSccIndex) { - currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); - } - } - } - longestChainSize = std::max(longestChainSize, currentChainSize); - } - - unsortedSCCs.set(currentSccIndex, false); - sccStack.pop_back(); // pop the current scc index - sortedSCCs.push_back(std::move(scc)); - } - } - } - - if (longestChainSize > 0) { - this->longestSccChainSize = longestChainSize; + this->longestSccChainSize = 0; + this->sortedSccDecomposition->sortTopologically(*this->A, &(this->longestSccChainSize.get())); + } else { + this->sortedSccDecomposition->sortTopologically(*this->A); } } diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h index 7403423b7..fcf630706 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.h +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -67,7 +67,7 @@ namespace storm { NativeMultiplier multiplier; // cached auxiliary data - mutable std::unique_ptr> sortedSccDecomposition; + mutable std::unique_ptr> sortedSccDecomposition; mutable boost::optional longestSccChainSize; mutable std::unique_ptr> sccSolver; }; diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 92d909189..43e080850 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -73,15 +73,6 @@ namespace storm { createSortedSccDecomposition(needAdaptPrecision); } - //std::cout << "Sorted SCC decomposition: " << std::endl; - //for (auto const& scc : *this->sortedSccDecomposition) { - //std::cout << "SCC: "; - // for (auto const& row : scc) { - //std::cout << row << " "; - // } - //std::cout << std::endl; - //} - // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->A->getRowGroupCount()); @@ -149,90 +140,12 @@ namespace storm { template void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { // Obtain the scc decomposition - auto sccDecomposition = storm::storage::StronglyConnectedComponentDecomposition(*this->A); - - // Get a mapping from matrix row to the corresponding scc - STORM_LOG_THROW(sccDecomposition.size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); - std::vector sccIndices(this->A->getRowCount(), std::numeric_limits::max()); - uint32_t sccIndex = 0; - for (auto const& scc : sccDecomposition) { - for (auto const& row : scc) { - sccIndices[row] = sccIndex; - } - ++sccIndex; - } - - // Prepare the resulting set of sorted sccs - this->sortedSccDecomposition = std::make_unique>(); - std::vector& sortedSCCs = *this->sortedSccDecomposition; - sortedSCCs.reserve(sccDecomposition.size()); - - // Find a topological sort via DFS. - storm::storage::BitVector unsortedSCCs(sccDecomposition.size(), true); - std::vector sccStack, chainSizes; + this->sortedSccDecomposition = std::make_unique>(*this->A); if (needLongestChainSize) { - chainSizes.resize(sccDecomposition.size(), 1u); - } - uint32_t longestChainSize = 0; - uint32_t const token = std::numeric_limits::max(); - std::set successorSCCs; - - for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { - - sccStack.push_back(firstUnsortedScc); - while (!sccStack.empty()) { - uint32_t currentSccIndex = sccStack.back(); - if (currentSccIndex != token) { - // Check whether the SCC is still unprocessed - if (unsortedSCCs.get(currentSccIndex)) { - // Explore the successors of the scc. - storm::storage::StronglyConnectedComponent const& currentScc = sccDecomposition.getBlock(currentSccIndex); - // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. - sccStack.push_back(token); - // Now add all successors that are not already sorted. - // Successors should only be added once, so we first prepare a set of them and add them afterwards. - successorSCCs.clear(); - for (auto const& group : currentScc) { - for (auto const& entry : this->A->getRowGroup(group)) { - auto const& successorSCC = sccIndices[entry.getColumn()]; - if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { - successorSCCs.insert(successorSCC); - } - } - } - sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); - - } - } else { - // all successors of the current scc have already been explored. - sccStack.pop_back(); // pop the token - - currentSccIndex = sccStack.back(); - storm::storage::StronglyConnectedComponent& scc = sccDecomposition.getBlock(currentSccIndex); - - // Compute the longest chain size for this scc - if (needLongestChainSize) { - uint32_t& currentChainSize = chainSizes[currentSccIndex]; - for (auto const& row : scc) { - for (auto const& entry : this->A->getRow(row)) { - auto const& successorSCC = sccIndices[entry.getColumn()]; - if (successorSCC != currentSccIndex) { - currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); - } - } - } - longestChainSize = std::max(longestChainSize, currentChainSize); - } - - unsortedSCCs.set(currentSccIndex, false); - sccStack.pop_back(); // pop the current scc index - sortedSCCs.push_back(std::move(scc)); - } - } - } - - if (longestChainSize > 0) { - this->longestSccChainSize = longestChainSize; + this->longestSccChainSize = 0; + this->sortedSccDecomposition->sortTopologically(*this->A, &(this->longestSccChainSize.get())); + } else { + this->sortedSccDecomposition->sortTopologically(*this->A); } } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index 3ac93955d..9cf3c3d11 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -21,7 +21,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void clearCache() const override; virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; @@ -54,7 +53,7 @@ namespace storm { storm::storage::SparseMatrix const* A; // cached auxiliary data - mutable std::unique_ptr> sortedSccDecomposition; + mutable std::unique_ptr> sortedSccDecomposition; mutable boost::optional longestSccChainSize; mutable std::unique_ptr> sccSolver; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index af98331a7..f6567985c 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -2,6 +2,9 @@ #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace storage { @@ -226,6 +229,91 @@ namespace storm { } } + template + void StronglyConnectedComponentDecomposition::sortTopologically(storm::storage::SparseMatrix const& transitions, uint64_t* longestChainSize) { + + // Get a mapping from state to the corresponding scc + STORM_LOG_THROW(this->size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); + std::vector sccIndices(transitions.getRowGroupCount(), std::numeric_limits::max()); + uint32_t sccIndex = 0; + for (auto const& scc : *this) { + for (auto const& state : scc) { + sccIndices[state] = sccIndex; + } + ++sccIndex; + } + + // Prepare the resulting set of sorted sccs + std::vector sortedSCCs; + sortedSCCs.reserve(this->size()); + + // Find a topological sort via DFS. + storm::storage::BitVector unsortedSCCs(this->size(), true); + std::vector sccStack, chainSizes; + if (longestChainSize != nullptr) { + chainSizes.resize(this->size(), 1u); + *longestChainSize = 0; + } + uint32_t const token = std::numeric_limits::max(); + std::set successorSCCs; + + for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { + + sccStack.push_back(firstUnsortedScc); + while (!sccStack.empty()) { + uint32_t currentSccIndex = sccStack.back(); + if (currentSccIndex != token) { + // Check whether the SCC is still unprocessed + if (unsortedSCCs.get(currentSccIndex)) { + // Explore the successors of the scc. + storm::storage::StronglyConnectedComponent const& currentScc = this->getBlock(currentSccIndex); + // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. + sccStack.push_back(token); + // Now add all successors that are not already sorted. + // Successors should only be added once, so we first prepare a set of them and add them afterwards. + successorSCCs.clear(); + for (auto const& state : currentScc) { + for (auto const& entry : transitions.getRowGroup(state)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { + successorSCCs.insert(successorSCC); + } + } + } + sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); + + } + } else { + // all successors of the current scc have already been explored. + sccStack.pop_back(); // pop the token + + currentSccIndex = sccStack.back(); + storm::storage::StronglyConnectedComponent& scc = this->getBlock(currentSccIndex); + + // Compute the longest chain size for this scc + if (longestChainSize != nullptr) { + uint32_t& currentChainSize = chainSizes[currentSccIndex]; + for (auto const& state : scc) { + for (auto const& entry : transitions.getRowGroup(state)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex) { + currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); + } + } + } + *longestChainSize = std::max(*longestChainSize, currentChainSize); + } + + unsortedSCCs.set(currentSccIndex, false); + sccStack.pop_back(); // pop the current scc index + sortedSCCs.push_back(std::move(scc)); + } + } + } + this->blocks = std::move(sortedSCCs); + } + + // Explicitly instantiate the SCC decomposition. template class StronglyConnectedComponentDecomposition; template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, bool dropNaiveSccs, bool onlyBottomSccs); diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.h b/src/storm/storage/StronglyConnectedComponentDecomposition.h index 20552a87b..04cebff92 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.h +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.h @@ -131,6 +131,14 @@ namespace storm { */ StronglyConnectedComponentDecomposition& operator=(StronglyConnectedComponentDecomposition&& other); + + /*! + * Sorts the SCCs topologically: The ith block can only reach states in block j const& transitions, uint64_t* longestChainSize = nullptr); + private: /*! * Performs the SCC decomposition of the given model. As a side-effect this fills the vector of From 7e639b4328c72da33a875080beed46593a7a5348 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 09:50:55 +0100 Subject: [PATCH 121/647] multiplier settings and environment --- src/storm/environment/SubEnvironment.cpp | 2 + .../solver/MultiplierEnvironment.cpp | 33 +++++++++++++++ .../solver/MultiplierEnvironment.h | 23 +++++++++++ .../environment/solver/SolverEnvironment.cpp | 9 +++++ .../environment/solver/SolverEnvironment.h | 4 ++ src/storm/settings/SettingsManager.cpp | 2 + .../settings/modules/MultiplierSettings.cpp | 40 +++++++++++++++++++ .../settings/modules/MultiplierSettings.h | 34 ++++++++++++++++ 8 files changed, 147 insertions(+) create mode 100644 src/storm/environment/solver/MultiplierEnvironment.cpp create mode 100644 src/storm/environment/solver/MultiplierEnvironment.h create mode 100644 src/storm/settings/modules/MultiplierSettings.cpp create mode 100644 src/storm/settings/modules/MultiplierSettings.h diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index 45c833110..f11b2b1bf 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -4,6 +4,7 @@ #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" #include "storm/environment/solver/TopologicalSolverEnvironment.h" @@ -40,6 +41,7 @@ namespace storm { template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; + template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; diff --git a/src/storm/environment/solver/MultiplierEnvironment.cpp b/src/storm/environment/solver/MultiplierEnvironment.cpp new file mode 100644 index 000000000..85e3bac77 --- /dev/null +++ b/src/storm/environment/solver/MultiplierEnvironment.cpp @@ -0,0 +1,33 @@ +#include "storm/environment/solver/MultiplierEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/MultiplierSettings.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + + MultiplierEnvironment::MultiplierEnvironment() { + auto const& multiplierSettings = storm::settings::getModule(); + type = multiplierSettings.getMultiplierType(); + typeSetFromDefault = multiplierSettings.isMultiplierTypeSetFromDefaultValue(); + } + + MultiplierEnvironment::~MultiplierEnvironment() { + // Intentionally left empty + } + + storm::solver::MultiplierType const& MultiplierEnvironment::getType() const { + return type; + } + + bool const& MultiplierEnvironment::isTypeSetFromDefault() const { + return typeSetFromDefault; + } + + void MultiplierEnvironment::setType(storm::solver::MultiplierType value, bool isSetFromDefault) { + type = value; + typeSetFromDefault = isSetFromDefault; + } + +} diff --git a/src/storm/environment/solver/MultiplierEnvironment.h b/src/storm/environment/solver/MultiplierEnvironment.h new file mode 100644 index 000000000..d9e35f5fb --- /dev/null +++ b/src/storm/environment/solver/MultiplierEnvironment.h @@ -0,0 +1,23 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class MultiplierEnvironment { + public: + + MultiplierEnvironment(); + ~MultiplierEnvironment(); + + storm::solver::MultiplierType const& getType() const; + bool const& isTypeSetFromDefault() const; + void setType(storm::solver::MultiplierType value, bool isSetFromDefault = false); + + private: + storm::solver::MultiplierType type; + bool typeSetFromDefault; + }; +} + diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index 5fc371072..42600adbb 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -1,6 +1,7 @@ #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" @@ -36,6 +37,14 @@ namespace storm { return minMaxSolverEnvironment.get(); } + MultiplierEnvironment& SolverEnvironment::multiplier() { + return multiplierEnvironment.get(); + } + + MultiplierEnvironment const& SolverEnvironment::multiplier() const { + return multiplierEnvironment.get(); + } + EigenSolverEnvironment& SolverEnvironment::eigen() { return eigenSolverEnvironment.get(); } diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index 32c3cb648..5e24652e1 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -15,6 +15,7 @@ namespace storm { class GmmxxSolverEnvironment; class NativeSolverEnvironment; class MinMaxSolverEnvironment; + class MultiplierEnvironment; class GameSolverEnvironment; class TopologicalSolverEnvironment; @@ -32,6 +33,8 @@ namespace storm { NativeSolverEnvironment const& native() const; MinMaxSolverEnvironment& minMax(); MinMaxSolverEnvironment const& minMax() const; + MultiplierEnvironment& multiplier(); + MultiplierEnvironment const& multiplier() const; GameSolverEnvironment& game(); GameSolverEnvironment const& game() const; TopologicalSolverEnvironment& topological(); @@ -54,6 +57,7 @@ namespace storm { SubEnvironment gameSolverEnvironment; SubEnvironment topologicalSolverEnvironment; SubEnvironment minMaxSolverEnvironment; + SubEnvironment multiplierEnvironment; storm::solver::EquationSolverType linearEquationSolverType; bool linearEquationSolverTypeSetFromDefault; diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 8477b221f..fc2b80b35 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -38,6 +38,7 @@ #include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" #include "storm/settings/Option.h" @@ -550,6 +551,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } diff --git a/src/storm/settings/modules/MultiplierSettings.cpp b/src/storm/settings/modules/MultiplierSettings.cpp new file mode 100644 index 000000000..d386bbf3a --- /dev/null +++ b/src/storm/settings/modules/MultiplierSettings.cpp @@ -0,0 +1,40 @@ +#include "storm/settings/modules/MultiplierSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/OptionBuilder.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string MultiplierSettings::moduleName = "multiplier"; + const std::string MultiplierSettings::multiplierTypeOptionName = "type"; + + MultiplierSettings::MultiplierSettings() : ModuleSettings(moduleName) { + std::vector multiplierTypes = {"native", "gmmxx"}; + this->addOption(storm::settings::OptionBuilder(moduleName, multiplierTypeOptionName, true, "Sets which type of multiplier is preferred.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplier.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplierTypes)).setDefaultValueString("gmmxx").build()).build()); + + } + + storm::solver::MultiplierType MultiplierSettings::getMultiplierType() const { + std::string type = this->getOption(multiplierTypeOptionName).getArgumentByName("name").getValueAsString(); + if (type == "native") { + return storm::solver::MultiplierType::Native; + } else if (type == "gmmxx") { + return storm::solver::MultiplierType::Gmmxx; + } + + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplier type '" << type << "'."); + } + + bool MultiplierSettings::isMultiplierTypeSetFromDefaultValue() const { + return !this->getOption(multiplierTypeOptionName).getArgumentByName("name").getHasBeenSet() || this->getOption(multiplierTypeOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + } + } +} diff --git a/src/storm/settings/modules/MultiplierSettings.h b/src/storm/settings/modules/MultiplierSettings.h new file mode 100644 index 000000000..ea5bfdd8c --- /dev/null +++ b/src/storm/settings/modules/MultiplierSettings.h @@ -0,0 +1,34 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/MultiplicationStyle.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the multiplier settings. + */ + class MultiplierSettings : public ModuleSettings { + public: + + MultiplierSettings(); + + storm::solver::MultiplierType getMultiplierType() const; + + bool isMultiplierTypeSetFromDefaultValue() const; + + // The name of the module. + static const std::string moduleName; + + private: + static const std::string multiplierTypeOptionName; + }; + + } + } +} From e5e2a2465bbfa4bfe7c044d9fb7340320dd522f5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 09:51:27 +0100 Subject: [PATCH 122/647] removed obsolete option --- src/storm/settings/modules/MinMaxEquationSolverSettings.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index fc5add0c4..ce8b5756c 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -120,7 +120,6 @@ namespace storm { static const std::string valueIterationMultiplicationStyleOptionName; static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string forceBoundsOptionName; - static const std::string quickValueIterationRestartOptionName; }; } From e02640fe8204d017387c473352988f41e2026482 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 09:52:31 +0100 Subject: [PATCH 123/647] multipliertype --- src/storm/solver/SolverSelectionOptions.cpp | 10 ++++++++++ src/storm/solver/SolverSelectionOptions.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 21693781a..d2148e9bc 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -24,6 +24,16 @@ namespace storm { return "invalid"; } + std::string toString(MultiplierType t) { + switch(t) { + case MultiplierType::Native: + return "Native"; + case MultiplierType::Gmmxx: + return "Gmmxx"; + } + return "invalid"; + } + std::string toString(LraMethod m) { switch(m) { case LraMethod::LinearProgramming: diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index e92c0ee0e..678bc1565 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -7,6 +7,7 @@ namespace storm { namespace solver { ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, IntervalIteration, SoundValueIteration, TopologicalCuda) + ExtendEnumsWithSelectionField(MultiplierType, Native, Gmmxx) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) From d0de99ba51b85d54eb256da0655d96ee7cea4007 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 09:53:51 +0100 Subject: [PATCH 124/647] fist version of new multiplier --- src/storm/solver/Multiplier.cpp | 75 ++++++++++++++ src/storm/solver/Multiplier.h | 126 +++++++++++++++++++++++ src/storm/solver/NativeMultiplier.cpp | 143 +++++++++++++++++--------- src/storm/solver/NativeMultiplier.h | 28 +++-- 4 files changed, 314 insertions(+), 58 deletions(-) create mode 100644 src/storm/solver/Multiplier.cpp create mode 100644 src/storm/solver/Multiplier.h diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp new file mode 100644 index 000000000..0375449bf --- /dev/null +++ b/src/storm/solver/Multiplier.cpp @@ -0,0 +1,75 @@ +#include "storm/solver/Multiplier.h" + +#include "storm-config.h" + +#include "storm/storage/SparseMatrix.h" + +#include "storm/adapters/RationalNumberAdapter.h" +#include "storm/adapters/RationalFunctionAdapter.h" + +#include "storm/utility/macros.h" +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/NativeMultiplier.h" +#include "storm/environment/solver/MultiplierEnvironment.h" + +namespace storm { + namespace solver { + + template + Multiplier::Multiplier(storm::storage::SparseMatrix const& matrix) : matrix(matrix), allowGaussSeidelMultiplications(false) { + // Intentionally left empty. + } + + template + bool Multiplier::getAllowGaussSeidelMultiplications() const { + return allowGaussSeidelMultiplications; + } + + template + void Multiplier::setAllowGaussSeidelMultiplications(bool value) { + allowGaussSeidelMultiplications = value; + } + + template + void Multiplier::clearCache() const { + cachedVector.reset(); + } + + template + void Multiplier::repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const { + for (uint64_t i = 0; i < n; ++i) { + multiply(env, x, b, x); + } + } + + template + void Multiplier::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, uint64_t n) const { + for (uint64_t i = 0; i < n; ++i) { + multiplyAndReduce(env, dir, rowGroupIndices, x, b, x); + } + } + + template + std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { + switch (env.solver().multiplier().getType()) { + case MultiplierType::Gmmxx: + //return std::make_unique>(matrix); + STORM_PRINT_AND_LOG("gmm mult not yet supported"); + case MultiplierType::Native: + return std::make_unique>(matrix); + } + } + + + template class Multiplier; + template class MultiplierFactory; + +#ifdef STORM_HAVE_CARL + template class Multiplier; + template class MultiplierFactory; + template class Multiplier; + template class MultiplierFactory; +#endif + + } +} diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h new file mode 100644 index 000000000..432bce2ed --- /dev/null +++ b/src/storm/solver/Multiplier.h @@ -0,0 +1,126 @@ +#pragma once + +#include "storm/solver/OptimizationDirection.h" +#include "storm/solver/MultiplicationStyle.h" + +namespace storm { + + class Environment; + + namespace storage { + template + class SparseMatrix; + } + + namespace solver { + + template + class Multiplier { + public: + + Multiplier(storm::storage::SparseMatrix const& matrix); + + /*! + * Retrieves whether Gauss Seidel style multiplications are allowed. + */ + bool getAllowGaussSeidelMultiplications() const; + + /*! + * Sets whether Gauss Seidel style multiplications are allowed. + */ + void setAllowGaussSeidelMultiplications(bool value); + + /*! + * Returns the multiplication style performed by this multiplier + */ + virtual MultiplicationStyle getMultiplicationStyle() const = 0; + + /* + * Clears the currently cached data of this multiplier in order to free some memory. + */ + virtual void clearCache() const; + + /*! + * Performs a matrix-vector multiplication x' = A*x + b. + * + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + */ + virtual void multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const = 0; + + /*! + * Performs a matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param rowGroupIndices A vector storing the row groups over which to reduce. + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + * @param choices If given, the choices made in the reduction process are written to this vector. + */ + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; + + /*! + * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After + * performing the necessary multiplications, the result is written to the input vector x. Note that the + * matrix A has to be given upon construction time of the solver object. + * + * @param x The initial vector with which to perform matrix-vector multiplication. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after each multiplication. If given, its length must be equal + * to the number of rows of A. + * @param n The number of times to perform the multiplication. + */ + void repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const; + + /*! + * Performs repeated matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param rowGroupIndices A vector storing the row groups over which to reduce. + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. + * @param n The number of times to perform the multiplication. + */ + void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, uint64_t n) const; + + /*! + * Multiplies the row with the given index with x and adds the given offset + * @param rowIndex The index of the considered row + * @param x The input vector with which the row is multiplied + */ + virtual ValueType multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const = 0; + + protected: + mutable std::unique_ptr> cachedVector; + storm::storage::SparseMatrix const& matrix; + private: + bool allowGaussSeidelMultiplications; + }; + + template + class MultiplierFactory { + public: + MultiplierFactory() = default; + ~MultiplierFactory() = default; + + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix); + + + }; + + } +} diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index ddbeb235f..c4155fcbf 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -2,6 +2,10 @@ #include "storm-config.h" +#include "storm/environment/solver/MultiplierEnvironment.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + #include "storm/storage/SparseMatrix.h" #include "storm/adapters/RationalNumberAdapter.h" @@ -13,89 +17,132 @@ namespace storm { namespace solver { template - NativeMultiplier::NativeMultiplier() : storm::utility::VectorHelper() { + NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. } - + template - void NativeMultiplier::multAdd(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { - std::vector* target = &result; - std::unique_ptr> temporary; - if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAdd'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); - } - - if (this->parallelize()) { - multAddParallel(matrix, x, b, result); + bool NativeMultiplier::parallelize(Environment const& env) const { +#ifdef STORM_HAVE_INTELTBB + return storm::settings::getModule().isUseIntelTbbSet(); +#else + return false; +#endif + } + + template + MultiplicationStyle NativeMultiplier::getMultiplicationStyle() const { + if (this->getAllowGaussSeidelMultiplications()) { + return MultiplicationStyle::GaussSeidel; } else { - matrix.multiplyWithVector(x, result, b); - } - - if (target == temporary.get()) { - std::swap(result, *temporary); + return MultiplicationStyle::Regular; } } template - void NativeMultiplier::multAddGaussSeidelBackward(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b) const { - matrix.multiplyWithVectorBackward(x, x, b); + void NativeMultiplier::multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const { + if (getMultiplicationStyle() == MultiplicationStyle::GaussSeidel) { + multAddGaussSeidelBackward(x, b); + if (&x != &result) { + result = x; + } + } else { + STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddParallel(x, b, *target); + } else { + multAdd(x, b, *target); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); + } + } } template - void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - std::vector* target = &result; - std::unique_ptr> temporary; - if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAddReduce'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); - } - - if (this->parallelize()) { - multAddReduceParallel(dir, rowGroupIndices, matrix, x, b, *target, choices); + void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { + if (getMultiplicationStyle() == MultiplicationStyle::GaussSeidel) { + multAddReduceGaussSeidelBackward(dir, rowGroupIndices, x, b, choices); + if (&x != &result) { + result = x; + } } else { - matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, *target, choices); - } - - if (target == temporary.get()) { - std::swap(result, *temporary); + STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); + } else { + multAddReduce(dir, rowGroupIndices, x, b, *target, choices); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); + } } } template - void NativeMultiplier::multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices) const { - matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); + ValueType NativeMultiplier::multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { + return this->matrix.multiplyRowWithVector(rowIndex, x); + } + + template + void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + this->matrix.multiplyWithVector(x, result, b); + } + + template + void NativeMultiplier::multAddGaussSeidelBackward(std::vector& x, std::vector const* b) const { + this->matrix.multiplyWithVectorBackward(x, x, b); + } + + template + void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); + } + + template + void NativeMultiplier::multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); } template - void NativeMultiplier::multAddParallel(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { + void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB matrix.multiplyWithVectorParallel(x, result, b); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAdd(matrix, x, b, result); + multAdd(x, b, result); #endif } template - void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAddReduce(dir, rowGroupIndices, matrix, x, b, result, choices); + multAddReduce(dir, rowGroupIndices, x, b, result, choices); #endif } - template - ValueType NativeMultiplier::multiplyRow(storm::storage::SparseMatrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const { - return matrix.multiplyRowWithVector(rowIndex, x); - } - template class NativeMultiplier; - #ifdef STORM_HAVE_CARL template class NativeMultiplier; template class NativeMultiplier; diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index ea8f543d4..b82598b0d 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/utility/VectorHelper.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/OptimizationDirection.h" @@ -13,20 +13,28 @@ namespace storm { namespace solver { template - class NativeMultiplier : public storm::utility::VectorHelper { + class NativeMultiplier : public Multiplier { public: - NativeMultiplier(); + NativeMultiplier(storm::storage::SparseMatrix const& matrix); - void multAdd(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddGaussSeidelBackward(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b) const; + virtual MultiplicationStyle getMultiplicationStyle() const override; + + virtual void multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual ValueType multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; + + private: + bool parallelize(Environment const& env) const; + + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddGaussSeidelBackward(std::vector& x, std::vector const* b) const; - void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; - void multAddParallel(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - ValueType multiplyRow(storm::storage::SparseMatrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const; }; } From f3c843561da628a730877e546247e9d61ace63a6 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 12:16:38 +0100 Subject: [PATCH 125/647] integrated new multiplier into native linear equation solver --- src/storm/solver/LinearEquationSolverTask.cpp | 16 -- src/storm/solver/LinearEquationSolverTask.h | 13 -- src/storm/solver/Multiplier.cpp | 12 +- src/storm/solver/Multiplier.h | 49 +++-- .../solver/NativeLinearEquationSolver.cpp | 180 ++++++++---------- src/storm/solver/NativeLinearEquationSolver.h | 21 +- src/storm/solver/NativeMultiplier.cpp | 105 ++++------ src/storm/solver/NativeMultiplier.h | 10 +- 8 files changed, 166 insertions(+), 240 deletions(-) delete mode 100644 src/storm/solver/LinearEquationSolverTask.cpp delete mode 100644 src/storm/solver/LinearEquationSolverTask.h diff --git a/src/storm/solver/LinearEquationSolverTask.cpp b/src/storm/solver/LinearEquationSolverTask.cpp deleted file mode 100644 index 91783ae36..000000000 --- a/src/storm/solver/LinearEquationSolverTask.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "storm/solver/LinearEquationSolverTask.h" - -namespace storm { - namespace solver { - - std::ostream& operator<<(std::ostream& out, LinearEquationSolverTask const& task) { - switch (task) { - case LinearEquationSolverTask::Unspecified: out << "unspecified"; break; - case LinearEquationSolverTask::SolveEquations: out << "solve equations"; break; - case LinearEquationSolverTask::Multiply: out << "multiply"; break; - } - return out; - } - - } -} diff --git a/src/storm/solver/LinearEquationSolverTask.h b/src/storm/solver/LinearEquationSolverTask.h deleted file mode 100644 index 5d3a401dd..000000000 --- a/src/storm/solver/LinearEquationSolverTask.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace storm { - namespace solver { - - enum class LinearEquationSolverTask { Unspecified, SolveEquations, Multiply }; - - std::ostream& operator<<(std::ostream& out, LinearEquationSolverTask const& style); - - } -} diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 0375449bf..d5da8654c 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -16,20 +16,10 @@ namespace storm { namespace solver { template - Multiplier::Multiplier(storm::storage::SparseMatrix const& matrix) : matrix(matrix), allowGaussSeidelMultiplications(false) { + Multiplier::Multiplier(storm::storage::SparseMatrix const& matrix) : matrix(matrix) { // Intentionally left empty. } - template - bool Multiplier::getAllowGaussSeidelMultiplications() const { - return allowGaussSeidelMultiplications; - } - - template - void Multiplier::setAllowGaussSeidelMultiplications(bool value) { - allowGaussSeidelMultiplications = value; - } - template void Multiplier::clearCache() const { cachedVector.reset(); diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 432bce2ed..78e8e60ad 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -20,21 +20,6 @@ namespace storm { Multiplier(storm::storage::SparseMatrix const& matrix); - /*! - * Retrieves whether Gauss Seidel style multiplications are allowed. - */ - bool getAllowGaussSeidelMultiplications() const; - - /*! - * Sets whether Gauss Seidel style multiplications are allowed. - */ - void setAllowGaussSeidelMultiplications(bool value); - - /*! - * Returns the multiplication style performed by this multiplier - */ - virtual MultiplicationStyle getMultiplicationStyle() const = 0; - /* * Clears the currently cached data of this multiplier in order to free some memory. */ @@ -50,7 +35,17 @@ namespace storm { * @param result The target vector into which to write the multiplication result. Its length must be equal * to the number of rows of A. Can be the same as the x vector. */ - virtual void multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const = 0; + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const = 0; + + /*! + * Performs a matrix-vector multiplication in gauss-seidel style. + * + * @param x The input/output vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + */ + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const = 0; /*! * Performs a matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups @@ -66,7 +61,23 @@ namespace storm { * to the number of rows of A. Can be the same as the x vector. * @param choices If given, the choices made in the reduction process are written to this vector. */ - virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; + + /*! + * Performs a matrix-vector multiplication in gauss-seidel style and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param rowGroupIndices A vector storing the row groups over which to reduce. + * @param x The input/output vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + * @param choices If given, the choices made in the reduction process are written to this vector. + */ + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const = 0; /*! * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After @@ -102,13 +113,11 @@ namespace storm { * @param rowIndex The index of the considered row * @param x The input vector with which the row is multiplied */ - virtual ValueType multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const = 0; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const = 0; protected: mutable std::unique_ptr> cachedVector; storm::storage::SparseMatrix const& matrix; - private: - bool allowGaussSeidelMultiplications; }; template diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index aa3c6b894..47f07f6f8 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -7,11 +7,13 @@ #include "storm/utility/NumberTraits.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" +#include "storm/solver/Multiplier.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/UnmetRequirementException.h" #include "storm/exceptions/PrecisionExceededException.h" + namespace storm { namespace solver { @@ -90,6 +92,14 @@ namespace storm { return converged; } + template + NativeLinearEquationSolver::JacobiDecomposition::JacobiDecomposition(Environment const& env, storm::storage::SparseMatrix const& A) { + auto decomposition = A.getJacobiDecomposition(); + this->LUMatrix = std::move(decomposition.first); + this->DVector = std::move(decomposition.second); + this->multiplier = storm::solver::MultiplierFactory().create(env, this->LUMatrix); + } + template bool NativeLinearEquationSolver::solveEquationsJacobi(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (Jacobi)"); @@ -100,16 +110,13 @@ namespace storm { // Get a Jacobi decomposition of the matrix A. if (!jacobiDecomposition) { - jacobiDecomposition = std::make_unique, std::vector>>(A->getJacobiDecomposition()); + jacobiDecomposition = std::make_unique(env, *A); } ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); bool relative = env.solver().native().getRelativeTerminationCriterion(); - storm::storage::SparseMatrix const& jacobiLU = jacobiDecomposition->first; - std::vector const& jacobiD = jacobiDecomposition->second; - std::vector* currentX = &x; std::vector* nextX = this->cachedRowVector.get(); @@ -121,10 +128,9 @@ namespace storm { this->startMeasureProgress(); while (!converged && !terminate && iterations < maxIter) { // Compute D^-1 * (b - LU * x) and store result in nextX. - multiplier.multAdd(jacobiLU, *currentX, nullptr, *nextX); - + jacobiDecomposition->multiplier->multiply(env, *currentX, nullptr, *nextX); storm::utility::vector::subtractVectors(b, *nextX, *nextX); - storm::utility::vector::multiplyVectorsPointwise(jacobiD, *nextX, *nextX); + storm::utility::vector::multiplyVectorsPointwise(jacobiDecomposition->DVector, *nextX, *nextX); // Now check if the process already converged within our precision. converged = storm::utility::vector::equalModuloPrecision(*currentX, *nextX, precision, relative); @@ -156,10 +162,11 @@ namespace storm { } template - NativeLinearEquationSolver::WalkerChaeData::WalkerChaeData(storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB) : t(storm::utility::convertNumber(1000.0)) { + NativeLinearEquationSolver::WalkerChaeData::WalkerChaeData(Environment const& env, storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB) : t(storm::utility::convertNumber(1000.0)) { computeWalkerChaeMatrix(originalMatrix); computeNewB(originalB); precomputeAuxiliaryData(); + multiplier = storm::solver::MultiplierFactory().create(env, this->matrix); } template @@ -218,7 +225,7 @@ namespace storm { // (1) Compute an equivalent equation system that has only non-negative coefficients. if (!walkerChaeData) { - walkerChaeData = std::make_unique(*this->A, b); + walkerChaeData = std::make_unique(env, *this->A, b); } // (2) Enlarge the vectors x and b to account for additional variables. @@ -242,7 +249,7 @@ namespace storm { // Create a vector that always holds Ax. std::vector currentAx(x.size()); - multiplier.multAdd(walkerChaeData->matrix, *currentX, nullptr, currentAx); + walkerChaeData->multiplier->multiply(env, *currentX, nullptr, currentAx); // (3) Perform iterations until convergence. bool converged = false; @@ -253,7 +260,7 @@ namespace storm { walkerChaeData->matrix.performWalkerChaeStep(*currentX, walkerChaeData->columnSums, walkerChaeData->b, currentAx, *nextX); // Compute new Ax. - multiplier.multAdd(walkerChaeData->matrix, *nextX, nullptr, currentAx); + walkerChaeData->multiplier->multiply(env, *nextX, nullptr, currentAx); // Check for convergence. converged = storm::utility::vector::computeSquaredNorm2Difference(currentAx, walkerChaeData->b) <= squaredErrorBound; @@ -294,7 +301,11 @@ namespace storm { } template - typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { + typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, storm::solver::Multiplier const& multiplier, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { + + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; @@ -306,9 +317,9 @@ namespace storm { while (!converged && !terminate && iterations < maxIterations) { if (useGaussSeidelMultiplication) { *newX = *currentX; - this->multiplier.multAddGaussSeidelBackward(*this->A, *newX, &b); + multiplier.multiplyGaussSeidel(env, *newX, &b); } else { - this->multiplier.multAdd(*this->A, *currentX, &b, *newX); + multiplier.multiply(env, *currentX, &b, *newX); } // Now check for termination. @@ -339,6 +350,9 @@ namespace storm { if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(getMatrixRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } std::vector* currentX = &x; SolverGuarantee guarantee = SolverGuarantee::None; if (this->hasCustomTerminationCondition()) { @@ -355,7 +369,7 @@ namespace storm { // Forward call to power iteration implementation. this->startMeasureProgress(); ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); - PowerIterationResult result = this->performPowerIteration(currentX, newX, b, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); + PowerIterationResult result = this->performPowerIteration(env, currentX, newX, b, *this->multiplier, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); // Swap the result in place. if (currentX == this->cachedRowVector.get()) { @@ -413,6 +427,10 @@ namespace storm { tmp = cachedRowVector2.get(); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } + bool converged = false; bool terminate = false; uint64_t iterations = 0; @@ -444,22 +462,22 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *lowerX, &b); + this->multiplier->multiplyGaussSeidel(env, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *upperX, &b); + this->multiplier->multiplyGaussSeidel(env, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } } else { - this->multiplier.multAdd(*this->A, *lowerX, &b, *tmp); + this->multiplier->multiply(env, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); - this->multiplier.multAdd(*this->A, *upperX, &b, *tmp); + this->multiplier->multiply(env, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -472,7 +490,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *lowerX, &b); + this->multiplier->multiplyGaussSeidel(env, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); } @@ -481,7 +499,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *upperX, &b); + this->multiplier->multiplyGaussSeidel(env, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } @@ -489,14 +507,14 @@ namespace storm { } } else { if (maxLowerDiff >= maxUpperDiff) { - this->multiplier.multAdd(*this->A, *lowerX, &b, *tmp); + this->multiplier->multiply(env, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); lowerStep = true; } else { - this->multiplier.multAdd(*this->A, *upperX, &b, *tmp); + this->multiplier->multiply(env, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -576,22 +594,26 @@ namespace storm { upperBound = value; } - void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, ValueType const& bi, ValueType& xi, ValueType& yi) { + void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { + xi = multiplier.multiplyRow(row, x, bi); + yi = multiplier.multiplyRow(row, y, storm::utility::zero()); + /* xi = bi; yi = storm::utility::zero(); for (auto const& entry : A.getRow(row)) { xi += entry.getValue() * x[entry.getColumn()]; yi += entry.getValue() * y[entry.getColumn()]; } + */ } - void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { + void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { auto xIt = x.rbegin(); auto yIt = y.rbegin(); uint64_t row = A.getRowCount(); while (row > 0) { --row; - multiplyRow(row, A, b[row], *xIt, *yIt); + multiplyRow(row, A, multiplier, b[row], *xIt, *yIt); ++xIt; ++yIt; } @@ -744,6 +766,10 @@ namespace storm { this->cachedRowVector = std::make_unique>(); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *this->A); + } + SoundPowerHelper helper(x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); // Prepare initial bounds for the solution (if given) @@ -765,7 +791,7 @@ namespace storm { uint64_t iterations = 0; while (!converged && iterations < env.solver().native().getMaximalNumberOfIterations()) { - helper.performIterationStep(*this->A, b); + helper.performIterationStep(*this->A, *this->multiplier, b); if (helper.checkConvergenceUpdateBounds(relevantValuesPtr)) { converged = true; } @@ -900,6 +926,9 @@ namespace storm { if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, *this, rationalA, rationalX, rationalB, *this->A, x, b, *this->cachedRowVector); @@ -922,14 +951,12 @@ namespace storm { typename std::enable_if::value && NumberTraits::IsExact, bool>::type NativeLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the same type is to be used for the imprecise part. - if (!this->linEqSolverA) { - this->linEqSolverA = this->linearEquationSolverFactory->create(*this->A); - this->linEqSolverA->setCachingEnabled(true); - } - if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, *this, *this->A, x, b, *this->A, *this->cachedRowVector, b, x); @@ -975,18 +1002,22 @@ namespace storm { NativeLinearEquationSolver impreciseSolver; impreciseSolver.setMatrix(impreciseA); impreciseSolver.setCachingEnabled(true); - + impreciseSolver.multiplier = storm::solver::MultiplierFactory().create(env, impreciseA); + bool converged = false; try { // Forward the call to the core rational search routine. converged = solveEquationsRationalSearchHelper(env, impreciseSolver, *this->A, x, b, impreciseA, impreciseX, impreciseB, impreciseTmpX); + impreciseSolver.clearCache(); } catch (storm::exceptions::PrecisionExceededException const& e) { STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic."); if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowGroupCount()); } - + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Translate the imprecise value iteration result to the one we are going to use from now on. auto targetIt = this->cachedRowVector->begin(); for (auto it = impreciseX.begin(), ite = impreciseX.end(); it != ite; ++it, ++targetIt) { @@ -1101,66 +1132,6 @@ namespace storm { return false; } - template - void NativeLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - if (&x != &result) { - multiplier.multAdd(*A, x, b, result); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAdd(*A, x, b, *this->cachedRowVector); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - void NativeLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (&x != &result) { - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, result, choices); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, *this->cachedRowVector, choices); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - bool NativeLinearEquationSolver::supportsGaussSeidelMultiplication() const { - return true; - } - - template - void NativeLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - STORM_LOG_ASSERT(this->A->getRowCount() == this->A->getColumnCount(), "This function is only applicable for square matrices."); - multiplier.multAddGaussSeidelBackward(*A, x, b); - } - - template - void NativeLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); - } - - template - ValueType NativeLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { - return multiplier.multiplyRow(*A, rowIndex, x); - } - - template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); @@ -1174,16 +1145,14 @@ namespace storm { template LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { LinearEquationSolverRequirements requirements; - if (task != LinearEquationSolverTask::Multiply) { - if (env.solver().native().isForceBoundsSet()) { - requirements.requireBounds(); - } - auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::IntervalIteration) { - requirements.requireBounds(); - } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { - requirements.requireLowerBounds(); - } + if (env.solver().native().isForceBoundsSet()) { + requirements.requireBounds(); + } + auto method = getMethod(env, storm::NumberTraits::IsExact); + if (method == NativeLinearEquationSolverMethod::IntervalIteration) { + requirements.requireBounds(); + } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { + requirements.requireLowerBounds(); } return requirements; } @@ -1193,6 +1162,7 @@ namespace storm { jacobiDecomposition.reset(); cachedRowVector2.reset(); walkerChaeData.reset(); + multiplier.reset(); LinearEquationSolver::clearCache(); } @@ -1207,7 +1177,7 @@ namespace storm { } template - std::unique_ptr> NativeLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> NativeLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 795f5ef19..7640f19eb 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -38,7 +38,7 @@ namespace storm { virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; - virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const override; virtual void clearCache() const override; @@ -58,7 +58,7 @@ namespace storm { template friend class NativeLinearEquationSolver; - PowerIterationResult performPowerIteration(std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; + PowerIterationResult performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; void logIterations(bool converged, bool terminate, uint64_t iterations) const; @@ -96,14 +96,22 @@ namespace storm { storm::storage::SparseMatrix const* A; // An object to dispatch all multiplication operations. - NativeMultiplier multiplier; + mutable std::unique_ptr> multiplier; // cached auxiliary data - mutable std::unique_ptr, std::vector>> jacobiDecomposition; mutable std::unique_ptr> cachedRowVector2; // A.getRowCount() rows + struct JacobiDecomposition { + JacobiDecomposition(Environment const& env, storm::storage::SparseMatrix const& A); + + storm::storage::SparseMatrix LUMatrix; + std::vector DVector; + std::unique_ptr> multiplier; + }; + mutable std::unique_ptr jacobiDecomposition; + struct WalkerChaeData { - WalkerChaeData(storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB); + WalkerChaeData(Environment const& env, storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB); void computeWalkerChaeMatrix(storm::storage::SparseMatrix const& originalMatrix); void computeNewB(std::vector const& originalB); @@ -112,6 +120,7 @@ namespace storm { storm::storage::SparseMatrix matrix; std::vector b; ValueType t; + std::unique_ptr> multiplier; // Auxiliary data. std::vector columnSums; @@ -125,7 +134,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index c4155fcbf..5fe7dde67 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -31,74 +31,61 @@ namespace storm { } template - MultiplicationStyle NativeMultiplier::getMultiplicationStyle() const { - if (this->getAllowGaussSeidelMultiplications()) { - return MultiplicationStyle::GaussSeidel; + void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddParallel(x, b, *target); } else { - return MultiplicationStyle::Regular; + multAdd(x, b, *target); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); } } template - void NativeMultiplier::multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const { - if (getMultiplicationStyle() == MultiplicationStyle::GaussSeidel) { - multAddGaussSeidelBackward(x, b); - if (&x != &result) { - result = x; - } - } else { - STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); - std::vector* target = &result; - if (&x == &result) { - if (this->cachedVector) { - this->cachedVector->resize(x.size()); - } else { - this->cachedVector = std::make_unique>(x.size()); - } - target = this->cachedVector.get(); - } - if (parallelize(env)) { - multAddParallel(x, b, *target); - } else { - multAdd(x, b, *target); - } - if (&x == &result) { - std::swap(result, *this->cachedVector); - } - } + void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector const& x, std::vector const* b) const { + this->matrix.multiplyWithVectorBackward(x, x, b); } template - void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (getMultiplicationStyle() == MultiplicationStyle::GaussSeidel) { - multAddReduceGaussSeidelBackward(dir, rowGroupIndices, x, b, choices); - if (&x != &result) { - result = x; - } - } else { - STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); - std::vector* target = &result; - if (&x == &result) { - if (this->cachedVector) { - this->cachedVector->resize(x.size()); - } else { - this->cachedVector = std::make_unique>(x.size()); - } - target = this->cachedVector.get(); - } - if (parallelize(env)) { - multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); + void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); } else { - multAddReduce(dir, rowGroupIndices, x, b, *target, choices); - } - if (&x == &result) { - std::swap(result, *this->cachedVector); + this->cachedVector = std::make_unique>(x.size()); } + target = this->cachedVector.get(); } + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); + } else { + multAddReduce(dir, rowGroupIndices, x, b, *target, choices); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); + } + } + + template + void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); } template - ValueType NativeMultiplier::multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { + ValueType NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { return this->matrix.multiplyRowWithVector(rowIndex, x); } @@ -107,21 +94,11 @@ namespace storm { this->matrix.multiplyWithVector(x, result, b); } - template - void NativeMultiplier::multAddGaussSeidelBackward(std::vector& x, std::vector const* b) const { - this->matrix.multiplyWithVectorBackward(x, x, b); - } - template void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); } - template - void NativeMultiplier::multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); - } - template void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index b82598b0d..e91dc519e 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -19,18 +19,18 @@ namespace storm { virtual MultiplicationStyle getMultiplicationStyle() const override; - virtual void multiply(Environment const& env, std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(Environment const& env, uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; private: bool parallelize(Environment const& env) const; void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddGaussSeidelBackward(std::vector& x, std::vector const* b) const; void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; From 541810f3b2606e7567800e340f9a6ad902049096 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 12:31:18 +0100 Subject: [PATCH 126/647] removed 'multiplication' part from remaining linear equation solvers --- .../solver/EigenLinearEquationSolver.cpp | 37 +----- src/storm/solver/EigenLinearEquationSolver.h | 6 +- .../EliminationLinearEquationSolver.cpp | 24 +--- .../solver/EliminationLinearEquationSolver.h | 6 +- .../solver/GmmxxLinearEquationSolver.cpp | 38 +------ src/storm/solver/GmmxxLinearEquationSolver.h | 16 +-- src/storm/solver/LinearEquationSolver.cpp | 105 ++---------------- src/storm/solver/LinearEquationSolver.h | 95 ++-------------- .../TopologicalLinearEquationSolver.cpp | 71 +----------- .../solver/TopologicalLinearEquationSolver.h | 11 +- 10 files changed, 32 insertions(+), 377 deletions(-) diff --git a/src/storm/solver/EigenLinearEquationSolver.cpp b/src/storm/solver/EigenLinearEquationSolver.cpp index bcba06888..afbc88a3b 100644 --- a/src/storm/solver/EigenLinearEquationSolver.cpp +++ b/src/storm/solver/EigenLinearEquationSolver.cpp @@ -240,41 +240,6 @@ namespace storm { return true; } - template - void EigenLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - // Typedef the map-type so we don't have to spell it out. - typedef decltype(StormEigen::Matrix::Map(b->data(), b->size())) MapType; - - auto eigenX = StormEigen::Matrix::Map(x.data(), x.size()); - auto eigenResult = StormEigen::Matrix::Map(result.data(), result.size()); - - std::unique_ptr eigenB; - if (b != nullptr) { - eigenB = std::make_unique(StormEigen::Matrix::Map(b->data(), b->size())); - } - - if (&x != &result) { - if (b != nullptr) { - eigenResult.noalias() = *eigenA * eigenX + *eigenB; - } else { - eigenResult.noalias() = *eigenA * eigenX; - } - } else { - if (b != nullptr) { - eigenResult = *eigenA * eigenX + *eigenB; - } else { - eigenResult = *eigenA * eigenX; - } - } - } - - template - ValueType EigenLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { - auto eigenX = StormEigen::Matrix::Map(x.data(), x.size()); - return (eigenA->row(rowIndex) * eigenX)(0); - } - - template LinearEquationSolverProblemFormat EigenLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::EquationSystem; @@ -291,7 +256,7 @@ namespace storm { } template - std::unique_ptr> EigenLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> EigenLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/EigenLinearEquationSolver.h b/src/storm/solver/EigenLinearEquationSolver.h index 0bdeabba1..63768563a 100644 --- a/src/storm/solver/EigenLinearEquationSolver.h +++ b/src/storm/solver/EigenLinearEquationSolver.h @@ -20,10 +20,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; - - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; protected: @@ -45,7 +41,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; }; diff --git a/src/storm/solver/EliminationLinearEquationSolver.cpp b/src/storm/solver/EliminationLinearEquationSolver.cpp index 2e67119d6..2873c04c4 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.cpp +++ b/src/storm/solver/EliminationLinearEquationSolver.cpp @@ -93,28 +93,6 @@ namespace storm { return true; } - template - void EliminationLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - if (&x != &result) { - A->multiplyWithVector(x, result); - if (b != nullptr) { - storm::utility::vector::addVectors(result, *b, result); - } - } else { - // If the two vectors are aliases, we need to create a temporary. - std::vector tmp(result.size()); - A->multiplyWithVector(x, tmp); - if (b != nullptr) { - storm::utility::vector::addVectors(tmp, *b, result); - } - } - } - - template - ValueType EliminationLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { - return A->multiplyRowWithVector(rowIndex, x); - } - template LinearEquationSolverProblemFormat EliminationLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::FixedPointSystem; @@ -131,7 +109,7 @@ namespace storm { } template - std::unique_ptr> EliminationLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> EliminationLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/EliminationLinearEquationSolver.h b/src/storm/solver/EliminationLinearEquationSolver.h index 57da6bbaa..d3c3f5992 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.h +++ b/src/storm/solver/EliminationLinearEquationSolver.h @@ -21,10 +21,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; - - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; protected: @@ -48,7 +44,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index f87a02a96..83d5b6ef6 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -5,7 +5,6 @@ #include "storm/adapters/GmmxxAdapter.h" -#include "storm/solver/GmmxxMultiplier.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/utility/vector.h" @@ -116,41 +115,6 @@ namespace storm { return false; } - template - void GmmxxLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - multiplier.multAdd(*gmmxxA, x, b, result); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - - template - void GmmxxLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - multiplier.multAddReduce(dir, rowGroupIndices, *gmmxxA, x, b, result, choices); - } - - template - bool GmmxxLinearEquationSolver::supportsGaussSeidelMultiplication() const { - return true; - } - - template - void GmmxxLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - multiplier.multAddGaussSeidelBackward(*gmmxxA, x, b); - } - - template - void GmmxxLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - multiplier.multAddReduceGaussSeidel(dir, rowGroupIndices, *gmmxxA, x, b, choices); - } - - template - ValueType GmmxxLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { - return multiplier.multiplyRow(*gmmxxA, rowIndex, x); - } - - template LinearEquationSolverProblemFormat GmmxxLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::EquationSystem; @@ -174,7 +138,7 @@ namespace storm { } template - std::unique_ptr> GmmxxLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GmmxxLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/GmmxxLinearEquationSolver.h b/src/storm/solver/GmmxxLinearEquationSolver.h index 434d5688a..f288e9f58 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.h +++ b/src/storm/solver/GmmxxLinearEquationSolver.h @@ -5,10 +5,8 @@ #include "storm/utility/gmm.h" -#include "storm/solver/GmmxxMultiplier.h" - #include "storm/solver/LinearEquationSolver.h" -#include "SolverSelectionOptions.h" +#include "storm/solver/SolverSelectionOptions.h" namespace storm { namespace solver { @@ -27,13 +25,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual bool supportsGaussSeidelMultiplication() const override; - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; virtual void clearCache() const override; @@ -51,9 +42,6 @@ namespace storm { // The matrix in gmm++ format. std::unique_ptr> gmmxxA; - // A multiplier object used to dispatch the multiplication calls. - GmmxxMultiplier multiplier; - // cached data obtained during solving mutable std::unique_ptr>> iluPreconditioner; mutable std::unique_ptr>> diagonalPreconditioner; @@ -64,7 +52,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index 193f2cc09..44eb42db0 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -31,89 +31,7 @@ namespace storm { } template - void LinearEquationSolver::repeatedMultiply(std::vector& x, std::vector const* b, uint_fast64_t n) const { - if (!cachedRowVector) { - cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - // We enable caching for this. But remember how the old setting was - bool cachingWasEnabled = isCachingEnabled(); - setCachingEnabled(true); - - // Set up some temporary variables so that we can just swap pointers instead of copying the result after - // each iteration. - std::vector* currentX = &x; - std::vector* nextX = cachedRowVector.get(); - - // Now perform matrix-vector multiplication as long as we meet the bound. - this->startMeasureProgress(); - for (uint_fast64_t i = 0; i < n; ++i) { - this->multiply(*currentX, b, *nextX); - std::swap(nextX, currentX); - - // Potentially show progress. - this->showProgressIterative(i, n); - } - - // If we performed an odd number of repetitions, we need to swap the contents of currentVector and x, - // because the output is supposed to be stored in the input vector x. - if (currentX == cachedRowVector.get()) { - std::swap(x, *currentX); - } - - // restore the old caching setting - setCachingEnabled(cachingWasEnabled); - - if (!isCachingEnabled()) { - clearCache(); - } - } - - template - void LinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (!cachedRowVector) { - cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - // We enable caching for this. But remember how the old setting was - bool cachingWasEnabled = isCachingEnabled(); - setCachingEnabled(true); - - this->multiply(x, b, *cachedRowVector); - vectorHelper.reduceVector(dir, *cachedRowVector, result, rowGroupIndices, choices); - - // restore the old caching setting - setCachingEnabled(cachingWasEnabled); - - if (!isCachingEnabled()) { - clearCache(); - } - } - -#ifdef STORM_HAVE_CARL - template<> - void LinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices ) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Reducing rational function vector is not supported."); - } -#endif - - template - bool LinearEquationSolver::supportsGaussSeidelMultiplication() const { - return false; - } - - template - void LinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This solver does not support the function 'multiplyGaussSeidel'."); - } - - template - void LinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This solver does not support the function 'multiplyAndReduceGaussSeidel'."); - } - - template - LinearEquationSolverRequirements LinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + LinearEquationSolverRequirements LinearEquationSolver::getRequirements(Environment const& env) const { return LinearEquationSolverRequirements(); } @@ -137,15 +55,15 @@ namespace storm { } template - std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix, LinearEquationSolverTask const& task) const { - std::unique_ptr> solver = this->create(env, task); + std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) const { + std::unique_ptr> solver = this->create(env); solver->setMatrix(matrix); return solver; } template - std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix&& matrix, LinearEquationSolverTask const& task) const { - std::unique_ptr> solver = this->create(env, task); + std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix&& matrix) const { + std::unique_ptr> solver = this->create(env); solver->setMatrix(std::move(matrix)); return solver; } @@ -156,8 +74,8 @@ namespace storm { } template - LinearEquationSolverRequirements LinearEquationSolverFactory::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { - return this->create(env)->getRequirements(env, task); + LinearEquationSolverRequirements LinearEquationSolverFactory::getRequirements(Environment const& env) const { + return this->create(env)->getRequirements(env); } template @@ -165,9 +83,8 @@ namespace storm { // Intentionally left empty. } - template<> - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if it is not supported by this value type @@ -188,7 +105,7 @@ namespace storm { } template<> - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if it is not supported by this value type @@ -208,11 +125,11 @@ namespace storm { } template - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if none was specified and we want sound computations - if (env.solver().isForceSoundness() && task != LinearEquationSolverTask::Multiply && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { + if (env.solver().isForceSoundness() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { if (env.solver().isLinearEquationSolverTypeSetFromDefaultValue()) { type = EquationSolverType::Native; STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver to guarantee sound results. If you want to override this, please explicitly specify a different solver."); diff --git a/src/storm/solver/LinearEquationSolver.h b/src/storm/solver/LinearEquationSolver.h index cc2f73a7a..c53c23393 100644 --- a/src/storm/solver/LinearEquationSolver.h +++ b/src/storm/solver/LinearEquationSolver.h @@ -22,8 +22,7 @@ namespace storm { namespace solver { /*! - * An interface that represents an abstract linear equation solver. In addition to solving a system of linear - * equations, the functionality to repeatedly multiply a matrix with a given vector is provided. + * An interface that represents an abstract linear equation solver. */ template class LinearEquationSolver : public AbstractEquationSolver { @@ -50,86 +49,6 @@ namespace storm { */ bool solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; - /*! - * Performs on matrix-vector multiplication x' = A*x + b. - * - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param result The target vector into which to write the multiplication result. Its length must be equal - * to the number of rows of A. - */ - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const = 0; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups - * so that the resulting vector has the size of number of row groups of A. - * - * @param dir The direction for the reduction step. - * @param rowGroupIndices A vector storing the row groups over which to reduce. - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param result The target vector into which to write the multiplication result. Its length must be equal - * to the number of rows of A. - * @param choices If given, the choices made in the reduction process are written to this vector. - */ - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - - /*! - * Retrieves whether this solver offers the gauss-seidel style multiplications. - */ - virtual bool supportsGaussSeidelMultiplication() const; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b. It does so in a gauss-seidel style, i.e. reusing - * the new x' components in the further multiplication. - * - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - */ - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups - * so that the resulting vector has the size of number of row groups of A. It does so in a gauss-seidel - * style, i.e. reusing the new x' components in the further multiplication. - * - * @param dir The direction for the reduction step. - * @param rowGroupIndices A vector storing the row groups over which to reduce. - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param choices If given, the choices made in the reduction process are written to this vector. - */ - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; - - /*! - * Multiplies the row with the given index with x and adds the given offset - * @param rowIndex The index of the considered row - * @param x The input vector with which the row is multiplied - * @param offset A value that is added to the matrix-vector multiplication result - */ - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const = 0; - - /*! - * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After - * performing the necessary multiplications, the result is written to the input vector x. Note that the - * matrix A has to be given upon construction time of the solver object. - * - * @param x The initial vector with which to perform matrix-vector multiplication. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after each multiplication. If given, its length must be equal - * to the number of rows of A. - * @param n The number of times to perform the multiplication. - */ - void repeatedMultiply(std::vector& x, std::vector const* b, uint_fast64_t n) const; - /*! * Retrieves the format in which this solver expects to solve equations. If the solver expects the equation * system format, it solves Ax = b. If it it expects a fixed point format, it solves Ax + b = x. @@ -140,7 +59,7 @@ namespace storm { * Retrieves the requirements of the solver under the current settings. Note that these requirements only * apply to solving linear equations and not to the matrix vector multiplications. */ - virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const; /*! * Sets whether some of the generated data during solver calls should be cached. @@ -195,7 +114,7 @@ namespace storm { * @param matrix The matrix that defines the equation system. * @return A pointer to the newly created solver. */ - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix) const; /*! * Creates a new linear equation solver instance with the given matrix. The caller gives up posession of the @@ -204,12 +123,12 @@ namespace storm { * @param matrix The matrix that defines the equation system. * @return A pointer to the newly created solver. */ - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix) const; /*! * Creates an equation solver with the current settings, but without a matrix. */ - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const = 0; + virtual std::unique_ptr> create(Environment const& env) const = 0; /*! * Creates a copy of this factory. @@ -225,7 +144,7 @@ namespace storm { * Retrieves the requirements of the solver if it was created with the current settings. Note that these * requirements only apply to solving linear equations and not to the matrix vector multiplications. */ - LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + LinearEquationSolverRequirements getRequirements(Environment const& env) const; }; template @@ -235,7 +154,7 @@ namespace storm { using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; }; diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 6778970c9..e3e733407 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -138,14 +138,13 @@ namespace storm { if (hasDiagonalEntry) { xi /= denominator; } - //std::cout << "Solved trivial scc " << sccState << " with result " << globalX[sccState] << std::endl; return true; } template bool TopologicalLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, std::vector& x, std::vector const& b) const { if (!this->sccSolver) { - this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment, LinearEquationSolverTask::SolveEquations); + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment); this->sccSolver->setCachingEnabled(true); this->sccSolver->setBoundsFromOtherSolver(*this); if (this->sccSolver->getEquationProblemFormat(sccSolverEnvironment) == LinearEquationSolverProblemFormat::EquationSystem) { @@ -165,7 +164,7 @@ namespace storm { // Set up the SCC solver if (!this->sccSolver) { - this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment, LinearEquationSolverTask::SolveEquations); + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment); this->sccSolver->setCachingEnabled(true); } @@ -215,75 +214,15 @@ namespace storm { return returnvalue; } - - template - void TopologicalLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - if (&x != &result) { - multiplier.multAdd(*A, x, b, result); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAdd(*A, x, b, *this->cachedRowVector); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - void TopologicalLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (&x != &result) { - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, result, choices); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, *this->cachedRowVector, choices); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - bool TopologicalLinearEquationSolver::supportsGaussSeidelMultiplication() const { - return true; - } - - template - void TopologicalLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - STORM_LOG_ASSERT(this->A->getRowCount() == this->A->getColumnCount(), "This function is only applicable for square matrices."); - multiplier.multAddGaussSeidelBackward(*A, x, b); - } - - template - void TopologicalLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); - } - - template - ValueType TopologicalLinearEquationSolver::multiplyRow(uint64_t const& rowIndex, std::vector const& x) const { - return multiplier.multiplyRow(*A, rowIndex, x); - } - template LinearEquationSolverProblemFormat TopologicalLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::FixedPointSystem; } template - LinearEquationSolverRequirements TopologicalLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + LinearEquationSolverRequirements TopologicalLinearEquationSolver::getRequirements(Environment const& env) const { // Return the requirements of the underlying solver - return GeneralLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), task); + return GeneralLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env)); } template @@ -305,7 +244,7 @@ namespace storm { } template - std::unique_ptr> TopologicalLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> TopologicalLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h index fcf630706..5a36ec9af 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.h +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -22,15 +22,8 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual bool supportsGaussSeidelMultiplication() const override; - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; - virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const override; virtual void clearCache() const override; @@ -77,7 +70,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; From 9e875adea9722c1cf02f452e3fbb531f6b110f5d Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 12:55:27 +0100 Subject: [PATCH 127/647] Using Multiplier in CTMC and DTMC model checkers --- .../csl/helper/SparseCtmcCslHelper.cpp | 11 ++++---- .../prctl/helper/HybridDtmcPrctlHelper.cpp | 17 ++++++------ .../prctl/helper/SparseDtmcPrctlHelper.cpp | 26 +++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 90d556133..5bf12da1f 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -9,6 +9,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" @@ -671,18 +672,16 @@ namespace storm { } } - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(uniformizedMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->setCachingEnabled(true); - + auto multiplier = storm::solver::MultiplierFactory().create(env, uniformizedMatrix); if (!useMixedPoissonProbabilities && foxGlynnResult.left > 1) { // Perform the matrix-vector multiplications (without adding). - solver->repeatedMultiply(values, addVector, foxGlynnResult.left - 1); + multiplier->repeatedMultiply(env, values, addVector, foxGlynnResult.left - 1); } else if (useMixedPoissonProbabilities) { std::function addAndScale = [&uniformizationRate] (ValueType const& a, ValueType const& b) { return a + b / uniformizationRate; }; // For the iterations below the left truncation point, we need to add and scale the result with the uniformization rate. for (uint_fast64_t index = 1; index < startingIteration; ++index) { - solver->repeatedMultiply(values, nullptr, 1); + multiplier->multiply(env, values, nullptr, values); storm::utility::vector::applyPointwise(result, values, result, addAndScale); } } @@ -692,7 +691,7 @@ namespace storm { ValueType weight = 0; std::function addAndScale = [&weight] (ValueType const& a, ValueType const& b) { return a + weight * b; }; for (uint_fast64_t index = startingIteration; index <= foxGlynnResult.right; ++index) { - solver->repeatedMultiply(values, addVector, 1); + multiplier->multiply(env, values, addVector, values); weight = foxGlynnResult.weights[index - foxGlynnResult.left]; storm::utility::vector::applyPointwise(result, values, result, addAndScale); diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index 280c5aaff..ca8f7e439 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -3,6 +3,7 @@ #include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Add.h" @@ -145,9 +146,9 @@ namespace storm { storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitSubmatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, &b, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitSubmatrix); + multiplier->repeatedMultiply(env, x, &b, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new storm::modelchecker::HybridQuantitativeCheckResult(model.getReachableStates(), model.getReachableStates() && !maybeStates, psiStates.template toAdd(), maybeStates, odd, x)); } else { @@ -170,9 +171,9 @@ namespace storm { storm::storage::SparseMatrix explicitMatrix = transitionMatrix.toMatrix(odd, odd); // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, nullptr, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiply(env, x, nullptr, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } @@ -196,8 +197,8 @@ namespace storm { std::vector b = totalRewardVector.toVector(odd); // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, &b, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiply(env, x, &b, stepBound); // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index f10e1155e..1fe8ca527 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -11,6 +11,7 @@ #include "storm/storage/ConsecutiveUint64DynamicPriorityQueue.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" @@ -69,10 +70,9 @@ namespace storm { // Create the vector with which to multiply. std::vector subresult(maybeStates.getNumberOfSetBits()); - // Perform the matrix vector multiplication as often as required by the formula bound. - goal.restrictRelevantValues(maybeStates); - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, std::move(submatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(subresult, &b, stepBound); + // Perform the matrix vector multiplication + auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); + multiplier->repeatedMultiply(env, subresult, &b, stepBound); // Set the values of the resulting vector accordingly. storm::utility::vector::setVectorValues(result, maybeStates, subresult); @@ -116,9 +116,9 @@ namespace storm { // Update some data for the case that the Matrix has changed if (epochModel.epochMatrixChanged) { x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero()); - linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix, storm::solver::LinearEquationSolverTask::SolveEquations); + linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix); linEqSolver->setCachingEnabled(true); - auto req = linEqSolver->getRequirements(env, storm::solver::LinearEquationSolverTask::SolveEquations); + auto req = linEqSolver->getRequirements(env); if (lowerBound) { linEqSolver->setLowerBound(lowerBound.get()); req.clearLowerBounds(); @@ -345,8 +345,8 @@ namespace storm { storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); // Perform one single matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(result, nullptr, 1); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->multiply(env, result, nullptr, result); return result; } @@ -359,8 +359,8 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix); // Perform the matrix vector multiplication as often as required by the formula bound. - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, transitionMatrix, storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(result, &totalRewardVector, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiply(env, result, &totalRewardVector, stepBound); return result; } @@ -374,9 +374,9 @@ namespace storm { std::vector result = rewardModel.getStateRewardVector(); // Perform the matrix vector multiplication as often as required by the formula bound. - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(result, nullptr, stepCount); - + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiply(env, result, nullptr, stepCount); + return result; } From 56061c0bfa67b5c292c625800f169336ec709ce3 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 13:26:53 +0100 Subject: [PATCH 128/647] Using multiplier in MDP Model checker helpers --- .../prctl/helper/HybridMdpPrctlHelper.cpp | 17 +++++++------ .../prctl/helper/SparseMdpPrctlHelper.cpp | 25 +++++++++---------- src/storm/solver/Multiplier.cpp | 11 +++++++- src/storm/solver/Multiplier.h | 5 ++-- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index 2e14497d5..8a1ef4c9c 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -21,6 +21,7 @@ #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" #include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/UncheckedRequirementException.h" @@ -309,8 +310,8 @@ namespace storm { // Translate the symbolic matrix/vector to their explicit representations. std::pair, std::vector> explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitRepresentation.first)); - solver->repeatedMultiply(env, dir, x, &explicitRepresentation.second, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); + multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new storm::modelchecker::HybridQuantitativeCheckResult(model.getReachableStates(), model.getReachableStates() && !maybeStates, psiStates.template toAdd(), maybeStates, odd, x)); @@ -334,9 +335,9 @@ namespace storm { std::vector x = rewardModel.getStateRewardVector().toVector(odd); // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix)); - solver->repeatedMultiply(env, dir, x, nullptr, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiplyAndReduce(env, dir, x, nullptr, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } @@ -359,9 +360,9 @@ namespace storm { std::pair, std::vector> explicitRepresentation = transitionMatrix.toMatrixVector(totalRewardVector, model.getNondeterminismVariables(), odd, odd); // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitRepresentation.first)); - solver->repeatedMultiply(env, dir, x, &explicitRepresentation.second, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); + multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index adaed4627..a589d3491 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -21,6 +21,7 @@ #include "storm/storage/Scheduler.h" #include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/LpSolver.h" #include "storm/settings/SettingsManager.h" @@ -75,9 +76,8 @@ namespace storm { // Create the vector with which to multiply. std::vector subresult(maybeStates.getNumberOfSetBits()); - goal.restrictRelevantValues(maybeStates); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix)); - solver->repeatedMultiply(env, subresult, &b, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); // Set the values of the resulting vector accordingly. storm::utility::vector::setVectorValues(result, maybeStates, subresult); @@ -272,8 +272,8 @@ namespace storm { std::vector result(transitionMatrix.getRowGroupCount()); storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); - std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, transitionMatrix); - solver->repeatedMultiply(env, dir, result, nullptr, 1); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->multiplyAndReduce(env, dir, result, nullptr, result); return result; } @@ -812,9 +812,9 @@ namespace storm { // Initialize result to state rewards of the this->getModel(). std::vector result(rewardModel.getStateRewardVector()); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(env, result, nullptr, stepCount); - + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, nullptr, stepCount); + return result; } @@ -831,8 +831,8 @@ namespace storm { // Initialize result to the zero vector. std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(env, result, &totalRewardVector, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, &totalRewardVector, stepBound); return result; } @@ -1459,12 +1459,11 @@ namespace storm { std::vector x(mecTransitions.getRowGroupCount(), storm::utility::zero()); std::vector xPrime = x; - auto solver = minMaxLinearEquationSolverFactory.create(env, std::move(mecTransitions)); - solver->setCachingEnabled(true); + auto multiplier = storm::solver::MultiplierFactory().create(env, mecTransitions); ValueType maxDiff, minDiff; while (true) { // Compute the obtained rewards for the next step - solver->repeatedMultiply(env, dir, x, &choiceRewards, 1); + multiplier->multiplyAndReduce(env, dir, x, &choiceRewards, x); // update xPrime and check for convergence // to avoid large (and numerically unstable) x-values, we substract a reference value. diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index d5da8654c..e48b29df2 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -24,6 +24,16 @@ namespace storm { void Multiplier::clearCache() const { cachedVector.reset(); } + + template + void Multiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) { + multiplyAndReduce(env, dir, this->matrix.getRowGroupIndices(), x, b, result, choices); + } + + template + void Multiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices = nullptr) { + multiplyAndReduceGaussSeidel(env, dir, this->matrix.getRowGroupIndices(), x, b, choices); + } template void Multiplier::repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const { @@ -49,7 +59,6 @@ namespace storm { return std::make_unique>(matrix); } } - template class Multiplier; template class MultiplierFactory; diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 78e8e60ad..4356c583e 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -61,6 +61,7 @@ namespace storm { * to the number of rows of A. Can be the same as the x vector. * @param choices If given, the choices made in the reduction process are written to this vector. */ + void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; /*! @@ -77,6 +78,7 @@ namespace storm { * to the number of rows of A. Can be the same as the x vector. * @param choices If given, the choices made in the reduction process are written to this vector. */ + void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const = 0; /*! @@ -97,7 +99,6 @@ namespace storm { * so that the resulting vector has the size of number of row groups of A. * * @param dir The direction for the reduction step. - * @param rowGroupIndices A vector storing the row groups over which to reduce. * @param x The input vector with which to multiply the matrix. Its length must be equal * to the number of columns of A. * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal @@ -106,7 +107,7 @@ namespace storm { * to the number of rows of A. * @param n The number of times to perform the multiplication. */ - void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, uint64_t n) const; + void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const; /*! * Multiplies the row with the given index with x and adds the given offset From b7bac59ae0052d725482b41b3a4df7a5f20a382f Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 27 Feb 2018 14:37:20 +0100 Subject: [PATCH 129/647] Using multiplier in IterativeMinMaxSolvers --- .../IterativeMinMaxLinearEquationSolver.cpp | 150 +++++++----------- .../IterativeMinMaxLinearEquationSolver.h | 21 +-- 2 files changed, 66 insertions(+), 105 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 2c8eb5481..587aa3169 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -22,17 +22,17 @@ namespace storm { namespace solver { template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty } template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(A, std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(A), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A), std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A)), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } @@ -221,12 +221,11 @@ namespace storm { MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - // Start by getting the requirements of the linear equation solver. - LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && !hasInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration) { - linEqTask = LinearEquationSolverTask::Multiply; - } - MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); + // Check whether a linear equation solver is needed and potentially start with its requirements + bool needsLinEqSolver = false; + needsLinEqSolver |= method == MinMaxMethod::PolicyIteration; + needsLinEqSolver |= method == MinMaxMethod::ValueIteration && (this->hasInitialScheduler() || hasInitialScheduler); + MinMaxLinearEquationSolverRequirements requirements = needsLinEqSolver ? MinMaxLinearEquationSolverRequirements(this->linearEquationSolverFactory->getRequirements(env)) : MinMaxLinearEquationSolverRequirements(); if (method == MinMaxMethod::ValueIteration) { if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique. @@ -275,15 +274,15 @@ namespace storm { } template - typename IterativeMinMaxLinearEquationSolver::ValueIterationResult IterativeMinMaxLinearEquationSolver::performValueIteration(OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { + typename IterativeMinMaxLinearEquationSolver::ValueIterationResult IterativeMinMaxLinearEquationSolver::performValueIteration(Environment const& env, OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { STORM_LOG_ASSERT(currentX != newX, "Vectors must not be aliased."); - // Get handle to linear equation solver. - storm::solver::LinearEquationSolver const& linearEquationSolver = *this->linEqSolverA; + // Get handle to multiplier. + storm::solver::Multiplier const& multiplier = *this->multiplierA; // Allow aliased multiplications. - bool useGaussSeidelMultiplication = linearEquationSolver.supportsGaussSeidelMultiplication() && multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; + bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = currentIterations; @@ -296,9 +295,9 @@ namespace storm { if (useGaussSeidelMultiplication) { // Copy over the current vector so we can modify it in-place. *newX = *currentX; - linearEquationSolver.multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *newX, &b); + multiplier.multiplyAndReduceGaussSeidel(env, dir, *newX, &b); } else { - linearEquationSolver.multiplyAndReduce(dir, this->A->getRowGroupIndices(), *currentX, &b, *newX); + multiplier.multiplyAndReduce(env, dir, *currentX, &b, *newX); } // Determine whether the method converged. @@ -325,9 +324,8 @@ namespace storm { template bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -387,7 +385,7 @@ namespace storm { std::vector* currentX = &x; this->startMeasureProgress(); - ValueIterationResult result = performValueIteration(dir, currentX, newX, b, storm::utility::convertNumber(env.solver().minMax().getPrecision()), env.solver().minMax().getRelativeTerminationCriterion(), guarantee, 0, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); + ValueIterationResult result = performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(env.solver().minMax().getPrecision()), env.solver().minMax().getRelativeTerminationCriterion(), guarantee, 0, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); // Swap the result into the output x. if (currentX == auxiliaryRowGroupVector.get()) { @@ -399,7 +397,7 @@ namespace storm { // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); + this->multiplierA->multiplyAndReduce(env, dir, x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); } if (!this->isCachingEnabled()) { @@ -443,9 +441,8 @@ namespace storm { bool IterativeMinMaxLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { STORM_LOG_THROW(this->hasUpperBound(), storm::exceptions::UnmetRequirementException, "Solver requires upper bound, but none was given."); - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -453,7 +450,7 @@ namespace storm { } // Allow aliased multiplications. - bool useGaussSeidelMultiplication = this->linEqSolverA->supportsGaussSeidelMultiplication() && env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; + bool useGaussSeidelMultiplication = env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; std::vector* lowerX = &x; this->createLowerBoundsVector(*lowerX); @@ -497,22 +494,22 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *lowerX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *upperX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } } else { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *lowerX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(lowerX, tmp); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *upperX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -525,7 +522,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *lowerX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); } @@ -534,7 +531,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *upperX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } @@ -542,14 +539,14 @@ namespace storm { } } else { if (maxLowerDiff >= maxUpperDiff) { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *lowerX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); lowerStep = true; } else { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *upperX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -604,7 +601,7 @@ namespace storm { // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); + this->multiplierA->multiplyAndReduce(env, dir, x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); } if (!this->isCachingEnabled()) { @@ -669,19 +666,24 @@ namespace storm { return maximize(dir) ? minIndex : maxIndex; } - void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, ValueType const& bi, ValueType& xi, ValueType& yi) { + void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { + xi = multiplier.multiplyRow(row, x, bi); + yi = multiplier.multiplyRow(row, y, storm::utility::zero()); + + /* xi = bi; yi = storm::utility::zero(); for (auto const& entry : A.getRow(row)) { xi += entry.getValue() * x[entry.getColumn()]; yi += entry.getValue() * y[entry.getColumn()]; } + */ } template - void performIterationStep(storm::storage::SparseMatrix const& A, std::vector const& b) { + void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValue(A, b); + performIterationStepUpdateDecisionValue(A, multiplier, b); } else { assert(decisionValue == getPrimaryBound()); auto xIt = x.rbegin(); @@ -693,7 +695,7 @@ namespace storm { // Perform the iteration for the first row in the group uint64_t row = *groupStartIt; ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); + multiplyRow(row, A, multiplier, b[row], xBest, yBest); ++row; // Only do more work if there are still rows in this row group if (row != groupEnd) { @@ -701,7 +703,7 @@ namespace storm { ValueType bestValue = xBest + yBest * getPrimaryBound(); for (;row < groupEnd; ++row) { // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); + multiplyRow(row, A, multiplier, b[row], xi, yi); ValueType currentValue = xi + yi * getPrimaryBound(); // Check if the current row is better then the previously found one if (better(currentValue, bestValue)) { @@ -722,7 +724,7 @@ namespace storm { } template - void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, std::vector const& b) { + void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { auto xIt = x.rbegin(); auto yIt = y.rbegin(); auto groupStartIt = A.getRowGroupIndices().rbegin(); @@ -732,7 +734,7 @@ namespace storm { // Perform the iteration for the first row in the group uint64_t row = *groupStartIt; ValueType xBest, yBest; - multiplyRow(row, A, b[row], xBest, yBest); + multiplyRow(row, A, multiplier, b[row], xBest, yBest); ++row; // Only do more work if there are still rows in this row group if (row != groupEnd) { @@ -742,7 +744,7 @@ namespace storm { ValueType bestValue = xBest + yBest * getPrimaryBound(); for (;row < groupEnd; ++row) { // Get the multiplication results - multiplyRow(row, A, b[row], xi, yi); + multiplyRow(row, A, multiplier, b[row], xi, yi); ValueType currentValue = xi + yi * getPrimaryBound(); // Check if the current row is better then the previously found one if (better(currentValue, bestValue)) { @@ -769,7 +771,7 @@ namespace storm { } } else { for (;row < groupEnd; ++row) { - multiplyRow(row, A, b[row], xi, yi); + multiplyRow(row, A, multiplier, b[row], xi, yi); // Update the best choice if (yi > yBest || (yi == yBest && better(xi, xBest))) { xTmp[xyTmpIndex] = std::move(xBest); @@ -978,6 +980,10 @@ namespace storm { this->auxiliaryRowGroupVector = std::make_unique>(); } + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); + } + SoundValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); // Prepare initial bounds for the solution (if given) @@ -999,13 +1005,13 @@ namespace storm { while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { if (minimize(dir)) { - helper.template performIterationStep(*this->A, b); + helper.template performIterationStep(*this->A, *this->multiplierA, b); if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } } else { assert(maximize(dir)); - helper.template performIterationStep(*this->A, b); + helper.template performIterationStep(*this->A, *this->multiplierA, b); if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } @@ -1085,11 +1091,6 @@ namespace storm { return false; } - template - void IterativeMinMaxLinearEquationSolver::createLinearEquationSolver(Environment const& env) const { - this->linEqSolverA = this->linearEquationSolverFactory->create(env, *this->A, LinearEquationSolverTask::Multiply); - } - template template typename std::enable_if::value && !NumberTraits::IsExact, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { @@ -1100,9 +1101,8 @@ namespace storm { std::vector rationalX(x.size()); std::vector rationalB = storm::utility::vector::convertNumericVector(b); - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -1130,9 +1130,8 @@ namespace storm { typename std::enable_if::value && NumberTraits::IsExact, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the same type is to be used for the imprecise part. - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -1182,13 +1181,14 @@ namespace storm { // Create imprecise solver from the imprecise data. IterativeMinMaxLinearEquationSolver impreciseSolver(std::make_unique>()); impreciseSolver.setMatrix(impreciseA); - impreciseSolver.createLinearEquationSolver(env); impreciseSolver.setCachingEnabled(true); + impreciseSolver.multiplierA = storm::solver::MultiplierFactory().create(env, impreciseA); bool converged = false; try { // Forward the call to the core rational search routine. converged = solveEquationsRationalSearchHelper(env, dir, impreciseSolver, *this->A, x, b, impreciseA, impreciseX, impreciseB, impreciseTmpX); + impreciseSolver.clearCache(); } catch (storm::exceptions::PrecisionExceededException const& e) { STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic."); @@ -1208,9 +1208,8 @@ namespace storm { impreciseB = std::vector(); impreciseA = storm::storage::SparseMatrix(); - if (!this->linEqSolverA) { - createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } // Forward the call to the core rational search routine, but now with our value type as the imprecise value type. @@ -1270,7 +1269,7 @@ namespace storm { impreciseSolver.startMeasureProgress(); while (status == SolverStatus::InProgress && overallIterations < env.solver().minMax().getMaximalNumberOfIterations()) { // Perform value iteration with the current precision. - typename IterativeMinMaxLinearEquationSolver::ValueIterationResult result = impreciseSolver.performValueIteration(dir, currentX, newX, b, storm::utility::convertNumber(precision), env.solver().minMax().getRelativeTerminationCriterion(), SolverGuarantee::LessOrEqual, overallIterations, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); + typename IterativeMinMaxLinearEquationSolver::ValueIterationResult result = impreciseSolver.performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(precision), env.solver().minMax().getRelativeTerminationCriterion(), SolverGuarantee::LessOrEqual, overallIterations, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); // At this point, the result of the imprecise value iteration is stored in the (imprecise) current x. @@ -1370,45 +1369,16 @@ namespace storm { template void IterativeMinMaxLinearEquationSolver::clearCache() const { + multiplierA.reset(); auxiliaryRowGroupVector.reset(); auxiliaryRowGroupVector2.reset(); - rowGroupOrdering.reset(); StandardMinMaxLinearEquationSolver::clearCache(); } - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory() { - // Intentionally left empty - } - - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty - } - - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : StandardMinMaxLinearEquationSolverFactory(solverType) { - // Intentionally left empty - } - - template - std::unique_ptr> IterativeMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); - - auto method = env.solver().minMax().getMethod(); - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); - - std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone()); - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - template class IterativeMinMaxLinearEquationSolver; - template class IterativeMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class IterativeMinMaxLinearEquationSolver; - template class IterativeMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index 5806ec4a2..1a5501089 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -5,6 +5,7 @@ #include "storm/utility/NumberTraits.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" #include "storm/solver/SolverStatus.h" @@ -68,31 +69,21 @@ namespace storm { template friend class IterativeMinMaxLinearEquationSolver; - ValueIterationResult performValueIteration(OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; + ValueIterationResult performValueIteration(Environment const& env, OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; void createLinearEquationSolver(Environment const& env) const; + /// The factory used to obtain linear equation solvers. + std::unique_ptr> linearEquationSolverFactory; + // possibly cached data + mutable std::unique_ptr> multiplierA; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries mutable std::unique_ptr> auxiliaryRowGroupVector2; // A.rowGroupCount() entries - mutable std::unique_ptr> rowGroupOrdering; // A.rowGroupCount() entries SolverStatus updateStatusIfNotConverged(SolverStatus status, std::vector const& x, uint64_t iterations, uint64_t maximalNumberOfIterations, SolverGuarantee const& guarantee) const; static void reportStatus(SolverStatus status, uint64_t iterations); }; - template - class IterativeMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - IterativeMinMaxLinearEquationSolverFactory(); - IterativeMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory); - IterativeMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - }; } } From 64ba34a3979931473bfbb2190c430467cebfc841 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 09:45:46 +0100 Subject: [PATCH 130/647] removed multiplication support from minmax equation solvers. Also removed Factories. --- .../solver/LpMinMaxLinearEquationSolver.cpp | 36 +----- .../solver/LpMinMaxLinearEquationSolver.h | 21 +--- .../solver/MinMaxLinearEquationSolver.cpp | 10 +- src/storm/solver/MinMaxLinearEquationSolver.h | 26 ---- .../StandardMinMaxLinearEquationSolver.cpp | 114 +----------------- .../StandardMinMaxLinearEquationSolver.h | 61 +--------- ...ologicalCudaMinMaxLinearEquationSolver.cpp | 19 --- ...opologicalCudaMinMaxLinearEquationSolver.h | 2 - .../solver/TopologicalLinearEquationSolver.h | 3 - .../TopologicalMinMaxLinearEquationSolver.cpp | 57 +-------- .../TopologicalMinMaxLinearEquationSolver.h | 26 +--- 11 files changed, 25 insertions(+), 350 deletions(-) diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp index 3add9ad41..5143fcdef 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp @@ -10,17 +10,17 @@ namespace storm { namespace solver { template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(std::unique_ptr>&& lpSolverFactory) : lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(A, std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(A), lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A), std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A)), lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } @@ -113,7 +113,7 @@ namespace storm { template MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { - MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, LinearEquationSolverTask::Multiply)); + MinMaxLinearEquationSolverRequirements requirements; // In case we need to retrieve a scheduler, the solution has to be unique if (!this->hasUniqueSolution() && this->isTrackSchedulerSet()) { @@ -127,38 +127,10 @@ namespace storm { return requirements; } - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(), lpSolverFactory(std::make_unique>()) { - // Intentionally left empty - } - - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolverFactory(), lpSolverFactory(std::move(lpSolverFactory)) { - // Intentionally left empty - } - - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolverFactory(std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { - // Intentionally left empty - } - - template - std::unique_ptr> LpMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::LinearProgramming, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - STORM_LOG_ASSERT(this->lpSolverFactory, "Lp solver factory not initialized."); - STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); - - std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone(), this->lpSolverFactory->clone()); - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - template class LpMinMaxLinearEquationSolver; - template class LpMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class LpMinMaxLinearEquationSolver; - template class LpMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.h b/src/storm/solver/LpMinMaxLinearEquationSolver.h index e8a531e67..72ba6871e 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.h +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.h @@ -13,9 +13,9 @@ namespace storm { template class LpMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: - LpMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& lpSolverFactory); virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; @@ -27,20 +27,5 @@ namespace storm { std::unique_ptr> lpSolverFactory; }; - template - class LpMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - LpMinMaxLinearEquationSolverFactory(); - LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - private: - std::unique_ptr> lpSolverFactory; - }; } } diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index 20194ec6b..f7cbf4bfe 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -40,12 +40,6 @@ namespace storm { solveEquations(env, convert(this->direction), x, b); } - template - void MinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, std::vector& x, std::vector* b, uint_fast64_t n) const { - STORM_LOG_THROW(isSet(this->direction), storm::exceptions::IllegalFunctionCallException, "Optimization direction not set."); - return repeatedMultiply(env, convert(this->direction), x, b, n); - } - template void MinMaxLinearEquationSolver::setOptimizationDirection(OptimizationDirection d) { direction = convert(d); @@ -204,7 +198,7 @@ namespace storm { } else if (method == MinMaxMethod::TopologicalCuda) { result = std::make_unique>(); } else if (method == MinMaxMethod::LinearProgramming) { - result = std::make_unique>(std::make_unique>(), std::make_unique>()); + result = std::make_unique>(std::make_unique>()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -219,7 +213,7 @@ namespace storm { if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::LinearProgramming) { - result = std::make_unique>(std::make_unique>(), std::make_unique>()); + result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::Topological) { result = std::make_unique>(); } else { diff --git a/src/storm/solver/MinMaxLinearEquationSolver.h b/src/storm/solver/MinMaxLinearEquationSolver.h index 159b3e46e..00788089c 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.h +++ b/src/storm/solver/MinMaxLinearEquationSolver.h @@ -60,32 +60,6 @@ namespace storm { */ void solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; - /*! - * Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes - * x[i+1] = min/max(A*x[i] + b) until x[n], where x[0] = x. After each multiplication and addition, the - * minimal/maximal value out of each row group is selected to reduce the resulting vector to obtain the - * vector for the next iteration. Note that the matrix A has to be given upon construction time of the - * solver object. - * - * @param d For minimum, all the value of a group of rows is the taken as the minimum over all rows and as - * the maximum otherwise. - * @param x The initial vector that is to be multiplied with the matrix. This is also the output parameter, - * i.e. after the method returns, this vector will contain the computed values. - * @param b If not null, this vector is added after each multiplication. - * @param n Specifies the number of iterations the matrix-vector multiplication is performed. - * @param multiplyResult If non-null, this memory is used as a scratch memory. If given, the length of this - * vector must be equal to the number of rows of A. - * @return The result of the repeated matrix-vector multiplication as the content of the vector x. - */ - virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const = 0; - - /*! - * Behaves the same as the other variant of multiply, with the - * distinction that instead of providing the optimization direction as an argument, the internally set - * optimization direction is used. Note: this method can only be called after setting the optimization direction. - */ - virtual void repeatedMultiply(Environment const& env, std::vector& x, std::vector* b , uint_fast64_t n) const; - /*! * Sets an optimization direction to use for calls to methods that do not explicitly provide one. */ diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index 57120ef77..c2878cebb 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -18,17 +18,17 @@ namespace storm { namespace solver { template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), A(nullptr) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver() : A(nullptr) { // Intentionally left empty. } template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localA(nullptr), A(&A) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(&A) { // Intentionally left empty. } template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localA(std::make_unique>(std::move(A))), A(localA.get()) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(std::make_unique>(std::move(A))), A(localA.get()) { // Intentionally left empty. } @@ -36,124 +36,20 @@ namespace storm { void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { this->localA = nullptr; this->A = &matrix; - clearCache(); + this->clearCache(); } template void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { this->localA = std::make_unique>(std::move(matrix)); this->A = this->localA.get(); - clearCache(); - } - - template - void StandardMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - if (!linEqSolverA) { - linEqSolverA = linearEquationSolverFactory->create(env, *A, LinearEquationSolverTask::Multiply); - linEqSolverA->setCachingEnabled(true); - } - - if (!auxiliaryRowGroupVector) { - auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); - } - - this->startMeasureProgress(); - for (uint64_t i = 0; i < n; ++i) { - linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, b, *auxiliaryRowGroupVector); - std::swap(x, *auxiliaryRowGroupVector); - - // Potentially show progress. - this->showProgressIterative(i, n); - } - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - - template - void StandardMinMaxLinearEquationSolver::clearCache() const { - linEqSolverA.reset(); - auxiliaryRowVector.reset(); - MinMaxLinearEquationSolver::clearCache(); - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory() : MinMaxLinearEquationSolverFactory(), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory) : MinMaxLinearEquationSolverFactory(), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : MinMaxLinearEquationSolverFactory() { - switch (solverType) { - case EquationSolverType::Gmmxx: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Eigen: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Native: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Elimination: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Topological: linearEquationSolverFactory = std::make_unique>(); break; - } - } - - template<> - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : MinMaxLinearEquationSolverFactory() { - switch (solverType) { - case EquationSolverType::Eigen: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Elimination: linearEquationSolverFactory = std::make_unique>(); break; - default: - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported equation solver for this data type."); - } - } - - template - std::unique_ptr> StandardMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - std::unique_ptr> result; - auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { - result = std::make_unique>(this->linearEquationSolverFactory->clone()); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The selected min max method is not supported by this solver."); - } - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - - template - GmmxxMinMaxLinearEquationSolverFactory::GmmxxMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Gmmxx) { - // Intentionally left empty. - } - - template - EigenMinMaxLinearEquationSolverFactory::EigenMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Eigen) { - // Intentionally left empty. - } - - template - NativeMinMaxLinearEquationSolverFactory::NativeMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Native) { - // Intentionally left empty. - } - - template - EliminationMinMaxLinearEquationSolverFactory::EliminationMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Elimination) { - // Intentionally left empty. + this->clearCache(); } template class StandardMinMaxLinearEquationSolver; - template class StandardMinMaxLinearEquationSolverFactory; - template class GmmxxMinMaxLinearEquationSolverFactory; - template class EigenMinMaxLinearEquationSolverFactory; - template class NativeMinMaxLinearEquationSolverFactory; - template class EliminationMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class StandardMinMaxLinearEquationSolver; - template class StandardMinMaxLinearEquationSolverFactory; - template class EigenMinMaxLinearEquationSolverFactory; - template class EliminationMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.h b/src/storm/solver/StandardMinMaxLinearEquationSolver.h index 580e89347..9e79f482b 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.h +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.h @@ -12,29 +12,17 @@ namespace storm { template class StandardMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { public: - StandardMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory); + StandardMinMaxLinearEquationSolver(); + explicit StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); + explicit StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; virtual ~StandardMinMaxLinearEquationSolver() = default; - virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; - - virtual void clearCache() const override; - protected: - // possibly cached data - mutable std::unique_ptr> linEqSolverA; - mutable std::unique_ptr> auxiliaryRowVector; // A.rowCount() entries - mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowCount() entries - - /// The factory used to obtain linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; - // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted // when the solver is destructed. std::unique_ptr> localA; @@ -44,48 +32,5 @@ namespace storm { storm::storage::SparseMatrix const* A; }; - template - class StandardMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { - public: - StandardMinMaxLinearEquationSolverFactory(); - StandardMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - protected: - std::unique_ptr> linearEquationSolverFactory; - - private: - void createLinearEquationSolverFactory() const; - }; - - template - class GmmxxMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - GmmxxMinMaxLinearEquationSolverFactory(); - }; - - template - class EigenMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - EigenMinMaxLinearEquationSolverFactory(); - }; - - template - class NativeMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - NativeMinMaxLinearEquationSolverFactory(); - }; - - template - class EliminationMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - EliminationMinMaxLinearEquationSolverFactory(); - }; - } } diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp index 839c9417f..f31d1cde3 100644 --- a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp @@ -447,25 +447,6 @@ namespace storm { return result; } - template - void TopologicalCudaMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - std::unique_ptr> multiplyResult = std::make_unique>(this->A->getRowCount()); - - // Now perform matrix-vector multiplication as long as we meet the bound of the formula. - for (uint_fast64_t i = 0; i < n; ++i) { - this->A->multiplyWithVector(x, *multiplyResult); - - // Add b if it is non-null. - if (b != nullptr) { - storm::utility::vector::addVectors(*multiplyResult, *b, *multiplyResult); - } - - // Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost - // element of the min/max operator stack. - storm::utility::vector::reduceVectorMinOrMax(dir, *multiplyResult, x, this->A->getRowGroupIndices()); - } - } - template TopologicalCudaMinMaxLinearEquationSolverFactory::TopologicalCudaMinMaxLinearEquationSolverFactory(bool trackScheduler) { // Intentionally left empty. diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h index f20f37b09..7005d9d8f 100644 --- a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h @@ -39,8 +39,6 @@ namespace storm { virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; - virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; - private: storm::storage::SparseMatrix const* A; std::unique_ptr> localA; diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h index 5a36ec9af..4c754c44e 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.h +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -56,9 +56,6 @@ namespace storm { // the pointer refers to localA. storm::storage::SparseMatrix const* A; - // An object to dispatch all multiplication operations. - NativeMultiplier multiplier; - // cached auxiliary data mutable std::unique_ptr> sortedSccDecomposition; mutable boost::optional longestSccChainSize; diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 43e080850..70c478ffd 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -14,32 +14,18 @@ namespace storm { namespace solver { template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() : localA(nullptr), A(nullptr) { + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { // Intentionally left empty. } template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(nullptr) { - this->setMatrix(A); - } - - template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(nullptr), A(nullptr) { - this->setMatrix(std::move(A)); - } - - template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& A) { - localA.reset(); - this->A = &A; - clearCache(); + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : StandardMinMaxLinearEquationSolver(A) { + // Intentionally left empty. } template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& A) { - localA = std::make_unique>(std::move(A)); - this->A = localA.get(); - clearCache(); + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : StandardMinMaxLinearEquationSolver(std::move(A)) { + // Intentionally left empty. } template @@ -59,12 +45,6 @@ namespace storm { STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(), "Provided x-vector has invalid size."); STORM_LOG_ASSERT(b.size() == this->A->getRowCount(), "Provided b-vector has invalid size."); - //std::cout << "Solving equation system with fixpoint characterization " << std::endl; - //std::cout << *this->A << std::endl; - //std::cout << storm::utility::vector::toString(b) << std::endl; - //std::cout << "Initial solution vector: " << std::endl; - //std::cout << storm::utility::vector::toString(x) << std::endl; - // For sound computations we need to increase the precision in each SCC bool needAdaptPrecision = env.solver().isForceSoundness(); @@ -307,24 +287,6 @@ namespace storm { return res; } - template - void TopologicalMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n) const { - - storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env); - - // Set up the SCC solver - if (!this->sccSolver) { - this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); - this->sccSolver->setCachingEnabled(true); - } - this->sccSolver->setMatrix(*this->A); - this->sccSolver->repeatedMultiply(sccSolverEnvironment, d, x, b, n); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - template MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { // Return the requirements of the underlying solver @@ -337,21 +299,14 @@ namespace storm { longestSccChainSize = boost::none; sccSolver.reset(); auxiliaryRowGroupVector.reset(); - MinMaxLinearEquationSolver::clearCache(); - } - - template - std::unique_ptr> TopologicalMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - return std::make_unique>(); + StandardMinMaxLinearEquationSolver::clearCache(); } // Explicitly instantiate the min max linear equation solver. template class TopologicalMinMaxLinearEquationSolver; - template class TopologicalMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class TopologicalMinMaxLinearEquationSolver; - template class TopologicalMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index 9cf3c3d11..cdbc781bc 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/StandardMinMaxLinearEquationSolver.h" #include "storm/solver/SolverSelectionOptions.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" @@ -12,18 +12,14 @@ namespace storm { namespace solver { template - class TopologicalMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { + class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: TopologicalMinMaxLinearEquationSolver(); TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); - virtual void setMatrix(storm::storage::SparseMatrix const& A) override; - virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void clearCache() const override; - virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override ; protected: @@ -44,29 +40,11 @@ namespace storm { // ... for the remaining cases (1 < scc.size() < x.size()) bool solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector& globalX, std::vector const& globalB) const; - // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted - // when the solver is destructed. - std::unique_ptr> localA; - - // A pointer to the original sparse matrix given to this solver. If the solver takes posession of the matrix - // the pointer refers to localA. - storm::storage::SparseMatrix const* A; - // cached auxiliary data mutable std::unique_ptr> sortedSccDecomposition; mutable boost::optional longestSccChainSize; mutable std::unique_ptr> sccSolver; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries }; - - template - class TopologicalMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { - public: - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - }; - } } From 66c5255d8c0a28a5055e1ebca90bedb4641059e3 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 09:46:11 +0100 Subject: [PATCH 131/647] Using multiplier in game solver --- src/storm/solver/StandardGameSolver.cpp | 20 +++++++++----------- src/storm/solver/StandardGameSolver.h | 6 +++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index bd1024a86..6140a5c15 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -159,9 +159,8 @@ namespace storm { template bool StandardGameSolver::solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { - if(!linEqSolverPlayer2Matrix) { - linEqSolverPlayer2Matrix = linearEquationSolverFactory->create(env, player2Matrix, storm::solver::LinearEquationSolverTask::Multiply); - linEqSolverPlayer2Matrix->setCachingEnabled(true); + if (!multiplierPlayer2Matrix) { + multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } if (!auxiliaryP2RowVector) { @@ -204,7 +203,7 @@ namespace storm { Status status = Status::InProgress; while (status == Status::InProgress) { - multiplyAndReduce(player1Dir, player2Dir, *currentX, &b, *linEqSolverPlayer2Matrix, multiplyResult, reducedMultiplyResult, *newX); + multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, multiplyResult, reducedMultiplyResult, *newX); // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { @@ -242,9 +241,8 @@ namespace storm { template void StandardGameSolver::repeatedMultiply(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - if(!linEqSolverPlayer2Matrix) { - linEqSolverPlayer2Matrix = linearEquationSolverFactory->create(env, player2Matrix, storm::solver::LinearEquationSolverTask::Multiply); - linEqSolverPlayer2Matrix->setCachingEnabled(true); + if (!multiplierPlayer2Matrix) { + multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } if (!auxiliaryP2RowVector) { @@ -258,7 +256,7 @@ namespace storm { std::vector& reducedMultiplyResult = *auxiliaryP2RowGroupVector; for (uint_fast64_t iteration = 0; iteration < n; ++iteration) { - multiplyAndReduce(player1Dir, player2Dir, x, b, *linEqSolverPlayer2Matrix, multiplyResult, reducedMultiplyResult, x); + multiplyAndReduce(env, player1Dir, player2Dir, x, b, *multiplierPlayer2Matrix, multiplyResult, reducedMultiplyResult, x); } if(!this->isCachingEnabled()) { @@ -267,9 +265,9 @@ namespace storm { } template - void StandardGameSolver::multiplyAndReduce(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::LinearEquationSolver const& linEqSolver, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const { + void StandardGameSolver::multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const { - linEqSolver.multiply(x, b, multiplyResult); + multiplier.multiply(env, x, b, multiplyResult); storm::utility::vector::reduceVectorMinOrMax(player2Dir, multiplyResult, p2ReducedMultiplyResult, player2Matrix.getRowGroupIndices()); @@ -404,7 +402,7 @@ namespace storm { template void StandardGameSolver::clearCache() const { - linEqSolverPlayer2Matrix.reset(); + multiplierPlayer2Matrix.reset(); auxiliaryP2RowVector.reset(); auxiliaryP2RowGroupVector.reset(); auxiliaryP1RowGroupVector.reset(); diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 336be3911..e9e8060a7 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -1,6 +1,7 @@ #pragma once #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/GameSolver.h" #include "SolverSelectionOptions.h" @@ -26,8 +27,7 @@ namespace storm { bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; // Computes p2Matrix * x + b, reduces the result w.r.t. player 2 choices, and then reduces the result w.r.t. player 1 choices. - void multiplyAndReduce(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, - storm::solver::LinearEquationSolver const& linEqSolver, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const; + void multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const; // Solves the equation system given by the two choice selections void getInducedMatrixVector(std::vector& x, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const; @@ -43,7 +43,7 @@ namespace storm { }; // possibly cached data - mutable std::unique_ptr> linEqSolverPlayer2Matrix; + mutable std::unique_ptr> multiplierPlayer2Matrix; mutable std::unique_ptr> auxiliaryP2RowVector; // player2Matrix.rowCount() entries mutable std::unique_ptr> auxiliaryP2RowGroupVector; // player2Matrix.rowGroupCount() entries mutable std::unique_ptr> auxiliaryP1RowGroupVector; // player1Matrix.rowGroupCount() entries From 50245d3d86b4786b545f33c3eeab240b7a50d5e4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 12:46:21 +0100 Subject: [PATCH 132/647] gmmm multiplier --- src/storm/solver/GmmxxMultiplier.cpp | 176 +++++++++++++++++---------- src/storm/solver/GmmxxMultiplier.h | 40 +++--- 2 files changed, 137 insertions(+), 79 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 5158d03fb..739cbdbe5 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -2,6 +2,9 @@ #include "storm/adapters/RationalNumberAdapter.h" #include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" #include "storm/utility/constants.h" #include "storm/exceptions/NotSupportedException.h" @@ -11,60 +14,113 @@ namespace storm { namespace solver { - template - GmmxxMultiplier::GmmxxMultiplier() : storm::utility::VectorHelper() { + template + GmmxxMultiplier::GmmxxMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. } - template - void GmmxxMultiplier::multAdd(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { - if (this->parallelize()) { - multAddParallel(matrix, x, b, result); - } else { - if (b) { - gmm::mult_add(matrix, x, *b, result); + template + void GmmxxMultiplier::initialize() const { + if (gmmMatrix.nrows() == 0) { + gmmMatrix = std::move(*storm::adapters::GmmxxAdapter().toGmmxxSparseMatrix(this->matrix)); + } + } + + template + void GmmxxMultiplier::clearCache() const { + gmmMatrix = gmm::csr_matrix(); + Multiplier::clearCache(); + } + + template + bool GmmxxMultiplier::parallelize(Environment const& env) const { +#ifdef STORM_HAVE_INTELTBB + return storm::settings::getModule().isUseIntelTbbSet(); +#else + return false; +#endif + } + + template + void GmmxxMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + initialize(); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); } else { - gmm::mult(matrix, x, result); + this->cachedVector = std::make_unique>(x.size()); } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddParallel(x, b, *target); + } else { + multAdd(x, b, *target); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); } } - template - void GmmxxMultiplier::multAddGaussSeidelBackward(gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b) const { - STORM_LOG_ASSERT(matrix.nr == matrix.nc, "Expecting square matrix."); + template + void GmmxxMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + initialize(); + STORM_LOG_ASSERT(gmmMatrix.nr == gmmMatrix.nc, "Expecting square matrix."); if (b) { - gmm::mult_add_by_row_bwd(matrix, x, *b, x, gmm::abstract_dense()); + gmm::mult_add_by_row_bwd(gmmMatrix, x, *b, x, gmm::abstract_dense()); } else { - gmm::mult_by_row_bwd(matrix, x, x, gmm::abstract_dense()); + gmm::mult_by_row_bwd(gmmMatrix, x, x, gmm::abstract_dense()); } } - template - void GmmxxMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - std::vector* target = &result; - std::unique_ptr> temporary; + template + void GmmxxMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + initialize(); + std::vector* target = &result; if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAddReduce'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); } - - if (this->parallelize()) { - multAddReduceParallel(dir, rowGroupIndices, matrix, x, b, *target, choices); + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); } else { - multAddReduceHelper(dir, rowGroupIndices, matrix, x, b, *target, choices); + multAddReduceHelper(dir, rowGroupIndices, x, b, *target, choices); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); } } - template - void GmmxxMultiplier::multAddReduceGaussSeidel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices) const { - multAddReduceHelper(dir, rowGroupIndices, matrix, x, b, x, choices); + template + void GmmxxMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + initialize(); + multAddReduceHelper(dir, rowGroupIndices, x, b, x, choices); } - template - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - typedef std::vector VectorType; - typedef gmm::csr_matrix MatrixType; + template + ValueType GmmxxMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { + initialize(); + return vect_sp(gmm::mat_const_row(gmmMatrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()) + offset; + } + + template + void GmmxxMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + if (b) { + gmm::mult_add(gmmMatrix, x, *b, result); + } else { + gmm::mult(gmmMatrix, x, result); + } + } + + template + void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + typedef std::vector VectorType; + typedef gmm::csr_matrix MatrixType; typename gmm::linalg_traits::const_iterator add_it, add_ite; if (b) { @@ -72,7 +128,7 @@ namespace storm { add_ite = gmm::vect_begin(*b) - 1; } typename gmm::linalg_traits::iterator target_it = gmm::vect_end(result) - 1; - typename gmm::linalg_traits::const_row_iterator itr = mat_row_const_end(matrix) - 1; + typename gmm::linalg_traits::const_row_iterator itr = mat_row_const_end(gmmMatrix) - 1; typename std::vector::iterator choice_it; if (choices) { choice_it = choices->end() - 1; @@ -84,7 +140,7 @@ namespace storm { *choice_it = 0; } - T currentValue = storm::utility::zero(); + ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. if (*row_group_it != *(row_group_it + 1)) { @@ -103,7 +159,7 @@ namespace storm { --itr; for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, --itr, --add_it) { - T newValue = b ? *add_it : storm::utility::zero(); + ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); if (choices) { @@ -127,29 +183,29 @@ namespace storm { } template<> - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type."); } - template - void GmmxxMultiplier::multAddParallel(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { + template + void GmmxxMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB if (b) { - gmm::mult_add_parallel(matrix, x, *b, result); + gmm::mult_add_parallel(x, *b, result); } else { - gmm::mult_parallel(matrix, x, result); + gmm::mult_parallel(x, result); } #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAdd(matrix, x, b, result); + multAdd(x, b, result); #endif } #ifdef STORM_HAVE_INTELTBB - template + template class TbbMultAddReduceFunctor { public: - TbbMultAddReduceFunctor(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { + TbbMultAddReduceFunctor(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { // Intentionally left empty. } @@ -158,7 +214,7 @@ namespace storm { auto groupIte = rowGroupIndices.begin() + range.end(); auto itr = mat_row_const_begin(matrix) + *groupIt; - typename std::vector::const_iterator bIt; + typename std::vector::const_iterator bIt; if (b) { bIt = b->begin() + *groupIt; } @@ -174,7 +230,7 @@ namespace storm { *choiceIt = 0; } - T currentValue = storm::utility::zero(); + ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. if (*groupIt != *(groupIt + 1)) { @@ -186,7 +242,7 @@ namespace storm { ++itr; for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr) { - T newValue = vect_sp(gmm::linalg_traits>::row(itr), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); + ValueType newValue = vect_sp(gmm::linalg_traits>::row(itr), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); if (b) { newValue += *bIt; ++bIt; @@ -208,37 +264,29 @@ namespace storm { private: storm::solver::OptimizationDirection dir; std::vector const& rowGroupIndices; - gmm::csr_matrix const& matrix; - std::vector const& x; - std::vector const* b; - std::vector& result; + gmm::csr_matrix const& matrix; + std::vector const& x; + std::vector const* b; + std::vector& result; std::vector* choices; }; #endif - template - void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, matrix, x, b, result, choices)); + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, this->gmmMatrix, x, b, result, choices)); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAddReduce(dir, rowGroupIndices, matrix, x, b, result, choices); + multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices); #endif } template<> - void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } - template - T GmmxxMultiplier::multiplyRow(gmm::csr_matrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const { - return vect_sp(gmm::mat_const_row(matrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); - } - - - - template class GmmxxMultiplier; #ifdef STORM_HAVE_CARL diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index aebdb069d..9ea4089b9 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -1,32 +1,42 @@ #pragma once -#include "storm/utility/VectorHelper.h" +#include "storm/solver/Multiplier.h" #include "storm/adapters/GmmxxAdapter.h" #include "storm-config.h" namespace storm { + + namespace storage { + template + class SparseMatrix; + } + namespace solver { - template - class GmmxxMultiplier : public storm::utility::VectorHelper { + template + class GmmxxMultiplier : public Multiplier { public: - GmmxxMultiplier(); + GmmxxMultiplier(storm::storage::SparseMatrix const& matrix); - void multAdd(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddGaussSeidelBackward(gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b) const; + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; + virtual void clearCache() const override; + private: + void initialize() const; - void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduceGaussSeidel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + bool parallelize(Environment const& env) const; - void multAddParallel(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - - T multiplyRow(gmm::csr_matrix const& matrix, uint64_t const& rowIndex, std::vector const& x) const; - - private: - void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + + mutable gmm::csr_matrix gmmMatrix; }; } From 5ff20b55e18ef0bce2c74ef280926c1de48776c4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 12:46:52 +0100 Subject: [PATCH 133/647] misc compilation issues --- src/storm/solver/Multiplier.cpp | 12 ++++++------ .../solver/NativeLinearEquationSolver.cpp | 18 +++++++----------- src/storm/solver/NativeLinearEquationSolver.h | 7 ------- src/storm/solver/NativeMultiplier.cpp | 4 +--- src/storm/solver/NativeMultiplier.h | 2 -- src/storm/solver/SolveGoal.h | 9 ++++----- 6 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index e48b29df2..b2b6dfd5e 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -10,6 +10,7 @@ #include "storm/utility/macros.h" #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/NativeMultiplier.h" +#include "storm/solver/GmmxxMultiplier.h" #include "storm/environment/solver/MultiplierEnvironment.h" namespace storm { @@ -26,12 +27,12 @@ namespace storm { } template - void Multiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) { + void Multiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { multiplyAndReduce(env, dir, this->matrix.getRowGroupIndices(), x, b, result, choices); } template - void Multiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices = nullptr) { + void Multiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices) const { multiplyAndReduceGaussSeidel(env, dir, this->matrix.getRowGroupIndices(), x, b, choices); } @@ -43,9 +44,9 @@ namespace storm { } template - void Multiplier::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, uint64_t n) const { + void Multiplier::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const { for (uint64_t i = 0; i < n; ++i) { - multiplyAndReduce(env, dir, rowGroupIndices, x, b, x); + multiplyAndReduce(env, dir, x, b, x); } } @@ -53,8 +54,7 @@ namespace storm { std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { switch (env.solver().multiplier().getType()) { case MultiplierType::Gmmxx: - //return std::make_unique>(matrix); - STORM_PRINT_AND_LOG("gmm mult not yet supported"); + return std::make_unique>(matrix); case MultiplierType::Native: return std::make_unique>(matrix); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 47f07f6f8..c524513f2 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -301,11 +301,7 @@ namespace storm { } template - typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, storm::solver::Multiplier const& multiplier, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { - - if (!this->multiplier) { - this->multiplier = storm::solver::MultiplierFactory().create(env, *A); - } + typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; @@ -317,9 +313,9 @@ namespace storm { while (!converged && !terminate && iterations < maxIterations) { if (useGaussSeidelMultiplication) { *newX = *currentX; - multiplier.multiplyGaussSeidel(env, *newX, &b); + this->multiplier->multiplyGaussSeidel(env, *newX, &b); } else { - multiplier.multiply(env, *currentX, &b, *newX); + this->multiplier->multiply(env, *currentX, &b, *newX); } // Now check for termination. @@ -369,7 +365,7 @@ namespace storm { // Forward call to power iteration implementation. this->startMeasureProgress(); ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); - PowerIterationResult result = this->performPowerIteration(env, currentX, newX, b, *this->multiplier, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); + PowerIterationResult result = this->performPowerIteration(env, currentX, newX, b, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); // Swap the result in place. if (currentX == this->cachedRowVector.get()) { @@ -596,7 +592,7 @@ namespace storm { void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { xi = multiplier.multiplyRow(row, x, bi); - yi = multiplier.multiplyRow(row, y, storm::utility::zero()); + yi = multiplier.multiplyRow(row, y, storm::utility::zero()); /* xi = bi; yi = storm::utility::zero(); @@ -873,7 +869,7 @@ namespace storm { impreciseSolver.startMeasureProgress(); while (status == SolverStatus::InProgress && overallIterations < maxIter) { // Perform value iteration with the current precision. - typename NativeLinearEquationSolver::PowerIterationResult result = impreciseSolver.performPowerIteration(currentX, newX, b, storm::utility::convertNumber(precision), relative, SolverGuarantee::LessOrEqual, overallIterations, maxIter, multiplicationStyle); + typename NativeLinearEquationSolver::PowerIterationResult result = impreciseSolver.performPowerIteration(env, currentX, newX, b, storm::utility::convertNumber(precision), relative, SolverGuarantee::LessOrEqual, overallIterations, maxIter, multiplicationStyle); // At this point, the result of the imprecise value iteration is stored in the (imprecise) current x. @@ -1143,7 +1139,7 @@ namespace storm { } template - LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env) const { LinearEquationSolverRequirements requirements; if (env.solver().native().isForceBoundsSet()) { requirements.requireBounds(); diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 7640f19eb..46ba3628e 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -30,13 +30,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual bool supportsGaussSeidelMultiplication() const override; - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const override; diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index 5fe7dde67..defe462f4 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -32,7 +32,6 @@ namespace storm { template void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { - STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { @@ -53,13 +52,12 @@ namespace storm { } template - void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector const& x, std::vector const* b) const { + void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { this->matrix.multiplyWithVectorBackward(x, x, b); } template void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - STORM_LOG_ASSERT(getMultiplicationStyle() == MultiplicationStyle::Regular, "Unexpected Multiplicationstyle."); std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index e91dc519e..e1cc4d01a 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -17,8 +17,6 @@ namespace storm { public: NativeMultiplier(storm::storage::SparseMatrix const& matrix); - virtual MultiplicationStyle getMultiplicationStyle() const override; - virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; diff --git a/src/storm/solver/SolveGoal.h b/src/storm/solver/SolveGoal.h index d93b86b91..9bd6f7e73 100644 --- a/src/storm/solver/SolveGoal.h +++ b/src/storm/solver/SolveGoal.h @@ -7,7 +7,6 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/logic/ComparisonType.h" #include "storm/storage/BitVector.h" -#include "storm/solver/LinearEquationSolverTask.h" #include "storm/solver/LinearEquationSolver.h" #include "storm/solver/MinMaxLinearEquationSolver.h" @@ -111,8 +110,8 @@ namespace storm { } template - std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix, storm::solver::LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) { - std::unique_ptr> solver = factory.create(env, std::forward(matrix), task); + std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix) { + std::unique_ptr> solver = factory.create(env, std::forward(matrix)); if (goal.isBounded()) { solver->setTerminationCondition(std::make_unique>(goal.relevantValues(), goal.boundIsStrict(), goal.thresholdValue(), goal.minimize())); } @@ -120,8 +119,8 @@ namespace storm { } template - std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix, storm::solver::LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) { - std::unique_ptr> solver = factory.create(env, std::forward(matrix), task); + std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix) { + std::unique_ptr> solver = factory.create(env, std::forward(matrix)); return solver; } From 02d2cf07b69e1c683a2213d44a7bb5f7343505be Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 12:47:08 +0100 Subject: [PATCH 134/647] using multiplier in PLA --- ...SparseDtmcParameterLiftingModelChecker.cpp | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp index dbbd9d7c2..6c2f15d21 100644 --- a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -10,7 +10,8 @@ #include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/solver/StandardMinMaxLinearEquationSolver.h" +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/utility/vector.h" #include "storm/utility/graph.h" #include "storm/utility/NumberTraits.h" @@ -249,49 +250,50 @@ namespace storm { parameterLifter->specifyRegion(region, dirForParameters); - auto solver = solverFactory->create(env, parameterLifter->getMatrix()); - solver->setHasUniqueSolution(); - if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); - if (upperResultBound) { - solver->setUpperBound(upperResultBound.get()); - } else if (solvingRequiresUpperRewardBounds) { - // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). - std::vector oneStepProbs; - oneStepProbs.reserve(parameterLifter->getMatrix().getRowCount()); - for (uint64_t row = 0; row < parameterLifter->getMatrix().getRowCount(); ++row) { - oneStepProbs.push_back(storm::utility::one() - parameterLifter->getMatrix().getRowSum(row)); - } - if (dirForParameters == storm::OptimizationDirection::Minimize) { - storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer dsmpi(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); - solver->setUpperBounds(dsmpi.computeUpperBounds()); - } else { - storm::modelchecker::helper::BaierUpperRewardBoundsComputer baier(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); - solver->setUpperBound(baier.computeUpperBound()); - } - } - if (!stepBound) solver->setTrackScheduler(true); - if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setInitialScheduler(std::move(minSchedChoices.get())); - if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setInitialScheduler(std::move(maxSchedChoices.get())); - if (this->currentCheckTask->isBoundSet() && solver->hasInitialScheduler()) { - // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). - std::unique_ptr> termCond; - storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); - if (storm::solver::minimize(dirForParameters)) { - // Terminate if the value for ALL relevant states is already below the threshold - termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), false); - } else { - // Terminate if the value for ALL relevant states is already above the threshold - termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); - } - solver->setTerminationCondition(std::move(termCond)); - } - - // Invoke the solver if (stepBound) { assert(*stepBound > 0); x = std::vector(maybeStates.getNumberOfSetBits(), storm::utility::zero()); - solver->repeatedMultiply(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(); + multiplier->repeatedMultiply(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); } else { + auto solver = solverFactory->create(env, parameterLifter->getMatrix()); + solver->setHasUniqueSolution(); + if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); + if (upperResultBound) { + solver->setUpperBound(upperResultBound.get()); + } else if (solvingRequiresUpperRewardBounds) { + // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). + std::vector oneStepProbs; + oneStepProbs.reserve(parameterLifter->getMatrix().getRowCount()); + for (uint64_t row = 0; row < parameterLifter->getMatrix().getRowCount(); ++row) { + oneStepProbs.push_back(storm::utility::one() - parameterLifter->getMatrix().getRowSum(row)); + } + if (dirForParameters == storm::OptimizationDirection::Minimize) { + storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer dsmpi(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); + solver->setUpperBounds(dsmpi.computeUpperBounds()); + } else { + storm::modelchecker::helper::BaierUpperRewardBoundsComputer baier(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); + solver->setUpperBound(baier.computeUpperBound()); + } + } + solver->setTrackScheduler(true); + if (storm::solver::minimize(dirForParameters) && minSchedChoices) solver->setInitialScheduler(std::move(minSchedChoices.get())); + if (storm::solver::maximize(dirForParameters) && maxSchedChoices) solver->setInitialScheduler(std::move(maxSchedChoices.get())); + if (this->currentCheckTask->isBoundSet() && solver->hasInitialScheduler()) { + // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). + std::unique_ptr> termCond; + storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); + if (storm::solver::minimize(dirForParameters)) { + // Terminate if the value for ALL relevant states is already below the threshold + termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), false); + } else { + // Terminate if the value for ALL relevant states is already above the threshold + termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); + } + solver->setTerminationCondition(std::move(termCond)); + } + + // Invoke the solver x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero()); solver->solveEquations(env, dirForParameters, x, parameterLifter->getVector()); if(storm::solver::minimize(dirForParameters)) { From 5be8de293ceac6b97aa54d053496b734b3ee601e Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 16:27:56 +0100 Subject: [PATCH 135/647] fixes when tbb is enabled --- src/storm/solver/GmmxxMultiplier.cpp | 4 ++-- src/storm/solver/NativeMultiplier.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 739cbdbe5..759bdba35 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -191,9 +191,9 @@ namespace storm { void GmmxxMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB if (b) { - gmm::mult_add_parallel(x, *b, result); + gmm::mult_add_parallel(gmmMatrix, x, *b, result); } else { - gmm::mult_parallel(x, result); + gmm::mult_parallel(gmmMatrix, x, result); } #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index defe462f4..3f84a4a8d 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -100,7 +100,7 @@ namespace storm { template void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB - matrix.multiplyWithVectorParallel(x, result, b); + this->matrix.multiplyWithVectorParallel(x, result, b); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); multAdd(x, b, result); @@ -110,7 +110,7 @@ namespace storm { template void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); + this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); multAddReduce(dir, rowGroupIndices, x, b, result, choices); From 69a27ddad6afdddd5fb7b3c11bee171d20d1323b Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 16:28:38 +0100 Subject: [PATCH 136/647] fixed compiling storm-pars --- .../region/SparseDtmcParameterLiftingModelChecker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp index 6c2f15d21..c27d7114e 100644 --- a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -253,8 +253,8 @@ namespace storm { if (stepBound) { assert(*stepBound > 0); x = std::vector(maybeStates.getNumberOfSetBits(), storm::utility::zero()); - auto multiplier = storm::solver::MultiplierFactory().create(); - multiplier->repeatedMultiply(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, parameterLifter->getMatrix()); + multiplier->repeatedMultiplyAndReduce(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); } else { auto solver = solverFactory->create(env, parameterLifter->getMatrix()); solver->setHasUniqueSolution(); From 4690ac1fafd6cd5726d7f325f7fc2e8b4039562f Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Feb 2018 16:57:16 +0100 Subject: [PATCH 137/647] Adding MultiplierTest --- .../storm/solver/LinearEquationSolverTest.cpp | 33 +---- .../solver/MinMaxLinearEquationSolverTest.cpp | 62 +++------ src/test/storm/solver/MultiplierTest.cpp | 123 ++++++++++++++++++ 3 files changed, 142 insertions(+), 76 deletions(-) create mode 100644 src/test/storm/solver/MultiplierTest.cpp diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index f1ef97220..3b5386c1f 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -32,14 +32,14 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::Power); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundPower); env.solver().native().setRelativeTerminationCriterion(false); env.solver().native().setPrecision(storm::utility::convertNumber("1e-6")); return env; } }; - class NativeDoubleQuickSoundPowerEnvironment { + class NativeDoubleIntervalIterationEnvironment { public: typedef double ValueType; static const bool isExact = false; @@ -47,7 +47,7 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::QuickPower); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::IntervalIteration); env.solver().native().setRelativeTerminationCriterion(false); env.solver().native().setPrecision(storm::utility::convertNumber("1e-6")); return env; @@ -294,7 +294,7 @@ namespace { typedef ::testing::Types< NativeDoublePowerEnvironment, NativeDoubleSoundPowerEnvironment, - NativeDoubleQuickSoundPowerEnvironment, + NativeDoubleIntervalIterationEnvironment, NativeDoubleJacobiEnvironment, NativeDoubleGaussSeidelEnvironment, NativeDoubleSorEnvironment, @@ -353,29 +353,4 @@ namespace { EXPECT_NEAR(x[1], this->parseNumber("457/9"), this->precision()); EXPECT_NEAR(x[2], this->parseNumber("875/18"), this->precision()); } - - TYPED_TEST(LinearEquationSolverTest, MatrixVectorMultiplication) { - typedef typename TestFixture::ValueType ValueType; - ASSERT_NO_THROW(storm::storage::SparseMatrixBuilder builder); - storm::storage::SparseMatrixBuilder builder; - ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(0, 4, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(1, 4, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(2, 3, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(2, 4, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(3, 4, this->parseNumber("1"))); - ASSERT_NO_THROW(builder.addNextValue(4, 4, this->parseNumber("1"))); - - storm::storage::SparseMatrix A; - ASSERT_NO_THROW(A = builder.build()); - - std::vector x(5); - x[4] = this->parseNumber("1"); - - auto factory = storm::solver::GeneralLinearEquationSolverFactory(); - auto solver = factory.create(this->env(), A); - ASSERT_NO_THROW(solver->repeatedMultiply(x, nullptr, 4)); - EXPECT_NEAR(x[0], this->parseNumber("1"), this->precision()); - } } \ No newline at end of file diff --git a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp index e34cf6a31..707b6ba4c 100644 --- a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp +++ b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp @@ -29,7 +29,20 @@ namespace { static const bool isExact = false; static storm::Environment createEnvironment() { storm::Environment env; - env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::SoundValueIteration); + env.solver().setForceSoundness(true); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); + return env; + } + }; + + class DoubleIntervalIterationEnvironment { + public: + typedef double ValueType; + static const bool isExact = false; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::IntervalIteration); env.solver().setForceSoundness(true); env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); return env; @@ -110,6 +123,7 @@ namespace { typedef ::testing::Types< DoubleViEnvironment, DoubleSoundViEnvironment, + DoubleIntervalIterationEnvironment, DoubleTopologicalViEnvironment, DoubleTopologicalCudaViEnvironment, DoublePIEnvironment, @@ -145,52 +159,6 @@ namespace { ASSERT_NO_THROW(solver->solveEquations(this->env(), storm::OptimizationDirection::Maximize, x, b)); EXPECT_NEAR(x[0], this->parseNumber("0.99"), this->precision()); } - - TYPED_TEST(MinMaxLinearEquationSolverTest, MatrixVectorMultiplication) { - typedef typename TestFixture::ValueType ValueType; - - storm::storage::SparseMatrixBuilder builder(0, 0, 0, false, true); - ASSERT_NO_THROW(builder.newRowGroup(0)); - ASSERT_NO_THROW(builder.addNextValue(0, 0, this->parseNumber("0.9"))); - ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("0.099"))); - ASSERT_NO_THROW(builder.addNextValue(0, 2, this->parseNumber("0.001"))); - ASSERT_NO_THROW(builder.addNextValue(1, 1, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("0.5"))); - ASSERT_NO_THROW(builder.newRowGroup(2)); - ASSERT_NO_THROW(builder.addNextValue(2, 1, this->parseNumber("1"))); - ASSERT_NO_THROW(builder.newRowGroup(3)); - ASSERT_NO_THROW(builder.addNextValue(3, 2, this->parseNumber("1"))); - - storm::storage::SparseMatrix A; - ASSERT_NO_THROW(A = builder.build()); - - std::vector initialX = {this->parseNumber("0"), this->parseNumber("1"), this->parseNumber("0")}; - std::vector x; - - auto factory = storm::solver::GeneralMinMaxLinearEquationSolverFactory(); - auto solver = factory.create(this->env(), A); - - x = initialX; - ASSERT_NO_THROW(solver->repeatedMultiply(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 1)); - EXPECT_NEAR(x[0], this->parseNumber("0.099"), this->precision()); - - x = initialX; - ASSERT_NO_THROW(solver->repeatedMultiply(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 2)); - EXPECT_NEAR(x[0], this->parseNumber("0.1881"), this->precision()); - - x = initialX; - ASSERT_NO_THROW(solver->repeatedMultiply(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 20)); - EXPECT_NEAR(x[0], this->parseNumber("0.5"), this->precision()); - - x = initialX; - ASSERT_NO_THROW(solver->repeatedMultiply(this->env(), storm::OptimizationDirection::Maximize, x, nullptr, 1)); - EXPECT_NEAR(x[0], this->parseNumber("0.5"), this->precision()); - - x = initialX; - ASSERT_NO_THROW(solver->repeatedMultiply(this->env(), storm::OptimizationDirection::Maximize, x, nullptr, 20)); - EXPECT_NEAR(x[0], this->parseNumber("0.923808265834023387639"), this->precision()); - } - } diff --git a/src/test/storm/solver/MultiplierTest.cpp b/src/test/storm/solver/MultiplierTest.cpp new file mode 100644 index 000000000..62a1a7c0c --- /dev/null +++ b/src/test/storm/solver/MultiplierTest.cpp @@ -0,0 +1,123 @@ +#include "gtest/gtest.h" +#include "storm-config.h" +#include "test/storm_gtest.h" + +#include "storm/storage/SparseMatrix.h" +#include "storm/solver/Multiplier.h" +#include "storm/environment/solver/MultiplierEnvironment.h" + +#include "storm/utility/vector.h" +namespace { + + class NativeEnvironment { + public: + typedef double ValueType; + static const bool isExact = false; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().multiplier().setType(storm::solver::MultiplierType::Native); + return env; + } + }; + + class GmmxxEnvironment { + public: + typedef double ValueType; + static const bool isExact = false; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().multiplier().setType(storm::solver::MultiplierType::Gmmxx); + return env; + } + }; + + template + class MultiplierTest : public ::testing::Test { + public: + typedef typename TestType::ValueType ValueType; + MultiplierTest() : _environment(TestType::createEnvironment()) {} + storm::Environment const& env() const { return _environment; } + ValueType precision() const { return TestType::isExact ? parseNumber("0") : parseNumber("1e-15");} + ValueType parseNumber(std::string const& input) const { return storm::utility::convertNumber(input);} + private: + storm::Environment _environment; + }; + + typedef ::testing::Types< + NativeEnvironment, + GmmxxEnvironment + > TestingTypes; + + TYPED_TEST_CASE(MultiplierTest, TestingTypes); + + TYPED_TEST(MultiplierTest, repeatedMultiplyTest) { + typedef typename TestFixture::ValueType ValueType; + ASSERT_NO_THROW(storm::storage::SparseMatrixBuilder builder); + storm::storage::SparseMatrixBuilder builder; + ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(0, 4, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(1, 4, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(2, 3, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(2, 4, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(3, 4, this->parseNumber("1"))); + ASSERT_NO_THROW(builder.addNextValue(4, 4, this->parseNumber("1"))); + + storm::storage::SparseMatrix A; + ASSERT_NO_THROW(A = builder.build()); + + std::vector x(5); + x[4] = this->parseNumber("1"); + + auto factory = storm::solver::MultiplierFactory(); + auto multiplier = factory.create(this->env(), A); + ASSERT_NO_THROW(multiplier->repeatedMultiply(this->env(), x, nullptr, 4)); + EXPECT_NEAR(x[0], this->parseNumber("1"), this->precision()); + } + + TYPED_TEST(MultiplierTest, repeatedMultiplyAndReduceTest) { + typedef typename TestFixture::ValueType ValueType; + + storm::storage::SparseMatrixBuilder builder(0, 0, 0, false, true); + ASSERT_NO_THROW(builder.newRowGroup(0)); + ASSERT_NO_THROW(builder.addNextValue(0, 0, this->parseNumber("0.9"))); + ASSERT_NO_THROW(builder.addNextValue(0, 1, this->parseNumber("0.099"))); + ASSERT_NO_THROW(builder.addNextValue(0, 2, this->parseNumber("0.001"))); + ASSERT_NO_THROW(builder.addNextValue(1, 1, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.addNextValue(1, 2, this->parseNumber("0.5"))); + ASSERT_NO_THROW(builder.newRowGroup(2)); + ASSERT_NO_THROW(builder.addNextValue(2, 1, this->parseNumber("1"))); + ASSERT_NO_THROW(builder.newRowGroup(3)); + ASSERT_NO_THROW(builder.addNextValue(3, 2, this->parseNumber("1"))); + + storm::storage::SparseMatrix A; + ASSERT_NO_THROW(A = builder.build()); + + std::vector initialX = {this->parseNumber("0"), this->parseNumber("1"), this->parseNumber("0")}; + std::vector x; + + auto factory = storm::solver::MultiplierFactory(); + auto multiplier = factory.create(this->env(), A); + + x = initialX; + ASSERT_NO_THROW(multiplier->repeatedMultiplyAndReduce(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 1)); + EXPECT_NEAR(x[0], this->parseNumber("0.099"), this->precision()); + + x = initialX; + ASSERT_NO_THROW(multiplier->repeatedMultiplyAndReduce(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 2)); + EXPECT_NEAR(x[0], this->parseNumber("0.1881"), this->precision()); + + x = initialX; + ASSERT_NO_THROW(multiplier->repeatedMultiplyAndReduce(this->env(), storm::OptimizationDirection::Minimize, x, nullptr, 20)); + EXPECT_NEAR(x[0], this->parseNumber("0.5"), this->precision()); + + x = initialX; + ASSERT_NO_THROW(multiplier->repeatedMultiplyAndReduce(this->env(), storm::OptimizationDirection::Maximize, x, nullptr, 1)); + EXPECT_NEAR(x[0], this->parseNumber("0.5"), this->precision()); + + x = initialX; + ASSERT_NO_THROW(multiplier->repeatedMultiplyAndReduce(this->env(), storm::OptimizationDirection::Maximize, x, nullptr, 20)); + EXPECT_NEAR(x[0], this->parseNumber("0.923808265834023387639"), this->precision()); + } + +} \ No newline at end of file From ba96fde3c980396879bee868f119b3ee88b6505a Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 10:27:11 +0100 Subject: [PATCH 138/647] fixed sum that was too much nested --- .../SparseCbAchievabilityQuery.cpp | 23 +++++---------- src/storm/utility/ExpressionHelper.cpp | 29 +++++++++++++++++++ src/storm/utility/ExpressionHelper.h | 28 ++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 src/storm/utility/ExpressionHelper.cpp create mode 100644 src/storm/utility/ExpressionHelper.h diff --git a/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp b/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp index 710fd92d3..5a65bd502 100644 --- a/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp +++ b/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp @@ -9,6 +9,7 @@ #include "storm/utility/vector.h" #include "storm/utility/solver.h" #include "storm/utility/Stopwatch.h" +#include "storm/utility/ExpressionHelper.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -99,11 +100,13 @@ namespace storm { for (auto& var : expectedChoiceVariables) { solver->add(var.getExpression() >= zero); } - storm::expressions::Expression bottomStateSum = zero; + std::vector bottomStateVarsAsExpression; + bottomStateVarsAsExpression.reserve(bottomStateVariables.size()); for (auto& var : bottomStateVariables) { solver->add(var.getExpression() >= zero); - bottomStateSum = bottomStateSum + var.getExpression(); + bottomStateVarsAsExpression.push_back(var.getExpression()); } + auto bottomStateSum = storm::utility::ExpressionHelper(this->expressionManager).sum(std::move(bottomStateVarsAsExpression)); solver->add(bottomStateSum == one); // assert that the "incoming" value of each state equals the "outgoing" value @@ -138,25 +141,15 @@ namespace storm { STORM_LOG_THROW(obj.formula->hasBound(), storm::exceptions::InvalidOperationException, "Invoked achievability query but no bound was specified for at least one objective."); STORM_LOG_THROW(obj.formula->asRewardOperatorFormula().hasRewardModelName(), storm::exceptions::InvalidOperationException, "Expected reward operator with a reward model name. Got " << *obj.formula << " instead."); std::vector rewards = getActionBasedExpectedRewards(obj.formula->asRewardOperatorFormula().getRewardModelName()); + + // Get the sum of all objective values std::vector objectiveValues; for (uint_fast64_t choice = 0; choice < rewards.size(); ++choice) { if (!storm::utility::isZero(rewards[choice])) { objectiveValues.push_back(this->expressionManager->rational(rewards[choice]) * expectedChoiceVariables[choice].getExpression()); } } - - // Get the sum of all objective values - // As the sum can potentially have many summands, we want to make sure that the formula tree is (roughly balanced) - auto vIt = objectiveValues.begin(); - while (objectiveValues.size() > 1) { - if (vIt == objectiveValues.end() || vIt == objectiveValues.end() - 1) { - vIt = objectiveValues.begin(); - } - *vIt = *vIt + objectiveValues.back(); - objectiveValues.pop_back(); - ++vIt; - } - storm::expressions::Expression objValue = objectiveValues.empty() ? zero : objectiveValues.front(); + auto objValue = storm::utility::ExpressionHelper(this->expressionManager).sum(std::move(objectiveValues)); // We need to actually evaluate the threshold as rational number. Otherwise a threshold like '<=16/9' might be considered as 1 due to integer division storm::expressions::Expression threshold = this->expressionManager->rational(obj.formula->getThreshold().evaluateAsRational()); diff --git a/src/storm/utility/ExpressionHelper.cpp b/src/storm/utility/ExpressionHelper.cpp new file mode 100644 index 000000000..219d6e39c --- /dev/null +++ b/src/storm/utility/ExpressionHelper.cpp @@ -0,0 +1,29 @@ +#include "storm/utility/ExpressionHelper.h" +#include "storm/utility/constants.h" + +namespace storm { + namespace utility { + + ExpressionHelper::ExpressionHelper(std::shared_ptr const& expressionManager) : manager(expressionManager) { + // Intentionally left empty + } + + storm::expressions::Expression ExpressionHelper::sum(std::vector&& summands) const { + if (summands.empty()) { + return manager->rational(storm::utility::zero()); + } + // As the sum can potentially have many summands, we want to make sure that the formula tree is (roughly balanced) + auto it = summands.begin(); + while (summands.size() > 1) { + if (it == summands.end() || it == summands.end() - 1) { + it = summands.begin(); + } + *it = *it + summands.back(); + summands.pop_back(); + ++it; + } + return summands.front(); + } + + } +} \ No newline at end of file diff --git a/src/storm/utility/ExpressionHelper.h b/src/storm/utility/ExpressionHelper.h new file mode 100644 index 000000000..6c171a286 --- /dev/null +++ b/src/storm/utility/ExpressionHelper.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/expressions/ExpressionManager.h" + +namespace storm { + namespace utility { + + class ExpressionHelper { + + public: + ExpressionHelper(std::shared_ptr const& expressionManager); + + /*! + * Creates an expression that is the sum over all the given summands. + */ + storm::expressions::Expression sum(std::vector&& summands) const; + + private: + + std::shared_ptr manager; + }; + + + } +} \ No newline at end of file From 51884895c81f07f744f58ecc0487b5fe560ba324 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 10:28:04 +0100 Subject: [PATCH 139/647] Removed linear equation solver factories in model checkers --- .../MILPMinimalLabelSetGenerator.h | 2 +- .../SMTMinimalLabelSetGenerator.h | 4 +- ...tractAbstractionRefinementModelChecker.cpp | 12 +- .../csl/HybridCtmcCslModelChecker.cpp | 21 ++- .../csl/HybridCtmcCslModelChecker.h | 3 - .../csl/SparseCtmcCslModelChecker.cpp | 25 ++-- .../csl/SparseCtmcCslModelChecker.h | 3 - .../SparseMarkovAutomatonCslModelChecker.cpp | 19 +-- .../SparseMarkovAutomatonCslModelChecker.h | 4 - .../csl/helper/HybridCtmcCslHelper.cpp | 102 +++++++------- .../csl/helper/HybridCtmcCslHelper.h | 20 +-- .../csl/helper/SparseCtmcCslHelper.cpp | 128 +++++++++--------- .../csl/helper/SparseCtmcCslHelper.h | 30 ++-- .../helper/SparseMarkovAutomatonCslHelper.cpp | 77 ++++++----- .../helper/SparseMarkovAutomatonCslHelper.h | 22 +-- .../prctl/HybridDtmcPrctlModelChecker.cpp | 23 ++-- .../prctl/HybridDtmcPrctlModelChecker.h | 4 - .../prctl/HybridMdpPrctlModelChecker.cpp | 19 +-- .../prctl/HybridMdpPrctlModelChecker.h | 4 - .../prctl/SparseDtmcPrctlModelChecker.cpp | 33 ++--- .../prctl/SparseDtmcPrctlModelChecker.h | 4 - .../prctl/SparseMdpPrctlModelChecker.cpp | 31 ++--- .../prctl/SparseMdpPrctlModelChecker.h | 4 - .../prctl/SymbolicDtmcPrctlModelChecker.cpp | 19 +-- .../prctl/SymbolicDtmcPrctlModelChecker.h | 4 - .../prctl/SymbolicMdpPrctlModelChecker.cpp | 18 +-- .../prctl/SymbolicMdpPrctlModelChecker.h | 5 - .../prctl/helper/HybridDtmcPrctlHelper.cpp | 24 ++-- .../prctl/helper/HybridDtmcPrctlHelper.h | 16 +-- .../prctl/helper/HybridMdpPrctlHelper.cpp | 16 ++- .../prctl/helper/HybridMdpPrctlHelper.h | 12 +- .../prctl/helper/SparseDtmcPrctlHelper.cpp | 66 ++++----- .../prctl/helper/SparseDtmcPrctlHelper.h | 32 ++--- .../prctl/helper/SparseMdpPrctlHelper.cpp | 96 ++++++------- .../prctl/helper/SparseMdpPrctlHelper.h | 30 ++-- .../prctl/helper/SymbolicDtmcPrctlHelper.cpp | 27 ++-- .../prctl/helper/SymbolicDtmcPrctlHelper.h | 16 +-- .../prctl/helper/SymbolicMdpPrctlHelper.cpp | 29 ++-- .../prctl/helper/SymbolicMdpPrctlHelper.h | 16 +-- ...licParametricDtmcPrctlModelCheckerTest.cpp | 2 +- .../SymbolicBisimulationDecompositionTest.cpp | 12 +- 41 files changed, 490 insertions(+), 544 deletions(-) diff --git a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h b/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h index da7c55b77..758740de8 100644 --- a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h @@ -935,7 +935,7 @@ namespace storm { double maximalReachabilityProbability = 0; if (checkThresholdFeasible) { storm::modelchecker::helper::SparseMdpPrctlHelper modelcheckerHelper; - std::vector result = std::move(modelcheckerHelper.computeUntilProbabilities(env, false, mdp.getTransitionMatrix(), mdp.getBackwardTransitions(), phiStates, psiStates, false, false, storm::solver::GeneralMinMaxLinearEquationSolverFactory()).values); + std::vector result = std::move(modelcheckerHelper.computeUntilProbabilities(env, false, mdp.getTransitionMatrix(), mdp.getBackwardTransitions(), phiStates, psiStates, false, false).values); for (auto state : mdp.getInitialStates()) { maximalReachabilityProbability = std::max(maximalReachabilityProbability, result[state]); } diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 94b828479..4aff07fae 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1606,10 +1606,10 @@ namespace storm { STORM_LOG_DEBUG("Invoking model checker."); if (model.isOfType(storm::models::ModelType::Dtmc)) { - allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, storm::solver::GeneralLinearEquationSolverFactory()); + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false); } else { storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; - allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, false, storm::solver::GeneralMinMaxLinearEquationSolverFactory()).values); + allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, false).values); } for (auto state : model.getInitialStates()) { result = std::max(result, allStatesResult[state]); diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp index 81281a2cd..1fdcf2907 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp @@ -332,12 +332,12 @@ namespace storm { } if (isRewardFormula) { - storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, abstractModel, abstractModel.getTransitionMatrix(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybe, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicLinearEquationSolverFactory(), startValues); + storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, abstractModel, abstractModel.getTransitionMatrix(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybe, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), startValues); result.first = std::make_unique>(abstractModel.getReachableStates(), values); result.second = result.first->clone(); } else { - storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, abstractModel, abstractModel.getTransitionMatrix(), maybe, qualitativeResults.getProb1Min().getStates(), storm::solver::GeneralSymbolicLinearEquationSolverFactory(), startValues); + storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, abstractModel, abstractModel.getTransitionMatrix(), maybe, qualitativeResults.getProb1Min().getStates(), startValues); result.first = std::make_unique>(abstractModel.getReachableStates(), values); result.second = result.first->clone(); @@ -371,20 +371,20 @@ namespace storm { uint64_t abstractionPlayer = this->getAbstractionPlayer(); if (isRewardFormula) { - result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), minStartValues); + result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), minStartValues); if (abstractionPlayer == 0) { result.second = result.first->clone(); } else { - result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); + result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); } } else { - result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), maybeMin, qualitativeResults.getProb1Min().getStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), minStartValues); + result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), maybeMin, qualitativeResults.getProb1Min().getStates(), minStartValues); if (abstractionPlayer == 0) { result.second = result.first->clone(); } else { - result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), maybeMax, qualitativeResults.getProb1Max().getStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); + result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), maybeMax, qualitativeResults.getProb1Max().getStates(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); } } diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp index dd6b2e8c1..4d2507288 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp @@ -17,12 +17,7 @@ namespace storm { namespace modelchecker { template - HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -53,7 +48,7 @@ namespace storm { SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -72,7 +67,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -95,7 +90,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - return storm::modelchecker::helper::HybridCtmcCslHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), lowerBound, upperBound, *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), lowerBound, upperBound); } template @@ -103,7 +98,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(!rewardPathFormula.isStepBounded(), storm::exceptions::NotImplementedException, "Currently step-bounded properties on CTMCs are not supported."); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -111,7 +106,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on CTMCs are not supported."); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -120,12 +115,12 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector()); } template std::unique_ptr HybridCtmcCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); } // Explicitly instantiate the model checker. diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h index 19189f361..f66f3c10e 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h @@ -20,7 +20,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridCtmcCslModelChecker(ModelType const& model); - explicit HybridCtmcCslModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -41,8 +40,6 @@ namespace storm { template::SupportsExponential, int>::type = 0> bool canHandleImplementation(CheckTask const& checkTask) const; - // An object that is used for solving linear equations and performing matrix-vector multiplication. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp index c9467b9fe..52d49815e 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -24,12 +24,7 @@ namespace storm { namespace modelchecker { template - SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } @@ -72,7 +67,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), lowerBound, upperBound, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), lowerBound, upperBound); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -81,7 +76,7 @@ namespace storm { storm::logic::NextFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -92,7 +87,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -100,7 +95,7 @@ namespace storm { std::unique_ptr SparseCtmcCslModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(!rewardPathFormula.isStepBounded(), storm::exceptions::NotImplementedException, "Currently step-bounded properties on CTMCs are not supported."); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -108,7 +103,7 @@ namespace storm { std::unique_ptr SparseCtmcCslModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on CTMCs are not supported."); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -118,7 +113,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -129,14 +124,14 @@ namespace storm { ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); storm::storage::SparseMatrix probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseCtmcCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { storm::storage::SparseMatrix probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), &this->getModel().getExitRateVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), &this->getModel().getExitRateVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -146,7 +141,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h index 86a43778e..9bf94fe93 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -20,7 +20,6 @@ namespace storm { typedef typename SparseCtmcModelType::RewardModelType RewardModelType; explicit SparseCtmcCslModelChecker(SparseCtmcModelType const& model); - explicit SparseCtmcCslModelChecker(SparseCtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -42,8 +41,6 @@ namespace storm { template::SupportsExponential, int>::type = 0> bool canHandleImplementation(CheckTask const& checkTask) const; - // An object that is used for solving linear equations and performing matrix-vector multiplication. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 026c1fa5c..74c976fd6 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -22,12 +22,7 @@ namespace storm { namespace modelchecker { template - SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolverFactory) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::move(minMaxLinearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::make_unique>()) { + SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } @@ -66,7 +61,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound)); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -78,7 +73,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -90,7 +85,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -103,7 +98,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -111,7 +106,7 @@ namespace storm { std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute long run average rewards in non-closed Markov automaton."); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -123,7 +118,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 57b1a63a6..60cf49d37 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseMarkovAutomatonModelType::ValueType ValueType; typedef typename SparseMarkovAutomatonModelType::RewardModelType RewardModelType; - explicit SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolver); explicit SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model); // The implemented methods of the AbstractModelChecker interface. @@ -30,9 +29,6 @@ namespace storm { virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. - std::unique_ptr> minMaxLinearEquationSolverFactory; }; } } diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp index 7713719ed..dcd589378 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp @@ -27,9 +27,9 @@ namespace storm { namespace helper { template - std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { - return HybridDtmcPrctlHelper::computeReachabilityRewards(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), rewardModel.divideStateRewardVector(exitRateVector), targetStates, qualitative, linearEquationSolverFactory); + return HybridDtmcPrctlHelper::computeReachabilityRewards(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), rewardModel.divideStateRewardVector(exitRateVector), targetStates, qualitative); } template @@ -38,16 +38,16 @@ namespace storm { } template - std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return HybridDtmcPrctlHelper::computeUntilProbabilities(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { + return HybridDtmcPrctlHelper::computeUntilProbabilities(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), phiStates, psiStates, qualitative); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound) { // If the time bounds are [0, inf], we rather call untimed reachability. if (storm::utility::isZero(lowerBound) && upperBound == storm::utility::infinity()) { - return computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative, linearEquationSolverFactory); + return computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative); } // From this point on, we know that we have to solve a more complicated problem [t, t'] with either t != 0 @@ -88,7 +88,7 @@ namespace storm { // Finally compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); - std::vector subresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound, uniformizationRate, values); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), (psiStates || !statesWithProbabilityGreater0) && model.getReachableStates(), @@ -98,7 +98,7 @@ namespace storm { // Start by computing the (unbounded) reachability probabilities of reaching psi states while // staying in phi states. - std::unique_ptr unboundedResult = computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::unique_ptr unboundedResult = computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative); // Compute the set of relevant states. storm::dd::Bdd relevantStates = statesWithProbabilityGreater0 && phiStates; @@ -126,7 +126,7 @@ namespace storm { storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); // Compute the transient probabilities. - result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result, linearEquationSolverFactory); + result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !relevantStates && model.getReachableStates(), model.getManager().template getAddZero(), relevantStates, odd, result)); } else { @@ -152,7 +152,7 @@ namespace storm { // Compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); - std::vector subResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound - lowerBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound - lowerBound, uniformizationRate, values); // Transform the explicit result to a hybrid check result, so we can easily convert it to // a symbolic qualitative format. @@ -187,7 +187,7 @@ namespace storm { uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, relevantStates, uniformizationRate); explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !relevantStates && model.getReachableStates(), model.getManager().template getAddZero(), relevantStates, odd, newSubresult)); } else { @@ -207,7 +207,7 @@ namespace storm { storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, statesWithProbabilityGreater0, uniformizationRate); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !statesWithProbabilityGreater0 && model.getReachableStates(), model.getManager().template getAddZero(), statesWithProbabilityGreater0, odd, newSubresult)); } @@ -219,12 +219,12 @@ namespace storm { } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -243,19 +243,19 @@ namespace storm { storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, result, linearEquationSolverFactory); + result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, result); } return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, result)); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing instantaneous rewards is unsupported for this value type."); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -282,17 +282,17 @@ namespace storm { std::vector explicitTotalRewardVector = totalRewardVector.toVector(odd); // Finally, compute the transient probabilities. - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, explicitTotalRewardVector, linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, explicitTotalRewardVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing cumulative rewards is unsupported for this value type."); } template - std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates) { storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); // Create ODD for the translation. @@ -301,13 +301,13 @@ namespace storm { storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, psiStates.toVector(odd), &explicitExitRateVector, linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, psiStates.toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template - std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel) { STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); @@ -318,7 +318,7 @@ namespace storm { storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, model.getColumnVariables(), exitRateVector, true).toVector(odd), &explicitExitRateVector, linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, model.getColumnVariables(), exitRateVector, true).toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } @@ -349,50 +349,50 @@ namespace storm { // Explicit instantiations. // Cudd, double. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, double uniformizationRate); // Sylvan, double. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, double uniformizationRate); // Sylvan, rational number. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, storm::RationalNumber uniformizationRate); // Sylvan, rational function. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, storm::RationalFunction uniformizationRate); diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h index 5e27a0709..8814ca9a7 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h @@ -21,37 +21,37 @@ namespace storm { class HybridCtmcCslHelper { public: template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template - static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); template - static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); template - static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template static std::unique_ptr computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); template - static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); /*! * Converts the given rate-matrix into a time-abstract probability matrix. diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 5bf12da1f..931693450 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -30,13 +30,13 @@ namespace storm { namespace modelchecker { namespace helper { template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound) { uint_fast64_t numberOfStates = rateMatrix.getRowCount(); // If the time bounds are [0, inf], we rather call untimed reachability. if (storm::utility::isZero(lowerBound) && upperBound == storm::utility::infinity()) { - return computeUntilProbabilities(env, std::move(goal), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative, linearEquationSolverFactory); + return computeUntilProbabilities(env, std::move(goal), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative); } // From this point on, we know that we have to solve a more complicated problem [t, t'] with either t != 0 @@ -81,7 +81,7 @@ namespace storm { // Finally compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNumberOfSetBits(), storm::utility::zero()); - std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound, uniformizationRate, values); result = std::vector(numberOfStates, storm::utility::zero()); storm::utility::vector::setVectorValues(result, statesWithProbabilityGreater0NonPsi, subresult); @@ -91,7 +91,7 @@ namespace storm { // Start by computing the (unbounded) reachability probabilities of reaching psi states while // staying in phi states. - result = computeUntilProbabilities(env, storm::solver::SolveGoal(), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative, linearEquationSolverFactory); + result = computeUntilProbabilities(env, storm::solver::SolveGoal(), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative); // Determine the set of states that must be considered further. storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; @@ -109,7 +109,7 @@ namespace storm { storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, relevantStates, uniformizationRate, exitRates); // Compute the transient probabilities. - subResult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, subResult, linearEquationSolverFactory); + subResult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, subResult); // Fill in the correct values. storm::utility::vector::setVectorValues(result, ~relevantStates, storm::utility::zero()); @@ -139,7 +139,7 @@ namespace storm { // Start by computing the transient probabilities of reaching a psi state in time t' - t. std::vector values(statesWithProbabilityGreater0NonPsi.getNumberOfSetBits(), storm::utility::zero()); - std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound - lowerBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound - lowerBound, uniformizationRate, values); storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; std::vector newSubresult = std::vector(relevantStates.getNumberOfSetBits()); @@ -157,7 +157,7 @@ namespace storm { // Finally, we compute the second set of transient probabilities. uniformizedMatrix = computeUniformizedMatrix(rateMatrix, relevantStates, uniformizationRate, exitRates); - newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); // Fill in the correct values. result = std::vector(numberOfStates, storm::utility::zero()); @@ -180,7 +180,7 @@ namespace storm { // Finally, we compute the second set of transient probabilities. storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, statesWithProbabilityGreater0, uniformizationRate, exitRates); - newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); // Fill in the correct values. result = std::vector(numberOfStates, storm::utility::zero()); @@ -197,22 +197,22 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::storage::BitVector const&, storm::storage::BitVector const&, std::vector const&, bool, double, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::storage::BitVector const&, storm::storage::BitVector const&, std::vector const&, bool, double, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } template - std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseDtmcPrctlHelper::computeUntilProbabilities(env, std::move(goal), computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative) { + return SparseDtmcPrctlHelper::computeUntilProbabilities(env, std::move(goal), computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative); } template - std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseDtmcPrctlHelper::computeNextProbabilities(env, computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates, linearEquationSolverFactory); + std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates) { + return SparseDtmcPrctlHelper::computeNextProbabilities(env, computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -231,19 +231,19 @@ namespace storm { STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, storm::storage::BitVector(numberOfStates, true), uniformizationRate, exitRateVector); - result = computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, result, linearEquationSolverFactory); + result = computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, result); } return result; } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing instantaneous rewards is unsupported for this value type."); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -270,16 +270,16 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, exitRateVector); // Finally, compute the transient probabilities. - return computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, totalRewardVector, linearEquationSolverFactory); + return computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, totalRewardVector); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing cumulative rewards is unsupported for this value type."); } template - std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative) { // Compute expected time on CTMC by reduction to DTMC with rewards. storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); @@ -295,11 +295,11 @@ namespace storm { } } - return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative, linearEquationSolverFactory); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative); } template - std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative) { STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); @@ -326,11 +326,11 @@ namespace storm { totalRewardVector = rewardModel.getStateActionRewardVector(); } - return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative, linearEquationSolverFactory); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector) { // If there are no goal states, we avoid the computation and directly return zero. uint_fast64_t numberOfStates = probabilityMatrix.getRowCount(); @@ -353,30 +353,28 @@ namespace storm { } return zero; }, - exitRateVector, - linearEquationSolverFactory); + exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); - return computeLongRunAverageRewards(env, std::move(goal), probabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, *exitRateVector), exitRateVector, linearEquationSolverFactory); + return computeLongRunAverageRewards(env, std::move(goal), probabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, *exitRateVector), exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector) { return computeLongRunAverages(env, std::move(goal), probabilityMatrix, [&stateRewardVector] (storm::storage::sparse::state_type const& state) -> ValueType { return stateRewardVector[state]; }, - exitRateVector, - linearEquationSolverFactory); + exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory){ + std::vector SparseCtmcCslHelper::computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector){ uint_fast64_t numberOfStates = probabilityMatrix.getRowCount(); // Start by decomposing the CTMC into its BSCCs. @@ -493,6 +491,7 @@ namespace storm { { // Check solver requirements + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); // Check whether we have the right input format for the solver. STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); @@ -564,6 +563,7 @@ namespace storm { rewardSolution = std::vector(rewardEquationSystemMatrix.getColumnCount(), one); { + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; // Check solver requirements STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); // Check whether we have the right input format for the solver. @@ -623,7 +623,7 @@ namespace storm { } template::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values) { ValueType lambda = timeBound * uniformizationRate; @@ -729,58 +729,58 @@ namespace storm { } - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeUniformizedMatrix(storm::storage::SparseMatrix const& rateMatrix, storm::storage::BitVector const& maybeStates, double uniformizationRate, std::vector const& exitRates); - template std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, double timeBound, double uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, double timeBound, double uniformizationRate, std::vector values); #ifdef STORM_HAVE_CARL - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeProbabilityMatrix(storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRates); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeProbabilityMatrix(storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRates); diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h index e1e6f3c43..28125c7c9 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h @@ -19,43 +19,43 @@ namespace storm { class SparseCtmcCslHelper { public: template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); template - static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); template - static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); template ::SupportsExponential, int>::type = 0> - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); template - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); template - static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); /*! * Computes the matrix representing the transitions of the uniformized CTMC. @@ -84,7 +84,7 @@ namespace storm { * @return The vector of transient probabilities. */ template::SupportsExponential, int>::type = 0> - static std::vector computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values); /*! * Converts the given rate-matrix into a time-abstract probability matrix. @@ -108,7 +108,7 @@ namespace storm { private: template - static std::vector computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector); }; } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 62672023b..7e4047f08 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -36,7 +36,7 @@ namespace storm { namespace helper { template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps) { // Start by computing four sparse matrices: // * a matrix aMarkovian with all (discretized) transitions from Markovian non-goal states to all Markovian non-goal states. @@ -104,6 +104,7 @@ namespace storm { // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -153,12 +154,12 @@ namespace storm { } template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -185,7 +186,7 @@ namespace storm { std::vector vProbabilistic(probabilisticNonGoalStates.getNumberOfSetBits()); std::vector vMarkovian(markovianNonGoalStates.getNumberOfSetBits()); - computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, psiStates, markovianNonGoalStates, probabilisticNonGoalStates, vMarkovian, vProbabilistic, delta, numberOfSteps, minMaxLinearEquationSolverFactory); + computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, psiStates, markovianNonGoalStates, probabilisticNonGoalStates, vMarkovian, vProbabilistic, delta, numberOfSteps); // (4) If the lower bound of interval was non-zero, we need to take the current values as the starting values for a subsequent value iteration. if (lowerBound != storm::utility::zero()) { @@ -203,7 +204,7 @@ namespace storm { STORM_LOG_INFO("Performing " << numberOfSteps << " iterations (delta=" << delta << ") for interval [0, " << lowerBound << "]." << std::endl); // Compute the bounded reachability for interval [0, b-a]. - computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, storm::storage::BitVector(numberOfStates), markovianStates, ~markovianStates, vAllMarkovian, vAllProbabilistic, delta, numberOfSteps, minMaxLinearEquationSolverFactory); + computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, storm::storage::BitVector(numberOfStates), markovianStates, ~markovianStates, vAllMarkovian, vAllProbabilistic, delta, numberOfSteps); // Create the result vector out of vAllProbabilistic and vAllMarkovian and return it. std::vector result(numberOfStates, storm::utility::zero()); @@ -222,18 +223,18 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } template - std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { - return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false, minMaxLinearEquationSolverFactory).values); + std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative) { + return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false).values); } template - std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates) { // Get a reward model where the state rewards are scaled accordingly std::vector stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero()); @@ -243,11 +244,11 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights); RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector)); - return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; + return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false).values; } template - std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -267,12 +268,12 @@ namespace storm { storm::utility::vector::setVectorValues(stateRewards, markovianStates & psiStates, storm::utility::one()); storm::models::sparse::StandardRewardModel rewardModel(std::move(stateRewards)); - return computeLongRunAverageRewards(env, dir, transitionMatrix, backwardTransitions, exitRateVector, markovianStates, rewardModel, minMaxLinearEquationSolverFactory); + return computeLongRunAverageRewards(env, dir, transitionMatrix, backwardTransitions, exitRateVector, markovianStates, rewardModel); } template - std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -301,7 +302,7 @@ namespace storm { } // Compute the LRA value for the current MEC. - lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec, minMaxLinearEquationSolverFactory)); + lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec)); } // For fast transition rewriting, we build some auxiliary data structures. @@ -403,6 +404,7 @@ namespace storm { std::vector x(numberOfSspStates); // Check for requirements of the solver. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -429,7 +431,7 @@ namespace storm { } template - std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates) { // Get a reward model representing expected sojourn times std::vector rewardValues(transitionMatrix.getRowCount(), storm::utility::zero()); @@ -438,11 +440,11 @@ namespace storm { } storm::models::sparse::StandardRewardModel rewardModel(boost::none, std::move(rewardValues)); - return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; + return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false).values; } template - ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // If the mec only consists of a single state, we compute the LRA value directly if (++mec.begin() == mec.end()) { @@ -462,7 +464,7 @@ namespace storm { if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec); } else if (method == storm::solver::LraMethod::ValueIteration) { - return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec, minMaxLinearEquationSolverFactory); + return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -534,7 +536,7 @@ namespace storm { } template - ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // Initialize data about the mec @@ -616,6 +618,7 @@ namespace storm { // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearLowerBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -661,45 +664,45 @@ namespace storm { } - template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); - template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, double delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, double delta, uint64_t numberOfSteps); - template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); - template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, storm::RationalNumber delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, storm::RationalNumber delta, uint64_t numberOfSteps); - template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 655f6ebf2..e570c2f2f 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -18,33 +18,33 @@ namespace storm { public: template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); template - static std::vector computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); template - static std::vector computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates); template - static std::vector computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); template - static std::vector computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel); template - static std::vector computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); private: template ::SupportsExponential, int>::type = 0> - static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps); template ::SupportsExponential, int>::type = 0> - static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps); /*! * Computes the long-run average value for the given maximal end component of a Markov automaton. @@ -63,11 +63,11 @@ namespace storm { * @return The long-run average of being in a goal state for the given MEC. */ template - static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template static ValueType computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template - static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); }; diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 208dfcfd4..94b7ca4e1 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -26,12 +26,7 @@ namespace storm { namespace modelchecker { template - HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -48,7 +43,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -56,7 +51,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -76,21 +71,21 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -98,7 +93,7 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } @@ -108,12 +103,12 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); } template class HybridDtmcPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h index 2b69dda58..d76ae69ac 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h @@ -18,7 +18,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridDtmcPrctlModelChecker(ModelType const& model); - explicit HybridDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -33,9 +32,6 @@ namespace storm { virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index 12524aed6..6ae7ea4bc 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -32,12 +32,7 @@ namespace storm { namespace modelchecker { template - HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -64,7 +59,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -73,7 +68,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -95,7 +90,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template @@ -103,7 +98,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -111,7 +106,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -120,7 +115,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h index cff28c1ca..246a991d5 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h @@ -25,7 +25,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridMdpPrctlModelChecker(ModelType const& model); - explicit HybridMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -38,9 +37,6 @@ namespace storm { virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 36e6eb9a2..5fea015ef 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -24,12 +24,7 @@ namespace storm { namespace modelchecker { template - SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } @@ -49,7 +44,7 @@ namespace storm { opInfo.bound = checkTask.getBound(); } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); - auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula, *linearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(!pathFormula.hasLowerBound() && pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have single upper time bound."); @@ -58,7 +53,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); std::unique_ptr result = std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); return result; } @@ -69,7 +64,7 @@ namespace storm { storm::logic::NextFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -80,7 +75,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -89,7 +84,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -103,11 +98,11 @@ namespace storm { opInfo.bound = checkTask.getBound(); } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); - auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula, *linearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -116,7 +111,7 @@ namespace storm { std::unique_ptr SparseDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -125,7 +120,7 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -134,13 +129,13 @@ namespace storm { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), nullptr, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), nullptr); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseDtmcPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), nullptr, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), nullptr); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -156,7 +151,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -171,7 +166,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index c4284218a..ebc7d39a3 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseDtmcModelType::RewardModelType RewardModelType; explicit SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model); - explicit SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -34,9 +33,6 @@ namespace storm { virtual std::unique_ptr computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index bb51f372d..074a679b6 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -31,12 +31,7 @@ namespace storm { namespace modelchecker { template - SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolverFactory) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::move(minMaxLinearEquationSolverFactory)) { + SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } @@ -67,7 +62,7 @@ namespace storm { } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates(), *minMaxLinearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(!pathFormula.hasLowerBound() && pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have single upper time bound."); @@ -76,7 +71,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -87,7 +82,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -99,7 +94,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); @@ -113,7 +108,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(ret))); } @@ -130,7 +125,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector()); } template @@ -146,11 +141,11 @@ namespace storm { } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates(), *minMaxLinearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -160,7 +155,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -170,7 +165,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); @@ -184,14 +179,14 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - std::vector result = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 84c6d7ddc..5ea9a010a 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseMdpModelType::RewardModelType RewardModelType; explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model); - explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model, std::unique_ptr>&& MinMaxLinearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -33,9 +32,6 @@ namespace storm { virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. - std::unique_ptr> minMaxLinearEquationSolverFactory; }; } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp index ec61ae28d..e8af30350 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp @@ -23,12 +23,7 @@ namespace storm { namespace modelchecker { template - SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -45,7 +40,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -54,7 +49,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -76,7 +71,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); return std::unique_ptr>(new SymbolicQuantitativeCheckResult(this->getModel().getReachableStates(), numericResult)); } @@ -84,7 +79,7 @@ namespace storm { std::unique_ptr SymbolicDtmcPrctlModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr>(new SymbolicQuantitativeCheckResult(this->getModel().getReachableStates(), numericResult)); } @@ -92,7 +87,7 @@ namespace storm { std::unique_ptr SymbolicDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -101,7 +96,7 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h index f0f09d965..311669bf7 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h @@ -16,7 +16,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit SymbolicDtmcPrctlModelChecker(ModelType const& model); - explicit SymbolicDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -28,9 +27,6 @@ namespace storm { virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp index e80ebaec8..3c813d001 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp @@ -21,13 +21,9 @@ namespace storm { namespace modelchecker { - template - SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } template - SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(new storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory()) { + SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -45,7 +41,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -54,7 +50,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -76,7 +72,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template @@ -84,7 +80,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -92,7 +88,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -101,7 +97,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector()); } template class SymbolicMdpPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h index a36358ba8..b116af0fc 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit SymbolicMdpPrctlModelChecker(ModelType const& model); - explicit SymbolicMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -28,11 +27,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index ca8f7e439..e5a7df87b 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -30,7 +30,7 @@ namespace storm { namespace helper { template - std::unique_ptr HybridDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. STORM_LOG_TRACE("Found " << phiStates.getNonZeroCount() << " phi states and " << psiStates.getNonZeroCount() << " psi states."); @@ -63,6 +63,7 @@ namespace storm { storm::dd::Add subvector = submatrix * prob1StatesAsColumn; subvector = subvector.sumAbstract(model.getColumnVariables()); + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); req.clearUpperBounds(); @@ -98,8 +99,8 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr HybridDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -111,7 +112,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0 = storm::utility::graph::performProbGreater0(model, transitionMatrix.notZero(), phiStates, psiStates, stepBound); @@ -157,7 +158,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -179,7 +180,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -218,7 +219,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -254,6 +255,7 @@ namespace storm { // Check the requirements of a linear equation solver // We might need to compute upper reward bounds for which the oneStepTargetProbabilities are needed. boost::optional> oneStepTargetProbs; + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); if (req.requiresUpperBounds()) { @@ -307,22 +309,22 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates) { // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); - std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, targetStates.toVector(odd), linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, targetStates.toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template - std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel) { // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); - std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(model.getTransitionMatrix(), model.getColumnVariables()).toVector(odd), linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(model.getTransitionMatrix(), model.getColumnVariables()).toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h index 7bbee1795..67896c8bc 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h @@ -23,23 +23,23 @@ namespace storm { public: typedef typename storm::models::symbolic::Model::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); - static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates); - static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel); }; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index 8a1ef4c9c..47ea6c1b4 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -123,7 +123,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. storm::dd::Bdd transitionMatrixBdd = transitionMatrix.notZero(); @@ -147,6 +147,7 @@ namespace storm { // If we minimize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Minimize; // Check for requirements of the solver early so we can adjust the maybe state computation accordingly. + storm::solver::GeneralMinMaxLinearEquationSolverFactory linearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; SolverRequirementsData solverRequirementsData; @@ -259,8 +260,8 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Maximize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr HybridMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Maximize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -271,7 +272,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0; @@ -321,7 +322,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -343,7 +344,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -488,7 +489,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -518,6 +519,7 @@ namespace storm { // If we maximize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Maximize; // Check for requirements of the solver this early so we can adapt the maybe states accordingly. + storm::solver::GeneralMinMaxLinearEquationSolverFactory linearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; bool extendMaybeStates = false; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h index 224830220..78ee1f7d3 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h @@ -24,19 +24,19 @@ namespace storm { public: typedef typename storm::models::symbolic::NondeterministicModel::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); }; } diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 1fe8ca527..9e0da7157 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -43,7 +43,7 @@ namespace storm { namespace modelchecker { namespace helper { template - std::vector SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); // If we identify the states that have probability 0 of reaching the target states, we can exclude them in the further analysis. @@ -111,11 +111,12 @@ namespace storm { } template - std::vector analyzeNonTrivialDtmcEpochModel(Environment const& env, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& linEqSolver, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional const& lowerBound, boost::optional const& upperBound) { + std::vector analyzeNonTrivialDtmcEpochModel(Environment const& env, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& linEqSolver, boost::optional const& lowerBound, boost::optional const& upperBound) { // Update some data for the case that the Matrix has changed if (epochModel.epochMatrixChanged) { x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero()); + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix); linEqSolver->setCachingEnabled(true); auto req = linEqSolver->getRequirements(env); @@ -150,13 +151,13 @@ namespace storm { } template<> - std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The specified property is not supported by this value type."); return std::map(); } template - std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula) { storm::utility::Stopwatch swAll(true), swBuild, swCheck; storm::modelchecker::helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(model, rewardBoundedFormula); @@ -180,7 +181,8 @@ namespace storm { // In case of cdf export we store the necessary data. std::vector> cdfData; - // Set the correct equation problem format + // Set the correct equation problem format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; rewardUnfolding.setEquationSystemFormatForEpochModel(linearEquationSolverFactory.getEquationProblemFormat(preciseEnv)); bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(preciseEnv) == solver::LinearEquationSolverProblemFormat::EquationSystem; @@ -196,7 +198,7 @@ namespace storm { if ((convertToEquationSystem && epochModel.epochMatrix.isIdentityMatrix()) || (!convertToEquationSystem && epochModel.epochMatrix.getEntryCount() == 0)) { rewardUnfolding.setSolutionForCurrentEpoch(analyzeTrivialDtmcEpochModel(epochModel)); } else { - rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialDtmcEpochModel(preciseEnv, epochModel, x, b, linEqSolver, linearEquationSolverFactory, lowerBound, upperBound)); + rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialDtmcEpochModel(preciseEnv, epochModel, x, b, linEqSolver, lowerBound, upperBound)); } swCheck.stop(); if (storm::settings::getModule().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { @@ -243,7 +245,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); @@ -291,6 +293,7 @@ namespace storm { // In this case we have have to compute the probabilities. // Check whether we need to convert the input to equation system format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; // We can eliminate the rows and columns from the original transition probability matrix. @@ -329,9 +332,9 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative) { goal.oneMinus(); - std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), ~psiStates, qualitative, linearEquationSolverFactory); + std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), ~psiStates, qualitative); for (auto& entry : result) { entry = storm::utility::one() - entry; } @@ -339,7 +342,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates) { // Create the vector with which to multiply and initialize it correctly. std::vector result(transitionMatrix.getRowCount()); storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); @@ -351,7 +354,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Initialize result to the null vector. std::vector result(transitionMatrix.getRowCount()); @@ -366,7 +369,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount) { // Only compute the result if the model has a state-based reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -381,13 +384,13 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); }, - targetStates, qualitative, linearEquationSolverFactory, + targetStates, qualitative, [&] () { return rewardModel.getStatesWithZeroReward(transitionMatrix); }, @@ -395,7 +398,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const& maybeStates) { @@ -403,7 +406,7 @@ namespace storm { storm::utility::vector::selectVectorValues(result, maybeStates, totalStateRewardVector); return result; }, - targetStates, qualitative, linearEquationSolverFactory, + targetStates, qualitative, [&] () { return storm::utility::vector::filterZero(totalStateRewardVector); }, @@ -424,7 +427,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); @@ -462,6 +465,7 @@ namespace storm { } else { if (!maybeStates.empty()) { // Check whether we need to convert the input to equation system format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; // In this case we have to compute the reward values for the remaining states. @@ -514,27 +518,27 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, std::move(goal), transitionMatrix, psiStates, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates) { + return SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, std::move(goal), transitionMatrix, psiStates, nullptr); } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, rewardModel, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel) { + return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, rewardModel, nullptr); } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, stateRewards, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards) { + return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, stateRewards, nullptr); } template - typename SparseDtmcPrctlHelper::BaierTransformedModel SparseDtmcPrctlHelper::computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + typename SparseDtmcPrctlHelper::BaierTransformedModel SparseDtmcPrctlHelper::computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards) { BaierTransformedModel result; // Start by computing all 'before' states, i.e. the states for which the conditional probability is defined. - std::vector probabilitiesToReachConditionStates = computeUntilProbabilities(env, storm::solver::SolveGoal(), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), conditionStates, false, linearEquationSolverFactory); + std::vector probabilitiesToReachConditionStates = computeUntilProbabilities(env, storm::solver::SolveGoal(), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), conditionStates, false); result.beforeStates = storm::storage::BitVector(targetStates.size(), true); uint_fast64_t state = 0; @@ -666,13 +670,13 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative) { // Prepare result vector. std::vector result(transitionMatrix.getRowCount(), storm::utility::infinity()); if (!conditionStates.empty()) { - BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, boost::none, linearEquationSolverFactory); + BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, boost::none); if (transformedModel.noTargetStates) { storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero()); @@ -690,7 +694,7 @@ namespace storm { newRelevantValues = transformedModel.getNewRelevantStates(); } goal.setRelevantValues(std::move(newRelevantValues)); - std::vector conditionalProbabilities = computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative, linearEquationSolverFactory); + std::vector conditionalProbabilities = computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative); storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalProbabilities); } @@ -700,12 +704,12 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative) { // Prepare result vector. std::vector result(transitionMatrix.getRowCount(), storm::utility::infinity()); if (!conditionStates.empty()) { - BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, rewardModel.getTotalRewardVector(transitionMatrix), linearEquationSolverFactory); + BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, rewardModel.getTotalRewardVector(transitionMatrix)); if (transformedModel.noTargetStates) { storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero()); @@ -723,7 +727,7 @@ namespace storm { newRelevantValues = transformedModel.getNewRelevantStates(); } goal.setRelevantValues(std::move(newRelevantValues)); - std::vector conditionalRewards = computeReachabilityRewards(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), transformedModel.stateRewards.get(), transformedModel.targetStates.get(), qualitative, linearEquationSolverFactory); + std::vector conditionalRewards = computeReachabilityRewards(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), transformedModel.stateRewards.get(), transformedModel.targetStates.get(), qualitative); storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalRewards); } } diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index e9b4f939f..a4e2882bc 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -28,36 +28,36 @@ namespace storm { class SparseDtmcPrctlHelper { public: - static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::map computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::map computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula); - static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates); - static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative); - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount); - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates); - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel); - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards); - static std::vector computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative); - static std::vector computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative); private: - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); struct BaierTransformedModel { BaierTransformedModel() : noTargetStates(false) { @@ -74,7 +74,7 @@ namespace storm { bool noTargetStates; }; - static BaierTransformedModel computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static BaierTransformedModel computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards); }; } } diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index a589d3491..1e53cf314 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -50,7 +50,7 @@ namespace storm { namespace helper { template - std::vector SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // Determine the states that have 0 probability of reaching the target states. @@ -138,11 +138,12 @@ namespace storm { } template - std::vector analyzeNonTrivialMdpEpochModel(Environment const& env, OptimizationDirection dir, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& minMaxSolver, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, boost::optional const& lowerBound, boost::optional const& upperBound) { + std::vector analyzeNonTrivialMdpEpochModel(Environment const& env, OptimizationDirection dir, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& minMaxSolver, boost::optional const& lowerBound, boost::optional const& upperBound) { // Update some data for the case that the Matrix has changed if (epochModel.epochMatrixChanged) { x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero()); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; minMaxSolver = minMaxLinearEquationSolverFactory.create(env, epochModel.epochMatrix); minMaxSolver->setHasUniqueSolution(); minMaxSolver->setOptimizationDirection(dir); @@ -184,7 +185,7 @@ namespace storm { } template - std::map SparseMdpPrctlHelper::computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::map SparseMdpPrctlHelper::computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates) { storm::utility::Stopwatch swAll(true), swBuild, swCheck; // Get lower and upper bounds for the solution. @@ -218,7 +219,7 @@ namespace storm { if (epochModel.epochMatrix.getEntryCount() == 0) { rewardUnfolding.setSolutionForCurrentEpoch(analyzeTrivialMdpEpochModel(dir, epochModel)); } else { - rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialMdpEpochModel(preciseEnv, dir, epochModel, x, b, minMaxSolver, minMaxLinearEquationSolverFactory, lowerBound, upperBound)); + rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialMdpEpochModel(preciseEnv, dir, epochModel, x, b, minMaxSolver, lowerBound, upperBound)); } swCheck.stop(); if (storm::settings::getModule().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { @@ -266,7 +267,7 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates) { // Create the vector with which to multiply and initialize it correctly. std::vector result(transitionMatrix.getRowGroupCount()); @@ -423,7 +424,7 @@ namespace storm { } template - SparseMdpHintType computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, boost::optional const& selectedChoices = boost::none) { + SparseMdpHintType computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices = boost::none) { SparseMdpHintType result; // The solution to the min-max equation system is unique if we minimize until probabilities or @@ -434,6 +435,7 @@ namespace storm { // Check for requirements of the solver. bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().hasSchedulerHint(); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, hasSchedulerHint); if (!requirements.empty()) { @@ -516,12 +518,13 @@ namespace storm { }; template - MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix&& submatrix, std::vector const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, SparseMdpHintType& hint) { + MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix&& submatrix, std::vector const& b, bool produceScheduler, SparseMdpHintType& hint) { // Initialize the solution vector. std::vector x = hint.hasValueHint() ? std::move(hint.getValueHint()) : std::vector(submatrix.getRowGroupCount(), hint.hasLowerResultBound() ? hint.getLowerResultBound() : storm::utility::zero()); // Set up the solver. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix)); solver->setRequirementsChecked(); solver->setHasUniqueSolution(hint.hasUniqueSolution()); @@ -703,7 +706,7 @@ namespace storm { } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { STORM_LOG_THROW(!qualitative || !produceScheduler, storm::exceptions::InvalidSettingsException, "Cannot produce scheduler when performing qualitative model checking only."); // Prepare resulting vector. @@ -733,7 +736,7 @@ namespace storm { // In this case we have have to compute the remaining probabilities. // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = computeHints(env, SolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1, minMaxLinearEquationSolverFactory); + SparseMdpHintType hintInformation = computeHints(env, SolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -752,7 +755,7 @@ namespace storm { } // Now compute the results for the maybe states. - MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, minMaxLinearEquationSolverFactory, hintInformation); + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { @@ -781,7 +784,7 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, bool useMecBasedTechnique) { + std::vector SparseMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool useMecBasedTechnique) { if (useMecBasedTechnique) { storm::storage::MaximalEndComponentDecomposition mecDecomposition(transitionMatrix, backwardTransitions, psiStates); storm::storage::BitVector statesInPsiMecs(transitionMatrix.getRowGroupCount()); @@ -791,10 +794,10 @@ namespace storm { } } - return std::move(computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, psiStates, statesInPsiMecs, qualitative, false, minMaxLinearEquationSolverFactory).values); + return std::move(computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, psiStates, statesInPsiMecs, qualitative, false).values); } else { goal.oneMinus(); - std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), ~psiStates, qualitative, false, minMaxLinearEquationSolverFactory).values; + std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), ~psiStates, qualitative, false).values; for (auto& element : result) { element = storm::utility::one() - element; } @@ -804,7 +807,7 @@ namespace storm { template template - std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount) { // Only compute the result if the model has a state-based reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -820,7 +823,7 @@ namespace storm { template template - std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -839,14 +842,14 @@ namespace storm { template template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, [&rewardModel] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(rowCount, transitionMatrix, maybeStates); }, - targetStates, qualitative, produceScheduler, minMaxLinearEquationSolverFactory, + targetStates, qualitative, produceScheduler, [&] () { return rewardModel.getStatesWithZeroReward(transitionMatrix); }, @@ -858,7 +861,7 @@ namespace storm { #ifdef STORM_HAVE_CARL template - std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative) { // Only compute the result if the reward model is not empty. STORM_LOG_THROW(!intervalRewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, \ @@ -871,7 +874,7 @@ namespace storm { } return result; }, - targetStates, qualitative, false, minMaxLinearEquationSolverFactory, + targetStates, qualitative, false, [&] () { return intervalRewardModel.getStatesWithFilter(transitionMatrix, [&](storm::Interval const& i) {return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());}); }, @@ -881,7 +884,7 @@ namespace storm { } template<> - std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&&, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::models::sparse::StandardRewardModel const&, bool, storm::storage::BitVector const&, bool, storm::solver::MinMaxLinearEquationSolverFactory const&) { + std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&&, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::models::sparse::StandardRewardModel const&, bool, storm::storage::BitVector const&, bool) { STORM_LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Computing reachability rewards is unsupported for this data type."); } #endif @@ -1094,7 +1097,7 @@ namespace storm { } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint) { // Prepare resulting vector. std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); @@ -1129,7 +1132,7 @@ namespace storm { } // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, minMaxLinearEquationSolverFactory, selectedChoices); + SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, selectedChoices); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -1161,7 +1164,7 @@ namespace storm { } // Now compute the results for the maybe states. - MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, minMaxLinearEquationSolverFactory, hintInformation); + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { @@ -1189,7 +1192,7 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates) { // If there are no goal states, we avoid the computation and directly return zero. if (psiStates.empty()) { @@ -1206,12 +1209,12 @@ namespace storm { std::vector stateRewards(psiStates.size(), storm::utility::zero()); storm::utility::vector::setVectorValues(stateRewards, psiStates, storm::utility::one()); storm::models::sparse::StandardRewardModel rewardModel(std::move(stateRewards)); - return computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, minMaxLinearEquationSolverFactory); + return computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel); } template template - std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -1230,7 +1233,7 @@ namespace storm { for (uint_fast64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) { storm::storage::MaximalEndComponent const& mec = mecDecomposition[currentMecIndex]; - lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(env, goal.direction(), transitionMatrix, rewardModel, mec, minMaxLinearEquationSolverFactory); + lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(env, goal.direction(), transitionMatrix, rewardModel, mec); // Gather information for later use. for (auto const& stateChoicesPair : mec) { @@ -1336,6 +1339,7 @@ namespace storm { storm::storage::SparseMatrix sspMatrix = sspMatrixBuilder.build(currentChoice, numberOfSspStates, numberOfSspStates); // Check for requirements of the solver. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction()); requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); @@ -1365,7 +1369,7 @@ namespace storm { template template - ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // If the mec only consists of a single state, we compute the LRA value directly if (++mec.begin() == mec.end()) { @@ -1387,7 +1391,7 @@ namespace storm { if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, rewardModel, mec); } else if (method == storm::solver::LraMethod::ValueIteration) { - return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, rewardModel, mec, minMaxLinearEquationSolverFactory); + return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, rewardModel, mec); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -1395,7 +1399,7 @@ namespace storm { template template - ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // Initialize data about the mec storm::storage::BitVector mecStates(transitionMatrix.getRowGroupCount(), false); @@ -1532,7 +1536,7 @@ namespace storm { } template - std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates) { std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); @@ -1568,7 +1572,7 @@ namespace storm { STORM_LOG_DEBUG("Computing probabilities to satisfy condition."); std::chrono::high_resolution_clock::time_point conditionStart = std::chrono::high_resolution_clock::now(); - std::vector conditionProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector conditionProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, false, false).values); std::chrono::high_resolution_clock::time_point conditionEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed probabilities to satisfy for condition in " << std::chrono::duration_cast(conditionEnd - conditionStart).count() << "ms."); @@ -1579,7 +1583,7 @@ namespace storm { STORM_LOG_DEBUG("Computing probabilities to reach target."); std::chrono::high_resolution_clock::time_point targetStart = std::chrono::high_resolution_clock::now(); - std::vector targetProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector targetProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false).values); std::chrono::high_resolution_clock::time_point targetEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed probabilities to reach target in " << std::chrono::duration_cast(targetEnd - targetStart).count() << "ms."); @@ -1671,7 +1675,7 @@ namespace storm { } std::chrono::high_resolution_clock::time_point conditionalStart = std::chrono::high_resolution_clock::now(); - std::vector goalProbabilities = std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector goalProbabilities = std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false).values); std::chrono::high_resolution_clock::time_point conditionalEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed conditional probabilities in transformed model in " << std::chrono::duration_cast(conditionalEnd - conditionalStart).count() << "ms."); @@ -1679,22 +1683,22 @@ namespace storm { } template class SparseMdpPrctlHelper; - template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint); - template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template double SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); + template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); + template double SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); + template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); #ifdef STORM_HAVE_CARL template class SparseMdpPrctlHelper; - template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint); - template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); + template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); + template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); + template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); #endif diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index 5a6f5ae2b..920bb4d47 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -39,44 +39,44 @@ namespace storm { class SparseMdpPrctlHelper { public: - static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::map computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::map computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates); - static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates); - static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, bool useMecBasedTechnique = false); + static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool useMecBasedTechnique = false); template - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount); template - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); template - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); #ifdef STORM_HAVE_CARL - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative); #endif - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel); - static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates); private: - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); template - static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template - static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template static ValueType computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp index 9993640bc..2b64db267 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp @@ -19,7 +19,7 @@ namespace storm { namespace helper { template - storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. STORM_LOG_TRACE("Found " << phiStates.getNonZeroCount() << " phi states and " << psiStates.getNonZeroCount() << " psi states."); @@ -35,7 +35,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeUntilProbabilities(env, model, transitionMatrix, maybeStates, statesWithProbability01.second, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeUntilProbabilities(env, model, transitionMatrix, maybeStates, statesWithProbability01.second, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return statesWithProbability01.second.template toAdd(); } @@ -43,7 +43,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -60,6 +60,7 @@ namespace storm { // Finally cut away all columns targeting non-maybe states and convert the matrix into the matrix needed // for solving the equation system (i.e. compute (I-A)). submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) { submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; } @@ -73,8 +74,8 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { - storm::dd::Add result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + storm::dd::Add SymbolicDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + storm::dd::Add result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result = result.getDdManager().template getAddOne() - result; return result; } @@ -86,7 +87,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0 = storm::utility::graph::performProbGreater0(model, transitionMatrix.notZero(), phiStates, psiStates, stepBound); @@ -110,6 +111,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, submatrix, maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(model.getManager().template getAddZero(), &subvector, stepBound); @@ -120,7 +122,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -128,22 +130,24 @@ namespace storm { storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, model.getReachableStates(), model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); return solver->multiply(model.getManager().template getAddZero(), &totalRewardVector, stepBound); } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, model.getReachableStates(), model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); return solver->multiply(rewardModel.getStateRewardVector(), nullptr, stepBound); } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -162,7 +166,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, maybeStates, targetStates, infinityStates, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, maybeStates, targetStates, infinityStates, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), model.getManager().getConstant(storm::utility::zero())); } @@ -170,7 +174,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -185,6 +189,7 @@ namespace storm { // Finally cut away all columns targeting non-maybe states and convert the matrix into the matrix needed // for solving the equation system (i.e. compute (I-A)). submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) { submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; } diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h index dc6307db1..995936786 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h @@ -20,23 +20,23 @@ namespace storm { public: typedef typename storm::models::symbolic::Model::RewardModelType RewardModelType; - static storm::dd::Add computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static storm::dd::Add computeNextProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static storm::dd::Add computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static storm::dd::Add computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); }; } diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp index 523ba2711..506396a54 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp @@ -45,7 +45,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -65,6 +65,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Now solve the resulting equation system. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); if (storm::solver::minimize(dir)) { @@ -101,7 +102,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. std::pair, storm::dd::Bdd> statesWithProbability01; @@ -121,7 +122,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeUntilProbabilities(env, dir, model, transitionMatrix, maybeStates, statesWithProbability01.second, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeUntilProbabilities(env, dir, model, transitionMatrix, maybeStates, statesWithProbability01.second, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return std::unique_ptr(new storm::modelchecker::SymbolicQuantitativeCheckResult(model.getReachableStates(), statesWithProbability01.second.template toAdd())); } @@ -129,8 +130,8 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Minimize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr SymbolicMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Minimize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -147,7 +148,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0; @@ -174,7 +175,8 @@ namespace storm { // Finally cut away all columns targeting non-maybe states. submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); - + + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, model.getManager().template getAddZero(), &subvector, stepBound); @@ -185,11 +187,12 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(transitionMatrix, model.getReachableStates(), model.getIllegalMask(), model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, rewardModel.getStateRewardVector(), nullptr, stepBound); @@ -197,7 +200,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -205,6 +208,7 @@ namespace storm { storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(model.getTransitionMatrix(), model.getReachableStates(), model.getIllegalMask(), model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, model.getManager().template getAddZero(), &totalRewardVector, stepBound); @@ -212,7 +216,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -232,6 +236,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Now solve the resulting equation system. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); if (storm::solver::maximize(dir)) { @@ -268,7 +273,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, boost::optional> const& startValues) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -289,7 +294,7 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeReachabilityRewards(env, dir, model, transitionMatrix, transitionMatrixBdd, rewardModel, maybeStates, targetStates, infinityStates, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeReachabilityRewards(env, dir, model, transitionMatrix, transitionMatrixBdd, rewardModel, maybeStates, targetStates, infinityStates, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return std::unique_ptr(new storm::modelchecker::SymbolicQuantitativeCheckResult(model.getReachableStates(), infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), model.getManager().template getAddZero()))); } diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h index c8737299c..e21342008 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h @@ -24,23 +24,23 @@ namespace storm { public: typedef typename storm::models::symbolic::NondeterministicModel::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); }; } diff --git a/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp b/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp index 31c5d7436..de5e6f849 100644 --- a/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp @@ -40,7 +40,7 @@ TEST(SymbolicDtmcPrctlModelCheckerTest, Die_RationalFunction_Sylvan) { std::shared_ptr> dtmc = model->as>(); - storm::modelchecker::SymbolicDtmcPrctlModelChecker> checker(*dtmc, std::unique_ptr>(new storm::solver::SymbolicEliminationLinearEquationSolverFactory())); + storm::modelchecker::SymbolicDtmcPrctlModelChecker> checker(*dtmc); std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("P=? [F \"one\"]"); diff --git a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp index fbaaf5df4..d339bd027 100644 --- a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp +++ b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp @@ -71,7 +71,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { std::shared_ptr> quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker(*quotientMdp); storm::parser::FormulaParser formulaParser; std::shared_ptr minFormula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"one\"]"); @@ -97,7 +97,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker2(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker2(*quotientMdp); result = checker2.check(*minFormula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(quotientMdp->getReachableStates(), quotientMdp->getInitialStates())); @@ -117,7 +117,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Cudd) { ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker3(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker3(*quotientMdp); result = checker3.check(*minFormula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(quotientMdp->getReachableStates(), quotientMdp->getInitialStates())); @@ -191,7 +191,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { std::shared_ptr> quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker(*quotientMdp); storm::parser::FormulaParser formulaParser; std::shared_ptr minFormula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"one\"]"); @@ -217,7 +217,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker2(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker2(*quotientMdp); result = checker2.check(*minFormula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(quotientMdp->getReachableStates(), quotientMdp->getInitialStates())); @@ -237,7 +237,7 @@ TEST(SymbolicModelBisimulationDecomposition, DiePartialQuotient_Sylvan) { ASSERT_TRUE(quotient->isSymbolicModel()); quotientMdp = quotient->as>(); - storm::modelchecker::SymbolicMdpPrctlModelChecker> checker3(*quotientMdp, std::make_unique>()); + storm::modelchecker::SymbolicMdpPrctlModelChecker> checker3(*quotientMdp); result = checker3.check(*minFormula); result->filter(storm::modelchecker::SymbolicQualitativeCheckResult(quotientMdp->getReachableStates(), quotientMdp->getInitialStates())); From 1b6200e4eb16f8dcf9a9a5ae1e85432c226bb081 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 12:50:06 +0100 Subject: [PATCH 140/647] added missing includes --- src/storm/solver/Multiplier.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 4356c583e..c420984e7 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "storm/solver/OptimizationDirection.h" #include "storm/solver/MultiplicationStyle.h" From 65676235bb328f9af9b75c5e3802c71e889b2160 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 12:52:54 +0100 Subject: [PATCH 141/647] fixed selection options for native equation solver method --- src/storm/settings/modules/NativeEquationSolverSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index ce92cef82..123298b2c 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -27,7 +27,7 @@ namespace storm { const std::string NativeEquationSolverSettings::powerMethodSymmetricUpdatesOptionName = "symmetricupdates"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch", "qpower" }; + std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "soundpower", "interval-iteration", "ratsearch" }; this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); From 48945d1199a5f7701f427538236f89c8c9dc89ad Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 14:29:19 +0100 Subject: [PATCH 142/647] improved multiplyRow method --- src/storm/solver/GmmxxMultiplier.cpp | 4 ++-- src/storm/solver/GmmxxMultiplier.h | 2 +- .../IterativeMinMaxLinearEquationSolver.cpp | 10 +--------- src/storm/solver/Multiplier.cpp | 6 ++++++ src/storm/solver/Multiplier.h | 15 +++++++++++++-- src/storm/solver/NativeLinearEquationSolver.cpp | 9 +-------- src/storm/solver/NativeMultiplier.cpp | 15 +++++++++++++-- src/storm/solver/NativeMultiplier.h | 4 +++- 8 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 759bdba35..9618e2495 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -103,9 +103,9 @@ namespace storm { } template - ValueType GmmxxMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { + void GmmxxMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { initialize(); - return vect_sp(gmm::mat_const_row(gmmMatrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()) + offset; + value += vect_sp(gmm::mat_const_row(gmmMatrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); } template diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index 9ea4089b9..87bee797e 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -24,7 +24,7 @@ namespace storm { virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; virtual void clearCache() const override; private: void initialize() const; diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 587aa3169..184c1e027 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -667,17 +667,9 @@ namespace storm { } void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { - xi = multiplier.multiplyRow(row, x, bi); - yi = multiplier.multiplyRow(row, y, storm::utility::zero()); - - /* xi = bi; yi = storm::utility::zero(); - for (auto const& entry : A.getRow(row)) { - xi += entry.getValue() * x[entry.getColumn()]; - yi += entry.getValue() * y[entry.getColumn()]; - } - */ + multiplier.multiplyRow2(row, x, xi, y, yi); } template diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index b2b6dfd5e..26bb4d85b 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -50,6 +50,12 @@ namespace storm { } } + template + void Multiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + multiplyRow(rowIndex, x1, val1); + multiplyRow(rowIndex, x2, val2); + } + template std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { switch (env.solver().multiplier().getType()) { diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index c420984e7..87d51b2f5 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -113,11 +113,22 @@ namespace storm { void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const; /*! - * Multiplies the row with the given index with x and adds the given offset + * Multiplies the row with the given index with x and adds the result to the provided value * @param rowIndex The index of the considered row * @param x The input vector with which the row is multiplied + * @param value The multiplication result is added to this value. */ - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const = 0; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const = 0; + + /*! + * Multiplies the row with the given index with x1 and x2 and adds the given offset o1 and o2, respectively + * @param rowIndex The index of the considered row + * @param x1 The first input vector with which the row is multiplied + * @param val1 The first multiplication result is added to this value. + * @param x2 The second input vector with which the row is multiplied + * @param val2 The second multiplication result is added to this value. + */ + virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const; protected: mutable std::unique_ptr> cachedVector; diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index c524513f2..51b8fa3c9 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -591,16 +591,9 @@ namespace storm { } void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { - xi = multiplier.multiplyRow(row, x, bi); - yi = multiplier.multiplyRow(row, y, storm::utility::zero()); - /* xi = bi; yi = storm::utility::zero(); - for (auto const& entry : A.getRow(row)) { - xi += entry.getValue() * x[entry.getColumn()]; - yi += entry.getValue() * y[entry.getColumn()]; - } - */ + multiplier.multiplyRow2(row, x, xi, y, yi); } void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index 3f84a4a8d..13b27c617 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -83,10 +83,21 @@ namespace storm { } template - ValueType NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const { - return this->matrix.multiplyRowWithVector(rowIndex, x); + void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + value += entry.getValue() * x[entry.getColumn()]; + } + } + + template + void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + val1 += entry.getValue() * x1[entry.getColumn()]; + val2 += entry.getValue() * x2[entry.getColumn()]; + } } + template void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { this->matrix.multiplyWithVector(x, result, b); diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index e1cc4d01a..73d1f84dc 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -21,7 +21,9 @@ namespace storm { virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual ValueType multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType const& offset) const override; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; + virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const override; + private: bool parallelize(Environment const& env) const; From 4eb187ba4f462bebf09274baf8a0e3e82baae86d Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 17:53:44 +0100 Subject: [PATCH 143/647] Added a new native multiplier --- .../settings/modules/MultiplierSettings.cpp | 4 +- src/storm/solver/InPlaceMultiplier.cpp | 138 ++++++++++++ src/storm/solver/InPlaceMultiplier.h | 41 ++++ src/storm/solver/Multiplier.cpp | 3 + src/storm/solver/Multiplier.h | 10 +- src/storm/solver/NativeMultiplier.cpp | 211 +++++++++++++++--- src/storm/solver/NativeMultiplier.h | 11 +- src/storm/solver/SolverSelectionOptions.cpp | 2 + src/storm/solver/SolverSelectionOptions.h | 2 +- 9 files changed, 377 insertions(+), 45 deletions(-) create mode 100644 src/storm/solver/InPlaceMultiplier.cpp create mode 100644 src/storm/solver/InPlaceMultiplier.h diff --git a/src/storm/settings/modules/MultiplierSettings.cpp b/src/storm/settings/modules/MultiplierSettings.cpp index d386bbf3a..7e8058c45 100644 --- a/src/storm/settings/modules/MultiplierSettings.cpp +++ b/src/storm/settings/modules/MultiplierSettings.cpp @@ -15,7 +15,7 @@ namespace storm { const std::string MultiplierSettings::multiplierTypeOptionName = "type"; MultiplierSettings::MultiplierSettings() : ModuleSettings(moduleName) { - std::vector multiplierTypes = {"native", "gmmxx"}; + std::vector multiplierTypes = {"native", "inplace", "gmmxx"}; this->addOption(storm::settings::OptionBuilder(moduleName, multiplierTypeOptionName, true, "Sets which type of multiplier is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplier.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplierTypes)).setDefaultValueString("gmmxx").build()).build()); @@ -25,6 +25,8 @@ namespace storm { std::string type = this->getOption(multiplierTypeOptionName).getArgumentByName("name").getValueAsString(); if (type == "native") { return storm::solver::MultiplierType::Native; + } else if (type == "inplace") { + return storm::solver::MultiplierType::InPlace; } else if (type == "gmmxx") { return storm::solver::MultiplierType::Gmmxx; } diff --git a/src/storm/solver/InPlaceMultiplier.cpp b/src/storm/solver/InPlaceMultiplier.cpp new file mode 100644 index 000000000..abfd4463a --- /dev/null +++ b/src/storm/solver/InPlaceMultiplier.cpp @@ -0,0 +1,138 @@ +#include "storm/solver/InPlaceMultiplier.h" + +#include "storm-config.h" + +#include "storm/environment/solver/MultiplierEnvironment.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + +#include "storm/storage/SparseMatrix.h" + +#include "storm/adapters/RationalNumberAdapter.h" +#include "storm/adapters/RationalFunctionAdapter.h" + +#include "storm/utility/macros.h" + +namespace storm { + namespace solver { + + template + InPlaceMultiplier::InPlaceMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { + // Intentionally left empty. + } + + template + bool InPlaceMultiplier::parallelize(Environment const& env) const { +#ifdef STORM_HAVE_INTELTBB + return storm::settings::getModule().isUseIntelTbbSet(); +#else + return false; +#endif + } + + template + void InPlaceMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddParallel(x, b, *target); + } else { + multAdd(x, b, *target); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); + } + } + + template + void InPlaceMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + this->matrix.multiplyWithVectorBackward(x, x, b); + } + + template + void InPlaceMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); + } else { + multAddReduce(dir, rowGroupIndices, x, b, *target, choices); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); + } + } + + template + void InPlaceMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); + } + + template + void InPlaceMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + value += entry.getValue() * x[entry.getColumn()]; + } + } + + template + void InPlaceMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + val1 += entry.getValue() * x1[entry.getColumn()]; + val2 += entry.getValue() * x2[entry.getColumn()]; + } + } + + + template + void InPlaceMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + this->matrix.multiplyWithVector(x, result, b); + } + + template + void InPlaceMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); + } + + template + void InPlaceMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { +#ifdef STORM_HAVE_INTELTBB + this->matrix.multiplyWithVectorParallel(x, result, b); +#else + STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); + multAdd(x, b, result); +#endif + } + + template + void InPlaceMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { +#ifdef STORM_HAVE_INTELTBB + this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); +#else + STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); + multAddReduce(dir, rowGroupIndices, x, b, result, choices); +#endif + } + + template class InPlaceMultiplier; +#ifdef STORM_HAVE_CARL + template class InPlaceMultiplier; + template class InPlaceMultiplier; +#endif + + } +} diff --git a/src/storm/solver/InPlaceMultiplier.h b/src/storm/solver/InPlaceMultiplier.h new file mode 100644 index 000000000..d02c74bfb --- /dev/null +++ b/src/storm/solver/InPlaceMultiplier.h @@ -0,0 +1,41 @@ +#pragma once + +#include "storm/solver/Multiplier.h" + +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + namespace storage { + template + class SparseMatrix; + } + + namespace solver { + + template + class InPlaceMultiplier : public Multiplier { + public: + InPlaceMultiplier(storm::storage::SparseMatrix const& matrix); + + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; + virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const override; + + + private: + bool parallelize(Environment const& env) const; + + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; + + void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + + void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + + }; + + } +} diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 26bb4d85b..a57633db6 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -11,6 +11,7 @@ #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/NativeMultiplier.h" #include "storm/solver/GmmxxMultiplier.h" +#include "storm/solver/InPlaceMultiplier.h" #include "storm/environment/solver/MultiplierEnvironment.h" namespace storm { @@ -63,6 +64,8 @@ namespace storm { return std::make_unique>(matrix); case MultiplierType::Native: return std::make_unique>(matrix); + case MultiplierType::InPlace: + return std::make_unique>(matrix); } } diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 87d51b2f5..77dc831c3 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -116,17 +116,17 @@ namespace storm { * Multiplies the row with the given index with x and adds the result to the provided value * @param rowIndex The index of the considered row * @param x The input vector with which the row is multiplied - * @param value The multiplication result is added to this value. + * @param value The multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. */ virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const = 0; /*! * Multiplies the row with the given index with x1 and x2 and adds the given offset o1 and o2, respectively * @param rowIndex The index of the considered row - * @param x1 The first input vector with which the row is multiplied - * @param val1 The first multiplication result is added to this value. - * @param x2 The second input vector with which the row is multiplied - * @param val2 The second multiplication result is added to this value. + * @param x1 The first input vector with which the row is multiplied. + * @param val1 The first multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. + * @param x2 The second input vector with which the row is multiplied. + * @param val2 The second multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. */ virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const; diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index 13b27c617..f2e74bb71 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -1,3 +1,4 @@ +#include #include "storm/solver/NativeMultiplier.h" #include "storm-config.h" @@ -12,17 +13,40 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" +#include "storm/utility/vector.h" namespace storm { namespace solver { - template - NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { + template + NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix), numRows(0) { // Intentionally left empty. } - template - bool NativeMultiplier::parallelize(Environment const& env) const { + template + void NativeMultiplier::initialize() const { + if (numRows == 0) { + numRows = this->matrix.getRowCount(); + entries.clear(); + columns.clear(); + rowIndications.clear(); + entries.reserve(this->matrix.getNonzeroEntryCount()); + columns.reserve(this->matrix.getColumnCount()); + rowIndications.reserve(numRows + 1); + + rowIndications.push_back(0); + for (IndexType r = 0; r < numRows; ++r) { + for (auto const& entry : this->matrix.getRow(r)) { + entries.push_back(entry.getValue()); + columns.push_back(entry.getColumn()); + } + rowIndications.push_back(entries.size()); + } + } + } + + template + bool NativeMultiplier::parallelize(Environment const& env) const { #ifdef STORM_HAVE_INTELTBB return storm::settings::getModule().isUseIntelTbbSet(); #else @@ -30,8 +54,9 @@ namespace storm { #endif } - template - void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + template + void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + initialize(); std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { @@ -51,13 +76,32 @@ namespace storm { } } - template - void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { - this->matrix.multiplyWithVectorBackward(x, x, b); + template + void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + initialize(); + // multiply the rows in backwards order + IndexType r = numRows; + if (b) { + std::vector const& bRef = *b; + while (r > 0) { + --r; + ValueType xr = bRef[r]; + this->multiplyRow(r, x, xr); + x[r] = std::move(xr); + } + } else { + while (r > 0) { + --r; + ValueType xr = storm::utility::zero(); + this->multiplyRow(r, x, xr); + x[r] = std::move(xr); + } + } } - template - void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + initialize(); std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { @@ -77,39 +121,132 @@ namespace storm { } } - template - void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); + template + void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + initialize(); + assert(rowGroupIndices.size() - 1 == x.size()); + // multiply the rowgroups in backwards order + IndexType g = x.size(); + if (choices) { + while (g > 0) { + --g; + x[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b, &((*choices)[g])); + } + } else { + while (g > 0) { + --g; + x[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b); + } + } } - template - void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { - for (auto const& entry : this->matrix.getRow(rowIndex)) { - value += entry.getValue() * x[entry.getColumn()]; + template + void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + initialize(); + assert(rowIndex < numRows); + IndexType const& rowStart = rowIndications[rowIndex]; + IndexType const& rowEnd = rowIndications[rowIndex + 1]; + for (IndexType e = rowStart; e < rowEnd; ++e) { + value += entries[e] * x[columns[e]]; } } - template - void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { - for (auto const& entry : this->matrix.getRow(rowIndex)) { - val1 += entry.getValue() * x1[entry.getColumn()]; - val2 += entry.getValue() * x2[entry.getColumn()]; + template + void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + initialize(); + assert(rowIndex < numRows); + IndexType const& rowStart = rowIndications[rowIndex]; + IndexType const& rowEnd = rowIndications[rowIndex + 1]; + for (IndexType e = rowStart; e < rowEnd; ++e) { + val1 += entries[e] * x1[columns[e]]; + val2 += entries[e] * x2[columns[e]]; } } + + template + ValueType NativeMultiplier::multiplyAndReduceRowGroup(OptimizationDirection const& dir, IndexType const& groupStart, IndexType const& groupEnd, std::vector const& x, std::vector const* b, uint_fast64_t* choice) const { + // Compute value for first row + ValueType result = b ? (*b)[groupStart] : storm::utility::zero(); + multiplyRow(groupStart, x, result); + if (choice) { + *choice = 0; + // Compute the value for the remaining rows. Keep track of the optimal choice + for (IndexType r = groupStart + 1; r < groupEnd; ++r) { + ValueType rowVal = b ? (*b)[r] : storm::utility::zero(); + multiplyRow(r, x, rowVal); + if (dir == OptimizationDirection::Minimize) { + if (rowVal < result) { + result = std::move(rowVal); + *choice = r - groupStart; + } + } else { + if (rowVal > result) { + result = std::move(rowVal); + *choice = r - groupStart; + } + } + } + } else { + // Compute the value for the remaining rows + for (IndexType r = groupStart + 1; r < groupEnd; ++r) { + ValueType rowVal = b ? (*b)[r] : storm::utility::zero(); + multiplyRow(r, x, rowVal); + if (dir == OptimizationDirection::Minimize) { + if (rowVal < result) { + result = std::move(rowVal); + } + } else { + if (rowVal > result) { + result = std::move(rowVal); + } + } + } + } + return result; + } + + template<> + storm::RationalFunction NativeMultiplier::multiplyAndReduceRowGroup(OptimizationDirection const&, uint32_t const&, uint32_t const&, std::vector const&, std::vector const*, uint_fast64_t*) const { + STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "This operation is not supported with the given value type."); + return storm::utility::zero(); + } - - template - void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { - this->matrix.multiplyWithVector(x, result, b); + template + void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + // multiply the rows sequentially (in forward order) + if (b) { + std::vector const& bRef = *b; + for (IndexType r = 0; r < numRows; ++r) { + ValueType xr = bRef[r]; + this->multiplyRow(r, x, xr); + result[r] = std::move(xr); + } + } else { + for (IndexType r = 0; r < numRows; ++r) { + ValueType xr = storm::utility::zero(); + this->multiplyRow(r, x, xr); + result[r] = std::move(xr); + } + } } - template - void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); + template + void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + assert(rowGroupIndices.size() - 1 == x.size()); + // multiply the rowgroups in forward order + if (choices) { + for (IndexType g = 0, groupsEnd = x.size(); g < groupsEnd; ++g) { + result[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b, &((*choices)[g])); + } + } else { + for (IndexType g = 0, groupsEnd = x.size(); g < groupsEnd; ++g) { + result[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b); + } + } } - template - void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { + template + void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB this->matrix.multiplyWithVectorParallel(x, result, b); #else @@ -118,8 +255,8 @@ namespace storm { #endif } - template - void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); #else @@ -128,10 +265,10 @@ namespace storm { #endif } - template class NativeMultiplier; + template class NativeMultiplier; #ifdef STORM_HAVE_CARL - template class NativeMultiplier; - template class NativeMultiplier; + template class NativeMultiplier; + template class NativeMultiplier; #endif } diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index 73d1f84dc..d915b8fc7 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -12,7 +12,7 @@ namespace storm { namespace solver { - template + template class NativeMultiplier : public Multiplier { public: NativeMultiplier(storm::storage::SparseMatrix const& matrix); @@ -28,6 +28,10 @@ namespace storm { private: bool parallelize(Environment const& env) const; + void initialize() const; + + ValueType multiplyAndReduceRowGroup(OptimizationDirection const& dir, IndexType const& groupStart, IndexType const& groupEnd, std::vector const& x, std::vector const* b, uint_fast64_t* choice = nullptr) const; + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; @@ -35,6 +39,11 @@ namespace storm { void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + mutable std::vector entries; + mutable std::vector columns; + mutable std::vector rowIndications; + mutable IndexType numRows; + }; } diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index d2148e9bc..bcbe9cc47 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -28,6 +28,8 @@ namespace storm { switch(t) { case MultiplierType::Native: return "Native"; + case MultiplierType::InPlace: + return "InPlace"; case MultiplierType::Gmmxx: return "Gmmxx"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index 678bc1565..74d1dbc3c 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -7,7 +7,7 @@ namespace storm { namespace solver { ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, IntervalIteration, SoundValueIteration, TopologicalCuda) - ExtendEnumsWithSelectionField(MultiplierType, Native, Gmmxx) + ExtendEnumsWithSelectionField(MultiplierType, Native, InPlace, Gmmxx) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) From e491dc381385b00db3b3abd356524f4d3658da77 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 17:54:00 +0100 Subject: [PATCH 144/647] fixed usage of multiplyrow --- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 8 +++++--- src/storm/solver/NativeLinearEquationSolver.cpp | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 184c1e027..845e7495e 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -667,9 +667,11 @@ namespace storm { } void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { - xi = bi; - yi = storm::utility::zero(); - multiplier.multiplyRow2(row, x, xi, y, yi); + ValueType xRes = bi; + ValueType yRes = storm::utility::zero(); + multiplier.multiplyRow2(row, x, xRes, y, yRes); + xi = std::move(xRes); + yi = std::move(yRes); } template diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 51b8fa3c9..48a2819c7 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -591,9 +591,11 @@ namespace storm { } void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { - xi = bi; - yi = storm::utility::zero(); - multiplier.multiplyRow2(row, x, xi, y, yi); + ValueType xRes = bi; + ValueType yRes = storm::utility::zero(); + multiplier.multiplyRow2(row, x, xRes, y, yRes); + xi = std::move(xRes); + yi = std::move(yRes); } void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { From ff18956fbbe0b31a31d4446c7f06d1e235472d2d Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 19:57:09 +0100 Subject: [PATCH 145/647] reverted back to old native multiplier --- .../settings/modules/MultiplierSettings.cpp | 2 - src/storm/solver/Multiplier.cpp | 2 - src/storm/solver/NativeMultiplier.cpp | 211 +++--------------- src/storm/solver/NativeMultiplier.h | 12 +- src/storm/solver/SolverSelectionOptions.cpp | 2 - src/storm/solver/SolverSelectionOptions.h | 2 +- 6 files changed, 39 insertions(+), 192 deletions(-) diff --git a/src/storm/settings/modules/MultiplierSettings.cpp b/src/storm/settings/modules/MultiplierSettings.cpp index 7e8058c45..befa91086 100644 --- a/src/storm/settings/modules/MultiplierSettings.cpp +++ b/src/storm/settings/modules/MultiplierSettings.cpp @@ -25,8 +25,6 @@ namespace storm { std::string type = this->getOption(multiplierTypeOptionName).getArgumentByName("name").getValueAsString(); if (type == "native") { return storm::solver::MultiplierType::Native; - } else if (type == "inplace") { - return storm::solver::MultiplierType::InPlace; } else if (type == "gmmxx") { return storm::solver::MultiplierType::Gmmxx; } diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index a57633db6..0da52a06a 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -64,8 +64,6 @@ namespace storm { return std::make_unique>(matrix); case MultiplierType::Native: return std::make_unique>(matrix); - case MultiplierType::InPlace: - return std::make_unique>(matrix); } } diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index f2e74bb71..13b27c617 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -1,4 +1,3 @@ -#include #include "storm/solver/NativeMultiplier.h" #include "storm-config.h" @@ -13,40 +12,17 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" -#include "storm/utility/vector.h" namespace storm { namespace solver { - template - NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix), numRows(0) { + template + NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. } - template - void NativeMultiplier::initialize() const { - if (numRows == 0) { - numRows = this->matrix.getRowCount(); - entries.clear(); - columns.clear(); - rowIndications.clear(); - entries.reserve(this->matrix.getNonzeroEntryCount()); - columns.reserve(this->matrix.getColumnCount()); - rowIndications.reserve(numRows + 1); - - rowIndications.push_back(0); - for (IndexType r = 0; r < numRows; ++r) { - for (auto const& entry : this->matrix.getRow(r)) { - entries.push_back(entry.getValue()); - columns.push_back(entry.getColumn()); - } - rowIndications.push_back(entries.size()); - } - } - } - - template - bool NativeMultiplier::parallelize(Environment const& env) const { + template + bool NativeMultiplier::parallelize(Environment const& env) const { #ifdef STORM_HAVE_INTELTBB return storm::settings::getModule().isUseIntelTbbSet(); #else @@ -54,9 +30,8 @@ namespace storm { #endif } - template - void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { - initialize(); + template + void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { @@ -76,32 +51,13 @@ namespace storm { } } - template - void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { - initialize(); - // multiply the rows in backwards order - IndexType r = numRows; - if (b) { - std::vector const& bRef = *b; - while (r > 0) { - --r; - ValueType xr = bRef[r]; - this->multiplyRow(r, x, xr); - x[r] = std::move(xr); - } - } else { - while (r > 0) { - --r; - ValueType xr = storm::utility::zero(); - this->multiplyRow(r, x, xr); - x[r] = std::move(xr); - } - } + template + void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + this->matrix.multiplyWithVectorBackward(x, x, b); } - template - void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - initialize(); + template + void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { std::vector* target = &result; if (&x == &result) { if (this->cachedVector) { @@ -121,132 +77,39 @@ namespace storm { } } - template - void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - initialize(); - assert(rowGroupIndices.size() - 1 == x.size()); - // multiply the rowgroups in backwards order - IndexType g = x.size(); - if (choices) { - while (g > 0) { - --g; - x[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b, &((*choices)[g])); - } - } else { - while (g > 0) { - --g; - x[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b); - } - } - } - - template - void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { - initialize(); - assert(rowIndex < numRows); - IndexType const& rowStart = rowIndications[rowIndex]; - IndexType const& rowEnd = rowIndications[rowIndex + 1]; - for (IndexType e = rowStart; e < rowEnd; ++e) { - value += entries[e] * x[columns[e]]; - } + template + void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); } - template - void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { - initialize(); - assert(rowIndex < numRows); - IndexType const& rowStart = rowIndications[rowIndex]; - IndexType const& rowEnd = rowIndications[rowIndex + 1]; - for (IndexType e = rowStart; e < rowEnd; ++e) { - val1 += entries[e] * x1[columns[e]]; - val2 += entries[e] * x2[columns[e]]; + template + void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + value += entry.getValue() * x[entry.getColumn()]; } } - template - ValueType NativeMultiplier::multiplyAndReduceRowGroup(OptimizationDirection const& dir, IndexType const& groupStart, IndexType const& groupEnd, std::vector const& x, std::vector const* b, uint_fast64_t* choice) const { - // Compute value for first row - ValueType result = b ? (*b)[groupStart] : storm::utility::zero(); - multiplyRow(groupStart, x, result); - if (choice) { - *choice = 0; - // Compute the value for the remaining rows. Keep track of the optimal choice - for (IndexType r = groupStart + 1; r < groupEnd; ++r) { - ValueType rowVal = b ? (*b)[r] : storm::utility::zero(); - multiplyRow(r, x, rowVal); - if (dir == OptimizationDirection::Minimize) { - if (rowVal < result) { - result = std::move(rowVal); - *choice = r - groupStart; - } - } else { - if (rowVal > result) { - result = std::move(rowVal); - *choice = r - groupStart; - } - } - } - } else { - // Compute the value for the remaining rows - for (IndexType r = groupStart + 1; r < groupEnd; ++r) { - ValueType rowVal = b ? (*b)[r] : storm::utility::zero(); - multiplyRow(r, x, rowVal); - if (dir == OptimizationDirection::Minimize) { - if (rowVal < result) { - result = std::move(rowVal); - } - } else { - if (rowVal > result) { - result = std::move(rowVal); - } - } - } + template + void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + val1 += entry.getValue() * x1[entry.getColumn()]; + val2 += entry.getValue() * x2[entry.getColumn()]; } - return result; - } - - template<> - storm::RationalFunction NativeMultiplier::multiplyAndReduceRowGroup(OptimizationDirection const&, uint32_t const&, uint32_t const&, std::vector const&, std::vector const*, uint_fast64_t*) const { - STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "This operation is not supported with the given value type."); - return storm::utility::zero(); } - template - void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { - // multiply the rows sequentially (in forward order) - if (b) { - std::vector const& bRef = *b; - for (IndexType r = 0; r < numRows; ++r) { - ValueType xr = bRef[r]; - this->multiplyRow(r, x, xr); - result[r] = std::move(xr); - } - } else { - for (IndexType r = 0; r < numRows; ++r) { - ValueType xr = storm::utility::zero(); - this->multiplyRow(r, x, xr); - result[r] = std::move(xr); - } - } + + template + void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + this->matrix.multiplyWithVector(x, result, b); } - template - void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - assert(rowGroupIndices.size() - 1 == x.size()); - // multiply the rowgroups in forward order - if (choices) { - for (IndexType g = 0, groupsEnd = x.size(); g < groupsEnd; ++g) { - result[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b, &((*choices)[g])); - } - } else { - for (IndexType g = 0, groupsEnd = x.size(); g < groupsEnd; ++g) { - result[g] = multiplyAndReduceRowGroup(dir, rowGroupIndices[g], rowGroupIndices[g + 1], x, b); - } - } + template + void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); } - template - void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { + template + void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB this->matrix.multiplyWithVectorParallel(x, result, b); #else @@ -255,8 +118,8 @@ namespace storm { #endif } - template - void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); #else @@ -265,10 +128,10 @@ namespace storm { #endif } - template class NativeMultiplier; + template class NativeMultiplier; #ifdef STORM_HAVE_CARL - template class NativeMultiplier; - template class NativeMultiplier; + template class NativeMultiplier; + template class NativeMultiplier; #endif } diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index d915b8fc7..90b0f1454 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -12,7 +12,7 @@ namespace storm { namespace solver { - template + template class NativeMultiplier : public Multiplier { public: NativeMultiplier(storm::storage::SparseMatrix const& matrix); @@ -24,14 +24,9 @@ namespace storm { virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const override; - private: bool parallelize(Environment const& env) const; - void initialize() const; - - ValueType multiplyAndReduceRowGroup(OptimizationDirection const& dir, IndexType const& groupStart, IndexType const& groupEnd, std::vector const& x, std::vector const* b, uint_fast64_t* choice = nullptr) const; - void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; @@ -39,11 +34,6 @@ namespace storm { void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - mutable std::vector entries; - mutable std::vector columns; - mutable std::vector rowIndications; - mutable IndexType numRows; - }; } diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index bcbe9cc47..d2148e9bc 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -28,8 +28,6 @@ namespace storm { switch(t) { case MultiplierType::Native: return "Native"; - case MultiplierType::InPlace: - return "InPlace"; case MultiplierType::Gmmxx: return "Gmmxx"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index 74d1dbc3c..678bc1565 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -7,7 +7,7 @@ namespace storm { namespace solver { ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, IntervalIteration, SoundValueIteration, TopologicalCuda) - ExtendEnumsWithSelectionField(MultiplierType, Native, InPlace, Gmmxx) + ExtendEnumsWithSelectionField(MultiplierType, Native, Gmmxx) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) From c1ecc223036763d888d4a495fe88c3ee8a7ffed1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 1 Mar 2018 19:58:42 +0100 Subject: [PATCH 146/647] new multiplyRow method for sound vi --- .../IterativeMinMaxLinearEquationSolver.cpp | 81 +++++++++++++------ .../solver/NativeLinearEquationSolver.cpp | 58 ++++++++++--- 2 files changed, 102 insertions(+), 37 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 845e7495e..3b80a215b 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -1,4 +1,5 @@ #include +#include #include "storm/solver/IterativeMinMaxLinearEquationSolver.h" @@ -614,7 +615,12 @@ namespace storm { template class SoundValueIterationHelper { public: - SoundValueIterationHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision, uint64_t sizeOfLargestRowGroup) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + + typedef uint32_t IndexType; + + SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision), rowGroupIndices(matrix.getRowGroupIndices()) { + STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); + uint64_t sizeOfLargestRowGroup = matrix.getSizeOfLargestRowGroup(); xTmp.resize(sizeOfLargestRowGroup); yTmp.resize(sizeOfLargestRowGroup); x.assign(x.size(), storm::utility::zero()); @@ -623,6 +629,22 @@ namespace storm { decisionValueBlocks = false; convergencePhase1 = true; firstIndexViolatingConvergence = 0; + + numRows = matrix.getRowCount(); + matrixValues.clear(); + matrixColumns.clear(); + rowIndications.clear(); + matrixValues.reserve(matrix.getNonzeroEntryCount()); + matrixColumns.reserve(matrix.getColumnCount()); + rowIndications.reserve(numRows + 1); + rowIndications.push_back(0); + for (IndexType r = 0; r < numRows; ++r) { + for (auto const& entry : matrix.getRow(r)) { + matrixValues.push_back(entry.getValue()); + matrixColumns.push_back(entry.getColumn()); + } + rowIndications.push_back(matrixValues.size()); + } } @@ -666,30 +688,38 @@ namespace storm { return maximize(dir) ? minIndex : maxIndex; } - void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { + void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { + assert(rowIndex < numRows); ValueType xRes = bi; ValueType yRes = storm::utility::zero(); - multiplier.multiplyRow2(row, x, xRes, y, yRes); + + auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; + auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; + auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; + for (; entryIt != entryItE; ++entryIt, ++colIt) { + xRes += *entryIt * x[*colIt]; + yRes += *entryIt * y[*colIt]; + } xi = std::move(xRes); yi = std::move(yRes); } template - void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { + void performIterationStep(std::vector const& b) { if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValue(A, multiplier, b); + performIterationStepUpdateDecisionValue(b); } else { assert(decisionValue == getPrimaryBound()); auto xIt = x.rbegin(); auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); + auto groupStartIt = rowGroupIndices.rbegin(); uint64_t groupEnd = *groupStartIt; ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + for (auto groupStartIte = rowGroupIndices.rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; + IndexType row = *groupStartIt; ValueType xBest, yBest; - multiplyRow(row, A, multiplier, b[row], xBest, yBest); + multiplyRow(row, b[row], xBest, yBest); ++row; // Only do more work if there are still rows in this row group if (row != groupEnd) { @@ -697,7 +727,7 @@ namespace storm { ValueType bestValue = xBest + yBest * getPrimaryBound(); for (;row < groupEnd; ++row) { // Get the multiplication results - multiplyRow(row, A, multiplier, b[row], xi, yi); + multiplyRow(row, b[row], xi, yi); ValueType currentValue = xi + yi * getPrimaryBound(); // Check if the current row is better then the previously found one if (better(currentValue, bestValue)) { @@ -718,17 +748,17 @@ namespace storm { } template - void performIterationStepUpdateDecisionValue(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { + void performIterationStepUpdateDecisionValue(std::vector const& b) { auto xIt = x.rbegin(); auto yIt = y.rbegin(); - auto groupStartIt = A.getRowGroupIndices().rbegin(); + auto groupStartIt = rowGroupIndices.rbegin(); uint64_t groupEnd = *groupStartIt; ++groupStartIt; - for (auto groupStartIte = A.getRowGroupIndices().rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + for (auto groupStartIte = rowGroupIndices.rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { // Perform the iteration for the first row in the group uint64_t row = *groupStartIt; ValueType xBest, yBest; - multiplyRow(row, A, multiplier, b[row], xBest, yBest); + multiplyRow(row, b[row], xBest, yBest); ++row; // Only do more work if there are still rows in this row group if (row != groupEnd) { @@ -738,7 +768,7 @@ namespace storm { ValueType bestValue = xBest + yBest * getPrimaryBound(); for (;row < groupEnd; ++row) { // Get the multiplication results - multiplyRow(row, A, multiplier, b[row], xi, yi); + multiplyRow(row, b[row], xi, yi); ValueType currentValue = xi + yi * getPrimaryBound(); // Check if the current row is better then the previously found one if (better(currentValue, bestValue)) { @@ -765,7 +795,7 @@ namespace storm { } } else { for (;row < groupEnd; ++row) { - multiplyRow(row, A, multiplier, b[row], xi, yi); + multiplyRow(row, b[row], xi, yi); // Update the best choice if (yi > yBest || (yi == yBest && better(xi, xBest))) { xTmp[xyTmpIndex] = std::move(xBest); @@ -963,6 +993,12 @@ namespace storm { bool relative; ValueType precision; + + std::vector matrixValues; + std::vector matrixColumns; + std::vector rowIndications; + std::vector::index_type> const& rowGroupIndices; + IndexType numRows; }; template @@ -973,12 +1009,9 @@ namespace storm { if (!this->auxiliaryRowGroupVector) { this->auxiliaryRowGroupVector = std::make_unique>(); } - - if (!this->multiplierA) { - this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); - } - - SoundValueIterationHelper helper(x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision()), this->A->getSizeOfLargestRowGroup()); + + // TODO: implement caching for the helper + SoundValueIterationHelper helper(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { @@ -999,13 +1032,13 @@ namespace storm { while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { if (minimize(dir)) { - helper.template performIterationStep(*this->A, *this->multiplierA, b); + helper.template performIterationStep(b); if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } } else { assert(maximize(dir)); - helper.template performIterationStep(*this->A, *this->multiplierA, b); + helper.template performIterationStep(b); if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { status = SolverStatus::Converged; } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 48a2819c7..96daa55b4 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -1,5 +1,7 @@ #include "storm/solver/NativeLinearEquationSolver.h" +#include + #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/utility/ConstantsComparator.h" @@ -12,7 +14,7 @@ #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/UnmetRequirementException.h" #include "storm/exceptions/PrecisionExceededException.h" - +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace solver { @@ -573,11 +575,31 @@ namespace storm { template class SoundPowerHelper { public: - SoundPowerHelper(std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + + typedef uint32_t IndexType; + + SoundPowerHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { + STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); x.assign(x.size(), storm::utility::zero()); y.assign(x.size(), storm::utility::one()); convergencePhase1 = true; firstIndexViolatingConvergence = 0; + + numRows = matrix.getRowCount(); + matrixValues.clear(); + matrixColumns.clear(); + rowIndications.clear(); + matrixValues.reserve(matrix.getNonzeroEntryCount()); + matrixColumns.reserve(matrix.getColumnCount()); + rowIndications.reserve(numRows + 1); + rowIndications.push_back(0); + for (IndexType r = 0; r < numRows; ++r) { + for (auto const& entry : matrix.getRow(r)) { + matrixValues.push_back(entry.getValue()); + matrixColumns.push_back(entry.getColumn()); + } + rowIndications.push_back(matrixValues.size()); + } } inline void setLowerBound(ValueType const& value) { @@ -590,21 +612,29 @@ namespace storm { upperBound = value; } - void multiplyRow(uint64_t const& row, storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, ValueType const& bi, ValueType& xi, ValueType& yi) { + void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { + assert(rowIndex < numRows); ValueType xRes = bi; ValueType yRes = storm::utility::zero(); - multiplier.multiplyRow2(row, x, xRes, y, yRes); + + auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; + auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; + auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; + for (; entryIt != entryItE; ++entryIt, ++colIt) { + xRes += *entryIt * x[*colIt]; + yRes += *entryIt * y[*colIt]; + } xi = std::move(xRes); yi = std::move(yRes); } - void performIterationStep(storm::storage::SparseMatrix const& A, storm::solver::Multiplier const& multiplier, std::vector const& b) { + void performIterationStep(std::vector const& b) { auto xIt = x.rbegin(); auto yIt = y.rbegin(); - uint64_t row = A.getRowCount(); + IndexType row = numRows; while (row > 0) { --row; - multiplyRow(row, A, multiplier, b[row], *xIt, *yIt); + multiplyRow(row, b[row], *xIt, *yIt); ++xIt; ++yIt; } @@ -744,6 +774,11 @@ namespace storm { bool convergencePhase1; uint64_t firstIndexViolatingConvergence; + std::vector matrixValues; + std::vector matrixColumns; + std::vector rowIndications; + IndexType numRows; + bool relative; ValueType precision; }; @@ -757,11 +792,8 @@ namespace storm { this->cachedRowVector = std::make_unique>(); } - if (!this->multiplier) { - this->multiplier = storm::solver::MultiplierFactory().create(env, *this->A); - } - - SoundPowerHelper helper(x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + // TODO: implement caching for the helper + SoundPowerHelper helper(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { @@ -782,7 +814,7 @@ namespace storm { uint64_t iterations = 0; while (!converged && iterations < env.solver().native().getMaximalNumberOfIterations()) { - helper.performIterationStep(*this->A, *this->multiplier, b); + helper.performIterationStep(b); if (helper.checkConvergenceUpdateBounds(relevantValuesPtr)) { converged = true; } From 24382630dcbdb6e459ef350658b697e6fabb1049 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 2 Mar 2018 09:19:49 +0100 Subject: [PATCH 147/647] removed output of performed iterations to cout --- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 5 ----- .../pcaa/StandardPcaaWeightVectorChecker.h | 8 -------- src/storm/solver/AbstractEquationSolver.h | 9 --------- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 3 --- src/storm/solver/NativeLinearEquationSolver.cpp | 4 ---- src/storm/solver/TopologicalLinearEquationSolver.cpp | 5 ----- .../solver/TopologicalMinMaxLinearEquationSolver.cpp | 7 ------- 7 files changed, 41 deletions(-) diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index e3c734bf0..9a8b39c4e 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -194,8 +194,6 @@ namespace storm { std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero()); solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues); - this->overallPerformedIterations += solver->overallPerformedIterations; - solver->overallPerformedIterations = 0; this->weightedResult = std::vector(transitionMatrix.getRowGroupCount()); transformReducedSolutionToOriginalModel(ecQuotient->matrix, ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecQuotient->ecqToOriginalChoiceMapping, ecQuotient->originalToEcqStateMapping, this->weightedResult, this->optimalChoices); @@ -278,9 +276,6 @@ namespace storm { STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); solver->solveEquations(env, x, b); - this->overallPerformedIterations += solver->overallPerformedIterations; - solver->overallPerformedIterations = 0; - // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); } diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h index 10cba6fbc..b28a80ac6 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h @@ -37,14 +37,6 @@ namespace storm { StandardPcaaWeightVectorChecker(SparseMultiObjectivePreprocessorResult const& preprocessorResult); - virtual ~StandardPcaaWeightVectorChecker() { - if (overallPerformedIterations != 0) { - std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; - } - } - - mutable uint64_t overallPerformedIterations = 0; - /*! * - computes the optimal expected reward w.r.t. the weighted sum of the rewards of the individual objectives * - extracts the scheduler that induces this optimum diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index 7d9013566..c71bed0a7 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -17,15 +17,6 @@ namespace storm { public: AbstractEquationSolver(); - virtual ~AbstractEquationSolver() { - if (overallPerformedIterations != 0) { - std::cout << "PERFORMEDITERATIONS: " << overallPerformedIterations << std::endl; - } - } - - mutable uint64_t overallPerformedIterations = 0; - - /*! * Sets a custom termination condition that is used together with the regular termination condition of the * solver. diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 3b80a215b..8da065298 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -586,7 +586,6 @@ namespace storm { } reportStatus(status, iterations); - this->overallPerformedIterations += iterations; // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); @@ -1062,8 +1061,6 @@ namespace storm { reportStatus(status, iterations); - this->overallPerformedIterations += iterations; - if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 96daa55b4..4251589ea 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -565,8 +565,6 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - this->overallPerformedIterations += iterations; - this->logIterations(converged, terminate, iterations); return converged; @@ -832,8 +830,6 @@ namespace storm { this->logIterations(converged, terminate, iterations); - this->overallPerformedIterations += iterations; - if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index e3e733407..bd5313381 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -82,7 +82,6 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; - ++this->overallPerformedIterations; } else { sccAsBitVector.clear(); for (auto const& state : scc) { @@ -93,10 +92,6 @@ namespace storm { } } - if (this->sccSolver) { - this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; - this->sccSolver->overallPerformedIterations = 0; - } if (!this->isCachingEnabled()) { clearCache(); } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 70c478ffd..2c8951fc3 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -80,7 +80,6 @@ namespace storm { for (auto const& scc : *this->sortedSccDecomposition) { if (scc.isTrivial()) { returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; - ++this->overallPerformedIterations; } else { sccRowGroupsAsBitVector.clear(); sccRowsAsBitVector.clear(); @@ -104,12 +103,6 @@ namespace storm { } } - if (this->sccSolver) { - this->overallPerformedIterations += this->sccSolver->overallPerformedIterations; - this->sccSolver->overallPerformedIterations = 0; - } - - if (!this->isCachingEnabled()) { clearCache(); } From d6f2261ca98c0c1a62fd30f2c96d78d9709666a4 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 2 Mar 2018 10:26:32 +0100 Subject: [PATCH 148/647] enable representatives in quotient extraction also for MDP/MA --- src/storm/storage/dd/Bdd.cpp | 40 +++++++++++++++++++ src/storm/storage/dd/Bdd.h | 13 ++++++ .../dd/bisimulation/QuotientExtractor.cpp | 34 ++++++++++------ 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/storm/storage/dd/Bdd.cpp b/src/storm/storage/dd/Bdd.cpp index d17bbd3d4..c2452ed3b 100644 --- a/src/storm/storage/dd/Bdd.cpp +++ b/src/storm/storage/dd/Bdd.cpp @@ -359,6 +359,46 @@ namespace storm { } } + template + Bdd Bdd::renameVariablesConcretize(std::set const& from, std::set const& to) const { + std::vector> fromBdds; + std::vector> toBdds; + + for (auto const& metaVariable : from) { + STORM_LOG_THROW(this->containsMetaVariable(metaVariable), storm::exceptions::InvalidOperationException, "Cannot rename variable '" << metaVariable.getName() << "' that is not present."); + DdMetaVariable const& ddMetaVariable = this->getDdManager().getMetaVariable(metaVariable); + for (auto const& ddVariable : ddMetaVariable.getDdVariables()) { + fromBdds.push_back(ddVariable.getInternalBdd()); + } + } + std::sort(fromBdds.begin(), fromBdds.end(), [] (InternalBdd const& a, InternalBdd const& b) { return a.getLevel() < b.getLevel(); } ); + for (auto const& metaVariable : to) { + STORM_LOG_THROW(!this->containsMetaVariable(metaVariable), storm::exceptions::InvalidOperationException, "Cannot rename to variable '" << metaVariable.getName() << "' that is already present."); + DdMetaVariable const& ddMetaVariable = this->getDdManager().getMetaVariable(metaVariable); + for (auto const& ddVariable : ddMetaVariable.getDdVariables()) { + toBdds.push_back(ddVariable.getInternalBdd()); + } + } + std::sort(toBdds.begin(), toBdds.end(), [] (InternalBdd const& a, InternalBdd const& b) { return a.getLevel() < b.getLevel(); } ); + + std::set newContainedMetaVariables = to; + std::set_difference(this->getContainedMetaVariables().begin(), this->getContainedMetaVariables().end(), from.begin(), from.end(), std::inserter(newContainedMetaVariables, newContainedMetaVariables.begin())); + + STORM_LOG_ASSERT(toBdds.size() >= fromBdds.size(), "Unable to perform rename-concretize with mismatching sizes."); + + if (fromBdds.size() == toBdds.size()) { + return Bdd(this->getDdManager(), internalBdd.swapVariables(fromBdds, toBdds), newContainedMetaVariables); + } else { + InternalBdd negatedCube = this->getDdManager().getBddOne().getInternalBdd(); + for (uint64_t index = fromBdds.size(); index < toBdds.size(); ++index) { + negatedCube &= !toBdds[index]; + } + toBdds.resize(fromBdds.size()); + + return Bdd(this->getDdManager(), (internalBdd && negatedCube).swapVariables(fromBdds, toBdds), newContainedMetaVariables); + } + } + template template Add Bdd::toAdd() const { diff --git a/src/storm/storage/dd/Bdd.h b/src/storm/storage/dd/Bdd.h index c80e6a43b..bfb845c70 100644 --- a/src/storm/storage/dd/Bdd.h +++ b/src/storm/storage/dd/Bdd.h @@ -298,6 +298,19 @@ namespace storm { */ Bdd renameVariablesAbstract(std::set const& from, std::set const& to) const; + /*! + * Renames the given meta variables in the BDD. The number of the underlying DD variables of the from meta + * variable set needs to be at most as large as the to meta variable set. If the amount of variables coincide, + * this operation coincides with renameVariables. Otherwise, it first adds a unique encoding in terms of the + * superfluous variables and then performs the renaming. + * + * @param from The meta variables to be renamed. The current ADD needs to contain all these meta variables. + * @param to The meta variables that are the target of the renaming process. The current ADD must not contain + * any of these meta variables. + * @return The resulting ADD. + */ + Bdd renameVariablesConcretize(std::set const& from, std::set const& to) const; + /*! * Retrieves whether this DD represents the constant one function. * diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index 593f1491a..108164a2a 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -936,10 +936,6 @@ namespace storm { bool useRepresentativesForThisExtraction = this->useRepresentatives; if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { - if (modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { - STORM_LOG_WARN_COND(!useRepresentativesForThisExtraction, "Using representatives is unsupported for MDPs, falling back to regular extraction."); - useRepresentativesForThisExtraction = false; - } // Sanity checks. STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size."); @@ -948,16 +944,20 @@ namespace storm { std::set blockVariableSet = {partition.getBlockVariable()}; std::set blockPrimeVariableSet = {partition.getPrimedBlockVariable()}; std::vector> blockMetaVariablePairs = {std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())}; + + auto start = std::chrono::high_resolution_clock::now(); + // Compute representatives. storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); + partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + if (useRepresentativesForThisExtraction) { - storm::dd::Bdd partitionAsBddOverPrimedBlockVariable = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); - storm::dd::Bdd representativePartition = partitionAsBddOverPrimedBlockVariable.existsAbstractRepresentative(model.getColumnVariables()).renameVariables(model.getColumnVariables(), blockVariableSet); - partitionAsBdd = (representativePartition && partitionAsBddOverPrimedBlockVariable).existsAbstract(blockPrimeVariableSet); + storm::dd::Bdd partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); + storm::dd::Bdd tmp = (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet); + partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet); } - auto start = std::chrono::high_resolution_clock::now(); - partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables()); storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables()); @@ -989,7 +989,6 @@ namespace storm { storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(blockAndRowVariables, blockPrimeAndColumnVariables), model.getColumnVariables()); // Pick a representative from each block. - auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); partitionAsBdd &= representatives; partitionAsAdd *= partitionAsBdd.template toAdd(); @@ -1047,6 +1046,7 @@ namespace storm { std::shared_ptr> QuotientExtractor::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); + bool useRepresentativesForThisExtraction = this->useRepresentatives; if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { STORM_LOG_WARN_COND(!this->useRepresentatives, "Using representatives is unsupported for this extraction, falling back to regular extraction."); @@ -1058,10 +1058,19 @@ namespace storm { std::set blockPrimeVariableSet = {partition.getPrimedBlockVariable()}; std::vector> blockMetaVariablePairs = {std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())}; - storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); - auto start = std::chrono::high_resolution_clock::now(); + + // Compute representatives. + storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + + if (useRepresentativesForThisExtraction) { + storm::dd::Bdd partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); + storm::dd::Bdd tmp = (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet); + partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet); + } + storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables()).renameVariablesAbstract(blockVariableSet, model.getRowVariables()); storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables()).renameVariablesAbstract(blockVariableSet, model.getRowVariables()); @@ -1093,7 +1102,6 @@ namespace storm { storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(model.getRowVariables(), model.getColumnVariables()), model.getColumnVariables()).renameVariablesAbstract(blockVariableSet, model.getColumnVariables()); // Pick a representative from each block. - auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); partitionAsBdd &= representatives; partitionAsAdd = partitionAsBdd.template toAdd(); From 6638984b8e5be62d7a972c01d6f91db96c907bbe Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 2 Mar 2018 12:56:13 +0100 Subject: [PATCH 149/647] fixed an issue in sylvan refiner when not reusing block numbers --- .../InternalSylvanSignatureRefiner.cpp | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp index 07c46fc3c..9d47e648e 100644 --- a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp +++ b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp @@ -49,7 +49,7 @@ namespace storm { LACE_ME; - nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 0; + nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 1; signatures.resize(nextFreeBlockIndex); // Perform the actual recursive refinement step. @@ -161,6 +161,8 @@ namespace storm { } } + static const uint64_t NO_ELEMENT_MARKER = -1ull; + static uint64_t sylvan_search_or_insert(uint64_t sig, uint64_t previous_block, InternalSylvanSignatureRefinerBase* refiner) { uint64_t hash = sylvan_hash(sig, previous_block); @@ -189,7 +191,7 @@ namespace storm { } pos++; if (pos >= refiner->currentCapacity) pos = 0; - if (++count >= 128) return 0; + if (++count >= 128) return NO_ELEMENT_MARKER; } } @@ -219,11 +221,11 @@ namespace storm { } return sylvan_cube(vars, e.data()); } - + TASK_3(BDD, sylvan_assign_block, BDD, sig, BDD, previous_block, InternalSylvanSignatureRefinerBase*, refiner) { assert(previous_block != mtbdd_false); // if so, incorrect call! - + // maybe do garbage collection sylvan_gc_test(); @@ -232,21 +234,25 @@ namespace storm { sig = (uint64_t)-1; } - // try to claim previous block number - assert(previous_block != sylvan_false); - const uint64_t p_b = CALL(sylvan_decode_block, previous_block); - assert(p_b < refiner->signatures.size()); - - for (;;) { - BDD cur = *(volatile BDD*)&refiner->signatures[p_b]; - if (cur == sig) return previous_block; - if (cur != 0) break; - if (cas(&refiner->signatures[p_b], 0, sig)) return previous_block; + if (refiner->options.reuseBlockNumbers) { + // try to claim previous block number + assert(previous_block != sylvan_false); + const uint64_t p_b = CALL(sylvan_decode_block, previous_block); + assert(p_b < refiner->signatures.size()); + + for (;;) { + BDD cur = *(volatile BDD*)&refiner->signatures[p_b]; + if (cur == sig) return previous_block; + if (cur != 0) break; + if (cas(&refiner->signatures[p_b], 0, sig)) return previous_block; + } } // no previous block number, search or insert uint64_t c; - while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == 0) CALL(sylvan_grow, refiner); + while ((c = sylvan_search_or_insert(sig, refiner->options.reuseBlockNumbers ? previous_block : sig, refiner)) == NO_ELEMENT_MARKER) { + CALL(sylvan_grow, refiner); + } return CALL(sylvan_encode_block, refiner->blockCube.getInternalBdd().getSylvanBdd().GetBDD(), refiner->numberOfBlockVariables, c); } From ea21aca117f6fef689e7f38f5aab269fe7ae2d8a Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 2 Mar 2018 13:34:19 +0100 Subject: [PATCH 150/647] second attempt at fixing issue when not reusing blocks --- .../InternalSylvanSignatureRefiner.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp index 9d47e648e..ce14cd837 100644 --- a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp +++ b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp @@ -11,13 +11,15 @@ namespace storm { namespace dd { namespace bisimulation { + static const uint64_t NO_ELEMENT_MARKER = -1ull; + InternalSylvanSignatureRefinerBase::InternalSylvanSignatureRefinerBase(storm::dd::DdManager const& manager, storm::expressions::Variable const& blockVariable, std::set const& stateVariables, storm::dd::Bdd const& nondeterminismVariables, storm::dd::Bdd const& nonBlockVariables, InternalSignatureRefinerOptions const& options) : manager(manager), blockVariable(blockVariable), stateVariables(stateVariables), nondeterminismVariables(nondeterminismVariables), nonBlockVariables(nonBlockVariables), options(options), numberOfBlockVariables(manager.getMetaVariable(blockVariable).getNumberOfDdVariables()), blockCube(manager.getMetaVariable(blockVariable).getCube()), nextFreeBlockIndex(0), numberOfRefinements(0), currentCapacity(1ull << 20), resizeFlag(0) { // Perform garbage collection to clean up stuff not needed anymore. LACE_ME; sylvan_gc(); - table.resize(3 * currentCapacity); + table.resize(3 * currentCapacity, NO_ELEMENT_MARKER); } template @@ -30,13 +32,14 @@ namespace storm { Partition InternalSignatureRefiner::refine(Partition const& oldPartition, Signature const& signature) { std::pair, boost::optional>> newPartitionDds = refine(oldPartition, signature.getSignatureAdd()); ++numberOfRefinements; + return oldPartition.replacePartition(newPartitionDds.first, nextFreeBlockIndex, nextFreeBlockIndex, newPartitionDds.second); } template void InternalSignatureRefiner::clearCaches() { for (auto& e : this->table) { - e = 0ull; + e = NO_ELEMENT_MARKER; } for (auto& e : this->signatures) { e = 0ull; @@ -49,7 +52,7 @@ namespace storm { LACE_ME; - nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 1; + nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 0; signatures.resize(nextFreeBlockIndex); // Perform the actual recursive refinement step. @@ -142,7 +145,7 @@ namespace storm { uint64_t oldCapacity = refiner->currentCapacity; refiner->currentCapacity <<= 1; - refiner->table = std::vector(3 * refiner->currentCapacity); + refiner->table = std::vector(3 * refiner->currentCapacity, NO_ELEMENT_MARKER); CALL(sylvan_rehash, 0, oldCapacity, refiner); @@ -161,8 +164,6 @@ namespace storm { } } - static const uint64_t NO_ELEMENT_MARKER = -1ull; - static uint64_t sylvan_search_or_insert(uint64_t sig, uint64_t previous_block, InternalSylvanSignatureRefinerBase* refiner) { uint64_t hash = sylvan_hash(sig, previous_block); @@ -175,13 +176,13 @@ namespace storm { ptr = refiner->table.data() + pos*3; a = *ptr; if (a == sig) { - while ((b=ptr[1]) == 0) continue; + while ((b=ptr[1]) == NO_ELEMENT_MARKER) continue; if (b == previous_block) { - while ((c=ptr[2]) == 0) continue; + while ((c=ptr[2]) == NO_ELEMENT_MARKER) continue; return c; } - } else if (a == 0) { - if (cas(ptr, 0, sig)) { + } else if (a == NO_ELEMENT_MARKER) { + if (cas(ptr, NO_ELEMENT_MARKER, sig)) { c = ptr[2] = __sync_fetch_and_add(&refiner->nextFreeBlockIndex, 1); ptr[1] = previous_block; return c; @@ -250,7 +251,7 @@ namespace storm { // no previous block number, search or insert uint64_t c; - while ((c = sylvan_search_or_insert(sig, refiner->options.reuseBlockNumbers ? previous_block : sig, refiner)) == NO_ELEMENT_MARKER) { + while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == NO_ELEMENT_MARKER) { CALL(sylvan_grow, refiner); } From acf297a81195d52f3c7f3155d3ec81401d4a8d68 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 2 Mar 2018 15:12:31 +0100 Subject: [PATCH 151/647] fixing precision issue in sanity check and silencing min-max solver a bit --- src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp | 3 ++- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 1e53cf314..2acc4f299 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -548,9 +548,10 @@ namespace storm { #ifndef NDEBUG // As a sanity check, make sure our local upper bounds were in fact correct. if (solver->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + auto precision = storm::utility::convertNumber(storm::settings::getModule().getPrecision()); auto resultIt = x.begin(); for (auto const& entry : solver->getUpperBounds()) { - STORM_LOG_ASSERT(*resultIt <= entry, "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); + STORM_LOG_ASSERT(*resultIt <= entry + precision, "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); ++resultIt; } } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 8da065298..406dd46bb 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -1383,8 +1383,8 @@ namespace storm { template void IterativeMinMaxLinearEquationSolver::reportStatus(SolverStatus status, uint64_t iterations) { switch (status) { - case SolverStatus::Converged: STORM_LOG_INFO("Iterative solver converged after " << iterations << " iterations."); break; - case SolverStatus::TerminatedEarly: STORM_LOG_INFO("Iterative solver terminated early after " << iterations << " iterations."); break; + case SolverStatus::Converged: STORM_LOG_TRACE("Iterative solver converged after " << iterations << " iterations."); break; + case SolverStatus::TerminatedEarly: STORM_LOG_TRACE("Iterative solver terminated early after " << iterations << " iterations."); break; case SolverStatus::MaximalIterationsExceeded: STORM_LOG_WARN("Iterative solver did not converge after " << iterations << " iterations."); break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Iterative solver terminated unexpectedly."); From fdc2f2bd0c6cf185983d1c129c835becd4889b22 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 2 Mar 2018 18:32:16 +0100 Subject: [PATCH 152/647] removed wrong include to make it compile again --- src/storm/solver/LinearEquationSolver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm/solver/LinearEquationSolver.h b/src/storm/solver/LinearEquationSolver.h index c53c23393..525623781 100644 --- a/src/storm/solver/LinearEquationSolver.h +++ b/src/storm/solver/LinearEquationSolver.h @@ -8,7 +8,6 @@ #include "storm/solver/MultiplicationStyle.h" #include "storm/solver/LinearEquationSolverProblemFormat.h" #include "storm/solver/LinearEquationSolverRequirements.h" -#include "storm/solver/LinearEquationSolverTask.h" #include "storm/solver/OptimizationDirection.h" #include "storm/utility/VectorHelper.h" From 77a031aaeb0972187c38808194b02d7e00204768 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 3 Mar 2018 10:46:51 +0100 Subject: [PATCH 153/647] changed encoding of spirit parser, fixed an issue in variable information related to how many bits are necessary to store the state, changed some output formatting --- src/storm-pgcl/parser/PgclParser.cpp | 2 +- src/storm/generator/VariableInformation.cpp | 2 +- src/storm/parser/ExpressionParser.cpp | 2 +- src/storm/parser/FormulaParser.cpp | 2 +- src/storm/parser/FormulaParserGrammar.cpp | 2 +- src/storm/parser/ImcaMarkovAutomatonParser.cpp | 2 +- src/storm/parser/PrismParser.cpp | 11 +++++++---- src/storm/parser/SpiritParserDefinitions.h | 7 ++++++- src/storm/solver/TopologicalLinearEquationSolver.cpp | 4 ++-- src/storm/storage/BitVectorHashMap.cpp | 2 ++ 10 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/storm-pgcl/parser/PgclParser.cpp b/src/storm-pgcl/parser/PgclParser.cpp index 6ecde3054..2afe737be 100755 --- a/src/storm-pgcl/parser/PgclParser.cpp +++ b/src/storm-pgcl/parser/PgclParser.cpp @@ -40,7 +40,7 @@ namespace storm { storm::parser::PgclParser grammar(filename, first); try { // Start the parsing run. - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing of PGCL program failed."); STORM_LOG_DEBUG("Parse of PGCL program finished."); } catch(qi::expectation_failure const& e) { diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index e691300c6..26bd2ecf8 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -114,7 +114,7 @@ namespace storm { uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const { uint_fast64_t result = totalBitOffset; - if (roundTo64Bit) { + if (roundTo64Bit & ((result & ((1ull << 6) - 1)) != 0)) { result = ((result >> 6) + 1) << 6; } return result; diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm/parser/ExpressionParser.cpp index f78e47d13..492fb337d 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm/parser/ExpressionParser.cpp @@ -196,7 +196,7 @@ namespace storm { try { // Start parsing. - bool succeeded = qi::phrase_parse(iter, last, *this, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, *this, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse expression '" << expressionString << "'."); STORM_LOG_DEBUG("Parsed expression successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/FormulaParser.cpp b/src/storm/parser/FormulaParser.cpp index e592f141c..d9d7cd518 100644 --- a/src/storm/parser/FormulaParser.cpp +++ b/src/storm/parser/FormulaParser.cpp @@ -97,7 +97,7 @@ namespace storm { // Create grammar. try { // Start parsing. - bool succeeded = qi::phrase_parse(iter, last, *grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, *grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse formula."); STORM_LOG_DEBUG("Parsed formula successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/FormulaParserGrammar.cpp b/src/storm/parser/FormulaParserGrammar.cpp index 9e8191ad2..2cd8773c9 100644 --- a/src/storm/parser/FormulaParserGrammar.cpp +++ b/src/storm/parser/FormulaParserGrammar.cpp @@ -147,7 +147,7 @@ namespace storm { start = (qi::eps >> filterProperty[phoenix::push_back(qi::_val, qi::_1)] | qi::eps(phoenix::bind(&FormulaParserGrammar::areConstantDefinitionsAllowed, phoenix::ref(*this))) >> constantDefinition | qi::eps) - % +(qi::char_("\n;")) >> qi::skip(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi; + % +(qi::char_("\n;")) >> qi::skip(storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi; start.name("start"); // Enable the following lines to print debug output for most the rules. diff --git a/src/storm/parser/ImcaMarkovAutomatonParser.cpp b/src/storm/parser/ImcaMarkovAutomatonParser.cpp index 01cb93671..f55d09219 100644 --- a/src/storm/parser/ImcaMarkovAutomatonParser.cpp +++ b/src/storm/parser/ImcaMarkovAutomatonParser.cpp @@ -248,7 +248,7 @@ namespace storm { try { // Start parsing. ImcaParserGrammar grammar; - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), components); + bool succeeded = qi::phrase_parse(iter, last, grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), components); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse imca file."); STORM_LOG_DEBUG("Parsed imca file successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/PrismParser.cpp b/src/storm/parser/PrismParser.cpp index 18f42d39c..e54e02b18 100644 --- a/src/storm/parser/PrismParser.cpp +++ b/src/storm/parser/PrismParser.cpp @@ -37,11 +37,13 @@ namespace storm { } storm::prism::Program PrismParser::parseFromString(std::string const& input, std::string const& filename, bool prismCompatibility) { - PositionIteratorType first(input.begin()); + bool hasByteOrderMark = input.size() >= 3 && input[0] == '\xEF' && input[1] == '\xBB' && input[2] == '\xBF'; + + PositionIteratorType first(hasByteOrderMark ? input.begin() + 3 : input.begin()); PositionIteratorType iter = first; PositionIteratorType last(input.end()); STORM_LOG_ASSERT(first != last, "Illegal input to PRISM parser."); - + // Create empty result; storm::prism::Program result; @@ -49,7 +51,8 @@ namespace storm { storm::parser::PrismParser grammar(filename, first, prismCompatibility); try { // Start first run. - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + storm::spirit_encoding::space_type space; + bool succeeded = qi::phrase_parse(iter, last, grammar, space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in first pass."); STORM_LOG_DEBUG("First pass of parsing PRISM input finished."); @@ -58,7 +61,7 @@ namespace storm { iter = first; last = PositionIteratorType(input.end()); grammar.moveToSecondRun(); - succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + succeeded = qi::phrase_parse(iter, last, grammar, space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in second pass."); } catch (qi::expectation_failure const& e) { // If the parser expected content different than the one provided, display information about the location of the error. diff --git a/src/storm/parser/SpiritParserDefinitions.h b/src/storm/parser/SpiritParserDefinitions.h index 412a6bc37..d48d7a7a6 100644 --- a/src/storm/parser/SpiritParserDefinitions.h +++ b/src/storm/parser/SpiritParserDefinitions.h @@ -6,6 +6,7 @@ // Include boost spirit. #define BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_UNICODE #include #include #include @@ -21,6 +22,10 @@ typedef std::string::const_iterator BaseIteratorType; typedef boost::spirit::line_pos_iterator PositionIteratorType; typedef PositionIteratorType Iterator; -typedef BOOST_TYPEOF(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi)) Skipper; +namespace storm { + namespace spirit_encoding = boost::spirit::unicode; +} + +typedef BOOST_TYPEOF(storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi)) Skipper; #endif /* STORM_PARSER_SPIRITPARSERDEFINITIONS_H_ */ diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index bd5313381..7568f3c65 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -68,9 +68,9 @@ namespace storm { storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); - std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); if (this->longestSccChainSize) { - std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl; + STORM_LOG_INFO("Longest SCC chain size is " << this->longestSccChainSize.get() << "."); } // Handle the case where there is just one large SCC diff --git a/src/storm/storage/BitVectorHashMap.cpp b/src/storm/storage/BitVectorHashMap.cpp index 7bfe1595e..67c151bde 100644 --- a/src/storm/storage/BitVectorHashMap.cpp +++ b/src/storm/storage/BitVectorHashMap.cpp @@ -96,10 +96,12 @@ namespace storm { std::swap(oldValues, values); // Now iterate through the elements and reinsert them in the new storage. + uint64_t oldSize = numberOfElements; numberOfElements = 0; for (auto bucketIndex : oldOccupied) { findOrAddAndGetBucket(oldBuckets.get(bucketIndex * bucketSize, bucketSize), oldValues[bucketIndex]); } + STORM_LOG_ASSERT(oldSize == numberOfElements, "Size mismatch in rehashing. Size before was " << oldSize << " and new size is " << numberOfElements << "."); } template From 207b608e20df193642901306bd73689ab85d74ba Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 3 Mar 2018 16:13:49 +0100 Subject: [PATCH 154/647] using sylvan way of computing cache/table sizes given a memory bound --- .../dd/sylvan/InternalSylvanDdManager.cpp | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp b/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp index a2ded9452..eaab6e2c2 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp @@ -64,25 +64,39 @@ namespace storm { } lace_startup(0, 0, 0); - // Each node takes 24 bytes and the maximal memory is specified in megabytes. - uint_fast64_t totalNodesToStore = storm::settings::getModule().getMaximalMemory() * 1024 * 1024 / 24; + // Table/cache size computation taken from newer version of sylvan. + uint64_t memorycap = storm::settings::getModule().getMaximalMemory() * 1024 * 1024; - // Compute the power of two that still fits within the total numbers to store. - uint_fast64_t powerOfTwo = findLargestPowerOfTwoFitting(totalNodesToStore); + uint64_t table_ratio = 0; + uint64_t initial_ratio = 0; - STORM_LOG_THROW(powerOfTwo >= 16, storm::exceptions::InvalidSettingsException, "Too little memory assigned to sylvan."); + uint64_t max_t = 1; + uint64_t max_c = 1; + if (table_ratio > 0) { + max_t <<= table_ratio; + } else { + max_c <<= -table_ratio; + } - uint64_t maxTableSize = 1ull << powerOfTwo; - uint64_t maxCacheSize = 1ull << (powerOfTwo - 1); - if (maxTableSize + maxCacheSize > totalNodesToStore) { - maxTableSize >>= 1; + uint64_t cur = max_t * 24 + max_c * 36; + STORM_LOG_THROW(cur <= memorycap, storm::exceptions::InvalidSettingsException, "Memory cap incompatible with default table ratio."); + + while (2*cur < memorycap && max_t < 0x0000040000000000) { + max_t *= 2; + max_c *= 2; + cur *= 2; } - uint64_t initialTableSize = 1ull << std::max(powerOfTwo - 4, static_cast(16)); - uint64_t initialCacheSize = initialTableSize; + uint64_t min_t = max_t, min_c = max_c; + while (initial_ratio > 0 && min_t > 0x1000 && min_c > 0x1000) { + min_t >>= 1; + min_c >>= 1; + initial_ratio--; + } + // End of copied code. - STORM_LOG_DEBUG("Initializing sylvan. Initial/max table size: " << initialTableSize << "/" << maxTableSize << ", initial/max cache size: " << initialCacheSize << "/" << maxCacheSize << "."); - sylvan::Sylvan::initPackage(initialTableSize, maxTableSize, initialCacheSize, maxCacheSize); + STORM_LOG_DEBUG("Initializing sylvan library. Initial/max table size: " << min_t << "/" << max_t << ", initial/max cache size: " << min_c << "/" << max_c << "."); + sylvan::Sylvan::initPackage(min_t, max_t, min_c, max_c); sylvan::Sylvan::initBdd(); sylvan::Sylvan::initMtbdd(); From 2e15674580aa8df78698d9f734d05114ee55cfc0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 4 Mar 2018 14:55:23 +0100 Subject: [PATCH 155/647] fixed an issue in state-act reward refinement for nondet models --- .../NondeterministicModelPartitionRefiner.cpp | 12 ++++++++++++ .../NondeterministicModelPartitionRefiner.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp index 129c426c7..d047acfde 100644 --- a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp +++ b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp @@ -73,6 +73,18 @@ namespace storm { return choicePartition; } + template + bool NondeterministicModelPartitionRefiner::refineWrtStateRewards(storm::dd::Add const& stateRewards) { + STORM_LOG_TRACE("Refining with respect to state rewards."); + Partition newStatePartition = this->stateSignatureRefiner.refine(this->statePartition, Signature(stateRewards)); + if (newStatePartition == this->statePartition) { + return false; + } else { + this->statePartition = newStatePartition; + return true; + } + } + template bool NondeterministicModelPartitionRefiner::refineWrtStateActionRewards(storm::dd::Add const& stateActionRewards) { STORM_LOG_TRACE("Refining with respect to state-action rewards."); diff --git a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h index bf2717998..0dae7f90e 100644 --- a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h +++ b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h @@ -34,6 +34,8 @@ namespace storm { private: virtual bool refineWrtStateActionRewards(storm::dd::Add const& stateActionRewards) override; + virtual bool refineWrtStateRewards(storm::dd::Add const& stateRewards) override; + // The model to refine. storm::models::symbolic::NondeterministicModel const& model; From 139752eb662fb3844a5354691e2cd94506bd82e3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 4 Mar 2018 20:53:17 +0100 Subject: [PATCH 156/647] added option to perform dd-bisimulation using exact arithmetic --- src/storm-cli-utilities/model-handling.h | 25 +++++++++++----- src/storm/models/Model.h | 1 + src/storm/models/ModelBase.h | 2 +- src/storm/models/symbolic/Ctmc.cpp | 18 ++++++++++++ src/storm/models/symbolic/Ctmc.h | 3 ++ src/storm/models/symbolic/Dtmc.cpp | 18 ++++++++++++ src/storm/models/symbolic/Dtmc.h | 4 +++ src/storm/models/symbolic/MarkovAutomaton.cpp | 18 ++++++++++++ src/storm/models/symbolic/MarkovAutomaton.h | 3 ++ src/storm/models/symbolic/Mdp.cpp | 18 ++++++++++++ src/storm/models/symbolic/Mdp.h | 3 ++ src/storm/models/symbolic/Model.cpp | 29 +++++++++++++++++++ src/storm/models/symbolic/Model.h | 10 +++++++ .../models/symbolic/StandardRewardModel.cpp | 7 +++++ .../models/symbolic/StandardRewardModel.h | 3 ++ .../settings/modules/BisimulationSettings.cpp | 6 ++++ .../settings/modules/BisimulationSettings.h | 8 +++++ 17 files changed, 168 insertions(+), 8 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index bdc1ee630..b1d667d64 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -665,7 +665,7 @@ namespace storm { return model; } - template + template void processInputWithValueTypeAndDdlib(SymbolicInput const& input) { auto coreSettings = storm::settings::getModule(); auto abstractionSettings = storm::settings::getModule(); @@ -674,19 +674,26 @@ namespace storm { storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine(); if (engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement && abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) { - verifyWithAbstractionRefinementEngine(input); + verifyWithAbstractionRefinementEngine(input); } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { - verifyWithExplorationEngine(input); + verifyWithExplorationEngine(input); } else { - std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); + std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); if (model) { + if (!std::is_same::value) { + if (model->isSymbolicModel()) { + auto symbolicModel = model->as>(); + model = symbolicModel->template toValueType(); + } + } + if (coreSettings.isCounterexampleSet()) { auto ioSettings = storm::settings::getModule(); - generateCounterexamples(model, input); + generateCounterexamples(model, input); } else { auto ioSettings = storm::settings::getModule(); - verifyModel(model, input, coreSettings); + verifyModel(model, input, coreSettings); } } } @@ -696,10 +703,14 @@ namespace storm { void processInputWithValueType(SymbolicInput const& input) { auto coreSettings = storm::settings::getModule(); auto generalSettings = storm::settings::getModule(); + auto bisimulationSettings = storm::settings::getModule(); if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && generalSettings.isExactSet()) { STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); - processInputWithValueTypeAndDdlib(input); + processInputWithValueTypeAndDdlib(input); + } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && std::is_same::value && generalSettings.isBisimulationSet() && bisimulationSettings.useExactArithmeticInDdBisimulation()) { + STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); + processInputWithValueTypeAndDdlib(input); } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD) { processInputWithValueTypeAndDdlib(input); } else { diff --git a/src/storm/models/Model.h b/src/storm/models/Model.h index 4f17fdf24..52dfec2b6 100644 --- a/src/storm/models/Model.h +++ b/src/storm/models/Model.h @@ -16,6 +16,7 @@ namespace storm { Model(ModelType const& modelType) : ModelBase(modelType) { // Intentionally left empty. } + }; diff --git a/src/storm/models/ModelBase.h b/src/storm/models/ModelBase.h index 49f96d5ed..77fa5b60d 100644 --- a/src/storm/models/ModelBase.h +++ b/src/storm/models/ModelBase.h @@ -48,7 +48,7 @@ namespace storm { std::shared_ptr as() const { return std::dynamic_pointer_cast(this->shared_from_this()); } - + /*! * @brief Return the actual type of the model. * diff --git a/src/storm/models/symbolic/Ctmc.cpp b/src/storm/models/symbolic/Ctmc.cpp index e94079efc..4b05372be 100644 --- a/src/storm/models/symbolic/Ctmc.cpp +++ b/src/storm/models/symbolic/Ctmc.cpp @@ -84,11 +84,29 @@ namespace storm { return exitRates.get(); } + template + template + std::shared_ptr> Ctmc::toValueType() const { + typedef typename DeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getExitRateVector().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Ctmc; template class Ctmc; template class Ctmc; + template std::shared_ptr> Ctmc::toValueType() const; template class Ctmc; } // namespace symbolic diff --git a/src/storm/models/symbolic/Ctmc.h b/src/storm/models/symbolic/Ctmc.h index 68c4e7b35..0035e3ffb 100644 --- a/src/storm/models/symbolic/Ctmc.h +++ b/src/storm/models/symbolic/Ctmc.h @@ -141,6 +141,9 @@ namespace storm { */ storm::dd::Add const& getExitRateVector() const; + template + std::shared_ptr> toValueType() const; + private: mutable boost::optional> exitRates; }; diff --git a/src/storm/models/symbolic/Dtmc.cpp b/src/storm/models/symbolic/Dtmc.cpp index fdd478b71..2b4adb149 100644 --- a/src/storm/models/symbolic/Dtmc.cpp +++ b/src/storm/models/symbolic/Dtmc.cpp @@ -43,11 +43,29 @@ namespace storm { // Intentionally left empty. } + template + template + std::shared_ptr> Dtmc::toValueType() const { + typedef typename DeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Dtmc; template class Dtmc; template class Dtmc; + template std::shared_ptr> Dtmc::toValueType() const; template class Dtmc; } // namespace symbolic diff --git a/src/storm/models/symbolic/Dtmc.h b/src/storm/models/symbolic/Dtmc.h index ebe837e1c..76a3e81ca 100644 --- a/src/storm/models/symbolic/Dtmc.h +++ b/src/storm/models/symbolic/Dtmc.h @@ -76,6 +76,10 @@ namespace storm { std::vector> const& rowColumnMetaVariablePairs, std::map> labelToBddMap = std::map>(), std::unordered_map const& rewardModels = std::unordered_map()); + + template + std::shared_ptr> toValueType() const; + }; } // namespace symbolic diff --git a/src/storm/models/symbolic/MarkovAutomaton.cpp b/src/storm/models/symbolic/MarkovAutomaton.cpp index 09b2fe7b3..add866c8b 100644 --- a/src/storm/models/symbolic/MarkovAutomaton.cpp +++ b/src/storm/models/symbolic/MarkovAutomaton.cpp @@ -115,11 +115,29 @@ namespace storm { return this->exitRateVector; } + template + template + std::shared_ptr> MarkovAutomaton::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getMarkovianMarker(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class MarkovAutomaton; template class MarkovAutomaton; template class MarkovAutomaton; + template std::shared_ptr> MarkovAutomaton::toValueType() const; template class MarkovAutomaton; } // namespace symbolic diff --git a/src/storm/models/symbolic/MarkovAutomaton.h b/src/storm/models/symbolic/MarkovAutomaton.h index 30b1dbdfc..e2e0f3369 100644 --- a/src/storm/models/symbolic/MarkovAutomaton.h +++ b/src/storm/models/symbolic/MarkovAutomaton.h @@ -92,6 +92,9 @@ namespace storm { storm::dd::Add const& getExitRateVector() const; + template + std::shared_ptr> toValueType() const; + private: /*! * Computes the member data related to Markovian stuff. diff --git a/src/storm/models/symbolic/Mdp.cpp b/src/storm/models/symbolic/Mdp.cpp index c5de7a371..65bd49769 100644 --- a/src/storm/models/symbolic/Mdp.cpp +++ b/src/storm/models/symbolic/Mdp.cpp @@ -45,11 +45,29 @@ namespace storm { // Intentionally left empty. } + template + template + std::shared_ptr> Mdp::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Mdp; template class Mdp; template class Mdp; + template std::shared_ptr> Mdp::toValueType() const; template class Mdp; } // namespace symbolic diff --git a/src/storm/models/symbolic/Mdp.h b/src/storm/models/symbolic/Mdp.h index 771f0bd05..d8432ad49 100644 --- a/src/storm/models/symbolic/Mdp.h +++ b/src/storm/models/symbolic/Mdp.h @@ -83,6 +83,9 @@ namespace storm { std::map> labelToBddMap = std::map>(), std::unordered_map const& rewardModels = std::unordered_map()); + template + std::shared_ptr> toValueType() const; + }; } // namespace symbolic diff --git a/src/storm/models/symbolic/Model.cpp b/src/storm/models/symbolic/Model.cpp index 1c1ebf749..71897fded 100644 --- a/src/storm/models/symbolic/Model.cpp +++ b/src/storm/models/symbolic/Model.cpp @@ -2,6 +2,11 @@ #include +#include "storm/models/symbolic/Dtmc.h" +#include "storm/models/symbolic/Ctmc.h" +#include "storm/models/symbolic/Mdp.h" +#include "storm/models/symbolic/MarkovAutomaton.h" + #include "storm/exceptions/IllegalArgumentException.h" #include "storm/exceptions/InvalidOperationException.h" @@ -211,6 +216,11 @@ namespace storm { return labelToExpressionMap; } + template + std::map> const& Model::getLabelToBddMap() const { + return labelToBddMap; + } + template storm::dd::Add Model::getRowColumnIdentity() const { return (storm::utility::dd::getRowColumnDiagonal(this->getManager(), this->getRowColumnMetaVariablePairs()) && this->getReachableStates()).template toAdd(); @@ -372,11 +382,30 @@ namespace storm { return parameters; } + template + template + std::shared_ptr> Model::toValueType() const { + // Make a huge branching here as we cannot make a templated function virtual. + if (this->getType() == storm::models::ModelType::Dtmc) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::Ctmc) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::Mdp) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::MarkovAutomaton) { + return this->template as>()->template toValueType(); + } + + STORM_LOG_WARN("Could not convert value type of model."); + return nullptr; + } + // Explicitly instantiate the template class. template class Model; template class Model; template class Model; + template std::shared_ptr> Model::toValueType() const; template class Model; } // namespace symbolic } // namespace models diff --git a/src/storm/models/symbolic/Model.h b/src/storm/models/symbolic/Model.h index 42cf143f1..e194dfabc 100644 --- a/src/storm/models/symbolic/Model.h +++ b/src/storm/models/symbolic/Model.h @@ -327,6 +327,9 @@ namespace storm { std::set const& getParameters() const; + template + std::shared_ptr> toValueType() const; + protected: /*! * Sets the transition matrix of the model. @@ -342,6 +345,13 @@ namespace storm { */ std::map const& getLabelToExpressionMap() const; + /*! + * Retrieves the mapping of labels to their defining expressions. + * + * @returns The mapping of labels to their defining expressions. + */ + std::map> const& getLabelToBddMap() const; + /*! * Prints the information header (number of states and transitions) of the model to the specified stream. * diff --git a/src/storm/models/symbolic/StandardRewardModel.cpp b/src/storm/models/symbolic/StandardRewardModel.cpp index ffd94ad74..38bd56c5c 100644 --- a/src/storm/models/symbolic/StandardRewardModel.cpp +++ b/src/storm/models/symbolic/StandardRewardModel.cpp @@ -196,10 +196,17 @@ namespace storm { } } + template + template + StandardRewardModel StandardRewardModel::toValueType() const { + return StandardRewardModel(this->hasStateRewards() ? boost::make_optional(this->getStateRewardVector().template toValueType()) : boost::none, this->hasStateActionRewards() ? boost::make_optional(this->getStateActionRewardVector().template toValueType()) : boost::none, this->hasTransitionRewards() ? boost::make_optional(this->getTransitionRewardMatrix().template toValueType()) : boost::none); + } + template class StandardRewardModel; template class StandardRewardModel; template class StandardRewardModel; + template StandardRewardModel StandardRewardModel::toValueType() const; template class StandardRewardModel; } diff --git a/src/storm/models/symbolic/StandardRewardModel.h b/src/storm/models/symbolic/StandardRewardModel.h index c16f144e5..3d705e448 100644 --- a/src/storm/models/symbolic/StandardRewardModel.h +++ b/src/storm/models/symbolic/StandardRewardModel.h @@ -212,6 +212,9 @@ namespace storm { */ void reduceToStateBasedRewards(storm::dd::Add const& transitionMatrix, std::set const& rowVariables, std::set const& columnVariables, bool reduceToStateRewards); + template + StandardRewardModel toValueType() const; + private: // The state reward vector. boost::optional> optionalStateRewardVector; diff --git a/src/storm/settings/modules/BisimulationSettings.cpp b/src/storm/settings/modules/BisimulationSettings.cpp index 56b3419e9..0b7c219f5 100644 --- a/src/storm/settings/modules/BisimulationSettings.cpp +++ b/src/storm/settings/modules/BisimulationSettings.cpp @@ -21,6 +21,7 @@ namespace storm { const std::string BisimulationSettings::reuseOptionName = "reuse"; const std::string BisimulationSettings::initialPartitionOptionName = "init"; const std::string BisimulationSettings::refinementModeOptionName = "refine"; + const std::string BisimulationSettings::exactArithmeticDdOptionName = "ddexact"; BisimulationSettings::BisimulationSettings() : ModuleSettings(moduleName) { std::vector types = { "strong", "weak" }; @@ -31,6 +32,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, representativeOptionName, false, "Sets whether to use representatives in the quotient rather than block numbers.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, originalVariablesOptionName, false, "Sets whether to use the original variables in the quotient rather than the block variables.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exactArithmeticDdOptionName, false, "Sets whether to use exact arithmetic in dd-based bisimulation.").build()); std::vector signatureModes = { "eager", "lazy" }; this->addOption(storm::settings::OptionBuilder(moduleName, signatureModeOptionName, false, "Sets the signature computation mode.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(signatureModes)).setDefaultValueString("eager").build()).build()); @@ -84,6 +86,10 @@ namespace storm { return this->getOption(originalVariablesOptionName).getHasOptionBeenSet(); } + bool BisimulationSettings::useExactArithmeticInDdBisimulation() const { + return this->getOption(exactArithmeticDdOptionName).getHasOptionBeenSet(); + } + storm::dd::bisimulation::SignatureMode BisimulationSettings::getSignatureMode() const { std::string modeAsString = this->getOption(signatureModeOptionName).getArgumentByName("mode").getValueAsString(); if (modeAsString == "eager") { diff --git a/src/storm/settings/modules/BisimulationSettings.h b/src/storm/settings/modules/BisimulationSettings.h index eb9627f68..c06713a8a 100644 --- a/src/storm/settings/modules/BisimulationSettings.h +++ b/src/storm/settings/modules/BisimulationSettings.h @@ -63,6 +63,13 @@ namespace storm { */ bool isUseOriginalVariablesSet() const; + /*! + * Retrieves whether exact arithmetic is to be used in symbolic bisimulation minimization. + * + * @return True iff exact arithmetic is to be used in symbolic bisimulation minimization. + */ + bool useExactArithmeticInDdBisimulation() const; + /*! * Retrieves the mode to compute signatures. */ @@ -99,6 +106,7 @@ namespace storm { static const std::string initialPartitionOptionName; static const std::string refinementModeOptionName; static const std::string parallelismModeOptionName; + static const std::string exactArithmeticDdOptionName; }; } // namespace modules } // namespace settings From 51ebb47587a284c8528e05de6f9619453b415e96 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 5 Mar 2018 12:08:44 +0100 Subject: [PATCH 157/647] added timing measurements to symbolic to sparse conversion in hybrid model checkers --- .../csl/helper/HybridCtmcCslHelper.cpp | 75 ++++++++++++++++--- .../prctl/helper/HybridDtmcPrctlHelper.cpp | 56 +++++++++++--- .../prctl/helper/HybridMdpPrctlHelper.cpp | 55 +++++++++++--- 3 files changed, 155 insertions(+), 31 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp index dcd589378..841088ac2 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp @@ -18,6 +18,8 @@ #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/utility/Stopwatch.h" + #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/InvalidOperationException.h" @@ -79,12 +81,16 @@ namespace storm { // Compute the vector that is to be added as a compensation for removing the absorbing states. storm::dd::Add b = (statesWithProbabilityGreater0NonPsi.template toAdd() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); + storm::utility::Stopwatch conversionWatch(true); + // Create an ODD for the translation to an explicit representation. storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); // Convert the symbolic parts to their explicit representation. storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); std::vector explicitB = b.toVector(odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); // Finally compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); @@ -106,12 +112,18 @@ namespace storm { // Filter the unbounded result such that it only contains values for the relevant states. unboundedResult->filter(SymbolicQualitativeCheckResult(model.getReachableStates(), relevantStates)); + storm::utility::Stopwatch conversionWatch; + // Build an ODD for the relevant states. + conversionWatch.start(); storm::dd::Odd odd = relevantStates.createOdd(); + conversionWatch.stop(); std::vector result; if (unboundedResult->isHybridQuantitativeCheckResult()) { + conversionWatch.start(); std::unique_ptr explicitUnboundedResult = unboundedResult->asHybridQuantitativeCheckResult().toExplicitQuantitativeCheckResult(); + conversionWatch.stop(); result = std::move(explicitUnboundedResult->asExplicitQuantitativeCheckResult().getValueVector()); } else { STORM_LOG_THROW(unboundedResult->isSymbolicQuantitativeCheckResult(), storm::exceptions::InvalidStateException, "Expected check result of different type."); @@ -123,8 +135,11 @@ namespace storm { // Compute the uniformized matrix. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, relevantStates, uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Compute the transient probabilities. result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result); @@ -146,10 +161,12 @@ namespace storm { storm::dd::Add b = (statesWithProbabilityGreater0NonPsi.template toAdd() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); // Build an ODD for the relevant states and translate the symbolic parts to their explicit representation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); std::vector explicitB = b.toVector(odd); - + conversionWatch.stop(); + // Compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); std::vector subResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound - lowerBound, uniformizationRate, values); @@ -164,13 +181,15 @@ namespace storm { // Filter the unbounded result such that it only contains values for the relevant states. hybridResult.filter(SymbolicQualitativeCheckResult(model.getReachableStates(), relevantStates)); - + // Build an ODD for the relevant states. + conversionWatch.start(); odd = relevantStates.createOdd(); std::unique_ptr explicitResult = hybridResult.toExplicitQuantitativeCheckResult(); + conversionWatch.stop(); std::vector newSubresult = std::move(explicitResult->asExplicitQuantitativeCheckResult().getValueVector()); - + // Then compute the transient probabilities of being in such a state after t time units. For this, // we must re-uniformize the CTMC, so we need to compute the second uniformized matrix. uniformizationRate = 1.02 * (relevantStates.template toAdd() * exitRateVector).getMax(); @@ -185,19 +204,26 @@ namespace storm { // Finally, we compute the second set of transient probabilities. uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, relevantStates, uniformizationRate); + conversionWatch.start(); explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !relevantStates && model.getReachableStates(), model.getManager().template getAddZero(), relevantStates, odd, newSubresult)); } else { // In this case, the interval is of the form [t, t] with t != 0, t != inf. + storm::utility::Stopwatch conversionWatch; + // Build an ODD for the relevant states. + conversionWatch.start(); storm::dd::Odd odd = statesWithProbabilityGreater0.createOdd(); - + std::vector newSubresult = psiStates.template toAdd().toVector(odd); - + conversionWatch.stop(); + // Then compute the transient probabilities of being in such a state after t time units. For this, // we must re-uniformize the CTMC, so we need to compute the second uniformized matrix. ValueType uniformizationRate = 1.02 * (statesWithProbabilityGreater0.template toAdd() * exitRateVector).getMax(); @@ -205,8 +231,11 @@ namespace storm { // Finally, we compute the second set of transient probabilities. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, statesWithProbabilityGreater0, uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !statesWithProbabilityGreater0 && model.getReachableStates(), model.getManager().template getAddZero(), statesWithProbabilityGreater0, odd, newSubresult)); @@ -229,8 +258,12 @@ namespace storm { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch; + // Create ODD for the translation. + conversionWatch.start(); storm::dd::Odd odd = model.getReachableStates().createOdd(); + conversionWatch.stop(); // Initialize result to state rewards of the model. std::vector result = rewardModel.getStateRewardVector().toVector(odd); @@ -242,7 +275,11 @@ namespace storm { storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, result); } @@ -270,17 +307,25 @@ namespace storm { ValueType uniformizationRate = 1.02 * exitRateVector.getMax(); STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); + storm::utility::Stopwatch conversionWatch; + // Create ODD for the translation. + conversionWatch.start(); storm::dd::Odd odd = model.getReachableStates().createOdd(); + conversionWatch.stop(); // Compute the uniformized matrix. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); + conversionWatch.stop(); // Then compute the state reward vector to use in the computation. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, model.getColumnVariables(), exitRateVector, false); std::vector explicitTotalRewardVector = totalRewardVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Finally, compute the transient probabilities. std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, explicitTotalRewardVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); @@ -295,12 +340,16 @@ namespace storm { std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates) { storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, psiStates.toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); @@ -312,12 +361,16 @@ namespace storm { STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, model.getColumnVariables(), exitRateVector, true).toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index e5a7df87b..b90aa25be 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -20,11 +20,12 @@ #include "storm/modelchecker/results/SymbolicQuantitativeCheckResult.h" #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" +#include "storm/utility/Stopwatch.h" + #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/UncheckedRequirementException.h" - namespace storm { namespace modelchecker { namespace helper { @@ -46,8 +47,12 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -83,9 +88,12 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::convertNumber(0.5)); // Translate the symbolic matrix/vector to their explicit representations and solve the equation system. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitSubmatrix)); solver->setBounds(storm::utility::zero(), storm::utility::one()); solver->solveEquations(env, x, b); @@ -122,8 +130,12 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -144,9 +156,12 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::zero()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitSubmatrix); multiplier->repeatedMultiply(env, x, &b, stepBound); @@ -162,6 +177,8 @@ namespace storm { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch(true); + // Create the ODD for the translation between symbolic and explicit storage. storm::dd::Odd odd = model.getReachableStates().createOdd(); @@ -170,7 +187,9 @@ namespace storm { // Translate the symbolic matrix to its explicit representations. storm::storage::SparseMatrix explicitMatrix = transitionMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); multiplier->repeatedMultiply(env, x, nullptr, stepBound); @@ -187,16 +206,20 @@ namespace storm { // Compute the reward vector to add in each step based on the available reward models. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd odd = model.getReachableStates().createOdd(); - // Create the solution vector. std::vector x(model.getNumberOfStates(), storm::utility::zero()); + + storm::utility::Stopwatch conversionWatch(true); + + // Create the ODD for the translation between symbolic and explicit storage. + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Translate the symbolic matrix/vector to their explicit representations. storm::storage::SparseMatrix explicitMatrix = transitionMatrix.toMatrix(odd, odd); std::vector b = totalRewardVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); multiplier->repeatedMultiply(env, x, &b, stepBound); @@ -239,8 +262,12 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -281,9 +308,12 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::convertNumber(0.5)); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Create the upper bounds vector if one was requested. boost::optional> upperBounds; if (oneStepTargetProbs) { @@ -311,8 +341,11 @@ namespace storm { template std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates) { // Create ODD for the translation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, targetStates.toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); @@ -321,9 +354,12 @@ namespace storm { template std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel) { // Create ODD for the translation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(model.getTransitionMatrix(), model.getColumnVariables()).toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index 47ea6c1b4..90fbd61d0 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -23,6 +23,8 @@ #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/solver/Multiplier.h" +#include "storm/utility/Stopwatch.h" + #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/UncheckedRequirementException.h" @@ -174,8 +176,12 @@ namespace storm { extendedMaybeStates |= maybeStates.relationalProduct(transitionMatrixBdd.existsAbstract(model.getNondeterminismVariables()), model.getRowVariables(), model.getColumnVariables()); } + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = extendedMaybeStates.createOdd(); + conversionWatch.stop(); // Convert the maybe states BDD to an ADD. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -191,20 +197,21 @@ namespace storm { submatrix *= extendedMaybeStates.template toAdd().swapVariables(model.getRowColumnMetaVariablePairs()); // Only translate the matrix for now. + conversionWatch.start(); explicitRepresentation.first = submatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); // Get all original maybe states in the extended matrix. solverRequirementsData.properMaybeStates = maybeStates.toVector(odd); - + // Compute the target states within the set of extended maybe states. storm::storage::BitVector targetStates = (extendedMaybeStates && statesWithProbability01.second).toVector(odd); - + conversionWatch.stop(); + // Eliminate the end components and remove the states that are not interesting (target or non-filter). eliminateEndComponentsAndExtendedStatesUntilProbabilities(explicitRepresentation, solverRequirementsData, targetStates); // The solution becomes unique after end components have been eliminated. uniqueSolution = true; - } else { // Then compute the vector that contains the one-step probabilities to a state with probability 1 for all // maybe states. @@ -217,13 +224,17 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Translate the symbolic matrix/vector to their explicit representations and solve the equation system. + conversionWatch.start(); explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); + conversionWatch.stop(); if (requirements.requiresValidInitialScheduler()) { solverRequirementsData.initialScheduler = computeValidInitialSchedulerForUntilProbabilities(explicitRepresentation.first, explicitRepresentation.second); } } + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Create the solution vector. std::vector x(explicitRepresentation.first.getRowGroupCount(), storm::utility::zero()); @@ -287,8 +298,12 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -309,8 +324,11 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::zero()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); std::pair, std::vector> explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); @@ -326,6 +344,8 @@ namespace storm { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. storm::dd::Odd odd = model.getReachableStates().createOdd(); @@ -334,7 +354,9 @@ namespace storm { // Create the solution vector (and initialize it to the state rewards of the model). std::vector x = rewardModel.getStateRewardVector().toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); multiplier->repeatedMultiplyAndReduce(env, dir, x, nullptr, stepBound); @@ -351,15 +373,19 @@ namespace storm { // Compute the reward vector to add in each step based on the available reward models. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd odd = model.getReachableStates().createOdd(); - // Create the solution vector. std::vector x(model.getNumberOfStates(), storm::utility::zero()); + + storm::utility::Stopwatch conversionWatch(true); + + // Create the ODD for the translation between symbolic and explicit storage. + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Translate the symbolic matrix/vector to their explicit representations. std::pair, std::vector> explicitRepresentation = transitionMatrix.toMatrixVector(totalRewardVector, model.getNondeterminismVariables(), odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); @@ -546,8 +572,12 @@ namespace storm { // Compute the set of maybe states that we are required to keep in the translation to explicit. storm::dd::Bdd requiredMaybeStates = extendMaybeStates ? maybeStatesWithTargetStates : maybeStates; + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = requiredMaybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -562,14 +592,19 @@ namespace storm { // Then compute the reward vector to use in the computation. storm::dd::Add subvector = rewardModel.getTotalRewardVector(maybeStatesAdd, choiceFilterAdd, submatrix, model.getColumnVariables()); + conversionWatch.start(); std::vector rowGroupSizes = (submatrix.notZero().existsAbstract(model.getColumnVariables()) || subvector.notZero()).template toAdd().sumAbstract(model.getNondeterminismVariables()).toVector(odd); + conversionWatch.stop(); // Finally cut away all columns targeting non-maybe states (or non-(maybe or target) states, respectively). submatrix *= extendMaybeStates ? maybeStatesWithTargetStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd() : maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); std::pair, std::vector> explicitRepresentation = submatrix.toMatrixVector(std::move(rowGroupSizes), subvector, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Fulfill the solver's requirements. SolverRequirementsData solverRequirementsData; if (extendMaybeStates) { From 7150354b9d407280108e63bd813a6d7bcb824d9c Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 6 Mar 2018 14:32:41 +0100 Subject: [PATCH 158/647] fixing issue related to vector swapping in (explicit) value iteration and power method --- .../csl/helper/HybridCtmcCslHelper.cpp | 1 + .../IterativeMinMaxLinearEquationSolver.cpp | 16 +++++------ .../solver/NativeLinearEquationSolver.cpp | 28 +++++++++---------- .../TopologicalMinMaxLinearEquationSolver.cpp | 2 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp index 841088ac2..d76a28884 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp @@ -322,6 +322,7 @@ namespace storm { // Then compute the state reward vector to use in the computation. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, model.getColumnVariables(), exitRateVector, false); + conversionWatch.start(); std::vector explicitTotalRewardVector = totalRewardVector.toVector(odd); conversionWatch.stop(); STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 406dd46bb..decf30b34 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -288,8 +288,6 @@ namespace storm { // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = currentIterations; - std::vector* originalX = currentX; - SolverStatus status = SolverStatus::InProgress; while (status == SolverStatus::InProgress) { // Compute x' = min/max(A*x + b). @@ -315,11 +313,6 @@ namespace storm { this->showProgressIterative(iterations); } - // Swap the pointers so that the output is always in currentX. - if (originalX == newX) { - std::swap(currentX, newX); - } - return ValueIterationResult(iterations - currentIterations, status); } @@ -1282,7 +1275,9 @@ namespace storm { template template bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, IterativeMinMaxLinearEquationSolver const& impreciseSolver, storm::storage::SparseMatrix const& rationalA, std::vector& rationalX, std::vector const& rationalB, storm::storage::SparseMatrix const& A, std::vector& x, std::vector const& b, std::vector& tmpX) const { - + + std::vector const* originalX = &x; + std::vector* currentX = &x; std::vector* newX = &tmpX; @@ -1324,6 +1319,11 @@ namespace storm { } } + // Swap the two vectors if the current result is not in the original x. + if (currentX != originalX) { + std::swap(x, tmpX); + } + if (status == SolverStatus::InProgress && overallIterations == env.solver().minMax().getMaximalNumberOfIterations()) { status = SolverStatus::MaximalIterationsExceeded; } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 4251589ea..897b6522a 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -307,8 +307,6 @@ namespace storm { bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; - std::vector* originalX = currentX; - bool converged = false; bool terminate = this->terminateNow(*currentX, guarantee); uint64_t iterations = currentIterations; @@ -320,21 +318,16 @@ namespace storm { this->multiplier->multiply(env, *currentX, &b, *newX); } - // Now check for termination. + // Check for convergence. converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative); + + // Check for termination. + std::swap(currentX, newX); + ++iterations; terminate = this->terminateNow(*currentX, guarantee); // Potentially show progress. this->showProgressIterative(iterations); - - // Set up next iteration. - std::swap(currentX, newX); - ++iterations; - } - - // Swap the pointers so that the output is always in currentX. - if (originalX == newX) { - std::swap(currentX, newX); } return PowerIterationResult(iterations - currentIterations, converged ? SolverStatus::Converged : (terminate ? SolverStatus::TerminatedEarly : SolverStatus::MaximalIterationsExceeded)); @@ -883,6 +876,8 @@ namespace storm { bool relative = env.solver().native().getRelativeTerminationCriterion(); auto multiplicationStyle = env.solver().native().getPowerMethodMultiplicationStyle(); + std::vector const* originalX = &x; + std::vector* currentX = &x; std::vector* newX = &tmpX; @@ -907,10 +902,10 @@ namespace storm { // Make sure that currentX and rationalX are not aliased. std::vector* temporaryRational = TemporaryHelper::getTemporary(rationalX, currentX, newX); - + // Sharpen solution and place it in the temporary rational. bool foundSolution = sharpen(p, rationalA, *currentX, rationalB, *temporaryRational); - + // After sharpen, if a solution was found, it is contained in the free rational. if (foundSolution) { @@ -923,6 +918,11 @@ namespace storm { } } + // Swap the two vectors if the current result is not in the original x. + if (currentX != originalX) { + std::swap(x, tmpX); + } + if (status == SolverStatus::InProgress && overallIterations == maxIter) { status = SolverStatus::MaximalIterationsExceeded; } diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 2c8951fc3..19a2f0aef 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -58,7 +58,7 @@ namespace storm { storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); - std::cout << "Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->A->getRowGroupCount()) / static_cast(this->sortedSccDecomposition->size()) << "." << std::endl; + STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << " SCC(s). Average size is " << static_cast(this->A->getRowGroupCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); if (this->longestSccChainSize) { std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl; } From de2e94cac7af6449b2cad49a5efa64761bbe6821 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 6 Mar 2018 21:27:09 +0100 Subject: [PATCH 159/647] polished unifplus code a bit and made it the default MA (bounded reachability) solution method --- .../helper/SparseMarkovAutomatonCslHelper.cpp | 179 ++++++++---------- src/storm/settings/SettingsManager.cpp | 2 - .../modules/MarkovAutomatonSettings.cpp | 32 ---- .../modules/MarkovAutomatonSettings.h | 38 ---- .../modules/MinMaxEquationSolverSettings.cpp | 12 ++ .../modules/MinMaxEquationSolverSettings.h | 11 ++ .../TopologicalMinMaxLinearEquationSolver.cpp | 2 +- 7 files changed, 103 insertions(+), 173 deletions(-) delete mode 100644 src/storm/settings/modules/MarkovAutomatonSettings.cpp delete mode 100644 src/storm/settings/modules/MarkovAutomatonSettings.h diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index f0929c9a0..7bf5f10f5 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -10,7 +10,6 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" -#include "storm/settings/modules/MarkovAutomatonSettings.h" #include "storm/environment/Environment.h" @@ -22,8 +21,6 @@ #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/ExpressionManager.h" -//#include "storm/utility/numerical.h" - #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/solver/LpSolver.h" @@ -35,24 +32,9 @@ namespace storm { namespace modelchecker { namespace helper { - - /* - * with having only a subset of the originalMatrix/vector, we need to transform indice - */ - static uint64_t transformIndice(storm::storage::BitVector const& subset, uint64_t fakeId){ - uint64_t id =0; - uint64_t counter =0; - while(counter<=fakeId){ - if(subset[id]){ - counter++; - } - id++; - } - return id-1; - } template - void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t state, uint64_t const kind, ValueType lambda, uint64_t numberOfProbabilisticStates, std::vector> const & relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const & fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const& poisson, bool cycleFree) { + void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t state, uint64_t const kind, ValueType lambda, uint64_t numberOfProbabilisticChoices, std::vector> const & relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const& poisson, bool cycleFree) { if (unifVectors[kind][k][state] != -1) { // Result already calculated. @@ -72,7 +54,7 @@ namespace storm { // Goal state, independent from kind of state. if (psiStates[state]) { - if (kind == 0){ + if (kind == 0) { // Vd res = storm::utility::zero(); for (uint64_t i = k; i < N; ++i){ @@ -91,11 +73,11 @@ namespace storm { // Markovian non-goal state. if (markovianStates[state]) { - res = storm::utility::zero; + res = storm::utility::zero(); for (auto const& element : fullTransitionMatrix.getRow(rowGroupIndices[state])) { uint64_t to = element.getColumn(); if (unifVectors[kind][k+1][to] == -1) { - calculateUnifPlusVector(env, k+1, to, kind, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + calculateUnifPlusVector(env, k+1, to, kind, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); } res += element.getValue()*unifVectors[kind][k+1][to]; } @@ -111,24 +93,23 @@ namespace storm { auto row = fullTransitionMatrix.getRow(i); ValueType between = 0; for (auto const& element : row) { - uint64_t to = element.getColumn(); + uint64_t successor = element.getColumn(); // This should never happen, right? The model has no cycles, and therefore also no self-loops. - if (to == state) { + if (successor == state) { continue; } - if (unifVectors[kind][k][to] == -1) { - calculateUnifPlusVector(env, k, to, kind, lambda, numberOfProbabilisticStates, relativeReachability, dir, - unifVectors, fullTransitionMatrix, markovianStates, psiStates, - solver, poisson, cycleFree); + + if (unifVectors[kind][k][successor] == -1) { + calculateUnifPlusVector(env, k, successor, kind, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); } - between += element.getValue() * unifVectors[kind][k][to]; + between += element.getValue() * unifVectors[kind][k][successor]; } if (maximize(dir)) { - res = std::max(res, between); + res = storm::utility::max(res, between); } else { if (res != -1) { - res = std::min(res, between); + res = storm::utility::min(res, between); } else { res = between; } @@ -138,64 +119,65 @@ namespace storm { return; } - //not cycle free - use solver technique, calling SVI per default - //solving all sub-MDP's in one iteration - std::vector b(probSize, 0), x(numberOfProbabilisticStates,0); - //calculate b - uint64_t lineCounter=0; - for (int i =0; i b(numberOfProbabilisticChoices, storm::utility::zero()); + std::vector x(numberOfProbabilisticStates, storm::utility::zero()); + + // Compute right-hand side vector b. + uint64_t row = 0; + for (uint64_t i = 0; i < numberOfStates; ++i) { if (markovianStates[i]) { continue; } - auto rowStart = rowGroupIndices[i]; - auto rowEnd = rowGroupIndices[i + 1]; - for (auto j = rowStart; j < rowEnd; j++) { + + for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; j++) { uint64_t stateCount = 0; - res = 0; - for (auto &element:fullTransitionMatrix.getRow(j)) { - auto to = element.getColumn(); - if (!markovianStates[to]) { + res = storm::utility::zero(); + for (auto const& element : fullTransitionMatrix.getRow(j)) { + auto successor = element.getColumn(); + if (!markovianStates[successor]) { continue; } - if (unifVectors[kind][k][to] == -1) { - calculateUnifPlusVector(env, k, to, kind, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + + if (unifVectors[kind][k][successor] == -1) { + calculateUnifPlusVector(env, k, successor, kind, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); } - res = res + relativeReachability[j][stateCount] * unifVectors[kind][k][to]; - stateCount++; + res = res + relativeReachability[j][stateCount] * unifVectors[kind][k][successor]; + ++stateCount; } - b[lineCounter] = res; - lineCounter++; + + b[row] = res; + ++row; } } - solver->solveEquations(env, dir, x, b); - for (uint64_t i = 0; isolveEquations(env, dir, x, b); + + // Expand the solution for the probabilistic states to all states. + storm::utility::vector::setVectorValues(unifVectors[kind][k], ~markovianStates, x); } template - void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, - uint64_t k, uint64_t node, uint64_t const kind, ValueType lambda, uint64_t probSize, - std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, - storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, - std::unique_ptr> const& solver, - storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree){ - if (unifVectors[1][k][node]!=-1){return;} //dynamic programming. avoiding multiple calculation. - uint64_t N = unifVectors[1].size()-1; + void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t state, uint64_t const kind, ValueType lambda, uint64_t numberOfProbabilisticStates, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree) { + + // Avoiding multiple computation of the same value. + if (unifVectors[1][k][state] != -1) { + return; + } + uint64_t N = unifVectors[1].size() - 1; - ValueType res =0; - for (uint64_t i = k ; i < N ; i++ ){ - if (unifVectors[2][N-1-(i-k)][node]==-1){ - calculateUnifPlusVector(env, N-1-(i-k),node,2,lambda,probSize,relativeReachability,dir,unifVectors,fullTransitionMatrix, markovianStates,psiStates,solver, poisson, cycleFree); + ValueType res = storm::utility::zero(); + for (uint64_t i = k; i < N; ++i) { + if (unifVectors[2][N-1-(i-k)][state] == -1) { + calculateUnifPlusVector(env, N-1-(i-k), state, 2, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); } - if (i>=poisson.left && i<=poisson.right){ - res+=poisson.weights[i-poisson.left]*unifVectors[2][N-1-(i-k)][node]; + if (i >= poisson.left && i <= poisson.right) { + res += poisson.weights[i - poisson.left] * unifVectors[2][N-1-(i-k)][state]; } } - unifVectors[1][k][node]=res; + unifVectors[1][k][state] = res; } template @@ -245,10 +227,10 @@ namespace storm { bool cycleFree = sccDecomposition.empty(); // Vectors to store computed vectors. - std::vector>> unifVectors{}; + std::vector>> unifVectors(3); - // Transitions from goal states will be ignored. However, they are not allowed to be probabilistic - // to make sure we do not apply the MDP algorithm to them. + // Transitions from goal states will be ignored. However, we mark them as non-probabilistic to make sure + // we do not apply the MDP algorithm to them. storm::storage::BitVector markovianAndGoalStates = markovianStates | psiStates; probabilisticStates &= ~psiStates; @@ -257,15 +239,13 @@ namespace storm { // Extend the transition matrix with diagonal entries so we can change them easily during the uniformization step. typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates, allStates, true); - // Eliminate self-loops of probabilistic states. Is this really needed for the value iteration process? - eliminateProbabilisticSelfLoops(fullTransitionMatrix, markovianStates); + // Eliminate self-loops of probabilistic states. Is this really needed for the "slight value iteration" process? + eliminateProbabilisticSelfLoops(fullTransitionMatrix, markovianAndGoalStates); typename storm::storage::SparseMatrix probMatrix; - uint64_t numberOfProbabilisticStates = probabilisticStates.getNumberOfSetBits(); - if (numberOfProbabilisticStates > 0) { + uint64_t numberOfProbabilisticChoices = 0; + if (!probabilisticStates.empty()) { probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates, probabilisticStates, true); - - // row count? shouldn't this be row group count? - // probSize = probMatrix.getRowCount(); + numberOfProbabilisticChoices = probMatrix.getRowCount(); } // Get row grouping of transition matrix. @@ -289,13 +269,13 @@ namespace storm { std::unique_ptr> solver; if (!cycleFree) { for (uint64_t i = 0; i < numberOfStates; i++) { - if (markovianStates[i]) { + if (markovianAndGoalStates[i]) { continue; } for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; ++j) { - for (auto const& element: fullTransitionMatrix.getRow(j)) { - if (markovianStates[element.getColumn()]) { + for (auto const& element : fullTransitionMatrix.getRow(j)) { + if (markovianAndGoalStates[element.getColumn()]) { relativeReachabilities[j].push_back(element.getValue()); } } @@ -308,7 +288,7 @@ namespace storm { requirements.clearBounds(); STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - if (numberOfProbabilisticStates > 0) { + if (numberOfProbabilisticChoices > 0) { solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); solver->setHasUniqueSolution(); solver->setBounds(storm::utility::zero(), storm::utility::one()); @@ -318,6 +298,7 @@ namespace storm { } // Loop until result is within precision bound. + std::vector init(numberOfStates, -1); do { maxNorm = storm::utility::zero(); @@ -326,7 +307,7 @@ namespace storm { // (3) uniform - just applied to Markovian states. for (uint64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { - if (!markovianStates[i] || psiStates[i]) { + if (!markovianAndGoalStates[i] || psiStates[i]) { continue; } @@ -358,27 +339,25 @@ namespace storm { // Compute poisson distribution. storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda * T, epsilon * kappa / 100); - // Scale the weights so they add up to one. + // Scale the weights so they sum to one. for (auto& element : foxGlynnResult.weights) { element /= foxGlynnResult.totalWeight; } // (4) Define vectors/matrices. - std::vector init(numberOfStates, -1); std::vector> v = std::vector>(N + 1, init); - unifVectors.clear(); - unifVectors.push_back(v); - unifVectors.push_back(v); - unifVectors.push_back(v); + unifVectors[0] = v; + unifVectors[1] = v; + unifVectors[2] = v; // Define 0=vd, 1=vu, 2=wu. // (5) Compute vectors and maxNorm. - for (uint64_t i = 0; i < numberOfStates; i++) { - for (uint64_t k = N; k <= N; k--) { - calculateUnifPlusVector(env, k, i, 0, lambda, numberOfProbabilisticStates, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); - calculateUnifPlusVector(env, k, i, 2, lambda, numberOfProbabilisticStates, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); - calculateVu(env, relativeReachabilities, dir, k, i, 1, lambda, numberOfProbabilisticStates, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + for (uint64_t i = 0; i < numberOfStates; ++i) { + for (uint64_t k = N; k <= N; --k) { + calculateUnifPlusVector(env, k, i, 0, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + calculateUnifPlusVector(env, k, i, 2, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + calculateVu(env, relativeReachabilities, dir, k, i, 1, lambda, numberOfProbabilisticChoices, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); } } @@ -582,11 +561,11 @@ namespace storm { template ::SupportsExponential, int>::type> std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { - auto const& markovAutomatonSettings = storm::settings::getModule(); - if (markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::Imca) { + auto const& settings = storm::settings::getModule(); + if (settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca) { return computeBoundedUntilProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); } else { - STORM_LOG_ASSERT(markovAutomatonSettings.getTechnique() == storm::settings::modules::MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus, "Unknown solution technique."); + STORM_LOG_ASSERT(settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus, "Unknown solution method."); return computeBoundedUntilProbabilitiesUnifPlus(env, dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); } diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index 89ad6f3cb..fc2b80b35 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -38,7 +38,6 @@ #include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" -#include "storm/settings/modules/MarkovAutomatonSettings.h" #include "storm/settings/modules/MultiplierSettings.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -552,7 +551,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); } diff --git a/src/storm/settings/modules/MarkovAutomatonSettings.cpp b/src/storm/settings/modules/MarkovAutomatonSettings.cpp deleted file mode 100644 index 470de708f..000000000 --- a/src/storm/settings/modules/MarkovAutomatonSettings.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "storm/settings/modules/MarkovAutomatonSettings.h" - -#include "storm/settings/Option.h" -#include "storm/settings/OptionBuilder.h" -#include "storm/settings/ArgumentBuilder.h" -#include "storm/settings/Argument.h" - -#include "storm/settings/SettingsManager.h" - -namespace storm { - namespace settings { - namespace modules { - - const std::string MarkovAutomatonSettings::moduleName = "ma"; - const std::string MarkovAutomatonSettings::techniqueOptionName = "technique"; - - MarkovAutomatonSettings::MarkovAutomatonSettings() : ModuleSettings(moduleName) { - std::vector techniques = {"imca", "unifplus"}; - this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The technique to use to solve bounded reachability queries.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the technique to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(techniques)).setDefaultValueString("imca").build()).build()); - } - - MarkovAutomatonSettings::BoundedReachabilityTechnique MarkovAutomatonSettings::getTechnique() const { - std::string techniqueAsString = this->getOption(techniqueOptionName).getArgumentByName("name").getValueAsString(); - if (techniqueAsString == "imca") { - return MarkovAutomatonSettings::BoundedReachabilityTechnique::Imca; - } - return MarkovAutomatonSettings::BoundedReachabilityTechnique::UnifPlus; - } - - } - } -} diff --git a/src/storm/settings/modules/MarkovAutomatonSettings.h b/src/storm/settings/modules/MarkovAutomatonSettings.h deleted file mode 100644 index 60cdaa1b4..000000000 --- a/src/storm/settings/modules/MarkovAutomatonSettings.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "storm/settings/modules/ModuleSettings.h" - -namespace storm { - namespace settings { - namespace modules { - - /*! - * This class represents the settings for Sylvan. - */ - class MarkovAutomatonSettings : public ModuleSettings { - public: - enum class BoundedReachabilityTechnique { Imca, UnifPlus }; - - /*! - * Creates a new set of Markov automaton settings. - */ - MarkovAutomatonSettings(); - - /*! - * Retrieves the technique to use to solve bounded reachability properties. - * - * @return The selected technique. - */ - BoundedReachabilityTechnique getTechnique() const; - - // The name of the module. - static const std::string moduleName; - - private: - // Define the string names of the options as constants. - static const std::string techniqueOptionName; - }; - - } - } -} diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index add033af0..82c2ba59c 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -18,6 +18,7 @@ namespace storm { const std::string MinMaxEquationSolverSettings::precisionOptionName = "precision"; const std::string MinMaxEquationSolverSettings::absoluteOptionName = "absolute"; const std::string MinMaxEquationSolverSettings::lraMethodOptionName = "lramethod"; + const std::string MinMaxEquationSolverSettings::markovAutomatonBoundedReachabilityMethodOptionName = "mamethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; @@ -37,6 +38,9 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, lraMethodOptionName, false, "Sets which method is preferred for computing long run averages.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a long run average computation method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(lraMethods)).setDefaultValueString("vi").build()).build()); + std::vector maMethods = {"imca", "unifplus"}; + this->addOption(storm::settings::OptionBuilder(moduleName, markovAutomatonBoundedReachabilityMethodOptionName, true, "The method to use to solve bounded reachability queries on MAs.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); + std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); @@ -109,6 +113,14 @@ namespace storm { } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown lra solving technique '" << lraMethodString << "'."); } + + MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod MinMaxEquationSolverSettings::getMarkovAutomatonBoundedReachabilityMethod() const { + std::string techniqueAsString = this->getOption(markovAutomatonBoundedReachabilityMethodOptionName).getArgumentByName("name").getValueAsString(); + if (techniqueAsString == "imca") { + return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca; + } + return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus; + } storm::solver::MultiplicationStyle MinMaxEquationSolverSettings::getValueIterationMultiplicationStyle() const { std::string multiplicationStyleString = this->getOption(valueIterationMultiplicationStyleOptionName).getArgumentByName("name").getValueAsString(); diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index ce8b5756c..f64988b6a 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -18,6 +18,9 @@ namespace storm { // An enumeration of all available convergence criteria. enum class ConvergenceCriterion { Absolute, Relative }; + // An enumeration of all available bounded reachability methods for MAs. + enum class MarkovAutomatonBoundedReachabilityMethod { Imca, UnifPlus }; + MinMaxEquationSolverSettings(); /*! @@ -90,6 +93,13 @@ namespace storm { */ storm::solver::LraMethod getLraMethod() const; + /*! + * Retrieves the method to be used for bounded reachability on MAs. + * + * @return The selected method. + */ + MarkovAutomatonBoundedReachabilityMethod getMarkovAutomatonBoundedReachabilityMethod() const; + /*! * Retrieves the multiplication style to use in the min-max methods. * @@ -117,6 +127,7 @@ namespace storm { static const std::string precisionOptionName; static const std::string absoluteOptionName; static const std::string lraMethodOptionName; + static const std::string markovAutomatonBoundedReachabilityMethodOptionName; static const std::string valueIterationMultiplicationStyleOptionName; static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string forceBoundsOptionName; diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 19a2f0aef..c0d7e0460 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -60,7 +60,7 @@ namespace storm { STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << " SCC(s). Average size is " << static_cast(this->A->getRowGroupCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); if (this->longestSccChainSize) { - std::cout << "Longest SCC chain size is " << this->longestSccChainSize.get() << std::endl; + STORM_LOG_INFO("Longest SCC chain size is " << this->longestSccChainSize.get()); } bool returnValue = true; From b3c2d8bbd8b04961e35c9cecc629908c3f5a4c78 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 9 Mar 2018 10:35:14 +0100 Subject: [PATCH 160/647] added option to not include dynamic constraints in maxsat counterexample generation --- .../SMTMinimalLabelSetGenerator.h | 65 +++++++++++++++---- .../CounterexampleGeneratorSettings.cpp | 16 +++-- .../modules/CounterexampleGeneratorSettings.h | 8 +++ 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 4aff07fae..8a8edb0e6 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1322,6 +1322,24 @@ namespace storm { return getUsedLabelSet(*solver.getModel(), variableInformation); } + static void ruleOutSingleSolution(storm::solver::SmtSolver& solver, boost::container::flat_set const& labelSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { + std::vector formulae; + + boost::container::flat_set unknownLabels; + std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + for (auto const& label : unknownLabels) { + formulae.emplace_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + boost::container::flat_set remainingLabels; + std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + for (auto const& label : remainingLabels) { + formulae.emplace_back(variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + + STORM_LOG_DEBUG("Ruling out single solution."); + assertDisjunction(solver, formulae, *variableInformation.manager); + } + /*! * Analyzes the given sub-model that has a maximal reachability of zero (i.e. no psi states are reachable) and tries to construct assertions that aim to make at least one psi state reachable. * @@ -1618,6 +1636,19 @@ namespace storm { } public: + struct Options { + Options(bool checkThresholdFeasible = false) : checkThresholdFeasible(checkThresholdFeasible) { + auto const& settings = storm::settings::getModule(); + + encodeReachability = settings.isEncodeReachabilitySet(); + useDynamicConstraints = settings.isUseDynamicConstraintsSet(); + } + + bool checkThresholdFeasible; + bool encodeReachability; + bool useDynamicConstraints; + }; + /*! * Computes the minimal command set that is needed in the given model to exceed the given probability threshold for satisfying phi until psi. * @@ -1627,10 +1658,9 @@ namespace storm { * @param psiStates A bit vector characterizing all psi states in the model. * @param probabilityThreshold The threshold that is to be achieved or exceeded. * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). - * @param checkThresholdFeasible If set, it is verified that the model can actually achieve/exceed the given probability value. If this check - * is made and fails, an exception is thrown. + * @param options A set of options for customization. */ - static boost::container::flat_set getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), bool checkThresholdFeasible = false, bool includeReachabilityEncoding = false) { + static boost::container::flat_set getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 // Set up all clocks used for time measurement. auto totalClock = std::chrono::high_resolution_clock::now(); @@ -1669,7 +1699,7 @@ namespace storm { // (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set. double maximalReachabilityProbability = 0; - if (checkThresholdFeasible) { + if (options.checkThresholdFeasible) { maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates); STORM_LOG_THROW((strictBound && maximalReachabilityProbability >= probabilityThreshold) || (!strictBound && maximalReachabilityProbability > probabilityThreshold), storm::exceptions::InvalidArgumentException, "Given probability threshold " << probabilityThreshold << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability << "."); @@ -1684,7 +1714,7 @@ namespace storm { std::unique_ptr solver = std::make_unique(*manager); // (4) Create the variables for the relevant commands. - VariableInformation variableInformation = createVariables(manager, model, psiStates, relevancyInformation, includeReachabilityEncoding); + VariableInformation variableInformation = createVariables(manager, model, psiStates, relevancyInformation, options.encodeReachability); STORM_LOG_DEBUG("Created variables."); // (5) Now assert an adder whose result variables can later be used to constrain the nummber of label @@ -1697,7 +1727,7 @@ namespace storm { STORM_LOG_DEBUG("Asserting cuts."); assertCuts(symbolicModel, model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); STORM_LOG_DEBUG("Asserted cuts."); - if (includeReachabilityEncoding) { + if (options.encodeReachability) { assertReachabilityCuts(model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); STORM_LOG_DEBUG("Asserted reachability cuts."); } @@ -1749,15 +1779,22 @@ namespace storm { // Depending on whether the threshold was successfully achieved or not, we proceed by either analyzing the bad solution or stopping the iteration process. analysisClock = std::chrono::high_resolution_clock::now(); if ((strictBound && maximalReachabilityProbability < probabilityThreshold) || (!strictBound && maximalReachabilityProbability <= probabilityThreshold)) { - if (maximalReachabilityProbability == 0) { + if (maximalReachabilityProbability == storm::utility::zero()) { ++zeroProbabilityCount; - - // If there was no target state reachable, analyze the solution and guide the solver into the right direction. - analyzeZeroProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + } + + if (options.useDynamicConstraints) { + if (maximalReachabilityProbability == storm::utility::zero()) { + // If there was no target state reachable, analyze the solution and guide the solver into the right direction. + analyzeZeroProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + } else { + // If the reachability probability was greater than zero (i.e. there is a reachable target state), but the probability was insufficient to exceed + // the given threshold, we analyze the solution and try to guide the solver into the right direction. + analyzeInsufficientProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + } } else { - // If the reachability probability was greater than zero (i.e. there is a reachable target state), but the probability was insufficient to exceed - // the given threshold, we analyze the solution and try to guide the solver into the right direction. - analyzeInsufficientProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + // Do not guide solver, just rule out current solution. + ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); } } else { done = true; @@ -1948,7 +1985,7 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, boost::container::flat_set(), true, storm::settings::getModule().isEncodeReachabilitySet()); + auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, boost::container::flat_set(), true); auto endTime = std::chrono::high_resolution_clock::now(); std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp b/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp index b33a332df..2525f19b0 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp @@ -16,13 +16,15 @@ namespace storm { const std::string CounterexampleGeneratorSettings::minimalCommandSetOptionName = "mincmd"; const std::string CounterexampleGeneratorSettings::encodeReachabilityOptionName = "encreach"; const std::string CounterexampleGeneratorSettings::schedulerCutsOptionName = "schedcuts"; - + const std::string CounterexampleGeneratorSettings::noDynamicConstraintsOptionName = "nodyn"; + CounterexampleGeneratorSettings::CounterexampleGeneratorSettings() : ModuleSettings(moduleName) { std::vector techniques = {"maxsat", "milp"}; - this->addOption(storm::settings::OptionBuilder(moduleName, minimalCommandSetOptionName, true, "Computes a counterexample for the given model in terms of a minimal command set. Note that this requires the model to be given in a symbolic format.") + this->addOption(storm::settings::OptionBuilder(moduleName, minimalCommandSetOptionName, true, "Computes a counterexample for the given model in terms of a minimal command/edge set. Note that this requires the model to be given in a symbolic format.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("method", "Sets which technique is used to derive the counterexample.").setDefaultValueString("maxsat").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(techniques)).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, encodeReachabilityOptionName, true, "Sets whether to encode reachability for MAXSAT-based minimal command counterexample generation.").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, schedulerCutsOptionName, true, "Sets whether to add the scheduler cuts for MILP-based minimal command counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, encodeReachabilityOptionName, true, "Sets whether to encode reachability for MAXSAT-based counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, schedulerCutsOptionName, true, "Sets whether to add the scheduler cuts for MILP-based counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, noDynamicConstraintsOptionName, true, "Disables the generation of dynamic constraints in the MAXSAT-based counterexample generation.").build()); } bool CounterexampleGeneratorSettings::isMinimalCommandSetGenerationSet() const { @@ -44,7 +46,11 @@ namespace storm { bool CounterexampleGeneratorSettings::isUseSchedulerCutsSet() const { return this->getOption(schedulerCutsOptionName).getHasOptionBeenSet(); } - + + bool CounterexampleGeneratorSettings::isUseDynamicConstraintsSet() const { + return !this->getOption(noDynamicConstraintsOptionName).getHasOptionBeenSet(); + } + bool CounterexampleGeneratorSettings::check() const { // Ensure that the model was given either symbolically or explicitly. STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule().isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM format."); diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.h b/src/storm/settings/modules/CounterexampleGeneratorSettings.h index 03002c8f6..bdb0813a6 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.h +++ b/src/storm/settings/modules/CounterexampleGeneratorSettings.h @@ -56,6 +56,13 @@ namespace storm { */ bool isUseSchedulerCutsSet() const; + /*! + * Retrieves whether to use the dynamic constraints in the MAXSAT-based technique. + * + * @return True iff dynamic constraints are to be used. + */ + bool isUseDynamicConstraintsSet() const; + bool check() const override; // The name of the module. @@ -66,6 +73,7 @@ namespace storm { static const std::string minimalCommandSetOptionName; static const std::string encodeReachabilityOptionName; static const std::string schedulerCutsOptionName; + static const std::string noDynamicConstraintsOptionName; }; } // namespace modules From ec5a947d56e2e94e383f19272e4e3806d8103c4c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Sun, 11 Mar 2018 22:48:15 +0100 Subject: [PATCH 161/647] Enable LTO for gcc >= 7.0 again --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f284dae11..9cd46d914 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,11 +185,6 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # using GCC if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "gcc version must be at least 5.0.") - elseif (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0) - if (STORM_USE_LTO) - set(STORM_USE_LTO OFF) - message(WARNING "Disabling link-time optimization, because of known incompatibility of LTO with gcc >= 7.") - endif() endif() set(STORM_COMPILER_GCC ON) From 3beff87636beaa305c08dc726fa35c9162ab1796 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 12 Mar 2018 09:14:24 +0100 Subject: [PATCH 162/647] Try to fix LTO issue by adding virtual destructor --- .../TopologicalMinMaxLinearEquationSolver.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index cdbc781bc..617f9e1b2 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -6,32 +6,35 @@ #include "storm/storage/StronglyConnectedComponentDecomposition.h" namespace storm { - + class Environment; - + namespace solver { - + template class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: TopologicalMinMaxLinearEquationSolver(); TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); - + + virtual ~TopologicalMinMaxLinearEquationSolver() { + } + virtual void clearCache() const override; virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override ; protected: - + virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const override; private: storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const; - + // Creates an SCC decomposition and sorts the SCCs according to a topological sort. void createSortedSccDecomposition(bool needLongestChainSize) const; - + // Solves the SCC with the given index // ... for the case that the SCC is trivial bool solveTrivialScc(uint64_t const& sccState, OptimizationDirection d, std::vector& globalX, std::vector const& globalB) const; From a24de86ce1ee1ce107de01a248f348e243d86046 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 13 Mar 2018 13:41:12 +0100 Subject: [PATCH 163/647] Avoided duplicated code for sound value iteration --- .../IterativeMinMaxLinearEquationSolver.cpp | 406 +---------------- .../solver/NativeLinearEquationSolver.cpp | 213 +-------- .../helper/SoundValueIterationHelper.cpp | 418 ++++++++++++++++++ .../solver/helper/SoundValueIterationHelper.h | 147 ++++++ 4 files changed, 572 insertions(+), 612 deletions(-) create mode 100644 src/storm/solver/helper/SoundValueIterationHelper.cpp create mode 100644 src/storm/solver/helper/SoundValueIterationHelper.h diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index decf30b34..4bb4cc766 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -10,6 +10,7 @@ #include "storm/utility/KwekMehlhorn.h" #include "storm/utility/NumberTraits.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" @@ -604,395 +605,6 @@ namespace storm { return status == SolverStatus::Converged; } - template - class SoundValueIterationHelper { - public: - - typedef uint32_t IndexType; - - SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision), rowGroupIndices(matrix.getRowGroupIndices()) { - STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); - uint64_t sizeOfLargestRowGroup = matrix.getSizeOfLargestRowGroup(); - xTmp.resize(sizeOfLargestRowGroup); - yTmp.resize(sizeOfLargestRowGroup); - x.assign(x.size(), storm::utility::zero()); - y.assign(x.size(), storm::utility::one()); - hasDecisionValue = false; - decisionValueBlocks = false; - convergencePhase1 = true; - firstIndexViolatingConvergence = 0; - - numRows = matrix.getRowCount(); - matrixValues.clear(); - matrixColumns.clear(); - rowIndications.clear(); - matrixValues.reserve(matrix.getNonzeroEntryCount()); - matrixColumns.reserve(matrix.getColumnCount()); - rowIndications.reserve(numRows + 1); - rowIndications.push_back(0); - for (IndexType r = 0; r < numRows; ++r) { - for (auto const& entry : matrix.getRow(r)) { - matrixValues.push_back(entry.getValue()); - matrixColumns.push_back(entry.getColumn()); - } - rowIndications.push_back(matrixValues.size()); - } - } - - - inline void setLowerBound(ValueType const& value) { - hasLowerBound = true; - lowerBound = value; - } - - inline void setUpperBound(ValueType const& value) { - hasUpperBound = true; - upperBound = value; - } - - template - inline bool better(ValueType const& val1, ValueType const& val2) { - return maximize(dir) ? val1 > val2 : val1 < val2; - } - - template - inline ValueType& getPrimaryBound() { - return maximize(dir) ? upperBound : lowerBound; - } - - template - inline bool& hasPrimaryBound() { - return maximize(dir) ? hasUpperBound : hasLowerBound; - } - - template - inline ValueType& getSecondaryBound() { - return maximize(dir) ? lowerBound : upperBound; - } - - template - inline uint64_t& getPrimaryIndex() { - return maximize(dir) ? maxIndex : minIndex; - } - - template - inline uint64_t& getSecondaryIndex() { - return maximize(dir) ? minIndex : maxIndex; - } - - void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { - assert(rowIndex < numRows); - ValueType xRes = bi; - ValueType yRes = storm::utility::zero(); - - auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; - auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; - auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; - for (; entryIt != entryItE; ++entryIt, ++colIt) { - xRes += *entryIt * x[*colIt]; - yRes += *entryIt * y[*colIt]; - } - xi = std::move(xRes); - yi = std::move(yRes); - } - - template - void performIterationStep(std::vector const& b) { - if (!decisionValueBlocks) { - performIterationStepUpdateDecisionValue(b); - } else { - assert(decisionValue == getPrimaryBound()); - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = rowGroupIndices.rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = rowGroupIndices.rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - IndexType row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - ValueType bestValue = xBest + yBest * getPrimaryBound(); - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, b[row], xi, yi); - ValueType currentValue = xi + yi * getPrimaryBound(); - // Check if the current row is better then the previously found one - if (better(currentValue, bestValue)) { - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (currentValue == bestValue && yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - xBest = std::move(xi); - yBest = std::move(yi); - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - } - - template - void performIterationStepUpdateDecisionValue(std::vector const& b) { - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - auto groupStartIt = rowGroupIndices.rbegin(); - uint64_t groupEnd = *groupStartIt; - ++groupStartIt; - for (auto groupStartIte = rowGroupIndices.rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { - // Perform the iteration for the first row in the group - uint64_t row = *groupStartIt; - ValueType xBest, yBest; - multiplyRow(row, b[row], xBest, yBest); - ++row; - // Only do more work if there are still rows in this row group - if (row != groupEnd) { - ValueType xi, yi; - uint64_t xyTmpIndex = 0; - if (hasPrimaryBound()) { - ValueType bestValue = xBest + yBest * getPrimaryBound(); - for (;row < groupEnd; ++row) { - // Get the multiplication results - multiplyRow(row, b[row], xi, yi); - ValueType currentValue = xi + yi * getPrimaryBound(); - // Check if the current row is better then the previously found one - if (better(currentValue, bestValue)) { - if (yBest < yi) { - // We need to store the 'old' best value as it might be relevant for the decision value - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - } - xBest = std::move(xi); - yBest = std::move(yi); - bestValue = std::move(currentValue); - } else if (yBest > yi) { - // If the value for this row is not strictly better, it might still be equal and have a better y value - if (currentValue == bestValue) { - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - } else { - for (;row < groupEnd; ++row) { - multiplyRow(row, b[row], xi, yi); - // Update the best choice - if (yi > yBest || (yi == yBest && better(xi, xBest))) { - xTmp[xyTmpIndex] = std::move(xBest); - yTmp[xyTmpIndex] = std::move(yBest); - ++xyTmpIndex; - xBest = std::move(xi); - yBest = std::move(yi); - } else { - xTmp[xyTmpIndex] = std::move(xi); - yTmp[xyTmpIndex] = std::move(yi); - ++xyTmpIndex; - } - } - } - - // Update the decision value - for (uint64_t i = 0; i < xyTmpIndex; ++i) { - ValueType deltaY = yBest - yTmp[i]; - if (deltaY > storm::utility::zero()) { - ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; - if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { - decisionValue = std::move(newDecisionValue); - hasDecisionValue = true; - } - } - } - } - *xIt = std::move(xBest); - *yIt = std::move(yBest); - } - } - - template - bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr) { - - if (convergencePhase1) { - if (checkConvergencePhase1()) { - firstIndexViolatingConvergence = 0; - if (relevantValues != nullptr) { - firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); - } - } else { - return false; - } - } - STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); - - // Reaching this point means that we are in Phase 2: - // The difference between lower and upper bound has to be < precision at every (relevant) value - - // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds - ValueType lowerBoundCandidate, upperBoundCandidate; - if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { - updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); - checkIfDecisionValueBlocks(); - return checkConvergencePhase2(relevantValues); - } - return false; - } - - void setSolutionVector() { - STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); - - ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); - - STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " - << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") - << " and upper value bound " - << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") - << ". Decision value is " - << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") - << "."); - - } - - private: - - bool checkConvergencePhase1() { - // Return true if y ('the probability to stay within the matrix') is < 1 at every entry - for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { - static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); - if (NumberTraits::IsExact) { - if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { - return false; - } - } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { - return false; - } - } - } - convergencePhase1 = false; - return true; - } - - - bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { - return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); - } - - template - bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { - lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); - upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); - // Make sure that these candidates are at least as tight as the already known bounds - if (hasLowerBound && lowerBoundCandidate < lowerBound) { - lowerBoundCandidate = lowerBound; - } - if (hasUpperBound && upperBoundCandidate > upperBound) { - upperBoundCandidate = upperBound; - } - if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { - return true; - } - if (!decisionValueBlocks) { - return hasDecisionValue && better(decisionValue, getPrimaryBound()); - } - return false; - } - - template - void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { - auto xIt = x.begin(); - auto xIte = x.end(); - auto yIt = y.begin(); - for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { - ValueType currentBound = *xIt / (storm::utility::one() - *yIt); - if (decisionValueBlocks) { - if (better(getSecondaryBound(), currentBound)) { - getSecondaryIndex() = index; - getSecondaryBound() = std::move(currentBound); - } - } else { - if (currentBound < lowerBoundCandidate) { - minIndex = index; - lowerBoundCandidate = std::move(currentBound); - } else if (currentBound > upperBoundCandidate) { - maxIndex = index; - upperBoundCandidate = std::move(currentBound); - } - } - } - if ((maximize(dir) || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { - setLowerBound(lowerBoundCandidate); - } - if ((minimize(dir) || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { - setUpperBound(upperBoundCandidate); - } - } - - template - void checkIfDecisionValueBlocks() { - // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). - if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { - getPrimaryBound() = decisionValue; - decisionValueBlocks = true; - } - } - - template - bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr) { - // Check whether the desired precision is reached - if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // The current index satisfies the desired bound. We now move to the next index that violates it - while (true) { - ++firstIndexViolatingConvergence; - if (relevantValues != nullptr) { - firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); - } - if (firstIndexViolatingConvergence == x.size()) { - // Converged! - return true; - } else { - if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // not converged yet - return false; - } - } - } - } - return false; - } - - std::vector& x; - std::vector& y; - std::vector xTmp, yTmp; - - ValueType lowerBound, upperBound, decisionValue; - bool hasLowerBound, hasUpperBound, hasDecisionValue; - uint64_t minIndex, maxIndex; - bool convergencePhase1; - bool decisionValueBlocks; - uint64_t firstIndexViolatingConvergence; - - bool relative; - ValueType precision; - - std::vector matrixValues; - std::vector matrixColumns; - std::vector rowIndications; - std::vector::index_type> const& rowGroupIndices; - IndexType numRows; - }; - template bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { @@ -1003,7 +615,7 @@ namespace storm { } // TODO: implement caching for the helper - SoundValueIterationHelper helper(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + storm::solver::helper::SoundValueIterationHelper helper(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { @@ -1023,17 +635,9 @@ namespace storm { uint64_t iterations = 0; while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { - if (minimize(dir)) { - helper.template performIterationStep(b); - if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { - status = SolverStatus::Converged; - } - } else { - assert(maximize(dir)); - helper.template performIterationStep(b); - if (helper.template checkConvergenceUpdateBounds(relevantValuesPtr)) { - status = SolverStatus::Converged; - } + helper.performIterationStep(dir, b); + if (helper.checkConvergenceUpdateBounds(dir, relevantValuesPtr)) { + status = SolverStatus::Converged; } // Update environment variables. diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 897b6522a..dd67522a1 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -9,6 +9,7 @@ #include "storm/utility/NumberTraits.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/solver/Multiplier.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidEnvironmentException.h" @@ -563,216 +564,6 @@ namespace storm { return converged; } - template - class SoundPowerHelper { - public: - - typedef uint32_t IndexType; - - SoundPowerHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), minIndex(0), maxIndex(0), relative(relative), precision(precision) { - STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); - x.assign(x.size(), storm::utility::zero()); - y.assign(x.size(), storm::utility::one()); - convergencePhase1 = true; - firstIndexViolatingConvergence = 0; - - numRows = matrix.getRowCount(); - matrixValues.clear(); - matrixColumns.clear(); - rowIndications.clear(); - matrixValues.reserve(matrix.getNonzeroEntryCount()); - matrixColumns.reserve(matrix.getColumnCount()); - rowIndications.reserve(numRows + 1); - rowIndications.push_back(0); - for (IndexType r = 0; r < numRows; ++r) { - for (auto const& entry : matrix.getRow(r)) { - matrixValues.push_back(entry.getValue()); - matrixColumns.push_back(entry.getColumn()); - } - rowIndications.push_back(matrixValues.size()); - } - } - - inline void setLowerBound(ValueType const& value) { - hasLowerBound = true; - lowerBound = value; - } - - inline void setUpperBound(ValueType const& value) { - hasUpperBound = true; - upperBound = value; - } - - void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { - assert(rowIndex < numRows); - ValueType xRes = bi; - ValueType yRes = storm::utility::zero(); - - auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; - auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; - auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; - for (; entryIt != entryItE; ++entryIt, ++colIt) { - xRes += *entryIt * x[*colIt]; - yRes += *entryIt * y[*colIt]; - } - xi = std::move(xRes); - yi = std::move(yRes); - } - - void performIterationStep(std::vector const& b) { - auto xIt = x.rbegin(); - auto yIt = y.rbegin(); - IndexType row = numRows; - while (row > 0) { - --row; - multiplyRow(row, b[row], *xIt, *yIt); - ++xIt; - ++yIt; - } - } - - bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr) { - - if (convergencePhase1) { - if (checkConvergencePhase1()) { - firstIndexViolatingConvergence = 0; - if (relevantValues != nullptr) { - firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); - } - } else { - return false; - } - } - STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); - - // Reaching this point means that we are in Phase 2: - // The difference between lower and upper bound has to be < precision at every (relevant) value - - // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds - ValueType lowerBoundCandidate, upperBoundCandidate; - if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { - updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); - return checkConvergencePhase2(relevantValues); - } - return false; - } - - void setSolutionVector() { - STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); - - ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); - storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); - - STORM_LOG_INFO("Sound Power Iteration terminated with lower value bound " - << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") - << " and upper value bound " - << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") - << "."); - } - - private: - - bool checkConvergencePhase1() { - // Return true if y ('the probability to stay within the 'maybestates') is < 1 at every entry - for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { - static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); - if (NumberTraits::IsExact) { - if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { - return false; - } - } else { - if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { - return false; - } - } - } - convergencePhase1 = false; - return true; - } - - - bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { - return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); - } - - bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { - lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); - upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); - // Make sure that these candidates are at least as tight as the already known bounds - if (hasLowerBound && lowerBoundCandidate < lowerBound) { - lowerBoundCandidate = lowerBound; - } - if (hasUpperBound && upperBoundCandidate > upperBound) { - upperBoundCandidate = upperBound; - } - if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { - return true; - } - return false; - } - - void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { - auto xIt = x.begin(); - auto xIte = x.end(); - auto yIt = y.begin(); - for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { - ValueType currentBound = *xIt / (storm::utility::one() - *yIt); - if (currentBound < lowerBoundCandidate) { - minIndex = index; - lowerBoundCandidate = std::move(currentBound); - } else if (currentBound > upperBoundCandidate) { - maxIndex = index; - upperBoundCandidate = std::move(currentBound); - } - } - if (!hasLowerBound || lowerBoundCandidate > lowerBound) { - setLowerBound(lowerBoundCandidate); - } - if (!hasUpperBound || upperBoundCandidate < upperBound) { - setUpperBound(upperBoundCandidate); - } - } - - bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr) { - // Check whether the desired precision is reached - if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // The current index satisfies the desired bound. We now move to the next index that violates it - while (true) { - ++firstIndexViolatingConvergence; - if (relevantValues != nullptr) { - firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); - } - if (firstIndexViolatingConvergence == x.size()) { - // Converged! - return true; - } else { - if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { - // not converged yet - return false; - } - } - } - } - return false; - } - - std::vector& x; - std::vector& y; - - ValueType lowerBound, upperBound, decisionValue; - bool hasLowerBound, hasUpperBound, hasDecisionValue; - uint64_t minIndex, maxIndex; - bool convergencePhase1; - uint64_t firstIndexViolatingConvergence; - - std::vector matrixValues; - std::vector matrixColumns; - std::vector rowIndications; - IndexType numRows; - - bool relative; - ValueType precision; - }; template bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { @@ -784,7 +575,7 @@ namespace storm { } // TODO: implement caching for the helper - SoundPowerHelper helper(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + storm::solver::helper::SoundValueIterationHelper helper(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp new file mode 100644 index 000000000..c208cea55 --- /dev/null +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -0,0 +1,418 @@ +#include "storm/solver/helper/SoundValueIterationHelper.h" + +#include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" +#include "storm/utility/vector.h" +#include "storm/utility/macros.h" +#include "storm/utility/NumberTraits.h" + +#include "storm/exceptions/NotSupportedException.h" + + +namespace storm { + namespace solver { + namespace helper { + + template + SoundValueIterationHelper::SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), hasDecisionValue(false), convergencePhase1(true), decisionValueBlocks(false), firstIndexViolatingConvergence(0), minIndex(0), maxIndex(0), relative(relative), precision(precision), rowGroupIndices(nullptr) { + STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); + if (!matrix.hasTrivialRowGrouping()) { + rowGroupIndices = &matrix.getRowGroupIndices(); + uint64_t sizeOfLargestRowGroup = matrix.getSizeOfLargestRowGroup(); + xTmp.resize(sizeOfLargestRowGroup); + yTmp.resize(sizeOfLargestRowGroup); + } + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + + numRows = matrix.getRowCount(); + matrixValues.clear(); + matrixColumns.clear(); + rowIndications.clear(); + matrixValues.reserve(matrix.getNonzeroEntryCount()); + matrixColumns.reserve(matrix.getColumnCount()); + rowIndications.reserve(numRows + 1); + rowIndications.push_back(0); + for (IndexType r = 0; r < numRows; ++r) { + for (auto const& entry : matrix.getRow(r)) { + matrixValues.push_back(entry.getValue()); + matrixColumns.push_back(entry.getColumn()); + } + rowIndications.push_back(matrixValues.size()); + } + } + + template + SoundValueIterationHelper::SoundValueIterationHelper(SoundValueIterationHelper&& oldHelper, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), xTmp(std::move(oldHelper.xTmp)), yTmp(std::move(oldHelper.yTmp)), hasLowerBound(false), hasUpperBound(false), hasDecisionValue(false), convergencePhase1(true), decisionValueBlocks(false), firstIndexViolatingConvergence(0), minIndex(0), maxIndex(0), relative(relative), precision(precision), numRows(std::move(oldHelper.numRows)), matrixValues(std::move(oldHelper.matrixValues)), matrixColumns(std::move(oldHelper.matrixColumns)), rowIndications(std::move(oldHelper.rowIndications)), rowGroupIndices(oldHelper.rowGroupIndices) { + + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + } + + + template + void SoundValueIterationHelper::setLowerBound(ValueType const& value) { + hasLowerBound = true; + lowerBound = value; + } + + template + void SoundValueIterationHelper::setUpperBound(ValueType const& value) { + hasUpperBound = true; + upperBound = value; + } + + template + void SoundValueIterationHelper::multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { + assert(rowIndex < numRows); + ValueType xRes = bi; + ValueType yRes = storm::utility::zero(); + + auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; + auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; + auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; + for (; entryIt != entryItE; ++entryIt, ++colIt) { + xRes += *entryIt * x[*colIt]; + yRes += *entryIt * y[*colIt]; + } + xi = std::move(xRes); + yi = std::move(yRes); + } + + template + void SoundValueIterationHelper::performIterationStep(OptimizationDirection const& dir, std::vector const& b) { + if (rowGroupIndices) { + if (minimize(dir)) { + performIterationStep(b); + } else { + performIterationStep(b); + } + } else { + performIterationStep(b); + } + } + + template + void SoundValueIterationHelper::performIterationStep(std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + IndexType row = numRows; + while (row > 0) { + --row; + multiplyRow(row, b[row], *xIt, *yIt); + ++xIt; + ++yIt; + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::performIterationStep(std::vector const& b) { + if (!decisionValueBlocks) { + performIterationStepUpdateDecisionValue(b); + } else { + assert(decisionValue == getPrimaryBound()); + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = rowGroupIndices->rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = rowGroupIndices->rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + IndexType row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (currentValue == bestValue && yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + xBest = std::move(xi); + yBest = std::move(yi); + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::performIterationStepUpdateDecisionValue(std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = rowGroupIndices->rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = rowGroupIndices->rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + uint64_t xyTmpIndex = 0; + if (hasPrimaryBound()) { + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + if (yBest < yi) { + // We need to store the 'old' best value as it might be relevant for the decision value + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + } + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + if (currentValue == bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + } else { + for (;row < groupEnd; ++row) { + multiplyRow(row, b[row], xi, yi); + // Update the best choice + if (yi > yBest || (yi == yBest && better(xi, xBest))) { + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + + // Update the decision value + for (uint64_t i = 0; i < xyTmpIndex; ++i) { + ValueType deltaY = yBest - yTmp[i]; + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; + } + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + + template + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(OptimizationDirection const& dir, storm::storage::BitVector const* relevantValues) { + if (rowGroupIndices) { + if (minimize(dir)) { + return checkConvergenceUpdateBounds(relevantValues); + } else { + return checkConvergenceUpdateBounds(relevantValues); + } + } else { + return checkConvergenceUpdateBounds(relevantValues); + } + } + + template + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues) { + return checkConvergenceUpdateBounds(relevantValues); + } + + template + template::InternalOptimizationDirection dir> + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues) { + + if (convergencePhase1) { + if (checkConvergencePhase1()) { + firstIndexViolatingConvergence = 0; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); + } + } else { + return false; + } + } + STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + + // Reaching this point means that we are in Phase 2: + // The difference between lower and upper bound has to be < precision at every (relevant) value + + // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds + ValueType lowerBoundCandidate, upperBoundCandidate; + if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { + updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); + if (dir != InternalOptimizationDirection::None) { + checkIfDecisionValueBlocks(); + } + return checkConvergencePhase2(relevantValues); + } + return false; + } + + template + void SoundValueIterationHelper::setSolutionVector() { + STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); + + ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); + + STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " + << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") + << " and upper value bound " + << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") + << ". Decision value is " + << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") + << "."); + + } + + + template + bool SoundValueIterationHelper::checkConvergencePhase1() { + // Return true if y ('the probability to stay within the matrix') is < 1 at every entry + for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { + return false; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { + return false; + } + } + } + convergencePhase1 = false; + return true; + } + + + template + bool SoundValueIterationHelper::isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { + return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); + } + + template + template::InternalOptimizationDirection dir> + bool SoundValueIterationHelper::preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); + upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); + // Make sure that these candidates are at least as tight as the already known bounds + if (hasLowerBound && lowerBoundCandidate < lowerBound) { + lowerBoundCandidate = lowerBound; + } + if (hasUpperBound && upperBoundCandidate > upperBound) { + upperBoundCandidate = upperBound; + } + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { + return true; + } + if (dir != InternalOptimizationDirection::None && !decisionValueBlocks) { + return hasDecisionValue && better(decisionValue, getPrimaryBound()); + } + return false; + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + auto xIt = x.begin(); + auto xIte = x.end(); + auto yIt = y.begin(); + for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { + ValueType currentBound = *xIt / (storm::utility::one() - *yIt); + if (dir != InternalOptimizationDirection::None && decisionValueBlocks) { + if (better(getSecondaryBound(), currentBound)) { + getSecondaryIndex() = index; + getSecondaryBound() = std::move(currentBound); + } + } else { + if (currentBound < lowerBoundCandidate) { + minIndex = index; + lowerBoundCandidate = std::move(currentBound); + } else if (currentBound > upperBoundCandidate) { + maxIndex = index; + upperBoundCandidate = std::move(currentBound); + } + } + } + if ((dir != InternalOptimizationDirection::Minimize || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { + setLowerBound(lowerBoundCandidate); + } + if ((dir != InternalOptimizationDirection::Maximize || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { + setUpperBound(upperBoundCandidate); + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::checkIfDecisionValueBlocks() { + // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). + if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { + getPrimaryBound() = decisionValue; + decisionValueBlocks = true; + } + } + + template + bool SoundValueIterationHelper::checkConvergencePhase2(storm::storage::BitVector const* relevantValues) { + // Check whether the desired precision is reached + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); + } + if (firstIndexViolatingConvergence == x.size()) { + // Converged! + return true; + } else { + if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // not converged yet + return false; + } + } + } + } + return false; + } + + template class SoundValueIterationHelper; + template class SoundValueIterationHelper; + } + + } +} + diff --git a/src/storm/solver/helper/SoundValueIterationHelper.h b/src/storm/solver/helper/SoundValueIterationHelper.h new file mode 100644 index 000000000..d9f7bc476 --- /dev/null +++ b/src/storm/solver/helper/SoundValueIterationHelper.h @@ -0,0 +1,147 @@ +#pragma once + +#include + +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + + namespace storage { + template + class SparseMatrix; + + class BitVector; + } + + namespace solver { + namespace helper { + + + template + class SoundValueIterationHelper { + public: + + typedef uint32_t IndexType; + + /*! + * Creates a new helper from the given data + */ + SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision); + + /*! + * Creates a helper from the given data, considering the same matrix as the given old helper + */ + SoundValueIterationHelper(SoundValueIterationHelper&& oldHelper, std::vector& x, std::vector& y, bool relative, ValueType const& precision); + + /*! + * Sets the currently known lower / upper bound + */ + void setLowerBound(ValueType const& value); + void setUpperBound(ValueType const& value); + + void setSolutionVector(); + + /*! + * Performs one iteration step with respect to the given optimization direction. + */ + void performIterationStep(OptimizationDirection const& dir, std::vector const& b); + + /*! + * Performs one iteration step, assuming that the row grouping of the initial matrix is trivial. + */ + void performIterationStep(std::vector const& b); + + /*! + * Checks for convergence and updates the known lower/upper bounds. + */ + bool checkConvergenceUpdateBounds(OptimizationDirection const& dir, storm::storage::BitVector const* relevantValues = nullptr); + + /*! + * Checks for convergence and updates the known lower/upper bounds, assuming that the row grouping of the initial matrix is trivial. + */ + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr); + + private: + + enum class InternalOptimizationDirection { + None, Minimize, Maximize + }; + + template + void performIterationStep(std::vector const& b); + + template + void performIterationStepUpdateDecisionValue(std::vector const& b); + + void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi); + + template + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr); + + bool checkConvergencePhase1(); + bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr); + + bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub); + + template + bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate); + + template + void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate); + + template + void checkIfDecisionValueBlocks(); + + + // Auxiliary helper functions to avoid case distinctions due to different optimization directions + template + inline bool better(ValueType const& val1, ValueType const& val2) { + return (dir == InternalOptimizationDirection::Maximize) ? val1 > val2 : val1 < val2; + } + template + inline ValueType& getPrimaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? upperBound : lowerBound; + } + template + inline bool& hasPrimaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? hasUpperBound : hasLowerBound; + } + template + inline ValueType& getSecondaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? lowerBound : upperBound; + } + template + inline uint64_t& getPrimaryIndex() { + return (dir == InternalOptimizationDirection::Maximize) ? maxIndex : minIndex; + } + template + inline uint64_t& getSecondaryIndex() { + return (dir == InternalOptimizationDirection::Maximize) ? minIndex : maxIndex; + } + + + std::vector& x; + std::vector& y; + std::vector xTmp, yTmp; + + ValueType lowerBound, upperBound, decisionValue; + bool hasLowerBound, hasUpperBound, hasDecisionValue; + bool convergencePhase1; + bool decisionValueBlocks; + uint64_t firstIndexViolatingConvergence; + uint64_t minIndex, maxIndex; + + bool relative; + ValueType precision; + + IndexType numRows; + std::vector matrixValues; + std::vector matrixColumns; + std::vector rowIndications; + std::vector const* rowGroupIndices; + }; + + } + } +} + From be6d4f98541ce2a890ac5eada802e4a076f00984 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 13 Mar 2018 13:46:50 +0100 Subject: [PATCH 164/647] renamed 'sound power' to 'sound value iteration' --- .../modules/NativeEquationSolverSettings.cpp | 8 ++++---- src/storm/solver/NativeLinearEquationSolver.cpp | 12 ++++++------ src/storm/solver/NativeLinearEquationSolver.h | 2 +- src/storm/solver/SolverSelectionOptions.cpp | 4 ++-- src/storm/solver/SolverSelectionOptions.h | 2 +- .../storm/modelchecker/DtmcPrctlModelCheckerTest.cpp | 10 +++++----- src/test/storm/solver/LinearEquationSolverTest.cpp | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 123298b2c..a73d64bc2 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -27,7 +27,7 @@ namespace storm { const std::string NativeEquationSolverSettings::powerMethodSymmetricUpdatesOptionName = "symmetricupdates"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "soundpower", "interval-iteration", "ratsearch" }; + std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); @@ -67,9 +67,9 @@ namespace storm { return storm::solver::NativeLinearEquationSolverMethod::WalkerChae; } else if (linearEquationSystemTechniqueAsString == "power") { return storm::solver::NativeLinearEquationSolverMethod::Power; - } else if (linearEquationSystemTechniqueAsString == "soundpower") { - return storm::solver::NativeLinearEquationSolverMethod::SoundPower; - } else if (linearEquationSystemTechniqueAsString == "interval-iteration") { + } else if (linearEquationSystemTechniqueAsString == "sound-value-iteration" || linearEquationSystemTechniqueAsString == "svi") { + return storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration; + } else if (linearEquationSystemTechniqueAsString == "interval-iteration" || linearEquationSystemTechniqueAsString == "ii") { return storm::solver::NativeLinearEquationSolverMethod::IntervalIteration; } else if (linearEquationSystemTechniqueAsString == "ratsearch") { return storm::solver::NativeLinearEquationSolverMethod::RationalSearch; diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index dd67522a1..e7d1cf5e5 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -566,7 +566,7 @@ namespace storm { template - bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + bool NativeLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, std::vector& x, std::vector const& b) const { // Prepare the solution vectors. assert(x.size() == this->A->getRowCount()); @@ -906,9 +906,9 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } - } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::SoundPower && method != NativeLinearEquationSolverMethod::IntervalIteration && method != NativeLinearEquationSolverMethod::RationalSearch) { + } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::SoundValueIteration && method != NativeLinearEquationSolverMethod::IntervalIteration && method != NativeLinearEquationSolverMethod::RationalSearch) { if (env.solver().native().isMethodSetFromDefault()) { - method = NativeLinearEquationSolverMethod::SoundPower; + method = NativeLinearEquationSolverMethod::SoundValueIteration; STORM_LOG_INFO("Selecting '" + toString(method) + "' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); } else { STORM_LOG_WARN("The selected solution method does not guarantee sound results."); @@ -931,8 +931,8 @@ namespace storm { return this->solveEquationsWalkerChae(env, x, b); case NativeLinearEquationSolverMethod::Power: return this->solveEquationsPower(env, x, b); - case NativeLinearEquationSolverMethod::SoundPower: - return this->solveEquationsSoundPower(env, x, b); + case NativeLinearEquationSolverMethod::SoundValueIteration: + return this->solveEquationsSoundValueIteration(env, x, b); case NativeLinearEquationSolverMethod::IntervalIteration: return this->solveEquationsIntervalIteration(env, x, b); case NativeLinearEquationSolverMethod::RationalSearch: @@ -945,7 +945,7 @@ namespace storm { template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::SoundPower || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::IntervalIteration) { + if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::SoundValueIteration || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::IntervalIteration) { return LinearEquationSolverProblemFormat::FixedPointSystem; } else { return LinearEquationSolverProblemFormat::EquationSystem; diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 46ba3628e..6622de17f 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -64,7 +64,7 @@ namespace storm { virtual bool solveEquationsJacobi(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsWalkerChae(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; - virtual bool solveEquationsSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; + virtual bool solveEquationsSoundValueIteration(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsIntervalIteration(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsRationalSearch(storm::Environment const& env, std::vector& x, std::vector const& b) const; diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index d2148e9bc..d50d4875f 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -94,8 +94,8 @@ namespace storm { return "WalkerChae"; case NativeLinearEquationSolverMethod::Power: return "Power"; - case NativeLinearEquationSolverMethod::SoundPower: - return "SoundPower"; + case NativeLinearEquationSolverMethod::SoundValueIteration: + return "SoundValueIteration"; case NativeLinearEquationSolverMethod::IntervalIteration: return "IntervalIteration"; case NativeLinearEquationSolverMethod::RationalSearch: diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index 678bc1565..baea29dc1 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -15,7 +15,7 @@ namespace storm { ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination, Topological) ExtendEnumsWithSelectionField(SmtSolverType, Z3, Mathsat) - ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, SoundPower, IntervalIteration, RationalSearch) + ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, SoundValueIteration, IntervalIteration, RationalSearch) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverMethod, Bicgstab, Qmr, Gmres) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverPreconditioner, Ilu, Diagonal, None) ExtendEnumsWithSelectionField(EigenLinearEquationSolverMethod, SparseLU, Bicgstab, DGmres, Gmres) diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index 4ba411f18..ad6654ff4 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -206,7 +206,7 @@ namespace { } }; - class SparseNativeSoundPowerEnvironment { + class SparseNativeSoundValueIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // unused for sparse models static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; @@ -217,7 +217,7 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundPower); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration); env.solver().native().setPrecision(storm::utility::convertNumber(1e-6)); return env; } @@ -304,7 +304,7 @@ namespace { } }; - class HybridCuddNativeSoundPowerEnvironment { + class HybridCuddNativeSoundValueIterationEnvironment { public: static const storm::dd::DdType ddType = storm::dd::DdType::CUDD; static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Hybrid; @@ -481,13 +481,13 @@ namespace { SparseNativeWalkerChaeEnvironment, SparseNativeSorEnvironment, SparseNativePowerEnvironment, - SparseNativeSoundPowerEnvironment, + SparseNativeSoundValueIterationEnvironment, SparseNativeIntervalIterationEnvironment, SparseNativeRationalSearchEnvironment, SparseTopologicalEigenLUEnvironment, HybridSylvanGmmxxGmresEnvironment, HybridCuddNativeJacobiEnvironment, - HybridCuddNativeSoundPowerEnvironment, + HybridCuddNativeSoundValueIterationEnvironment, HybridSylvanNativeRationalSearchEnvironment, DdSylvanNativePowerEnvironment, DdCuddNativeJacobiEnvironment, diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index 3b5386c1f..f96f88e5d 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -24,7 +24,7 @@ namespace { } }; - class NativeDoubleSoundPowerEnvironment { + class NativeDoubleSoundValueIterationEnvironment { public: typedef double ValueType; static const bool isExact = false; @@ -32,7 +32,7 @@ namespace { storm::Environment env; env.solver().setForceSoundness(true); env.solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Native); - env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundPower); + env.solver().native().setMethod(storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration); env.solver().native().setRelativeTerminationCriterion(false); env.solver().native().setPrecision(storm::utility::convertNumber("1e-6")); return env; @@ -293,7 +293,7 @@ namespace { typedef ::testing::Types< NativeDoublePowerEnvironment, - NativeDoubleSoundPowerEnvironment, + NativeDoubleSoundValueIterationEnvironment, NativeDoubleIntervalIterationEnvironment, NativeDoubleJacobiEnvironment, NativeDoubleGaussSeidelEnvironment, From 8b00f8441edc11335d3902364a2444ee894fe373 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 13 Mar 2018 14:10:30 +0100 Subject: [PATCH 165/647] Improved caching for svi --- .../IterativeMinMaxLinearEquationSolver.cpp | 24 ++++++++++--------- .../IterativeMinMaxLinearEquationSolver.h | 2 ++ .../solver/NativeLinearEquationSolver.cpp | 21 +++++++++------- src/storm/solver/NativeLinearEquationSolver.h | 2 ++ .../helper/SoundValueIterationHelper.cpp | 1 - 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index 4bb4cc766..cbb1f30b9 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -10,7 +10,6 @@ #include "storm/utility/KwekMehlhorn.h" #include "storm/utility/NumberTraits.h" -#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" @@ -608,21 +607,23 @@ namespace storm { template bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - // Prepare the solution vectors. + // Prepare the solution vectors and the helper. assert(x.size() == this->A->getRowGroupCount()); if (!this->auxiliaryRowGroupVector) { this->auxiliaryRowGroupVector = std::make_unique>(); } - - // TODO: implement caching for the helper - storm::solver::helper::SoundValueIterationHelper helper(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); - + if (!this->soundValueIterationHelper) { + this->soundValueIterationHelper = std::make_unique>(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + } else { + this->soundValueIterationHelper = std::make_unique>(std::move(*this->soundValueIterationHelper), x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + } + // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { - helper.setLowerBound(this->getLowerBound(true)); + this->soundValueIterationHelper->setLowerBound(this->getLowerBound(true)); } if (this->hasUpperBound()) { - helper.setUpperBound(this->getUpperBound(true)); + this->soundValueIterationHelper->setUpperBound(this->getUpperBound(true)); } storm::storage::BitVector const* relevantValuesPtr = nullptr; @@ -635,8 +636,8 @@ namespace storm { uint64_t iterations = 0; while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { - helper.performIterationStep(dir, b); - if (helper.checkConvergenceUpdateBounds(dir, relevantValuesPtr)) { + this->soundValueIterationHelper->performIterationStep(dir, b); + if (this->soundValueIterationHelper->checkConvergenceUpdateBounds(dir, relevantValuesPtr)) { status = SolverStatus::Converged; } @@ -648,7 +649,7 @@ namespace storm { // Potentially show progress. this->showProgressIterative(iterations); } - helper.setSolutionVector(); + this->soundValueIterationHelper->setSolutionVector(); // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { @@ -1000,6 +1001,7 @@ namespace storm { multiplierA.reset(); auxiliaryRowGroupVector.reset(); auxiliaryRowGroupVector2.reset(); + soundValueIterationHelper.reset(); StandardMinMaxLinearEquationSolver::clearCache(); } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index 1a5501089..33da6e68e 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -7,6 +7,7 @@ #include "storm/solver/LinearEquationSolver.h" #include "storm/solver/Multiplier.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/solver/SolverStatus.h" @@ -80,6 +81,7 @@ namespace storm { mutable std::unique_ptr> multiplierA; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries mutable std::unique_ptr> auxiliaryRowGroupVector2; // A.rowGroupCount() entries + mutable std::unique_ptr> soundValueIterationHelper; SolverStatus updateStatusIfNotConverged(SolverStatus status, std::vector const& x, uint64_t iterations, uint64_t maximalNumberOfIterations, SolverGuarantee const& guarantee) const; static void reportStatus(SolverStatus status, uint64_t iterations); diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index e7d1cf5e5..9cd6b14d2 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -568,21 +568,23 @@ namespace storm { template bool NativeLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, std::vector& x, std::vector const& b) const { - // Prepare the solution vectors. + // Prepare the solution vectors and the helper. assert(x.size() == this->A->getRowCount()); if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(); } - - // TODO: implement caching for the helper - storm::solver::helper::SoundValueIterationHelper helper(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + if (!this->soundValueIterationHelper) { + this->soundValueIterationHelper = std::make_unique>(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + } else { + this->soundValueIterationHelper = std::make_unique>(std::move(*this->soundValueIterationHelper), x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + } // Prepare initial bounds for the solution (if given) if (this->hasLowerBound()) { - helper.setLowerBound(this->getLowerBound(true)); + this->soundValueIterationHelper->setLowerBound(this->getLowerBound(true)); } if (this->hasUpperBound()) { - helper.setUpperBound(this->getUpperBound(true)); + this->soundValueIterationHelper->setUpperBound(this->getUpperBound(true)); } storm::storage::BitVector const* relevantValuesPtr = nullptr; @@ -596,8 +598,8 @@ namespace storm { uint64_t iterations = 0; while (!converged && iterations < env.solver().native().getMaximalNumberOfIterations()) { - helper.performIterationStep(b); - if (helper.checkConvergenceUpdateBounds(relevantValuesPtr)) { + this->soundValueIterationHelper->performIterationStep(b); + if (this->soundValueIterationHelper->checkConvergenceUpdateBounds(relevantValuesPtr)) { converged = true; } @@ -610,7 +612,7 @@ namespace storm { // Potentially show progress. this->showProgressIterative(iterations); } - helper.setSolutionVector(); + this->soundValueIterationHelper->setSolutionVector(); this->logIterations(converged, terminate, iterations); @@ -973,6 +975,7 @@ namespace storm { cachedRowVector2.reset(); walkerChaeData.reset(); multiplier.reset(); + soundValueIterationHelper.reset(); LinearEquationSolver::clearCache(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 6622de17f..0cc493535 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -8,6 +8,7 @@ #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/NativeMultiplier.h" #include "storm/solver/SolverStatus.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/utility/NumberTraits.h" @@ -93,6 +94,7 @@ namespace storm { // cached auxiliary data mutable std::unique_ptr> cachedRowVector2; // A.getRowCount() rows + mutable std::unique_ptr> soundValueIterationHelper; struct JacobiDecomposition { JacobiDecomposition(Environment const& env, storm::storage::SparseMatrix const& A); diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index c208cea55..4a831e7c7 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -296,7 +296,6 @@ namespace storm { << "."); } - template bool SoundValueIterationHelper::checkConvergencePhase1() { From 12f8685080e10f2971304915b6470c2eab36ba8c Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 13 Mar 2018 15:55:51 +0100 Subject: [PATCH 166/647] Custom Termination Conditions for sound value iteration --- .../IterativeMinMaxLinearEquationSolver.cpp | 13 ++- .../solver/NativeLinearEquationSolver.cpp | 4 +- src/storm/solver/TerminationCondition.cpp | 96 ++++++++++++++++--- src/storm/solver/TerminationCondition.h | 15 +-- .../helper/SoundValueIterationHelper.cpp | 21 +++- .../solver/helper/SoundValueIterationHelper.h | 8 +- .../SparseDtmcParameterLiftingTest.cpp | 13 +++ .../modelchecker/MdpPrctlModelCheckerTest.cpp | 14 ++- 8 files changed, 151 insertions(+), 33 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index cbb1f30b9..a98bb83f2 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -636,15 +636,18 @@ namespace storm { uint64_t iterations = 0; while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { + ++iterations; this->soundValueIterationHelper->performIterationStep(dir, b); if (this->soundValueIterationHelper->checkConvergenceUpdateBounds(dir, relevantValuesPtr)) { status = SolverStatus::Converged; + } else { + // Update the status accordingly + if (this->hasCustomTerminationCondition() && this->soundValueIterationHelper->checkCustomTerminationCondition(this->getTerminationCondition())) { + status = SolverStatus::TerminatedEarly; + } else if (iterations >= env.solver().minMax().getMaximalNumberOfIterations()) { + status = SolverStatus::MaximalIterationsExceeded; + } } - - // Update environment variables. - ++iterations; - // TODO: Implement custom termination criterion. We would need to add our errors to the stepBoundedX values (only if in second phase) - status = updateStatusIfNotConverged(status, x, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None); // Potentially show progress. this->showProgressIterative(iterations); diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 9cd6b14d2..04c3d3c76 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -603,8 +603,8 @@ namespace storm { converged = true; } - // todo: custom termination check - // terminate = .... + // Check whether we terminate early. + terminate = this->hasCustomTerminationCondition() && this->soundValueIterationHelper->checkCustomTerminationCondition(this->getTerminationCondition()); // Update environment variables. ++iterations; diff --git a/src/storm/solver/TerminationCondition.cpp b/src/storm/solver/TerminationCondition.cpp index 745cc8a51..dcd88392b 100644 --- a/src/storm/solver/TerminationCondition.cpp +++ b/src/storm/solver/TerminationCondition.cpp @@ -4,12 +4,18 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace solver { template - bool NoTerminationCondition::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminationCondition::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + return terminateNow([¤tValues] (uint64_t const& i) {return currentValues[i];}, guarantee); + } + + template + bool NoTerminationCondition::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { return false; } @@ -24,14 +30,17 @@ namespace storm { } template - bool TerminateIfFilteredSumExceedsThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredSumExceedsThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::LessOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == filter.size(), "Vectors sizes mismatch."); - ValueType currentThreshold = storm::utility::vector::sum_if(currentValues, filter); - return strict ? currentThreshold > this->threshold : currentThreshold >= this->threshold; + ValueType sum = storm::utility::zero(); + for (auto pos : filter) { + sum += valueGetter(pos); + // Exiting this loop early is not possible as values might be negative + } + return strict ? sum > this->threshold : sum >= this->threshold; } template @@ -42,17 +51,47 @@ namespace storm { template TerminateIfFilteredExtremumExceedsThreshold::TerminateIfFilteredExtremumExceedsThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum) : TerminateIfFilteredSumExceedsThreshold(filter, threshold, strict), useMinimum(useMinimum) { // Intentionally left empty. + STORM_LOG_THROW(!this->filter.empty(), storm::exceptions::InvalidArgumentException, "Empty Filter; Can not take extremum over empty set."); + cachedExtremumIndex = this->filter.getNextSetIndex(0); } template - bool TerminateIfFilteredExtremumExceedsThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredExtremumExceedsThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::LessOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == this->filter.size(), "Vectors sizes mismatch."); - ValueType currentValue = useMinimum ? storm::utility::vector::min_if(currentValues, this->filter) : storm::utility::vector::max_if(currentValues, this->filter); - return this->strict ? currentValue > this->threshold : currentValue >= this->threshold; + ValueType extremum = valueGetter(cachedExtremumIndex); + if (useMinimum && (this->strict ? extremum <= this->threshold : extremum < this->threshold)) { + // The extremum can only become smaller so we can return right now. + return false; + } + + if (useMinimum) { + if (this->strict) { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + if (extremum <= this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + if (extremum < this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + } + } + + return this->strict ? extremum > this->threshold : extremum >= this->threshold; } template @@ -62,18 +101,47 @@ namespace storm { template TerminateIfFilteredExtremumBelowThreshold::TerminateIfFilteredExtremumBelowThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum) : TerminateIfFilteredSumExceedsThreshold(filter, threshold, strict), useMinimum(useMinimum) { - // Intentionally left empty. + STORM_LOG_THROW(!this->filter.empty(), storm::exceptions::InvalidArgumentException, "Empty Filter; Can not take extremum over empty set."); + cachedExtremumIndex = this->filter.getNextSetIndex(0); } template - bool TerminateIfFilteredExtremumBelowThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredExtremumBelowThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::GreaterOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == this->filter.size(), "Vectors sizes mismatch."); - ValueType currentValue = useMinimum ? storm::utility::vector::min_if(currentValues, this->filter) : storm::utility::vector::max_if(currentValues, this->filter); - return this->strict ? currentValue < this->threshold : currentValue <= this->threshold; + ValueType extremum = valueGetter(cachedExtremumIndex); + if (!useMinimum && (this->strict ? extremum >= this->threshold : extremum > this->threshold)) { + // The extremum can only become larger so we can return right now. + return false; + } + + if (useMinimum) { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + } + } else { + if (this->strict) { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + if (extremum >= this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + if (extremum > this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } + } + + return this->strict ? extremum < this->threshold : extremum <= this->threshold; } template diff --git a/src/storm/solver/TerminationCondition.h b/src/storm/solver/TerminationCondition.h index a8e21697e..98402d1af 100644 --- a/src/storm/solver/TerminationCondition.h +++ b/src/storm/solver/TerminationCondition.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "storm/solver/SolverGuarantee.h" #include "storm/storage/BitVector.h" @@ -15,7 +15,8 @@ namespace storm { /*! * Retrieves whether the guarantee provided by the solver for the current result is sufficient to terminate. */ - virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const = 0; + virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const; + virtual bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const = 0; /*! * Retrieves whether the termination criterion requires the given guarantee in order to decide termination. @@ -27,7 +28,7 @@ namespace storm { template class NoTerminationCondition : public TerminationCondition { public: - virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + virtual bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; }; @@ -36,7 +37,7 @@ namespace storm { public: TerminateIfFilteredSumExceedsThreshold(storm::storage::BitVector const& filter, ValueType const& threshold, bool strict); - bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: @@ -50,11 +51,12 @@ namespace storm { public: TerminateIfFilteredExtremumExceedsThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum); - bool terminateNow(std::vector const& currentValue, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: bool useMinimum; + mutable uint64_t cachedExtremumIndex; }; template @@ -62,11 +64,12 @@ namespace storm { public: TerminateIfFilteredExtremumBelowThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum); - bool terminateNow(std::vector const& currentValue, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: bool useMinimum; + mutable uint64_t cachedExtremumIndex; }; } } diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index 4a831e7c7..68bd1f03a 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -294,9 +294,28 @@ namespace storm { << ". Decision value is " << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") << "."); - } + template + bool SoundValueIterationHelper::checkCustomTerminationCondition(storm::solver::TerminationCondition const& condition) { + if (condition.requiresGuarantee(storm::solver::SolverGuarantee::GreaterOrEqual)) { + if (hasUpperBound && condition.terminateNow( + [&](uint64_t const& i) { + return x[i] + y[i] * upperBound; + }, storm::solver::SolverGuarantee::GreaterOrEqual)) { + return true; + } + } else if (condition.requiresGuarantee(storm::solver::SolverGuarantee::LessOrEqual)) { + if (hasLowerBound && condition.terminateNow( + [&](uint64_t const& i) { + return x[i] + y[i] * lowerBound; + }, storm::solver::SolverGuarantee::LessOrEqual)) { + return true; + } + } + return false; + } + template bool SoundValueIterationHelper::checkConvergencePhase1() { // Return true if y ('the probability to stay within the matrix') is < 1 at every entry diff --git a/src/storm/solver/helper/SoundValueIterationHelper.h b/src/storm/solver/helper/SoundValueIterationHelper.h index d9f7bc476..54cdc1fb1 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.h +++ b/src/storm/solver/helper/SoundValueIterationHelper.h @@ -3,6 +3,7 @@ #include #include "storm/solver/OptimizationDirection.h" +#include "storm/solver/TerminationCondition.h" namespace storm { @@ -61,6 +62,11 @@ namespace storm { */ bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr); + /*! + * Checks whether the provided termination condition triggers termination + */ + bool checkCustomTerminationCondition(storm::solver::TerminationCondition const& condition); + private: enum class InternalOptimizationDirection { @@ -92,7 +98,6 @@ namespace storm { template void checkIfDecisionValueBlocks(); - // Auxiliary helper functions to avoid case distinctions due to different optimization directions template inline bool better(ValueType const& val1, ValueType const& val2) { @@ -119,7 +124,6 @@ namespace storm { return (dir == InternalOptimizationDirection::Maximize) ? minIndex : maxIndex; } - std::vector& x; std::vector& y; std::vector xTmp, yTmp; diff --git a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp index b00b44c0d..dd6d59cf8 100644 --- a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp +++ b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp @@ -21,6 +21,18 @@ namespace { return env; } }; + + class DoubleSVIEnvironment { + public: + typedef double ValueType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::SoundValueIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); + return env; + } + }; + class RationalPiEnvironment { public: typedef storm::RationalNumber ValueType; @@ -44,6 +56,7 @@ namespace { typedef ::testing::Types< DoubleViEnvironment, + DoubleSVIEnvironment, RationalPiEnvironment > TestingTypes; diff --git a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp index 0538fa081..e0741fa30 100644 --- a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp @@ -438,6 +438,8 @@ namespace { TYPED_TEST(MdpPrctlModelCheckerTest, consensus) { std::string formulasString = "Pmax=? [F \"finished\"]"; formulasString += "; Pmax=? [F \"all_coins_equal_1\"]"; + formulasString += "; P<0.8 [F \"all_coins_equal_1\"]"; + formulasString += "; P<0.9 [F \"all_coins_equal_1\"]"; formulasString += "; Rmax=? [F \"all_coins_equal_1\"]"; formulasString += "; Rmin=? [F \"all_coins_equal_1\"]"; formulasString += "; Rmax=? [F \"finished\"]"; @@ -459,15 +461,21 @@ namespace { EXPECT_NEAR(this->parseNumber("57/64"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[2]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + EXPECT_FALSE(this->getQualitativeResultAtInitialState(model, result)); result = checker->check(this->env(), tasks[3]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + EXPECT_TRUE(this->getQualitativeResultAtInitialState(model, result)); result = checker->check(this->env(), tasks[4]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[5]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[6]); EXPECT_NEAR(this->parseNumber("75"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - result = checker->check(this->env(), tasks[5]); + result = checker->check(this->env(), tasks[7]); EXPECT_NEAR(this->parseNumber("48"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); } From ded1040d04f0e0fd97d66c0fca0ba7430afc9db4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 13 Mar 2018 17:08:37 +0100 Subject: [PATCH 167/647] added missing template instantiations --- src/storm/solver/TerminationCondition.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/solver/TerminationCondition.cpp b/src/storm/solver/TerminationCondition.cpp index dcd88392b..db3f12efd 100644 --- a/src/storm/solver/TerminationCondition.cpp +++ b/src/storm/solver/TerminationCondition.cpp @@ -149,10 +149,14 @@ namespace storm { return guarantee == SolverGuarantee::GreaterOrEqual; } + template class TerminationCondition; + template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; #ifdef STORM_HAVE_CARL + template class TerminationCondition; + template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; From 5f7cd177890b1f58b964a94c90866bf5ab560aa8 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 13 Mar 2018 19:42:56 +0100 Subject: [PATCH 168/647] added printing info when value type is converted after preprocessing --- src/storm-cli-utilities/model-handling.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index b1d667d64..3667d0af2 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -679,10 +679,11 @@ namespace storm { verifyWithExplorationEngine(input); } else { std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); - + if (model) { if (!std::is_same::value) { if (model->isSymbolicModel()) { + STORM_LOG_INFO("Converting symbolic model value type to fit the verification value type."); auto symbolicModel = model->as>(); model = symbolicModel->template toValueType(); } From 09866e4577e2108077a928d2c0735877d51b04d4 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 13 Mar 2018 21:44:49 +0100 Subject: [PATCH 169/647] enabling changing value type in quotient extraction of dd-bisimulation --- src/storm-cli-utilities/model-handling.h | 50 ++++---- src/storm/api/bisimulation.h | 10 +- ...ulationAbstractionRefinementModelChecker.h | 4 +- src/storm/models/symbolic/Model.cpp | 36 +++++- src/storm/models/symbolic/Model.h | 5 +- .../symbolic/StochasticTwoPlayerGame.cpp | 19 +++ .../models/symbolic/StochasticTwoPlayerGame.h | 3 + .../storage/dd/BisimulationDecomposition.cpp | 51 ++++---- .../storage/dd/BisimulationDecomposition.h | 8 +- .../bisimulation/PartialQuotientExtractor.cpp | 22 ++-- .../bisimulation/PartialQuotientExtractor.h | 6 +- .../dd/bisimulation/QuotientExtractor.cpp | 119 +++++++++--------- .../dd/bisimulation/QuotientExtractor.h | 12 +- 13 files changed, 204 insertions(+), 141 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 3667d0af2..c279dc742 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -322,43 +322,47 @@ namespace storm { } } - template - std::shared_ptr> preprocessDdModelBisimulation(std::shared_ptr> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { + template + std::shared_ptr> preprocessDdModelBisimulation(std::shared_ptr> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(), "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation."); STORM_LOG_INFO("Performing bisimulation minimization..."); - return storm::api::performBisimulationMinimization(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode()); + return storm::api::performBisimulationMinimization(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode()); } - template + template std::pair, bool> preprocessDdModel(std::shared_ptr> const& model, SymbolicInput const& input) { auto bisimulationSettings = storm::settings::getModule(); auto generalSettings = storm::settings::getModule(); - std::pair>, bool> result = std::make_pair(model, false); + std::pair>, bool> intermediateResult = std::make_pair(model, false); if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) { - result.first = preprocessDdMarkovAutomaton(result.first->template as>()); - result.second = true; + intermediateResult.first = preprocessDdMarkovAutomaton(intermediateResult.first->template as>()); + intermediateResult.second = true; } + std::unique_ptr>, bool>> result; + auto symbolicModel = intermediateResult.first->template as>(); if (generalSettings.isBisimulationSet()) { - result.first = preprocessDdModelBisimulation(model, input, bisimulationSettings); - result.second = true; + std::shared_ptr> newModel = preprocessDdModelBisimulation(symbolicModel, input, bisimulationSettings); + result = std::make_unique>, bool>>(newModel, true); + } else { + result = std::make_unique>, bool>>(symbolicModel->template toValueType(), !std::is_same::value); } - return result; + return *result; } - template + template std::pair, bool> preprocessModel(std::shared_ptr const& model, SymbolicInput const& input) { storm::utility::Stopwatch preprocessingWatch(true); std::pair, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { - result = preprocessSparseModel(result.first->as>(), input); + result = preprocessSparseModel(result.first->as>(), input); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - result = preprocessDdModel(result.first->as>(), input); + result = preprocessDdModel(result.first->as>(), input); } preprocessingWatch.stop(); @@ -639,13 +643,13 @@ namespace storm { } } - template + template std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { auto ioSettings = storm::settings::getModule(); auto buildSettings = storm::settings::getModule(); std::shared_ptr model; if (!buildSettings.isNoBuildModelSet()) { - model = buildModel(engine, input, ioSettings); + model = buildModel(engine, input, ioSettings); } if (model) { @@ -655,12 +659,12 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); if (model) { - auto preprocessingResult = preprocessModel(model, input); + auto preprocessingResult = preprocessModel(model, input); if (preprocessingResult.second) { model = preprocessingResult.first; model->printModelInformationToStream(std::cout); } - exportModel(model, input); + exportModel(model, input); } return model; } @@ -678,17 +682,9 @@ namespace storm { } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { verifyWithExplorationEngine(input); } else { - std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); + std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); if (model) { - if (!std::is_same::value) { - if (model->isSymbolicModel()) { - STORM_LOG_INFO("Converting symbolic model value type to fit the verification value type."); - auto symbolicModel = model->as>(); - model = symbolicModel->template toValueType(); - } - } - if (coreSettings.isCounterexampleSet()) { auto ioSettings = storm::settings::getModule(); generateCounterexamples(model, input); @@ -713,7 +709,7 @@ namespace storm { STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); processInputWithValueTypeAndDdlib(input); } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD) { - processInputWithValueTypeAndDdlib(input); + processInputWithValueTypeAndDdlib(input); } else { STORM_LOG_ASSERT(coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "Unknown DD library."); processInputWithValueTypeAndDdlib(input); diff --git a/src/storm/api/bisimulation.h b/src/storm/api/bisimulation.h index 9ad43f9bd..dc7181e87 100644 --- a/src/storm/api/bisimulation.h +++ b/src/storm/api/bisimulation.h @@ -55,8 +55,8 @@ namespace storm { } } - template - typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + template + typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp) || model->isOfType(storm::models::ModelType::MarkovAutomaton), storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is currently only available for DTMCs, CTMCs, MDPs and MAs."); STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported."); @@ -64,13 +64,13 @@ namespace storm { // Try to get rid of non state-rewards to easy bisimulation computation. model->reduceToStateBasedRewards(); - storm::dd::BisimulationDecomposition decomposition(*model, formulas, bisimulationType); + storm::dd::BisimulationDecomposition decomposition(*model, formulas, bisimulationType); decomposition.compute(mode); return decomposition.getQuotient(); } - template - typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + template + typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is not supported for this combination of DD library and value type."); return nullptr; } diff --git a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h index 9af7c3a8b..4fe5af95f 100644 --- a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h +++ b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h @@ -11,7 +11,7 @@ namespace storm { } namespace dd { - template + template class BisimulationDecomposition; } @@ -47,7 +47,7 @@ namespace storm { ModelType const& model; /// The bisimulation object that maintains and refines the model. - std::unique_ptr> bisimulation; + std::unique_ptr> bisimulation; /// Maintains the last abstract model that was returned. std::shared_ptr> lastAbstractModel; diff --git a/src/storm/models/symbolic/Model.cpp b/src/storm/models/symbolic/Model.cpp index 71897fded..ee90118cb 100644 --- a/src/storm/models/symbolic/Model.cpp +++ b/src/storm/models/symbolic/Model.cpp @@ -6,6 +6,7 @@ #include "storm/models/symbolic/Ctmc.h" #include "storm/models/symbolic/Mdp.h" #include "storm/models/symbolic/MarkovAutomaton.h" +#include "storm/models/symbolic/StochasticTwoPlayerGame.h" #include "storm/exceptions/IllegalArgumentException.h" #include "storm/exceptions/InvalidOperationException.h" @@ -384,7 +385,9 @@ namespace storm { template template - std::shared_ptr> Model::toValueType() const { + typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const { + STORM_LOG_TRACE("Converting value type of symbolic model from " << typeid(ValueType).name() << " to " << typeid(NewValueType).name() << "."); + // Make a huge branching here as we cannot make a templated function virtual. if (this->getType() == storm::models::ModelType::Dtmc) { return this->template as>()->template toValueType(); @@ -394,6 +397,28 @@ namespace storm { return this->template as>()->template toValueType(); } else if (this->getType() == storm::models::ModelType::MarkovAutomaton) { return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::S2pg) { + return this->template as>()->template toValueType(); + } + + STORM_LOG_WARN("Could not convert value type of model."); + return nullptr; + } + + template + template + typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const { + // Make a huge branching here as we cannot make a templated function virtual. + if (this->getType() == storm::models::ModelType::Dtmc) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::Ctmc) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::Mdp) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::MarkovAutomaton) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::S2pg) { + return std::make_shared>(*this->template as>()); } STORM_LOG_WARN("Could not convert value type of model."); @@ -403,9 +428,14 @@ namespace storm { // Explicitly instantiate the template class. template class Model; template class Model; - + + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template class Model; - template std::shared_ptr> Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; template class Model; } // namespace symbolic } // namespace models diff --git a/src/storm/models/symbolic/Model.h b/src/storm/models/symbolic/Model.h index e194dfabc..1dca3dc6d 100644 --- a/src/storm/models/symbolic/Model.h +++ b/src/storm/models/symbolic/Model.h @@ -328,8 +328,11 @@ namespace storm { std::set const& getParameters() const; template - std::shared_ptr> toValueType() const; + typename std::enable_if::value, std::shared_ptr>>::type toValueType() const; + template + typename std::enable_if::value, std::shared_ptr>>::type toValueType() const; + protected: /*! * Sets the transition matrix of the model. diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp index b4b59e934..677d80912 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp @@ -82,11 +82,30 @@ namespace storm { return player2Variables; } + template + template + std::shared_ptr> StochasticTwoPlayerGame::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getPlayer1Variables(), this->getPlayer2Variables(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + + } + // Explicitly instantiate the template class. template class StochasticTwoPlayerGame; template class StochasticTwoPlayerGame; #ifdef STORM_HAVE_CARL template class StochasticTwoPlayerGame; + template std::shared_ptr> StochasticTwoPlayerGame::toValueType() const; template class StochasticTwoPlayerGame; #endif diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.h b/src/storm/models/symbolic/StochasticTwoPlayerGame.h index d3f009593..569d258dd 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.h +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.h @@ -117,6 +117,9 @@ namespace storm { */ storm::dd::Bdd getIllegalPlayer2Mask() const; + template + std::shared_ptr> toValueType() const; + private: /*! * Prepare all illegal masks. diff --git a/src/storm/storage/dd/BisimulationDecomposition.cpp b/src/storm/storage/dd/BisimulationDecomposition.cpp index 682f5602d..d43dd9c65 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.cpp +++ b/src/storm/storage/dd/BisimulationDecomposition.cpp @@ -31,31 +31,31 @@ namespace storm { } } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, formulas), refiner(createRefiner(model, Partition::create(model, bisimulationType, formulas))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, formulas), refiner(createRefiner(model, Partition::create(model, bisimulationType, formulas))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, Partition const& initialPartition, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, initialPartition)) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, Partition const& initialPartition, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, initialPartition)) { this->initialize(); } - template - BisimulationDecomposition::~BisimulationDecomposition() = default; + template + BisimulationDecomposition::~BisimulationDecomposition() = default; - template - void BisimulationDecomposition::initialize() { + template + void BisimulationDecomposition::initialize() { auto const& generalSettings = storm::settings::getModule(); verboseProgress = generalSettings.isVerboseSet(); showProgressDelay = generalSettings.getShowProgressDelay(); @@ -69,8 +69,8 @@ namespace storm { STORM_LOG_TRACE("Initial partition has " << refiner->getStatePartition().getNodeCount() << " nodes."); } - template - void BisimulationDecomposition::compute(bisimulation::SignatureMode const& mode) { + template + void BisimulationDecomposition::compute(bisimulation::SignatureMode const& mode) { STORM_LOG_ASSERT(refiner, "No suitable refiner."); STORM_LOG_ASSERT(this->refiner->getStatus() != Status::FixedPoint, "Can only proceed if no fixpoint has been reached yet."); @@ -96,8 +96,8 @@ namespace storm { STORM_LOG_INFO("Partition refinement completed in " << std::chrono::duration_cast(end - start).count() << "ms (" << iterations << " iterations, signature: " << std::chrono::duration_cast(refiner->getTotalSignatureTime()).count() << "ms, refinement: " << std::chrono::duration_cast(refiner->getTotalRefinementTime()).count() << "ms)."); } - template - bool BisimulationDecomposition::compute(uint64_t steps, bisimulation::SignatureMode const& mode) { + template + bool BisimulationDecomposition::compute(uint64_t steps, bisimulation::SignatureMode const& mode) { STORM_LOG_ASSERT(refiner, "No suitable refiner."); STORM_LOG_ASSERT(this->refiner->getStatus() != Status::FixedPoint, "Can only proceed if no fixpoint has been reached yet."); STORM_LOG_ASSERT(steps > 0, "Can only perform positive number of steps."); @@ -123,24 +123,24 @@ namespace storm { return !refined; } - template - bool BisimulationDecomposition::getReachedFixedPoint() const { + template + bool BisimulationDecomposition::getReachedFixedPoint() const { return this->refiner->getStatus() == Status::FixedPoint; } - template - std::shared_ptr> BisimulationDecomposition::getQuotient() const { - std::shared_ptr> quotient; + template + std::shared_ptr> BisimulationDecomposition::getQuotient() const { + std::shared_ptr> quotient; if (this->refiner->getStatus() == Status::FixedPoint) { STORM_LOG_INFO("Starting full quotient extraction."); - QuotientExtractor extractor; + QuotientExtractor extractor; quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation); } else { STORM_LOG_THROW(model.getType() == storm::models::ModelType::Dtmc || model.getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidOperationException, "Can only extract partial quotient for discrete-time models."); STORM_LOG_INFO("Starting partial quotient extraction."); if (!partialQuotientExtractor) { - partialQuotientExtractor = std::make_unique>(model); + partialQuotientExtractor = std::make_unique>(model); } quotient = partialQuotientExtractor->extract(refiner->getStatePartition(), preservationInformation); @@ -150,8 +150,8 @@ namespace storm { return quotient; } - template - void BisimulationDecomposition::refineWrtRewardModels() { + template + void BisimulationDecomposition::refineWrtRewardModels() { for (auto const& rewardModelName : this->preservationInformation.getRewardModelNames()) { auto const& rewardModel = this->model.getRewardModel(rewardModelName); refiner->refineWrtRewardModel(rewardModel); @@ -162,6 +162,7 @@ namespace storm { template class BisimulationDecomposition; template class BisimulationDecomposition; + template class BisimulationDecomposition; template class BisimulationDecomposition; } diff --git a/src/storm/storage/dd/BisimulationDecomposition.h b/src/storm/storage/dd/BisimulationDecomposition.h index b5a088ca2..1a552c497 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.h +++ b/src/storm/storage/dd/BisimulationDecomposition.h @@ -29,11 +29,11 @@ namespace storm { template class PartitionRefiner; - template + template class PartialQuotientExtractor; } - template + template class BisimulationDecomposition { public: BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType); @@ -64,7 +64,7 @@ namespace storm { /*! * Retrieves the quotient model after the bisimulation decomposition was computed. */ - std::shared_ptr> getQuotient() const; + std::shared_ptr> getQuotient() const; private: void initialize(); @@ -80,7 +80,7 @@ namespace storm { std::unique_ptr> refiner; // A quotient extractor that is used when the fixpoint has not been reached yet. - mutable std::unique_ptr> partialQuotientExtractor; + mutable std::unique_ptr> partialQuotientExtractor; // A flag indicating whether progress is reported. bool verboseProgress; diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp index 9e5e34b54..fea92c755 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp @@ -15,18 +15,18 @@ namespace storm { namespace dd { namespace bisimulation { - template - PartialQuotientExtractor::PartialQuotientExtractor(storm::models::symbolic::Model const& model) : model(model) { + template + PartialQuotientExtractor::PartialQuotientExtractor(storm::models::symbolic::Model const& model) : model(model) { auto const& settings = storm::settings::getModule(); this->quotientFormat = settings.getQuotientFormat(); STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); } - template - std::shared_ptr> PartialQuotientExtractor::extract(Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> PartialQuotientExtractor::extract(Partition const& partition, PreservationInformation const& preservationInformation) { auto start = std::chrono::high_resolution_clock::now(); - std::shared_ptr> result; + std::shared_ptr> result; STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); result = extractDdQuotient(partition, preservationInformation); @@ -38,8 +38,8 @@ namespace storm { return result; } - template - std::shared_ptr> PartialQuotientExtractor::extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> PartialQuotientExtractor::extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Mdp) { @@ -122,16 +122,19 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), preservedLabelBdds, quotientRewardModels); + result = std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), preservedLabelBdds, quotientRewardModels); } else if (modelType == storm::models::ModelType::Mdp) { std::set allNondeterminismVariables; std::set_union(model.getRowVariables().begin(), model.getRowVariables().end(), model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end(), std::inserter(allNondeterminismVariables, allNondeterminismVariables.begin())); - return std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), model.getNondeterminismVariables(), allNondeterminismVariables, preservedLabelBdds, quotientRewardModels); + result = std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), model.getNondeterminismVariables(), allNondeterminismVariables, preservedLabelBdds, quotientRewardModels); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported quotient type."); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract partial quotient for this model type."); } @@ -142,6 +145,7 @@ namespace storm { #ifdef STORM_HAVE_CARL template class PartialQuotientExtractor; + template class PartialQuotientExtractor; template class PartialQuotientExtractor; #endif diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h index 26ae033e6..d5c638c2a 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h @@ -16,15 +16,15 @@ namespace storm { namespace dd { namespace bisimulation { - template + template class PartialQuotientExtractor { public: PartialQuotientExtractor(storm::models::symbolic::Model const& model); - std::shared_ptr> extract(Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extract(Partition const& partition, PreservationInformation const& preservationInformation); private: - std::shared_ptr> extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation); // The model for which to compute the partial quotient. storm::models::symbolic::Model const& model; diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index 108164a2a..25075a0e9 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -222,10 +222,10 @@ namespace storm { spp::sparse_hash_map visitedNodes; }; - template + template class InternalSparseQuotientExtractor; - template + template class InternalSparseQuotientExtractorBase { public: InternalSparseQuotientExtractorBase(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : model(model), manager(model.getManager()), isNondeterministic(false), partitionBdd(partitionBdd), numberOfBlocks(numberOfBlocks), blockVariable(blockVariable), representatives(representatives), matrixEntriesCreated(false) { @@ -259,23 +259,23 @@ namespace storm { virtual ~InternalSparseQuotientExtractorBase() = default; - storm::storage::SparseMatrix extractTransitionMatrix(storm::dd::Add const& transitionMatrix) { + storm::storage::SparseMatrix extractTransitionMatrix(storm::dd::Add const& transitionMatrix) { return extractMatrixInternal(transitionMatrix); } - std::vector extractStateVector(storm::dd::Add const& vector) { + std::vector extractStateVector(storm::dd::Add const& vector) { return extractVectorInternal(vector, this->rowVariablesCube, this->odd); } - std::vector extractStateActionVector(storm::dd::Add const& vector) { + std::vector extractStateActionVector(storm::dd::Add const& vector) { if (!this->isNondeterministic) { return extractStateVector(vector); } else { STORM_LOG_ASSERT(!this->rowPermutation.empty(), "Expected proper row permutation."); - std::vector valueVector = extractVectorInternal(vector, this->allSourceVariablesCube, this->nondeterminismOdd); + std::vector valueVector = extractVectorInternal(vector, this->allSourceVariablesCube, this->nondeterminismOdd); // Reorder the values according to the known row permutation. - std::vector reorderedValues(valueVector.size()); + std::vector reorderedValues(valueVector.size()); for (uint64_t pos = 0; pos < valueVector.size(); ++pos) { reorderedValues[pos] = valueVector[rowPermutation[pos]]; } @@ -292,14 +292,14 @@ namespace storm { } protected: - virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) = 0; + virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) = 0; - virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) = 0; + virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) = 0; - storm::storage::SparseMatrix createMatrixFromEntries() { + storm::storage::SparseMatrix createMatrixFromEntries() { for (auto& row : matrixEntries) { std::sort(row.begin(), row.end(), - [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { + [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { return a.getColumn() < b.getColumn(); }); } @@ -312,7 +312,7 @@ namespace storm { uint64_t rowCounter = 0; uint64_t lastState = this->isNondeterministic ? rowToState[rowPermutation.front()] : 0; - storm::storage::SparseMatrixBuilder builder(matrixEntries.size(), this->numberOfBlocks, 0, true, this->isNondeterministic); + storm::storage::SparseMatrixBuilder builder(matrixEntries.size(), this->numberOfBlocks, 0, true, this->isNondeterministic); if (this->isNondeterministic) { builder.newRowGroup(0); } @@ -343,7 +343,7 @@ namespace storm { return builder.build(); } - void addMatrixEntry(uint64_t row, uint64_t column, ValueType const& value) { + void addMatrixEntry(uint64_t row, uint64_t column, ExportValueType const& value) { this->matrixEntries[row].emplace_back(column, value); } @@ -390,7 +390,7 @@ namespace storm { bool matrixEntriesCreated; // The entries of the quotient matrix that is built. - std::vector>> matrixEntries; + std::vector>> matrixEntries; // A vector storing for each row which state it belongs to. std::vector rowToState; @@ -621,33 +621,33 @@ namespace storm { spp::sparse_hash_map blockToOffset; }; - template - class InternalSparseQuotientExtractor : public InternalSparseQuotientExtractorBase { + template + class InternalSparseQuotientExtractor : public InternalSparseQuotientExtractorBase { public: - InternalSparseQuotientExtractor(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : InternalSparseQuotientExtractorBase(model, partitionBdd, blockVariable, numberOfBlocks, representatives) { + InternalSparseQuotientExtractor(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : InternalSparseQuotientExtractorBase(model, partitionBdd, blockVariable, numberOfBlocks, representatives) { this->createBlockToOffsetMapping(); } private: - virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) override { + virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) override { this->createMatrixEntryStorage(); extractTransitionMatrixRec(matrix.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->isNondeterministic ? this->nondeterminismOdd : this->odd, 0, this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(), this->allSourceVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->nondeterminismVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->isNondeterministic ? &this->odd : nullptr, 0); return this->createMatrixFromEntries(); } - virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) override { - std::vector result(odd.getTotalOffset()); + virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) override { + std::vector result(odd.getTotalOffset()); extractVectorRec(vector.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(), variablesCube.getInternalBdd().getSylvanBdd().GetBDD(), odd, 0, result); return result; } - void extractVectorRec(MTBDD vector, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset, std::vector& result) { + void extractVectorRec(MTBDD vector, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset, std::vector& result) { if (representativesNode == sylvan_false || mtbdd_iszero(vector)) { return; } if (sylvan_isconst(variables)) { - result[offset] = storm::dd::InternalAdd::getValue(vector); + result[offset] = storm::utility::convertNumber(storm::dd::InternalAdd::getValue(vector)); } else { MTBDD vectorT; MTBDD vectorE; @@ -723,7 +723,7 @@ namespace storm { // If we have moved through all source variables, we must have arrived at a target block encoding. if (sylvan_isconst(variables)) { STORM_LOG_ASSERT(mtbdd_isleaf(transitionMatrixNode), "Expected constant node."); - this->addMatrixEntry(sourceOffset, blockToOffset.at(targetPartitionNode), storm::dd::InternalAdd::getValue(transitionMatrixNode)); + this->addMatrixEntry(sourceOffset, blockToOffset.at(targetPartitionNode), storm::utility::convertNumber(storm::dd::InternalAdd::getValue(transitionMatrixNode))); if (stateOdd) { this->assignRowToState(sourceOffset, stateOffset); } @@ -817,18 +817,18 @@ namespace storm { spp::sparse_hash_map blockToOffset; }; - template - QuotientExtractor::QuotientExtractor() : useRepresentatives(false) { + template + QuotientExtractor::QuotientExtractor() : useRepresentatives(false) { auto const& settings = storm::settings::getModule(); this->useRepresentatives = settings.isUseRepresentativesSet(); this->useOriginalVariables = settings.isUseOriginalVariablesSet(); this->quotientFormat = settings.getQuotientFormat(); } - template - std::shared_ptr> QuotientExtractor::extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto start = std::chrono::high_resolution_clock::now(); - std::shared_ptr> result; + std::shared_ptr> result; if (quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Sparse) { result = extractSparseQuotient(model, partition, preservationInformation); } else { @@ -842,8 +842,8 @@ namespace storm { return result; } - template - std::shared_ptr> QuotientExtractor::extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto states = partition.getStates().swapVariables(model.getRowColumnMetaVariablePairs()); storm::dd::Bdd partitionAsBdd = partition.storedAsAdd() ? partition.asAdd().toBdd() : partition.asBdd(); @@ -853,8 +853,8 @@ namespace storm { auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); STORM_LOG_ASSERT(representatives.getNonZeroCount() == partition.getNumberOfBlocks(), "Representatives size does not match that of the partition: " << representatives.getNonZeroCount() << " vs. " << partition.getNumberOfBlocks() << "."); STORM_LOG_ASSERT((representatives && partitionAsBdd).existsAbstract(model.getRowVariables()) == partitionAsBdd.existsAbstract(model.getRowVariables()), "Representatives do not cover all blocks."); - InternalSparseQuotientExtractor sparseExtractor(model, partitionAsBdd, partition.getBlockVariable(), partition.getNumberOfBlocks(), representatives); - storm::storage::SparseMatrix quotientTransitionMatrix = sparseExtractor.extractTransitionMatrix(model.getTransitionMatrix()); + InternalSparseQuotientExtractor sparseExtractor(model, partitionAsBdd, partition.getBlockVariable(), partition.getNumberOfBlocks(), representatives); + storm::storage::SparseMatrix quotientTransitionMatrix = sparseExtractor.extractTransitionMatrix(model.getTransitionMatrix()); auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); @@ -881,47 +881,47 @@ namespace storm { STORM_LOG_INFO("Quotient labels extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); start = std::chrono::high_resolution_clock::now(); - std::unordered_map> quotientRewardModels; + std::unordered_map> quotientRewardModels; for (auto const& rewardModelName : preservationInformation.getRewardModelNames()) { auto const& rewardModel = model.getRewardModel(rewardModelName); - boost::optional> quotientStateRewards; + boost::optional> quotientStateRewards; if (rewardModel.hasStateRewards()) { quotientStateRewards = sparseExtractor.extractStateVector(rewardModel.getStateRewardVector()); } - boost::optional> quotientStateActionRewards; + boost::optional> quotientStateActionRewards; if (rewardModel.hasStateActionRewards()) { quotientStateActionRewards = sparseExtractor.extractStateActionVector(rewardModel.getStateActionRewardVector()); } - quotientRewardModels.emplace(rewardModelName, storm::models::sparse::StandardRewardModel(std::move(quotientStateRewards), std::move(quotientStateActionRewards), boost::none)); + quotientRewardModels.emplace(rewardModelName, storm::models::sparse::StandardRewardModel(std::move(quotientStateRewards), std::move(quotientStateActionRewards), boost::none)); } end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); - std::shared_ptr> result; + std::shared_ptr> result; if (model.getType() == storm::models::ModelType::Dtmc) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::Ctmc) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::Mdp) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::MarkovAutomaton) { storm::models::symbolic::MarkovAutomaton const& markovAutomaton = *model.template as>(); boost::optional markovianStates = sparseExtractor.extractSetExists(markovAutomaton.getMarkovianStates()); - storm::storage::sparse::ModelComponents modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels), false, std::move(markovianStates)); + storm::storage::sparse::ModelComponents modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels), false, std::move(markovianStates)); modelComponents.exitRates = sparseExtractor.extractStateVector(markovAutomaton.getExitRateVector()); - result = std::make_shared>(std::move(modelComponents)); + result = std::make_shared>(std::move(modelComponents)); } return result; } - template - std::shared_ptr> QuotientExtractor::extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { if (this->useOriginalVariables) { return extractQuotientUsingOriginalVariables(model, partition, preservationInformation); @@ -930,8 +930,8 @@ namespace storm { } } - template - std::shared_ptr> QuotientExtractor::extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); bool useRepresentativesForThisExtraction = this->useRepresentatives; @@ -1028,22 +1028,25 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Ctmc) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Mdp) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } else { - return std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type."); } } - template - std::shared_ptr> QuotientExtractor::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); bool useRepresentativesForThisExtraction = this->useRepresentatives; @@ -1146,15 +1149,18 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Ctmc) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Mdp) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } else { - return std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type."); } @@ -1164,6 +1170,7 @@ namespace storm { template class QuotientExtractor; template class QuotientExtractor; + template class QuotientExtractor; template class QuotientExtractor; } diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.h b/src/storm/storage/dd/bisimulation/QuotientExtractor.h index b75b27b08..422453bf7 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.h @@ -16,19 +16,19 @@ namespace storm { namespace dd { namespace bisimulation { - template + template class QuotientExtractor { public: QuotientExtractor(); - std::shared_ptr> extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); private: - std::shared_ptr> extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); bool useRepresentatives; bool useOriginalVariables; From 316412c5d316041b9df88723af431b50bc375398 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 14 Mar 2018 10:46:06 +0100 Subject: [PATCH 170/647] fixed a bug related to closing symbolic Markov automata --- src/storm/builder/DdJaniModelBuilder.cpp | 8 ++++---- .../csl/helper/SparseMarkovAutomatonCslHelper.cpp | 2 ++ src/storm/models/symbolic/MarkovAutomaton.cpp | 4 ++-- src/storm/storage/dd/bisimulation/QuotientExtractor.cpp | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index a6620492e..507cde01a 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -1667,7 +1667,7 @@ namespace storm { result += extendedTransitions; } - + return ComposerResult(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, numberOfUsedNondeterminismVariables); } else if (modelType == storm::jani::ModelType::DTMC || modelType == storm::jani::ModelType::CTMC) { // Simply add all actions, but make sure to include the missing global variable identities. @@ -1830,7 +1830,7 @@ namespace storm { // For DTMCs, we can simply add the identity of the global module for all deadlock states. transitionMatrix += deadlockStatesAdd * globalIdentity; } else if (modelType == storm::jani::ModelType::MDP || modelType == storm::jani::ModelType::LTS || modelType == storm::jani::ModelType::MA) { - // For MDPs, however, we need to select an action associated with the self-loop, if we do not + // For nondeterministic models, however, we need to select an action associated with the self-loop, if we do not // want to attach a lot of self-loops to the deadlock states. storm::dd::Add action = encodeAction(boost::none, modelType == storm::jani::ModelType::MA ? boost::make_optional(true) : boost::none, variables); @@ -1967,10 +1967,10 @@ namespace storm { // Create a builder to compose and build the model. CombinedEdgesSystemComposer composer(preparedModel, actionInformation, variables, rewardVariables); ComposerResult system = composer.compose(); - + // Postprocess the variables in place. postprocessVariables(preparedModel.getModelType(), system, variables); - + // Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off). storm::dd::Bdd terminalStates = postprocessSystem(preparedModel, system, variables, options); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 7bf5f10f5..164310b20 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -261,6 +261,7 @@ namespace storm { for (ValueType const& rate : exitRateVector) { lambda = std::max(rate, lambda); } + STORM_LOG_TRACE("Initial lambda is " << lambda << "."); uint64_t N; ValueType maxNorm = storm::utility::zero(); @@ -369,6 +370,7 @@ namespace storm { // (6) Double lambda. lambda *= 2; + STORM_LOG_TRACE("Increased lambda to " << lambda << ", max diff is " << maxNorm << "."); } while (maxNorm > epsilon * (1 - kappa)); diff --git a/src/storm/models/symbolic/MarkovAutomaton.cpp b/src/storm/models/symbolic/MarkovAutomaton.cpp index add866c8b..111890edd 100644 --- a/src/storm/models/symbolic/MarkovAutomaton.cpp +++ b/src/storm/models/symbolic/MarkovAutomaton.cpp @@ -66,7 +66,7 @@ namespace storm { // Compute the vector of exit rates. this->exitRateVector = (this->getTransitionMatrix() * this->markovianMarker.template toAdd()).sumAbstract(columnAndNondeterminsmVariables); - + // Modify the transition matrix so all choices are probabilistic and the Markovian choices additionally // have a rate. this->transitionMatrix = this->transitionMatrix / this->markovianChoices.ite(this->exitRateVector, this->getManager().template getAddOne()); @@ -105,7 +105,7 @@ namespace storm { template MarkovAutomaton MarkovAutomaton::close() { // Create the new transition matrix by deleting all Markovian transitions from probabilistic states. - storm::dd::Add newTransitionMatrix = this->probabilisticStates.ite(this->getTransitionMatrix() * (!this->getMarkovianMarker()).template toAdd(), this->getTransitionMatrix()); + storm::dd::Add newTransitionMatrix = this->probabilisticStates.ite(this->getTransitionMatrix() * (!this->getMarkovianMarker()).template toAdd(), this->getTransitionMatrix() * this->getExitRateVector()); return MarkovAutomaton(this->getManagerAsSharedPointer(), this->getMarkovianMarker(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), newTransitionMatrix, this->getRowVariables(), this->getRowExpressionAdapter(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), this->getLabelToExpressionMap(), this->getRewardModels()); } diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index 25075a0e9..a4c3b014a 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -913,7 +913,7 @@ namespace storm { boost::optional markovianStates = sparseExtractor.extractSetExists(markovAutomaton.getMarkovianStates()); storm::storage::sparse::ModelComponents modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels), false, std::move(markovianStates)); modelComponents.exitRates = sparseExtractor.extractStateVector(markovAutomaton.getExitRateVector()); - + result = std::make_shared>(std::move(modelComponents)); } From 3cd1edb37822f2c1fc1a8006c2b5f59b0d75b545 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 14 Mar 2018 17:34:27 +0100 Subject: [PATCH 171/647] added virtual destructors to multipliers --- src/storm/solver/GmmxxMultiplier.h | 1 + src/storm/solver/Multiplier.h | 2 ++ src/storm/solver/NativeMultiplier.h | 1 + 3 files changed, 4 insertions(+) diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index 87bee797e..fdebd557d 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -19,6 +19,7 @@ namespace storm { class GmmxxMultiplier : public Multiplier { public: GmmxxMultiplier(storm::storage::SparseMatrix const& matrix); + virtual ~GmmxxMultiplier() = default; virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index 77dc831c3..a94934ae0 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -23,6 +23,8 @@ namespace storm { Multiplier(storm::storage::SparseMatrix const& matrix); + virtual ~Multiplier() = default; + /* * Clears the currently cached data of this multiplier in order to free some memory. */ diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index 90b0f1454..3d9e31a02 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -16,6 +16,7 @@ namespace storm { class NativeMultiplier : public Multiplier { public: NativeMultiplier(storm::storage::SparseMatrix const& matrix); + virtual ~NativeMultiplier() = default; virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; From 40285bac26f4cc6c8c0d882c728b90c707297da2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 14 Mar 2018 17:35:06 +0100 Subject: [PATCH 172/647] handled early termination in svi more carefully --- .../helper/SoundValueIterationHelper.cpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index 68bd1f03a..ab0ace1a7 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -282,9 +282,24 @@ namespace storm { template void SoundValueIterationHelper::setSolutionVector() { - STORM_LOG_WARN_COND(hasLowerBound && hasUpperBound, "No lower or upper result bound could be computed within the given number of Iterations."); - - ValueType meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + + // Due to a custom termination criterion it might be the case that one of the bounds was not yet established. + ValueType meanBound; + if (!hasLowerBound) { + STORM_LOG_WARN("No lower result bound was computed during sound value iteration."); + if (hasUpperBound) { + meanBound = upperBound; + } else { + STORM_LOG_WARN("No upper result bound was computed during sound value iteration."); + meanBound = storm::utility::zero(); + } + } else if (!hasUpperBound) { + STORM_LOG_WARN("No upper result bound was computed during sound value iteration."); + meanBound = lowerBound; + } else { + meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + } + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " From fc43d3f506c28970a533faa26909bd5cba5ab069 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 14 Mar 2018 19:53:25 +0100 Subject: [PATCH 173/647] Added a return type to some lambda expressions as this apparently caused trouble when using gmp numbers --- src/storm/solver/NativeLinearEquationSolver.cpp | 8 ++++---- src/storm/solver/helper/SoundValueIterationHelper.cpp | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index 04c3d3c76..eb8e9d6b9 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -245,10 +245,10 @@ namespace storm { std::vector* nextX = &walkerChaeData->newX; std::vector tmp = walkerChaeData->matrix.getRowSumVector(); - storm::utility::vector::applyPointwise(tmp, walkerChaeData->b, walkerChaeData->b, [this] (ValueType const& first, ValueType const& second) { return walkerChaeData->t * first + second; } ); + storm::utility::vector::applyPointwise(tmp, walkerChaeData->b, walkerChaeData->b, [this] (ValueType const& first, ValueType const& second) -> ValueType { return walkerChaeData->t * first + second; } ); // Add t to all entries of x. - storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) { return value + walkerChaeData->t; }); + storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) -> ValueType { return value + walkerChaeData->t; }); // Create a vector that always holds Ax. std::vector currentAx(x.size()); @@ -288,7 +288,7 @@ namespace storm { x.resize(this->A->getRowCount()); // Finalize solution vector. - storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) { return value - walkerChaeData->t; } ); + storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) -> ValueType { return value - walkerChaeData->t; } ); if (!this->isCachingEnabled()) { clearCache(); @@ -547,7 +547,7 @@ namespace storm { } // We take the means of the lower and upper bound so we guarantee the desired precision. - storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [] (ValueType const& a, ValueType const& b) { return (a + b) / storm::utility::convertNumber(2.0); }); + storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / storm::utility::convertNumber(2.0); }); // Since we shuffled the pointer around, we need to write the actual results to the input/output vector x. if (&x == tmp) { diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index ab0ace1a7..6e47bfe3e 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -282,7 +282,6 @@ namespace storm { template void SoundValueIterationHelper::setSolutionVector() { - // Due to a custom termination criterion it might be the case that one of the bounds was not yet established. ValueType meanBound; if (!hasLowerBound) { @@ -300,7 +299,7 @@ namespace storm { meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); } - storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) { return xi + yi * meanBound; }); + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) -> ValueType { return xi + yi * meanBound; }); STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") From 480894f1b62ca2dd964ed12fb8939323e4e46cae Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Mar 2018 14:14:30 +0100 Subject: [PATCH 174/647] Added missing topological settings to storm-pars --- src/storm-pars/settings/ParsSettings.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index f7eb39604..8359c34e9 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -15,6 +15,7 @@ #include "storm/settings/modules/EigenEquationSolverSettings.h" #include "storm/settings/modules/GmmxxEquationSolverSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/EliminationSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GameSolverSettings.h" @@ -43,6 +44,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); @@ -53,4 +55,4 @@ namespace storm { } } -} \ No newline at end of file +} From 95c19de1973e710692bb04c4ad3c961a50b15583 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Mar 2018 14:19:44 +0100 Subject: [PATCH 175/647] Added missing multiplier settings to storm-pars --- src/storm-pars/settings/ParsSettings.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index 8359c34e9..a0e9d8073 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -23,6 +23,7 @@ #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" namespace storm { @@ -52,6 +53,7 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } From c8c0b73e7aa9de7a58a980031f3cced755059d15 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Mar 2018 14:36:36 +0100 Subject: [PATCH 176/647] Removed duplicated test --- .../SymbolicBisimulationDecompositionTest.cpp | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/test/storage/SymbolicBisimulationDecompositionTest.cpp diff --git a/src/test/storage/SymbolicBisimulationDecompositionTest.cpp b/src/test/storage/SymbolicBisimulationDecompositionTest.cpp deleted file mode 100644 index 4948f7906..000000000 --- a/src/test/storage/SymbolicBisimulationDecompositionTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "gtest/gtest.h" -#include "storm-config.h" -#include "storm/parser/PrismParser.h" -#include "storm/storage/SymbolicModelDescription.h" -#include "storm/builder/DdPrismModelBuilder.h" -#include "storm/models/symbolic/Dtmc.h" -#include "storm/storage/dd/BisimulationDecomposition.h" - -TEST(SymbolicBisimulationDecompositionTest_Cudd, Die) { - storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); - storm::prism::Program program = modelDescription.preprocess().asPrismProgram(); - - std::shared_ptr> model = storm::builder::DdPrismModelBuilder().build(program); - - storm::dd::BisimulationDecomposition decomposition(*model, storm::dd::bisimulation::Partition::create(*model, {"one"})); - decomposition.compute(); -} - -TEST(SymbolicBisimulationDecompositionTest_Cudd, Crowds) { - storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); - storm::prism::Program program = modelDescription.preprocess().asPrismProgram(); - - std::shared_ptr> model = storm::builder::DdPrismModelBuilder().build(program); - - storm::dd::BisimulationDecomposition decomposition(*model, storm::dd::bisimulation::Partition::create(*model, {"observe0Greater1"})); - decomposition.compute(); -} From 6821d3c76c4a4ca672161ba5c5ccbd72bbc6dcaa Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Mar 2018 18:06:05 +0100 Subject: [PATCH 177/647] Different function for exact and approximate DFT analysis --- src/storm-dft-cli/storm-dft.cpp | 13 ++++---- src/storm-dft/api/storm-dft.h | 30 +++++++++++++++++-- .../modelchecker/dft/DFTModelChecker.cpp | 4 +-- .../modelchecker/dft/DFTModelChecker.h | 7 +++-- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 2d2e24b8e..f051570dc 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -95,12 +95,6 @@ void processOptions() { } } - // Set possible approximation error - double approximationError = 0.0; - if (faultTreeSettings.isApproximationErrorSet()) { - approximationError = faultTreeSettings.getApproximationError(); - } - // Build properties STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidSettingsException, "No property given."); std::string propString = properties[0]; @@ -111,7 +105,12 @@ void processOptions() { STORM_LOG_ASSERT(props.size() > 0, "No properties found."); // Carry out the actual analysis - storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); + if (faultTreeSettings.isApproximationErrorSet()) { + // Approximate analysis + storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), faultTreeSettings.getApproximationError()); + } else { + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC()); + } } /*! diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index fc88fe792..30b06a1e8 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -50,14 +50,38 @@ namespace storm { * @param symred Flag whether symmetry reduction should be used. * @param allowModularisation Flag whether modularisation should be applied if possible. * @param enableDC Flag whether Don't Care propagation should be used. - * @param approximationError Allowed approximation error, 0 indicates no approximation. + * + * @return Result. + */ + template + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC) { + storm::modelchecker::DFTModelChecker modelChecker; + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, 0.0); + modelChecker.printTimings(); + modelChecker.printResults(); + return results; + } + + /*! + * Approximate the analysis result of the given DFT according to the given properties. + * First the Markov model is built from the DFT and then this model is checked against the given properties. + * + * @param dft DFT. + * @param properties PCTL formulas capturing the properties to check. + * @param symred Flag whether symmetry reduction should be used. + * @param allowModularisation Flag whether modularisation should be applied if possible. + * @param enableDC Flag whether Don't Care propagation should be used. + * @param approximationError Allowed approximation error. + * + * @return Result. */ template - void analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { storm::modelchecker::DFTModelChecker modelChecker; - modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError); + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError); modelChecker.printTimings(); modelChecker.printResults(); + return results; } diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index d2b435c1c..c3e7996c7 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -14,7 +14,7 @@ namespace storm { namespace modelchecker { template - void DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { // Initialize this->approximationError = approximationError; totalTimer.start(); @@ -33,11 +33,11 @@ namespace storm { for (ValueType result : resultsValue) { checkResults.push_back(result); } - } else { checkResults = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError); } totalTimer.stop(); + return checkResults; } template diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index 597feb3cb..6da5d5aaa 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -17,12 +17,11 @@ namespace storm { template class DFTModelChecker { + public: typedef std::pair approximation_result; typedef std::vector> dft_results; typedef std::vector> property_vector; - public: - /*! * Constructor. */ @@ -38,8 +37,10 @@ namespace storm { * @param allowModularisation Flag indication if modularisation is allowed * @param enableDC Flag indicating if dont care propagation should be used * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * + * @return Model checking results for the given properties. */ - void check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0); + dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0); /*! * Print timings of all operations to stream. From 2c9f6294a45a97ee90eca6e2fc97666dbf2e8ebe Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 16 Mar 2018 18:51:24 +0100 Subject: [PATCH 178/647] Started on DFT regression tests --- resources/examples/testfiles/dft/and.dft | 4 ++ src/test/CMakeLists.txt | 3 +- src/test/storm-dft/CMakeLists.txt | 23 +++++++++ src/test/storm-dft/api/DftApiTest.cpp | 63 ++++++++++++++++++++++++ src/test/storm-dft/storm-test.cpp | 8 +++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 resources/examples/testfiles/dft/and.dft create mode 100644 src/test/storm-dft/CMakeLists.txt create mode 100644 src/test/storm-dft/api/DftApiTest.cpp create mode 100644 src/test/storm-dft/storm-test.cpp diff --git a/resources/examples/testfiles/dft/and.dft b/resources/examples/testfiles/dft/and.dft new file mode 100644 index 000000000..2b06cbe95 --- /dev/null +++ b/resources/examples/testfiles/dft/and.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" and "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d870d2b21..a693be0a0 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(storm) -add_subdirectory(storm-pars) \ No newline at end of file +add_subdirectory(storm-pars) +add_subdirectory(storm-dft) diff --git a/src/test/storm-dft/CMakeLists.txt b/src/test/storm-dft/CMakeLists.txt new file mode 100644 index 000000000..d461c2f9d --- /dev/null +++ b/src/test/storm-dft/CMakeLists.txt @@ -0,0 +1,23 @@ +# Base path for test files +set(STORM_TESTS_BASE_PATH "${PROJECT_SOURCE_DIR}/src/test/storm-dft") + +# Test Sources +file(GLOB_RECURSE ALL_FILES ${STORM_TESTS_BASE_PATH}/*.h ${STORM_TESTS_BASE_PATH}/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" test) + +# Note that the tests also need the source files, except for the main file +include_directories(${GTEST_INCLUDE_DIR}) + +foreach (testsuite api) + + file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) + add_executable (test-dft-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) + target_link_libraries(test-dft-${testsuite} storm-dft) + target_link_libraries(test-dft-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) + + add_dependencies(test-dft-${testsuite} test-resources) + add_test(NAME run-test-dft-${testsuite} COMMAND $) + add_dependencies(tests test-dft-${testsuite}) + +endforeach () diff --git a/src/test/storm-dft/api/DftApiTest.cpp b/src/test/storm-dft/api/DftApiTest.cpp new file mode 100644 index 000000000..93dffb5b8 --- /dev/null +++ b/src/test/storm-dft/api/DftApiTest.cpp @@ -0,0 +1,63 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "storm-dft/api/storm-dft.h" + +namespace { + + // Base holding information about test example + struct DftExample { + std::string file; + double expectedValue; + }; + struct DftAnalysisConfig { + DftExample example; + bool useSR; + bool useMod; + bool useDC; + }; + + // Base test for regression test + class DftAnalysisTestCase : public ::testing::TestWithParam> + { + protected: + DftAnalysisConfig analysisConfig { + std::get<0>(GetParam()), + std::get<1>(GetParam()), + std::get<2>(GetParam()), + std::get<3>(GetParam()) + }; + }; + + TEST_P(DftAnalysisTestCase, AnalyzeMTTF) { + std::stringstream stream; + stream << STORM_TEST_RESOURCES_DIR << "/dft/" << analysisConfig.example.file << ".dft"; + std::shared_ptr> dft = storm::api::loadDFTGalileo(stream.str()); + + std::string property = "Tmin=? [F \"failed\"]"; + std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); + + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, analysisConfig.useSR, analysisConfig.useMod, analysisConfig.useDC); + double result = boost::get(results[0]); + EXPECT_FLOAT_EQ(result, analysisConfig.example.expectedValue); + } + + TEST(DftApiTest, LoadFromGalileo) { + std::string file = STORM_TEST_RESOURCES_DIR "/dft/and.dft"; + std::shared_ptr> dft = storm::api::loadDFTGalileo(file); + } + + INSTANTIATE_TEST_CASE_P(RegularPolygon, DftAnalysisTestCase, ::testing::Combine( + testing::Values( + DftExample {"and", 3.0} + ), + ::testing::Bool(), // useSR + ::testing::Bool(), // useMod + ::testing::Bool() // useDC + ) + ); + + + TEST(DftApiTest, AnalyzeMTTF) { + } +} diff --git a/src/test/storm-dft/storm-test.cpp b/src/test/storm-dft/storm-test.cpp new file mode 100644 index 000000000..cf9106876 --- /dev/null +++ b/src/test/storm-dft/storm-test.cpp @@ -0,0 +1,8 @@ +#include "gtest/gtest.h" +#include "storm-dft/settings/DftSettings.h" + +int main(int argc, char **argv) { + storm::settings::initializeDftSettings("Storm-dft (Functional) Testing Suite", "test-dft"); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 752a1fff86e9d40ca6bb924ccababe1d65e02c3c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 19 Mar 2018 14:10:16 +0100 Subject: [PATCH 179/647] Use pars settings for pars tests --- src/test/storm-pars/storm-test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/storm-pars/storm-test.cpp b/src/test/storm-pars/storm-test.cpp index 203c56b40..14855a65a 100644 --- a/src/test/storm-pars/storm-test.cpp +++ b/src/test/storm-pars/storm-test.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" -#include "storm/settings/SettingsManager.h" +#include "storm-pars/settings/ParsSettings.h" int main(int argc, char **argv) { - storm::settings::initializeAll("Storm-pars (Functional) Testing Suite", "test-pars"); + storm::settings::initializeParsSettings("Storm-pars (Functional) Testing Suite", "test-pars"); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } From 9559a96fd70bb5876d525d39035f1b299f30ee10 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 19 Mar 2018 16:53:25 +0100 Subject: [PATCH 180/647] Travis: allow failure of LTO config --- .travis.yml | 16 ++++++++++++++++ travis/generate_travis.py | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2a08f13c7..e790a1123 100644 --- a/.travis.yml +++ b/.travis.yml @@ -360,4 +360,20 @@ jobs: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - docker commit storm mvolk/storm:travis; - docker push mvolk/storm:travis; + allow_failures: + - stage: Build (1st run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + - stage: Build (2nd run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + - stage: Build (3rd run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + - stage: Build (4th run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + - stage: Test all + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc diff --git a/travis/generate_travis.py b/travis/generate_travis.py index fd97dc253..52a81a678 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -27,6 +27,8 @@ stages = [ if __name__ == "__main__": + allow_failures = [] + s = "" # Initial config s += "#\n" @@ -130,15 +132,19 @@ if __name__ == "__main__": # Linux via Docker for config in configs_linux: + allow_fail = "" linux = config[0] compiler = config[1] build_type = config[2] s += " # {} - {}\n".format(linux, build_type) buildConfig = "" buildConfig += " - stage: {}\n".format(stage[0]) + allow_fail += " - stage: {}\n".format(stage[0]) buildConfig += " os: linux\n" + allow_fail += " os: linux\n" buildConfig += " compiler: {}\n".format(compiler) buildConfig += " env: CONFIG={} LINUX={} COMPILER={}\n".format(build_type, linux, compiler) + allow_fail += " env: CONFIG={} LINUX={} COMPILER={}\n".format(build_type, linux, compiler) buildConfig += " install:\n" if stage[1] == "Build1": buildConfig += " - rm -rf build\n" @@ -162,5 +168,11 @@ if __name__ == "__main__": else: assert False s += buildConfig + if "Travis" in build_type and "Release" in build_type: + allow_failures.append(allow_fail) + if len(allow_failures) > 0: + s += " allow_failures:\n" + for fail in allow_failures: + s += fail print(s) From ca8608db5c14e003563daa168acd33098c3c37e7 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 20 Mar 2018 13:54:53 +0100 Subject: [PATCH 181/647] Use different configurations in DFT tests --- src/test/storm-dft/api/DftApiTest.cpp | 63 ------------- .../storm-dft/api/DftModelCheckerTest.cpp | 91 +++++++++++++++++++ src/test/storm-dft/api/DftParserTest.cpp | 13 +++ 3 files changed, 104 insertions(+), 63 deletions(-) delete mode 100644 src/test/storm-dft/api/DftApiTest.cpp create mode 100644 src/test/storm-dft/api/DftModelCheckerTest.cpp create mode 100644 src/test/storm-dft/api/DftParserTest.cpp diff --git a/src/test/storm-dft/api/DftApiTest.cpp b/src/test/storm-dft/api/DftApiTest.cpp deleted file mode 100644 index 93dffb5b8..000000000 --- a/src/test/storm-dft/api/DftApiTest.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "gtest/gtest.h" -#include "storm-config.h" - -#include "storm-dft/api/storm-dft.h" - -namespace { - - // Base holding information about test example - struct DftExample { - std::string file; - double expectedValue; - }; - struct DftAnalysisConfig { - DftExample example; - bool useSR; - bool useMod; - bool useDC; - }; - - // Base test for regression test - class DftAnalysisTestCase : public ::testing::TestWithParam> - { - protected: - DftAnalysisConfig analysisConfig { - std::get<0>(GetParam()), - std::get<1>(GetParam()), - std::get<2>(GetParam()), - std::get<3>(GetParam()) - }; - }; - - TEST_P(DftAnalysisTestCase, AnalyzeMTTF) { - std::stringstream stream; - stream << STORM_TEST_RESOURCES_DIR << "/dft/" << analysisConfig.example.file << ".dft"; - std::shared_ptr> dft = storm::api::loadDFTGalileo(stream.str()); - - std::string property = "Tmin=? [F \"failed\"]"; - std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); - - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, analysisConfig.useSR, analysisConfig.useMod, analysisConfig.useDC); - double result = boost::get(results[0]); - EXPECT_FLOAT_EQ(result, analysisConfig.example.expectedValue); - } - - TEST(DftApiTest, LoadFromGalileo) { - std::string file = STORM_TEST_RESOURCES_DIR "/dft/and.dft"; - std::shared_ptr> dft = storm::api::loadDFTGalileo(file); - } - - INSTANTIATE_TEST_CASE_P(RegularPolygon, DftAnalysisTestCase, ::testing::Combine( - testing::Values( - DftExample {"and", 3.0} - ), - ::testing::Bool(), // useSR - ::testing::Bool(), // useMod - ::testing::Bool() // useDC - ) - ); - - - TEST(DftApiTest, AnalyzeMTTF) { - } -} diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp new file mode 100644 index 000000000..a2fdd4610 --- /dev/null +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -0,0 +1,91 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "storm-dft/api/storm-dft.h" + +namespace { + + // Configurations for DFT analysis + struct DftAnalysisConfig { + bool useSR; + bool useMod; + bool useDC; + }; + + class NoOptimizationsConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {false, false, false}; + } + }; + class DontCareConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {false, false, true}; + } + }; + class ModularisationConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {false, true, false}; + } + }; + class SymmetryReductionConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {true, false, false}; + } + }; + class AllOptimizationsConfig { + public: + typedef double ValueType; + static DftAnalysisConfig createConfig() { + return DftAnalysisConfig {true, true, true}; + } + }; + + // General base class for testing of DFT model checking + template + class DftModelCheckerTest : public ::testing::Test { + public: + typedef typename TestType::ValueType ValueType; + + DftModelCheckerTest() : config(TestType::createConfig()) { + } + + DftAnalysisConfig const& getConfig() const { + return config; + } + + double analyzeMTTF(std::string const& file) { + std::shared_ptr> dft = storm::api::loadDFTGalileo(file); + std::string property = "Tmin=? [F \"failed\"]"; + std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, config.useDC); + return boost::get(results[0]); + } + + private: + DftAnalysisConfig config; + }; + + typedef ::testing::Types< + NoOptimizationsConfig, + DontCareConfig, + ModularisationConfig, + SymmetryReductionConfig, + AllOptimizationsConfig + > TestingTypes; + + TYPED_TEST_CASE(DftModelCheckerTest, TestingTypes); + + TYPED_TEST(DftModelCheckerTest, AndMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/and.dft"); + EXPECT_FLOAT_EQ(result, 3.0); + } + +} diff --git a/src/test/storm-dft/api/DftParserTest.cpp b/src/test/storm-dft/api/DftParserTest.cpp new file mode 100644 index 000000000..48a621ac1 --- /dev/null +++ b/src/test/storm-dft/api/DftParserTest.cpp @@ -0,0 +1,13 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "storm-dft/api/storm-dft.h" + +namespace { + + TEST(DftParserTest, LoadFromGalileo) { + std::string file = STORM_TEST_RESOURCES_DIR "/dft/and.dft"; + std::shared_ptr> dft = storm::api::loadDFTGalileo(file); + } + +} From 48a0b88cd0d3266908c4f338559576f576fab618 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 20 Mar 2018 15:05:45 +0100 Subject: [PATCH 182/647] Fixed linking issues with duplicate symbols --- src/storm-dft/modelchecker/dft/DFTASFChecker.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/storm-dft/modelchecker/dft/DFTASFChecker.h b/src/storm-dft/modelchecker/dft/DFTASFChecker.h index c4a47116d..a4337bb58 100644 --- a/src/storm-dft/modelchecker/dft/DFTASFChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTASFChecker.h @@ -33,13 +33,15 @@ namespace storm { } + friend bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) { + return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex); + } + + private: uint64_t spareIndex; uint64_t childIndex; }; - bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) { - return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex); - } class DFTASFChecker { using ValueType = double; From 853901af452b1c3bbe8612bafb47846169c1fbee Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 20 Mar 2018 15:07:31 +0100 Subject: [PATCH 183/647] Introduced api dir in storm-gspn --- src/storm-dft/api/storm-dft.h | 5 +-- src/storm-gspn-cli/storm-gspn.cpp | 6 +-- src/storm-gspn/api/storm-gspn.cpp | 61 +++++++++++++++++++++++++++ src/storm-gspn/api/storm-gspn.h | 17 ++++++++ src/storm-gspn/storm-gspn.h | 69 ------------------------------- 5 files changed, 83 insertions(+), 75 deletions(-) create mode 100644 src/storm-gspn/api/storm-gspn.cpp create mode 100644 src/storm-gspn/api/storm-gspn.h delete mode 100644 src/storm-gspn/storm-gspn.h diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index 30b06a1e8..fe9a51917 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -10,8 +10,7 @@ #include "storm-dft/modelchecker/dft/DFTASFChecker.h" #include "storm-dft/transformations/DftToGspnTransformator.h" -#include "storm-gspn/storage/gspn/GSPN.h" -#include "storm-gspn/storm-gspn.h" +#include "storm-gspn/api/storm-gspn.h" namespace storm { namespace api { @@ -145,7 +144,7 @@ namespace storm { storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - storm::handleGSPNExportSettings(*gspn); + storm::api::handleGSPNExportSettings(*gspn); std::shared_ptr const& exprManager = gspn->getExpressionManager(); storm::builder::JaniGSPNBuilder builder(*gspn); diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index d6a493981..c1931e468 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -3,7 +3,7 @@ #include "storm-gspn/storage/gspn/GSPN.h" #include "storm-gspn/storage/gspn/GspnBuilder.h" #include "storm-gspn/builder/JaniGSPNBuilder.h" -#include "storm-gspn/storm-gspn.h" +#include "storm-gspn/api/storm-gspn.h" #include "storm/exceptions/BaseException.h" #include "storm/exceptions/WrongFormatException.h" @@ -108,10 +108,10 @@ int main(const int argc, const char **argv) { gspn->setCapacities(capacities); } - storm::handleGSPNExportSettings(*gspn); + storm::api::handleGSPNExportSettings(*gspn); if(storm::settings::getModule().isJaniFileSet()) { - storm::jani::Model* model = storm::buildJani(*gspn); + storm::jani::Model* model = storm::api::buildJani(*gspn); storm::api::exportJaniModel(*model, properties, storm::settings::getModule().getJaniFilename()); delete model; } diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp new file mode 100644 index 000000000..08796386b --- /dev/null +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -0,0 +1,61 @@ +#include "storm-gspn/api/storm-gspn.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/utility/file.h" +#include "storm-gspn/settings/modules/GSPNExportSettings.h" + + +namespace storm { + namespace api { + + storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn) { + storm::builder::JaniGSPNBuilder builder(gspn); + return builder.build(); + } + + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn) { + storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); + if (exportSettings.isWriteToDotSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToDotFilename(), fs); + gspn.writeDotToStream(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToPnproSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToPnproFilename(), fs); + gspn.toPnpro(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToPnmlSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToPnmlFilename(), fs); + gspn.toPnml(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToJsonSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToJsonFilename(), fs); + gspn.toJson(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isDisplayStatsSet()) { + std::cout << "============GSPN Statistics==============" << std::endl; + gspn.writeStatsToStream(std::cout); + std::cout << "=========================================" << std::endl; + } + + if (exportSettings.isWriteStatsToFileSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteStatsFilename(), fs); + gspn.writeStatsToStream(fs); + storm::utility::closeFile(fs); + } + } + + } +} diff --git a/src/storm-gspn/api/storm-gspn.h b/src/storm-gspn/api/storm-gspn.h new file mode 100644 index 000000000..7687c35e4 --- /dev/null +++ b/src/storm-gspn/api/storm-gspn.h @@ -0,0 +1,17 @@ +#pragma once + +#include "storm/storage/jani/Model.h" +#include "storm-gspn/storage/gspn/GSPN.h" +#include "storm-gspn/builder/JaniGSPNBuilder.h" + +namespace storm { + namespace api { + + /** + * Builds JANI model from GSPN. + */ + storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn); + + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn); + } +} diff --git a/src/storm-gspn/storm-gspn.h b/src/storm-gspn/storm-gspn.h deleted file mode 100644 index cc9fd9add..000000000 --- a/src/storm-gspn/storm-gspn.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "storm/storage/jani/Model.h" - -#include "storm-gspn/builder/JaniGSPNBuilder.h" -#include "storm-gspn/storage/gspn/GSPN.h" - -#include "storm/settings/SettingsManager.h" -#include "storm-gspn/settings/modules/GSPNExportSettings.h" - -#include "storm/utility/file.h" - -namespace storm { - /** - * Builds JANI model from GSPN. - */ - storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn) { - storm::builder::JaniGSPNBuilder builder(gspn); - return builder.build(); - } - - void handleGSPNExportSettings(storm::gspn::GSPN const& gspn) { - storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); - if (exportSettings.isWriteToDotSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToDotFilename(), fs); - gspn.writeDotToStream(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToPnproSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToPnproFilename(), fs); - gspn.toPnpro(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToPnmlSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToPnmlFilename(), fs); - gspn.toPnml(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToJsonSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToJsonFilename(), fs); - gspn.toJson(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isDisplayStatsSet()) { - std::cout << "============GSPN Statistics==============" << std::endl; - gspn.writeStatsToStream(std::cout); - std::cout << "=========================================" << std::endl; - } - - if (exportSettings.isWriteStatsToFileSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteStatsFilename(), fs); - gspn.writeStatsToStream(fs); - storm::utility::closeFile(fs); - } - - - - } - -} From 415e22743d488888582b0f7b8f85d58f39e66bd4 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 20 Mar 2018 18:01:35 +0100 Subject: [PATCH 184/647] Moved same parts of the dft api into cpp file --- src/storm-dft/api/storm-dft.cpp | 67 +++++++++++++++++++++++++++++ src/storm-dft/api/storm-dft.h | 75 ++------------------------------- 2 files changed, 70 insertions(+), 72 deletions(-) create mode 100644 src/storm-dft/api/storm-dft.cpp diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp new file mode 100644 index 000000000..91632739e --- /dev/null +++ b/src/storm-dft/api/storm-dft.cpp @@ -0,0 +1,67 @@ +#include "storm-dft/api/storm-dft.h" + +namespace storm { + namespace api { + + template<> + void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + storm::storage::DftJsonExporter::toFile(dft, file); + } + + template<> + void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); + } + + template<> + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + storm::modelchecker::DFTASFChecker asfChecker(dft); + asfChecker.convert(); + asfChecker.toFile(file); + } + + template<> + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to SMT does not support this data type."); + } + + template<> + void transformToGSPN(storm::storage::DFT const& dft) { + // Transform to GSPN + storm::transformations::dft::DftToGspnTransformator gspnTransformator(dft); + bool smart = true; + gspnTransformator.transform(smart); + storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); + uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); + + storm::api::handleGSPNExportSettings(*gspn); + + std::shared_ptr const& exprManager = gspn->getExpressionManager(); + storm::builder::JaniGSPNBuilder builder(*gspn); + storm::jani::Model* model = builder.build(); + storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); + + storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); + auto evtlFormula = std::make_shared(targetExpression); + auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); + auto tbUntil = std::make_shared(tbFormula); + + auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); + auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); + + storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); + if (janiSettings.isJaniFileSet()) { + storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); + } + + delete model; + delete gspn; + } + + template<> + void transformToGSPN(storm::storage::DFT const& dft) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation to GSPN not supported for this data type."); + } + + } +} diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index fe9a51917..003c03f14 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -83,18 +83,6 @@ namespace storm { return results; } - - /*! - * Export DFT to JSON file. - * - * @param dft DFT. - * @param file File. - */ - template - typename std::enable_if::value, void>::type exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { - storm::storage::DftJsonExporter::toFile(dft, file); - } - /*! * Export DFT to JSON file. * @@ -102,22 +90,7 @@ namespace storm { * @param file File. */ template - typename std::enable_if::value, void>::type exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); - } - - /*! - * Export DFT to SMT encoding. - * - * @param dft DFT. - * @param file File. - */ - template - typename std::enable_if::value, void>::type exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { - storm::modelchecker::DFTASFChecker asfChecker(dft); - asfChecker.convert(); - asfChecker.toFile(file); - } + void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file); /*! * Export DFT to SMT encoding. @@ -126,47 +99,7 @@ namespace storm { * @param file File. */ template - typename std::enable_if::value, void>::type exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to SMT does not support this data type."); - } - - /*! - * Transform DFT to GSPN. - * - * @param dft DFT. - */ - template - typename std::enable_if::value, void>::type transformToGSPN(storm::storage::DFT const& dft) { - // Transform to GSPN - storm::transformations::dft::DftToGspnTransformator gspnTransformator(dft); - bool smart = true; - gspnTransformator.transform(smart); - storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); - uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - - storm::api::handleGSPNExportSettings(*gspn); - - std::shared_ptr const& exprManager = gspn->getExpressionManager(); - storm::builder::JaniGSPNBuilder builder(*gspn); - storm::jani::Model* model = builder.build(); - storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); - - storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); - auto evtlFormula = std::make_shared(targetExpression); - auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - auto tbUntil = std::make_shared(tbFormula); - - auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); - auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - - storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); - if (janiSettings.isJaniFileSet()) { - storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); - } - - delete model; - delete gspn; - } + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file); /*! * Transform DFT to GSPN. @@ -174,9 +107,7 @@ namespace storm { * @param dft DFT. */ template - typename std::enable_if::value, void>::type transformToGSPN(storm::storage::DFT const& dft) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation to GSPN not supported for this data type."); - } + void transformToGSPN(storm::storage::DFT const& dft); } } From 3310f51857259e9eacf4ac2cbafe635531c0ba4f Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 20 Mar 2018 18:12:14 +0100 Subject: [PATCH 185/647] allowed for more fine grained solver requirements --- ...SparseDtmcParameterLiftingModelChecker.cpp | 6 +- .../csl/helper/SparseCtmcCslHelper.cpp | 6 +- .../helper/SparseMarkovAutomatonCslHelper.cpp | 8 +- ...ewardBoundedMdpPcaaWeightVectorChecker.cpp | 4 +- .../StandardMaPcaaWeightVectorChecker.cpp | 2 +- .../pcaa/StandardPcaaWeightVectorChecker.cpp | 9 +- .../prctl/helper/HybridDtmcPrctlHelper.cpp | 6 +- .../prctl/helper/HybridMdpPrctlHelper.cpp | 34 +++--- .../prctl/helper/SparseDtmcPrctlHelper.cpp | 6 +- .../prctl/helper/SparseMdpPrctlHelper.cpp | 16 +-- .../prctl/helper/SymbolicMdpPrctlHelper.cpp | 16 +-- .../LinearEquationSolverRequirements.cpp | 64 +++++++---- .../solver/LinearEquationSolverRequirements.h | 29 +++-- ...MinMaxLinearEquationSolverRequirements.cpp | 103 ++++++++++++------ .../MinMaxLinearEquationSolverRequirements.h | 41 ++++--- src/storm/solver/SolverRequirement.cpp | 32 ++++++ src/storm/solver/SolverRequirement.h | 39 +++++++ .../TopologicalMinMaxLinearEquationSolver.cpp | 16 +-- .../solver/MinMaxLinearEquationSolverTest.cpp | 2 +- 19 files changed, 299 insertions(+), 140 deletions(-) create mode 100644 src/storm/solver/SolverRequirement.cpp create mode 100644 src/storm/solver/SolverRequirement.h diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp index c27d7114e..a199b3781 100644 --- a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -152,7 +152,7 @@ namespace storm { // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearBounds(); - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solverFactory->setRequirementsChecked(true); } @@ -191,11 +191,11 @@ namespace storm { // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearLowerBounds(); - if (req.requiresUpperBounds()) { + if (req.upperBounds()) { solvingRequiresUpperRewardBounds = true; req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solverFactory->setRequirementsChecked(true); diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 931693450..7e50785d0 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -492,7 +492,8 @@ namespace storm { { // Check solver requirements storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; - STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + auto requirements = linearEquationSolverFactory.getRequirements(env); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); // Check whether we have the right input format for the solver. STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(bsccEquationSystem)); @@ -565,7 +566,8 @@ namespace storm { { storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; // Check solver requirements - STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + auto requirements = linearEquationSolverFactory.getRequirements(env); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); // Check whether we have the right input format for the solver. STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(rewardEquationSystemMatrix)); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 164310b20..8eb688d55 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -287,7 +287,7 @@ namespace storm { storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); if (numberOfProbabilisticChoices > 0) { solver = minMaxLinearEquationSolverFactory.create(env, probMatrix); @@ -449,7 +449,7 @@ namespace storm { storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, aProbabilistic); solver->setHasUniqueSolution(); @@ -757,7 +757,7 @@ namespace storm { storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, sspMatrix); solver->setHasUniqueSolution(); @@ -971,7 +971,7 @@ namespace storm { storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearLowerBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); auto solver = minMaxLinearEquationSolverFactory.create(env, std::move(aProbabilistic)); solver->setLowerBound(storm::utility::zero()); diff --git a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp index cc748983d..f5137b0a7 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp @@ -295,7 +295,7 @@ namespace storm { cachedData.linEqSolver->setUpperBound(*obj.upperResultBound); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); cachedData.linEqSolver->solveEquations(env, x, cachedData.bLinEq); auto resultIt = result.begin(); for (auto const& state : epochModel.epochInStates) { @@ -331,7 +331,7 @@ namespace storm { cachedData.minMaxSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); cachedData.minMaxSolver->setRequirementsChecked(true); cachedData.minMaxSolver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp index 211a12cc4..d43db0d5c 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp @@ -314,7 +314,7 @@ namespace storm { result->solver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the MinMaxSolver was not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); result->solver->setRequirementsChecked(true); result->solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index 9a8b39c4e..3dd8e8988 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -180,14 +180,14 @@ namespace storm { solver->setHasUniqueSolution(true); solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize); - setBoundsToSolver(*solver, req.requiresLowerBounds(), req.requiresUpperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix, ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues); + setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix, ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues); if (solver->hasLowerBound()) { req.clearLowerBounds(); } if (solver->hasUpperBound()) { req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solver->setRequirementsChecked(true); // Use the (0...0) vector as initial guess for the solution. @@ -266,15 +266,14 @@ namespace storm { solver->clearBounds(); storm::storage::BitVector submatrixRowsWithSumLessOne = deterministicMatrix.getRowFilter(maybeStates, maybeStates) % maybeStates; submatrixRowsWithSumLessOne.complement(); - this->setBoundsToSolver(*solver, req.requiresLowerBounds(), req.requiresUpperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b); + this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b); if (solver->hasLowerBound()) { req.clearLowerBounds(); } if (solver->hasUpperBound()) { req.clearUpperBounds(); } - - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solver->solveEquations(env, x, b); // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index b90aa25be..659a17cab 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -72,7 +72,7 @@ namespace storm { auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); req.clearUpperBounds(); - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); // Check whether we need to create an equation system. bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; @@ -285,14 +285,14 @@ namespace storm { storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); - if (req.requiresUpperBounds()) { + if (req.upperBounds()) { storm::dd::Add targetStatesAsColumn = targetStates.template toAdd(); targetStatesAsColumn = targetStatesAsColumn.swapVariables(model.getRowColumnMetaVariablePairs()); oneStepTargetProbs = submatrix * targetStatesAsColumn; oneStepTargetProbs = oneStepTargetProbs->sumAbstract(model.getColumnVariables()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); // Check whether we need to create an equation system. bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index 90fbd61d0..cca377b9d 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -155,18 +155,18 @@ namespace storm { SolverRequirementsData solverRequirementsData; bool extendMaybeStates = false; - if (!clearedRequirements.empty()) { - if (clearedRequirements.requiresNoEndComponents()) { + if (clearedRequirements.hasEnabledRequirement()) { + if (clearedRequirements.noEndComponents()) { STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearNoEndComponents(); } - if (clearedRequirements.requiresValidInitialScheduler()) { + if (clearedRequirements.validInitialScheduler()) { STORM_LOG_DEBUG("Scheduling valid scheduler computation, because the solver requires it."); clearedRequirements.clearValidInitialScheduler(); } clearedRequirements.clearBounds(); - STORM_LOG_THROW(clearedRequirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!clearedRequirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + clearedRequirements.getEnabledRequirementsAsString() + " not checked."); } storm::dd::Bdd extendedMaybeStates = maybeStates; @@ -228,7 +228,7 @@ namespace storm { explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); conversionWatch.stop(); - if (requirements.requiresValidInitialScheduler()) { + if (requirements.validInitialScheduler()) { solverRequirementsData.initialScheduler = computeValidInitialSchedulerForUntilProbabilities(explicitRepresentation.first, explicitRepresentation.second); } } @@ -251,7 +251,7 @@ namespace storm { solver->solveEquations(env, dir, x, explicitRepresentation.second); // If we included some target and non-filter states in the ODD, we need to expand the result from the solver. - if (requirements.requiresNoEndComponents() && solverRequirementsData.ecInformation) { + if (requirements.noEndComponents() && solverRequirementsData.ecInformation) { std::vector extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits()); solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x); x = std::move(extendedVector); @@ -549,24 +549,24 @@ namespace storm { storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; bool extendMaybeStates = false; - if (!clearedRequirements.empty()) { - if (clearedRequirements.requiresNoEndComponents()) { + if (clearedRequirements.hasEnabledRequirement()) { + if (clearedRequirements.noEndComponents()) { STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearNoEndComponents(); } - if (clearedRequirements.requiresValidInitialScheduler()) { + if (clearedRequirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearValidInitialScheduler(); } clearedRequirements.clearLowerBounds(); - if (clearedRequirements.requiresUpperBounds()) { + if (clearedRequirements.upperBounds()) { STORM_LOG_DEBUG("Computing upper bounds, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearUpperBounds(); } - STORM_LOG_THROW(clearedRequirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!clearedRequirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + clearedRequirements.getEnabledRequirementsAsString() + " not checked."); } // Compute the set of maybe states that we are required to keep in the translation to explicit. @@ -611,17 +611,17 @@ namespace storm { storm::storage::BitVector targetStates = computeTargetStatesForReachabilityRewardsFromExplicitRepresentation(explicitRepresentation.first); solverRequirementsData.properMaybeStates = ~targetStates; - if (requirements.requiresNoEndComponents()) { - eliminateEndComponentsAndTargetStatesReachabilityRewards(explicitRepresentation, solverRequirementsData, targetStates, requirements.requiresUpperBounds()); + if (requirements.noEndComponents()) { + eliminateEndComponentsAndTargetStatesReachabilityRewards(explicitRepresentation, solverRequirementsData, targetStates, requirements.upperBounds()); // The solution becomes unique after end components have been eliminated. uniqueSolution = true; } else { - if (requirements.requiresValidInitialScheduler()) { + if (requirements.validInitialScheduler()) { // Compute a valid initial scheduler. solverRequirementsData.initialScheduler = computeValidInitialSchedulerForReachabilityRewards(explicitRepresentation.first, solverRequirementsData.properMaybeStates, targetStates); } - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { solverRequirementsData.oneStepTargetProbabilities = computeOneStepTargetProbabilitiesFromExtendedExplicitRepresentation(explicitRepresentation.first, solverRequirementsData.properMaybeStates, targetStates); } @@ -641,7 +641,7 @@ namespace storm { solver->setHasUniqueSolution(uniqueSolution); // If the solver requires upper bounds, compute them now. - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { setUpperRewardBounds(*solver, dir, explicitRepresentation.first, explicitRepresentation.second, solverRequirementsData.oneStepTargetProbabilities.get()); } @@ -657,7 +657,7 @@ namespace storm { solver->solveEquations(env, dir, x, explicitRepresentation.second); // If we eliminated end components, we need to extend the solution vector. - if (requirements.requiresNoEndComponents() && solverRequirementsData.ecInformation) { + if (requirements.noEndComponents() && solverRequirementsData.ecInformation) { std::vector extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits()); solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x); x = std::move(extendedVector); diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 9e0da7157..03d3fb1a0 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -128,7 +128,7 @@ namespace storm { linEqSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); } // Prepare the right hand side of the equation system @@ -487,11 +487,11 @@ namespace storm { storm::solver::LinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env); boost::optional> upperRewardBounds; requirements.clearLowerBounds(); - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, rew0States)); requirements.clearUpperBounds(); } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "There are unchecked requirements of the solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); // If necessary, convert the matrix from the fixpoint notation to the form needed for the equation system. if (convertToEquationSystem) { diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 2acc4f299..0609db7ee 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -158,7 +158,7 @@ namespace storm { minMaxSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); minMaxSolver->setRequirementsChecked(); } else { auto choicesTmp = minMaxSolver->getSchedulerChoices(); @@ -437,10 +437,9 @@ namespace storm { bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().hasSchedulerHint(); storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, hasSchedulerHint); - if (!requirements.empty()) { - + if (requirements.hasEnabledRequirement()) { // If the solver still requires no end-components, we have to eliminate them later. - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { STORM_LOG_ASSERT(!result.hasUniqueSolution(), "The solver requires to eliminate the end components although the solution is already assumed to be unique."); STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it."); result.eliminateEndComponents = true; @@ -450,7 +449,7 @@ namespace storm { } // If the solver requires an initial scheduler, compute one now. - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); result.schedulerHint = computeValidSchedulerHint(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates, targetStates); requirements.clearValidInitialScheduler(); @@ -462,11 +461,11 @@ namespace storm { } else if (type == SolutionType::ExpectedRewards) { requirements.clearLowerBounds(); } - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { result.computeUpperBounds = true; requirements.clearUpperBounds(); } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "There are unchecked requirements of the solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } else { STORM_LOG_DEBUG("Solver has no requirements."); } @@ -1343,7 +1342,8 @@ namespace storm { storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction()); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); + std::vector sspResult(numberOfSspStates); goal.restrictRelevantValues(statesNotContainedInAnyMec); diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp index 506396a54..d5c9fea6e 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp @@ -75,20 +75,20 @@ namespace storm { // Check requirements of solver. storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(env, dir); boost::optional> initialScheduler; - if (!requirements.empty()) { - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.hasEnabledRequirement()) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); initialScheduler = computeValidSchedulerHint(EquationSystemType::UntilProbabilities, model, transitionMatrix, maybeStates, statesWithProbability1); requirements.clearValidInitialScheduler(); } requirements.clearBounds(); - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { // Check whether there are end components if (storm::utility::graph::performProb0E(model, transitionMatrix.notZero(), maybeStates, !maybeStates && model.getReachableStates()).isZero()) { requirements.clearNoEndComponents(); } } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Could not establish requirements of solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } if (initialScheduler) { solver->setInitialScheduler(initialScheduler.get()); @@ -246,20 +246,20 @@ namespace storm { // Check requirements of solver. storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(env, dir); boost::optional> initialScheduler; - if (!requirements.empty()) { - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.hasEnabledRequirement()) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); initialScheduler = computeValidSchedulerHint(EquationSystemType::ExpectedRewards, model, transitionMatrix, maybeStates, targetStates); requirements.clearValidInitialScheduler(); } requirements.clearLowerBounds(); - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { // Check whether there are end components if (storm::utility::graph::performProb0E(model, transitionMatrixBdd, maybeStates, !maybeStates && model.getReachableStates()).isZero()) { requirements.clearNoEndComponents(); } } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Could not establish requirements of solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } if (initialScheduler) { solver->setInitialScheduler(initialScheduler.get()); diff --git a/src/storm/solver/LinearEquationSolverRequirements.cpp b/src/storm/solver/LinearEquationSolverRequirements.cpp index 90662c6f9..445e776d7 100644 --- a/src/storm/solver/LinearEquationSolverRequirements.cpp +++ b/src/storm/solver/LinearEquationSolverRequirements.cpp @@ -3,52 +3,78 @@ namespace storm { namespace solver { - LinearEquationSolverRequirements::LinearEquationSolverRequirements() : lowerBounds(false), upperBounds(false) { + LinearEquationSolverRequirements::LinearEquationSolverRequirements() { // Intentionally left empty. } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireLowerBounds() { - lowerBounds = true; + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireLowerBounds(bool critical) { + lowerBoundsRequirement.enable(critical); return *this; } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireUpperBounds() { - upperBounds = true; + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireUpperBounds(bool critical) { + upperBoundsRequirement.enable(critical); return *this; } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireBounds() { - requireLowerBounds(); - requireUpperBounds(); + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireBounds(bool critical) { + requireLowerBounds(critical); + requireUpperBounds(critical); return *this; } - bool LinearEquationSolverRequirements::requiresLowerBounds() const { - return lowerBounds; + SolverRequirement const& LinearEquationSolverRequirements::lowerBounds() const { + return lowerBoundsRequirement; } - bool LinearEquationSolverRequirements::requiresUpperBounds() const { - return upperBounds; + SolverRequirement const& LinearEquationSolverRequirements::upperBounds() const { + return upperBoundsRequirement; } - bool LinearEquationSolverRequirements::requires(Element const& element) const { + SolverRequirement const& LinearEquationSolverRequirements::get(Element const& element) const { switch (element) { - case Element::LowerBounds: return lowerBounds; break; - case Element::UpperBounds: return upperBounds; break; + case Element::LowerBounds: return lowerBounds(); break; + case Element::UpperBounds: return upperBounds(); break; } } void LinearEquationSolverRequirements::clearLowerBounds() { - lowerBounds = false; + lowerBoundsRequirement.clear(); } void LinearEquationSolverRequirements::clearUpperBounds() { - upperBounds = false; + upperBoundsRequirement.clear(); } - bool LinearEquationSolverRequirements::empty() const { - return !lowerBounds && !upperBounds; + bool LinearEquationSolverRequirements::hasEnabledRequirement() const { + return lowerBoundsRequirement || upperBoundsRequirement; } + bool LinearEquationSolverRequirements::hasEnabledCriticalRequirement() const { + return lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical(); + } + + + std::string LinearEquationSolverRequirements::getEnabledRequirementsAsString() const { + std::string res = "["; + bool first = true; + if (lowerBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "lowerBounds"; + if (lowerBounds().isCritical()) { + res += "(mandatory)"; + } + } + if (upperBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "upperBounds"; + if (upperBounds().isCritical()) { + res += "(mandatory)"; + } + } + res += "]"; + return res; + } + } } diff --git a/src/storm/solver/LinearEquationSolverRequirements.h b/src/storm/solver/LinearEquationSolverRequirements.h index 8f5a126a7..a7e23d248 100644 --- a/src/storm/solver/LinearEquationSolverRequirements.h +++ b/src/storm/solver/LinearEquationSolverRequirements.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "storm/solver/SolverRequirement.h" + namespace storm { namespace solver { @@ -14,22 +18,29 @@ namespace storm { LinearEquationSolverRequirements(); - LinearEquationSolverRequirements& requireLowerBounds(); - LinearEquationSolverRequirements& requireUpperBounds(); - LinearEquationSolverRequirements& requireBounds(); + LinearEquationSolverRequirements& requireLowerBounds(bool critical = true); + LinearEquationSolverRequirements& requireUpperBounds(bool critical = true); + LinearEquationSolverRequirements& requireBounds(bool critical = true); - bool requiresLowerBounds() const; - bool requiresUpperBounds() const; - bool requires(Element const& element) const; + SolverRequirement const& lowerBounds() const; + SolverRequirement const& upperBounds() const; + SolverRequirement const& get(Element const& element) const; void clearLowerBounds(); void clearUpperBounds(); - bool empty() const; + bool hasEnabledRequirement() const; + bool hasEnabledCriticalRequirement() const; + + /*! + * Checks whether there are no critical requirements left. + * In case there is a critical requirement left an exception is thrown. + */ + std::string getEnabledRequirementsAsString() const; private: - bool lowerBounds; - bool upperBounds; + SolverRequirement lowerBoundsRequirement; + SolverRequirement upperBoundsRequirement; }; } diff --git a/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp b/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp index 005d57977..e16bbdf54 100644 --- a/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp @@ -3,76 +3,76 @@ namespace storm { namespace solver { - MinMaxLinearEquationSolverRequirements::MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements) : noEndComponents(false), validInitialScheduler(false), lowerBounds(linearEquationSolverRequirements.requiresLowerBounds()), upperBounds(linearEquationSolverRequirements.requiresUpperBounds()) { + MinMaxLinearEquationSolverRequirements::MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements) : lowerBoundsRequirement(linearEquationSolverRequirements.lowerBounds()), upperBoundsRequirement(linearEquationSolverRequirements.upperBounds()) { // Intentionally left empty. } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireNoEndComponents() { - noEndComponents = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireNoEndComponents(bool critical) { + noEndComponentsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireValidInitialScheduler() { - validInitialScheduler = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireValidInitialScheduler(bool critical) { + validInitialSchedulerRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireLowerBounds() { - lowerBounds = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireLowerBounds(bool critical) { + lowerBoundsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireUpperBounds() { - upperBounds = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireUpperBounds(bool critical) { + upperBoundsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireBounds() { - requireLowerBounds(); - requireUpperBounds(); + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireBounds(bool critical) { + requireLowerBounds(critical); + requireUpperBounds(critical); return *this; } - bool MinMaxLinearEquationSolverRequirements::requiresNoEndComponents() const { - return noEndComponents; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::noEndComponents() const { + return noEndComponentsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresValidInitialScheduler() const { - return validInitialScheduler; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::validInitialScheduler() const { + return validInitialSchedulerRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresLowerBounds() const { - return lowerBounds; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::lowerBounds() const { + return lowerBoundsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresUpperBounds() const { - return upperBounds; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::upperBounds() const { + return upperBoundsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requires(Element const& element) const { + SolverRequirement const& MinMaxLinearEquationSolverRequirements::get(Element const& element) const { switch (element) { - case Element::NoEndComponents: return noEndComponents; break; - case Element::ValidInitialScheduler: return validInitialScheduler; break; - case Element::LowerBounds: return lowerBounds; break; - case Element::UpperBounds: return upperBounds; break; + case Element::NoEndComponents: return noEndComponents(); break; + case Element::ValidInitialScheduler: return validInitialScheduler(); break; + case Element::LowerBounds: return lowerBounds(); break; + case Element::UpperBounds: return upperBounds(); break; } } void MinMaxLinearEquationSolverRequirements::clearNoEndComponents() { - noEndComponents = false; - validInitialScheduler = false; + noEndComponentsRequirement.clear(); + validInitialSchedulerRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearValidInitialScheduler() { - validInitialScheduler = false; + validInitialSchedulerRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearLowerBounds() { - lowerBounds = false; + lowerBoundsRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearUpperBounds() { - upperBounds = false; + upperBoundsRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearBounds() { @@ -80,8 +80,47 @@ namespace storm { clearUpperBounds(); } - bool MinMaxLinearEquationSolverRequirements::empty() const { - return !noEndComponents && !validInitialScheduler && !lowerBounds && !upperBounds; + bool MinMaxLinearEquationSolverRequirements::hasEnabledRequirement() const { + return noEndComponentsRequirement || validInitialSchedulerRequirement || lowerBoundsRequirement || upperBoundsRequirement; + } + + bool MinMaxLinearEquationSolverRequirements::hasEnabledCriticalRequirement() const { + return noEndComponentsRequirement.isCritical() || validInitialSchedulerRequirement.isCritical() || lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical(); + } + + std::string MinMaxLinearEquationSolverRequirements::getEnabledRequirementsAsString() const { + std::string res = "["; + bool first = true; + if (noEndComponents()) { + if (!first) { res += ", "; } else {first = false;} + res += "NoEndComponents"; + if (noEndComponents().isCritical()) { + res += "(mandatory)"; + } + } + if (validInitialScheduler()) { + if (!first) { res += ", "; } else {first = false;} + res += "validInitialScheduler"; + if (validInitialScheduler().isCritical()) { + res += "(mandatory)"; + } + } + if (lowerBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "lowerBounds"; + if (lowerBounds().isCritical()) { + res += "(mandatory)"; + } + } + if (upperBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "upperBounds"; + if (upperBounds().isCritical()) { + res += "(mandatory)"; + } + } + res += "]"; + return res; } } diff --git a/src/storm/solver/MinMaxLinearEquationSolverRequirements.h b/src/storm/solver/MinMaxLinearEquationSolverRequirements.h index 33e3511ad..06ba623c1 100644 --- a/src/storm/solver/MinMaxLinearEquationSolverRequirements.h +++ b/src/storm/solver/MinMaxLinearEquationSolverRequirements.h @@ -1,6 +1,9 @@ #pragma once +#include + #include "storm/solver/LinearEquationSolverRequirements.h" +#include "storm/solver/SolverRequirement.h" namespace storm { namespace solver { @@ -20,19 +23,21 @@ namespace storm { UpperBounds }; + // The type of a requirement. + MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements = LinearEquationSolverRequirements()); - MinMaxLinearEquationSolverRequirements& requireNoEndComponents(); - MinMaxLinearEquationSolverRequirements& requireValidInitialScheduler(); - MinMaxLinearEquationSolverRequirements& requireLowerBounds(); - MinMaxLinearEquationSolverRequirements& requireUpperBounds(); - MinMaxLinearEquationSolverRequirements& requireBounds(); + MinMaxLinearEquationSolverRequirements& requireNoEndComponents(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireValidInitialScheduler(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireLowerBounds(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireUpperBounds(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireBounds(bool critical = true); - bool requiresNoEndComponents() const; - bool requiresValidInitialScheduler() const; - bool requiresLowerBounds() const; - bool requiresUpperBounds() const; - bool requires(Element const& element) const; + SolverRequirement const& noEndComponents() const; + SolverRequirement const& validInitialScheduler() const; + SolverRequirement const& lowerBounds() const; + SolverRequirement const& upperBounds() const; + SolverRequirement const& get(Element const& element) const; void clearNoEndComponents(); void clearValidInitialScheduler(); @@ -40,13 +45,19 @@ namespace storm { void clearUpperBounds(); void clearBounds(); - bool empty() const; + bool hasEnabledRequirement() const; + bool hasEnabledCriticalRequirement() const; + + /*! + * Returns a string that enumerates the enabled requirements + */ + std::string getEnabledRequirementsAsString() const; private: - bool noEndComponents; - bool validInitialScheduler; - bool lowerBounds; - bool upperBounds; + SolverRequirement noEndComponentsRequirement; + SolverRequirement validInitialSchedulerRequirement; + SolverRequirement lowerBoundsRequirement; + SolverRequirement upperBoundsRequirement; }; } diff --git a/src/storm/solver/SolverRequirement.cpp b/src/storm/solver/SolverRequirement.cpp new file mode 100644 index 000000000..c898840aa --- /dev/null +++ b/src/storm/solver/SolverRequirement.cpp @@ -0,0 +1,32 @@ +#include "storm/solver/SolverRequirement.h" + +#include + +#include "storm/utility/vector.h" + +namespace storm { + namespace solver { + SolverRequirement::SolverRequirement() : enabled(false), critical(false) { + // Intentionally left empty + } + + SolverRequirement::operator bool() const { + return enabled; + } + + void SolverRequirement::enable(bool critical) { + this->enabled = true; + this->critical = critical; + } + + void SolverRequirement::clear() { + enabled = false; + critical = false; + } + + bool SolverRequirement::isCritical() const { + return this->critical; + } + + } +} diff --git a/src/storm/solver/SolverRequirement.h b/src/storm/solver/SolverRequirement.h new file mode 100644 index 000000000..cfdac2e18 --- /dev/null +++ b/src/storm/solver/SolverRequirement.h @@ -0,0 +1,39 @@ +#pragma once + +namespace storm { + namespace solver { + + class SolverRequirement { + public: + + SolverRequirement(); + SolverRequirement(SolverRequirement const& other) = default; + + /*! + * Returns true if this is a requirement of the considered solver. + */ + operator bool() const; + + /*! + * Enables this requirement. + * @param critical if set, it is assumed that the solver will fail in case this requirement is not met + */ + void enable(bool critical = true); + + /*! + * Clears this requirement. + */ + void clear(); + + /*! + * Returns true if the solver fails in case this requirement is not met. + */ + bool isCritical() const; + + private: + bool enabled; + bool critical; + }; + + } +} diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index c0d7e0460..92692b966 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -8,7 +8,7 @@ #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/UnexpectedException.h" -#include "storm/exceptions/UnmetRequirementException.h" +#include "storm/exceptions/UncheckedRequirementException.h" namespace storm { namespace solver { @@ -184,13 +184,13 @@ namespace storm { this->sccSolver->setInitialScheduler(std::move(choices)); } auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); - if (req.requiresUpperBounds() && this->hasUpperBound()) { + if (req.upperBounds() && this->hasUpperBound()) { req.clearUpperBounds(); } - if (req.requiresLowerBounds() && this->hasLowerBound()) { + if (req.lowerBounds() && this->hasLowerBound()) { req.clearLowerBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); this->sccSolver->setRequirementsChecked(true); bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, x, b); @@ -252,16 +252,16 @@ namespace storm { // Requirements auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); - if (req.requiresUpperBounds() && this->hasUpperBound()) { + if (req.upperBounds() && this->hasUpperBound()) { req.clearUpperBounds(); } - if (req.requiresLowerBounds() && this->hasLowerBound()) { + if (req.lowerBounds() && this->hasLowerBound()) { req.clearLowerBounds(); } - if (req.requiresValidInitialScheduler() && this->hasInitialScheduler()) { + if (req.validInitialScheduler() && this->hasInitialScheduler()) { req.clearValidInitialScheduler(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UnmetRequirementException, "Requirements of underlying solver not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); this->sccSolver->setRequirementsChecked(true); // Invoke scc solver diff --git a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp index 707b6ba4c..725590bc8 100644 --- a/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp +++ b/src/test/storm/solver/MinMaxLinearEquationSolverTest.cpp @@ -152,7 +152,7 @@ namespace { solver->setBounds(this->parseNumber("0"), this->parseNumber("2")); storm::solver::MinMaxLinearEquationSolverRequirements req = solver->getRequirements(this->env()); req.clearBounds(); - ASSERT_TRUE(req.empty()); + ASSERT_FALSE(req.hasEnabledRequirement()); ASSERT_NO_THROW(solver->solveEquations(this->env(), storm::OptimizationDirection::Minimize, x, b)); EXPECT_NEAR(x[0], this->parseNumber("0.5"), this->precision()); From 94fb16e65497802361eb92c92fd450216a92d2af Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 20 Mar 2018 18:38:40 +0100 Subject: [PATCH 186/647] svi now considers bounds by default --- src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp | 5 +---- src/storm/solver/NativeLinearEquationSolver.cpp | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index a98bb83f2..51289fb52 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -264,13 +264,10 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireNoEndComponents(); } + requirements.requireBounds(false); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver."); } - - if (env.solver().minMax().isForceBoundsSet()) { - requirements.requireBounds(); - } return requirements; } diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index eb8e9d6b9..ca0142249 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -957,14 +957,13 @@ namespace storm { template LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env) const { LinearEquationSolverRequirements requirements; - if (env.solver().native().isForceBoundsSet()) { - requirements.requireBounds(); - } auto method = getMethod(env, storm::NumberTraits::IsExact); if (method == NativeLinearEquationSolverMethod::IntervalIteration) { requirements.requireBounds(); } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { requirements.requireLowerBounds(); + } else if (method == NativeLinearEquationSolverMethod::SoundValueIteration) { + requirements.requireBounds(false); } return requirements; } From efcb7188516829218519bf171eaec172db482d72 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 20 Mar 2018 18:39:02 +0100 Subject: [PATCH 187/647] removed the --forcebounds setting --- .../solver/MinMaxSolverEnvironment.cpp | 9 --------- .../solver/NativeSolverEnvironment.cpp | 11 +---------- .../environment/solver/NativeSolverEnvironment.h | 3 --- .../modules/MinMaxEquationSolverSettings.cpp | 6 ------ .../modules/MinMaxEquationSolverSettings.h | 5 ----- .../modules/NativeEquationSolverSettings.cpp | 15 ++++----------- .../modules/NativeEquationSolverSettings.h | 6 +++--- 7 files changed, 8 insertions(+), 47 deletions(-) diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index ada4cc5da..536bf5913 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -17,7 +17,6 @@ namespace storm { considerRelativeTerminationCriterion = minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); multiplicationStyle = minMaxSettings.getValueIterationMultiplicationStyle(); - forceBounds = minMaxSettings.isForceBoundsSet(); symmetricUpdates = minMaxSettings.isForceIntervalIterationSymmetricUpdatesSet(); } @@ -70,14 +69,6 @@ namespace storm { multiplicationStyle = value; } - bool MinMaxSolverEnvironment::isForceBoundsSet() const { - return forceBounds; - } - - void MinMaxSolverEnvironment::setForceBounds(bool value) { - forceBounds = value; - } - bool MinMaxSolverEnvironment::isSymmetricUpdatesSet() const { return symmetricUpdates; } diff --git a/src/storm/environment/solver/NativeSolverEnvironment.cpp b/src/storm/environment/solver/NativeSolverEnvironment.cpp index 722fed3d1..149a2feb6 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.cpp +++ b/src/storm/environment/solver/NativeSolverEnvironment.cpp @@ -18,8 +18,7 @@ namespace storm { STORM_LOG_ASSERT(considerRelativeTerminationCriterion || nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); powerMethodMultiplicationStyle = nativeSettings.getPowerMethodMultiplicationStyle(); sorOmega = storm::utility::convertNumber(nativeSettings.getOmega()); - forceBounds = nativeSettings.isForceBoundsSet(); - symmetricUpdates = nativeSettings.isForcePowerMethodSymmetricUpdatesSet(); + symmetricUpdates = nativeSettings.isForceIntervalIterationSymmetricUpdatesSet(); } @@ -80,14 +79,6 @@ namespace storm { sorOmega = value; } - bool NativeSolverEnvironment::isForceBoundsSet() const { - return forceBounds; - } - - void NativeSolverEnvironment::setForceBounds(bool value) { - forceBounds = value; - } - bool NativeSolverEnvironment::isSymmetricUpdatesSet() const { return symmetricUpdates; } diff --git a/src/storm/environment/solver/NativeSolverEnvironment.h b/src/storm/environment/solver/NativeSolverEnvironment.h index b3c9ce457..d0b0e8b9b 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.h +++ b/src/storm/environment/solver/NativeSolverEnvironment.h @@ -27,8 +27,6 @@ namespace storm { void setPowerMethodMultiplicationStyle(storm::solver::MultiplicationStyle value); storm::RationalNumber const& getSorOmega() const; void setSorOmega(storm::RationalNumber const& value); - bool isForceBoundsSet() const; - void setForceBounds(bool value); bool isSymmetricUpdatesSet() const; void setSymmetricUpdates(bool value); @@ -40,7 +38,6 @@ namespace storm { bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle powerMethodMultiplicationStyle; storm::RationalNumber sorOmega; - bool forceBounds; bool symmetricUpdates; }; } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 82c2ba59c..186f0caf9 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -21,7 +21,6 @@ namespace storm { const std::string MinMaxEquationSolverSettings::markovAutomatonBoundedReachabilityMethodOptionName = "mamethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; - const std::string MinMaxEquationSolverSettings::forceBoundsOptionName = "forcebounds"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration", "topological"}; @@ -47,8 +46,6 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, intervalIterationSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, minmax solver always require that a priori bounds for the solution are computed.").build()); - } storm::solver::MinMaxMethod MinMaxEquationSolverSettings::getMinMaxEquationSolvingMethod() const { @@ -136,9 +133,6 @@ namespace storm { return this->getOption(intervalIterationSymmetricUpdatesOptionName).getHasOptionBeenSet(); } - bool MinMaxEquationSolverSettings::isForceBoundsSet() const { - return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); - } } } } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index f64988b6a..43d3d1b00 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -112,11 +112,6 @@ namespace storm { */ bool isForceIntervalIterationSymmetricUpdatesSet() const; - /*! - * Retrieves whether the force bounds option has been set. - */ - bool isForceBoundsSet() const; - // The name of the module. static const std::string moduleName; diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index a73d64bc2..3f0282f0a 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -23,8 +23,7 @@ namespace storm { const std::string NativeEquationSolverSettings::precisionOptionName = "precision"; const std::string NativeEquationSolverSettings::absoluteOptionName = "absolute"; const std::string NativeEquationSolverSettings::powerMethodMultiplicationStyleOptionName = "powmult"; - const std::string NativeEquationSolverSettings::forceBoundsOptionName = "forcebounds"; - const std::string NativeEquationSolverSettings::powerMethodSymmetricUpdatesOptionName = "symmetricupdates"; + const std::string NativeEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; @@ -42,9 +41,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, powerMethodMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for the power method.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, forceBoundsOptionName, false, "If set, the equation solver always require that a priori bounds for the solution are computed.").build()); - - this->addOption(storm::settings::OptionBuilder(moduleName, powerMethodSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, intervalIterationSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); } bool NativeEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { @@ -115,12 +112,8 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } - bool NativeEquationSolverSettings::isForcePowerMethodSymmetricUpdatesSet() const { - return this->getOption(powerMethodSymmetricUpdatesOptionName).getHasOptionBeenSet(); - } - - bool NativeEquationSolverSettings::isForceBoundsSet() const { - return this->getOption(forceBoundsOptionName).getHasOptionBeenSet(); + bool NativeEquationSolverSettings::isForceIntervalIterationSymmetricUpdatesSet() const { + return this->getOption(intervalIterationSymmetricUpdatesOptionName).getHasOptionBeenSet(); } bool NativeEquationSolverSettings::check() const { diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.h b/src/storm/settings/modules/NativeEquationSolverSettings.h index 1562a89c2..306e9750e 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.h +++ b/src/storm/settings/modules/NativeEquationSolverSettings.h @@ -94,9 +94,9 @@ namespace storm { ConvergenceCriterion getConvergenceCriterion() const; /*! - * Retrievew whether updates in power method have to be made symmetrically + * Retrievew whether updates in interval iteration have to be made symmetrically */ - bool isForcePowerMethodSymmetricUpdatesSet() const; + bool isForceIntervalIterationSymmetricUpdatesSet() const; /*! * Retrieves the multiplication style to use in the power method. @@ -123,7 +123,7 @@ namespace storm { static const std::string maximalIterationsOptionShortName; static const std::string precisionOptionName; static const std::string absoluteOptionName; - static const std::string powerMethodSymmetricUpdatesOptionName; + static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string powerMethodMultiplicationStyleOptionName; static const std::string forceBoundsOptionName; From df1571d73777c9bccc9ccd19e98875102d4e098f Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 11:17:34 +0100 Subject: [PATCH 188/647] Added more DFT tests --- resources/examples/testfiles/dft/fdep.dft | 8 ++ resources/examples/testfiles/dft/fdep2.dft | 5 ++ resources/examples/testfiles/dft/fdep3.dft | 5 ++ resources/examples/testfiles/dft/fdep4.dft | 7 ++ resources/examples/testfiles/dft/fdep5.dft | 7 ++ resources/examples/testfiles/dft/or.dft | 4 + resources/examples/testfiles/dft/pand.dft | 4 + resources/examples/testfiles/dft/pdep.dft | 12 +++ resources/examples/testfiles/dft/pdep2.dft | 9 ++ resources/examples/testfiles/dft/pdep3.dft | 5 ++ resources/examples/testfiles/dft/pdep4.dft | 7 ++ resources/examples/testfiles/dft/por.dft | 5 ++ resources/examples/testfiles/dft/seq.dft | 5 ++ resources/examples/testfiles/dft/seq2.dft | 6 ++ resources/examples/testfiles/dft/seq3.dft | 6 ++ resources/examples/testfiles/dft/seq4.dft | 7 ++ resources/examples/testfiles/dft/seq5.dft | 9 ++ resources/examples/testfiles/dft/spare.dft | 5 ++ resources/examples/testfiles/dft/spare2.dft | 8 ++ resources/examples/testfiles/dft/spare3.dft | 10 +++ resources/examples/testfiles/dft/spare4.dft | 9 ++ resources/examples/testfiles/dft/spare5.dft | 9 ++ resources/examples/testfiles/dft/spare6.dft | 7 ++ resources/examples/testfiles/dft/spare7.dft | 5 ++ resources/examples/testfiles/dft/spare8.dft | 7 ++ resources/examples/testfiles/dft/voting.dft | 5 ++ resources/examples/testfiles/dft/voting2.dft | 5 ++ resources/examples/testfiles/dft/voting3.dft | 5 ++ resources/examples/testfiles/dft/voting4.dft | 6 ++ .../storm-dft/api/DftModelCheckerTest.cpp | 82 ++++++++++++++++++- 30 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 resources/examples/testfiles/dft/fdep.dft create mode 100644 resources/examples/testfiles/dft/fdep2.dft create mode 100644 resources/examples/testfiles/dft/fdep3.dft create mode 100644 resources/examples/testfiles/dft/fdep4.dft create mode 100644 resources/examples/testfiles/dft/fdep5.dft create mode 100644 resources/examples/testfiles/dft/or.dft create mode 100644 resources/examples/testfiles/dft/pand.dft create mode 100644 resources/examples/testfiles/dft/pdep.dft create mode 100644 resources/examples/testfiles/dft/pdep2.dft create mode 100644 resources/examples/testfiles/dft/pdep3.dft create mode 100644 resources/examples/testfiles/dft/pdep4.dft create mode 100644 resources/examples/testfiles/dft/por.dft create mode 100644 resources/examples/testfiles/dft/seq.dft create mode 100644 resources/examples/testfiles/dft/seq2.dft create mode 100644 resources/examples/testfiles/dft/seq3.dft create mode 100644 resources/examples/testfiles/dft/seq4.dft create mode 100644 resources/examples/testfiles/dft/seq5.dft create mode 100644 resources/examples/testfiles/dft/spare.dft create mode 100644 resources/examples/testfiles/dft/spare2.dft create mode 100644 resources/examples/testfiles/dft/spare3.dft create mode 100644 resources/examples/testfiles/dft/spare4.dft create mode 100644 resources/examples/testfiles/dft/spare5.dft create mode 100644 resources/examples/testfiles/dft/spare6.dft create mode 100644 resources/examples/testfiles/dft/spare7.dft create mode 100644 resources/examples/testfiles/dft/spare8.dft create mode 100644 resources/examples/testfiles/dft/voting.dft create mode 100644 resources/examples/testfiles/dft/voting2.dft create mode 100644 resources/examples/testfiles/dft/voting3.dft create mode 100644 resources/examples/testfiles/dft/voting4.dft diff --git a/resources/examples/testfiles/dft/fdep.dft b/resources/examples/testfiles/dft/fdep.dft new file mode 100644 index 000000000..e597c46ce --- /dev/null +++ b/resources/examples/testfiles/dft/fdep.dft @@ -0,0 +1,8 @@ +toplevel "System"; +"System" or "Power" "Machine"; +"Power" fdep "B_Power" "P" "B"; +"Machine" or "P" "B"; + +"B_Power" lambda=0.5 dorm=0; +"P" lambda=0.5 dorm=0; +"B" lambda=0.5 dorm=0.5; diff --git a/resources/examples/testfiles/dft/fdep2.dft b/resources/examples/testfiles/dft/fdep2.dft new file mode 100644 index 000000000..a444ed4be --- /dev/null +++ b/resources/examples/testfiles/dft/fdep2.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C"; +"F" fdep "B" "C"; +"B" lambda=0.5 dorm=0; +"C" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep3.dft b/resources/examples/testfiles/dft/fdep3.dft new file mode 100644 index 000000000..3815c9973 --- /dev/null +++ b/resources/examples/testfiles/dft/fdep3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C" "F"; +"F" fdep "B" "C"; +"B" lambda=0.4 dorm=0; +"C" lambda=0.8 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep4.dft b/resources/examples/testfiles/dft/fdep4.dft new file mode 100644 index 000000000..7e3c5642a --- /dev/null +++ b/resources/examples/testfiles/dft/fdep4.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" or "F" "B"; +"F" fdep "E" "C" "D"; +"B" wsp "C" "D"; +"C" lambda=1 dorm=0; +"D" lambda=1 dorm=0.5; +"E" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep5.dft b/resources/examples/testfiles/dft/fdep5.dft new file mode 100644 index 000000000..2e0625dfb --- /dev/null +++ b/resources/examples/testfiles/dft/fdep5.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" and "B" "C" "D" "E"; +"F" fdep "B" "C" "D"; +"B" lambda=0.5 dorm=0; +"C" lambda=0.5 dorm=0; +"D" lambda=0.5 dorm=0; +"E" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/or.dft b/resources/examples/testfiles/dft/or.dft new file mode 100644 index 000000000..b1003da11 --- /dev/null +++ b/resources/examples/testfiles/dft/or.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" or "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/pand.dft b/resources/examples/testfiles/dft/pand.dft new file mode 100644 index 000000000..d752517b4 --- /dev/null +++ b/resources/examples/testfiles/dft/pand.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" pand "B" "C"; +"B" lambda=0.4 dorm=0.3; +"C" lambda=0.2 dorm=0.3; diff --git a/resources/examples/testfiles/dft/pdep.dft b/resources/examples/testfiles/dft/pdep.dft new file mode 100644 index 000000000..f8cb0382b --- /dev/null +++ b/resources/examples/testfiles/dft/pdep.dft @@ -0,0 +1,12 @@ +// From Junges2015 +// Example 3.19 + +toplevel "SF"; +"SF" or "A" "B" "PDEP"; +"A" pand "S" "MA"; +"B" and "MA" "MB"; +"PDEP" pdep=0.2 "MA" "S"; + +"S" lambda=0.5 dorm=0; +"MA" lambda=0.5 dorm=0; +"MB" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep2.dft b/resources/examples/testfiles/dft/pdep2.dft new file mode 100644 index 000000000..ab1c7a9b8 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep2.dft @@ -0,0 +1,9 @@ +toplevel "SF"; +"SF" or "A" "B" "PDEP"; +"A" pand "S" "MA"; +"B" and "MA" "MB"; +"PDEP" pdep=0.2 "MA" "S" "MB"; + +"S" lambda=0.5 dorm=0; +"MA" lambda=0.5 dorm=0; +"MB" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep3.dft b/resources/examples/testfiles/dft/pdep3.dft new file mode 100644 index 000000000..a9a73f472 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C" "F"; +"F" pdep=0.3 "B" "C"; +"B" lambda=0.4 dorm=0; +"C" lambda=0.8 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep4.dft b/resources/examples/testfiles/dft/pdep4.dft new file mode 100644 index 000000000..eace91847 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep4.dft @@ -0,0 +1,7 @@ +toplevel "SF"; +"SF" pand "S" "A" "B"; +"PDEP" pdep=0.2 "S" "A" "B"; + +"S" lambda=0.5 dorm=0; +"A" lambda=0.5 dorm=0; +"B" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/por.dft b/resources/examples/testfiles/dft/por.dft new file mode 100644 index 000000000..020687f62 --- /dev/null +++ b/resources/examples/testfiles/dft/por.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" por "B" "C" "D"; +"B" lambda=0.4 dorm=0.0; +"C" lambda=0.2 dorm=0.0; +"D" lambda=0.2 dorm=0.0; diff --git a/resources/examples/testfiles/dft/seq.dft b/resources/examples/testfiles/dft/seq.dft new file mode 100644 index 000000000..8f5459fd2 --- /dev/null +++ b/resources/examples/testfiles/dft/seq.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C"; +"X" seq "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq2.dft b/resources/examples/testfiles/dft/seq2.dft new file mode 100644 index 000000000..408d4c26d --- /dev/null +++ b/resources/examples/testfiles/dft/seq2.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" and "B" "C" "D"; +"X" seq "B" "C" "D"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; +"D" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq3.dft b/resources/examples/testfiles/dft/seq3.dft new file mode 100644 index 000000000..b22b9e8b6 --- /dev/null +++ b/resources/examples/testfiles/dft/seq3.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" and "C" "D"; +"X" seq "B" "C" "D"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; +"D" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq4.dft b/resources/examples/testfiles/dft/seq4.dft new file mode 100644 index 000000000..60bf149af --- /dev/null +++ b/resources/examples/testfiles/dft/seq4.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" and "T1" "B3"; +"T1" or "B1" "B2"; +"X" seq "B1" "B2" "B3"; +"B1" lambda=0.5 dorm=0.3; +"B2" lambda=0.5 dorm=0.3; +"B3" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq5.dft b/resources/examples/testfiles/dft/seq5.dft new file mode 100644 index 000000000..77b13ddeb --- /dev/null +++ b/resources/examples/testfiles/dft/seq5.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" and "T1" "T2"; +"T1" pand "B1" "B2"; +"T2" pand "B3" "B4"; +"X" seq "B4" "B3"; +"B1" lambda=0.7 dorm=0.3; +"B2" lambda=0.5 dorm=0.3; +"B3" lambda=0.5 dorm=0.3; +"B4" lambda=0.7 dorm=0.3; diff --git a/resources/examples/testfiles/dft/spare.dft b/resources/examples/testfiles/dft/spare.dft new file mode 100644 index 000000000..4c5d44ff4 --- /dev/null +++ b/resources/examples/testfiles/dft/spare.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" wsp "I" "M"; +"I" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare2.dft b/resources/examples/testfiles/dft/spare2.dft new file mode 100644 index 000000000..21b40cf73 --- /dev/null +++ b/resources/examples/testfiles/dft/spare2.dft @@ -0,0 +1,8 @@ +toplevel "A"; +"A" or "B" "C"; +"B" wsp "I" "J"; +"C" wsp "M" "J"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare3.dft b/resources/examples/testfiles/dft/spare3.dft new file mode 100644 index 000000000..ba0ac01d4 --- /dev/null +++ b/resources/examples/testfiles/dft/spare3.dft @@ -0,0 +1,10 @@ +toplevel "A"; +"A" or "B" "C" "D"; +"B" wsp "I" "M"; +"C" wsp "J" "M"; +"D" wsp "K" "M"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare4.dft b/resources/examples/testfiles/dft/spare4.dft new file mode 100644 index 000000000..a217c6e43 --- /dev/null +++ b/resources/examples/testfiles/dft/spare4.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" and "B" "C"; +"B" wsp "I" "J" "K"; +"C" wsp "M" "J"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare5.dft b/resources/examples/testfiles/dft/spare5.dft new file mode 100644 index 000000000..0cd15bf0e --- /dev/null +++ b/resources/examples/testfiles/dft/spare5.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" wsp "I" "B"; +"B" or "C" "J"; +"C" or "K" "L"; +"I" lambda=0.5 dorm=0; +"J" lambda=0.5 dorm=0; +"K" lambda=0.5 dorm=0; +"L" lambda=0.5 dorm=0; + diff --git a/resources/examples/testfiles/dft/spare6.dft b/resources/examples/testfiles/dft/spare6.dft new file mode 100644 index 000000000..d5f2b270b --- /dev/null +++ b/resources/examples/testfiles/dft/spare6.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" or "I" "B"; +"B" wsp "J" "M"; +"I" lambda=0.5 dorm=0.5; +"J" lambda=0.5 dorm=0.5; +"M" lambda=0.5 dorm=0.5; + diff --git a/resources/examples/testfiles/dft/spare7.dft b/resources/examples/testfiles/dft/spare7.dft new file mode 100644 index 000000000..a16429e6f --- /dev/null +++ b/resources/examples/testfiles/dft/spare7.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" wsp "K" "J" "I"; +"I" lambda=0.5 dorm=0.5; +"J" lambda=1 dorm=0.5; +"K" lambda=0.5 dorm=0.5; diff --git a/resources/examples/testfiles/dft/spare8.dft b/resources/examples/testfiles/dft/spare8.dft new file mode 100644 index 000000000..c67eaf022 --- /dev/null +++ b/resources/examples/testfiles/dft/spare8.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" wsp "I" "B"; +"B" wsp "J" "K"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/voting.dft b/resources/examples/testfiles/dft/voting.dft new file mode 100644 index 000000000..5c648d424 --- /dev/null +++ b/resources/examples/testfiles/dft/voting.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 1of3 "B" "C" "D"; +"B" lambda=0.1 dorm=0; +"C" lambda=0.2 dorm=0; +"D" lambda=0.3 dorm=0; diff --git a/resources/examples/testfiles/dft/voting2.dft b/resources/examples/testfiles/dft/voting2.dft new file mode 100644 index 000000000..9cdf299f3 --- /dev/null +++ b/resources/examples/testfiles/dft/voting2.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 1of3 "B" "C" "D"; +"B" lambda=0.3 dorm=0; +"C" lambda=0.4 dorm=0; +"D" lambda=1 dorm=0; diff --git a/resources/examples/testfiles/dft/voting3.dft b/resources/examples/testfiles/dft/voting3.dft new file mode 100644 index 000000000..107408fce --- /dev/null +++ b/resources/examples/testfiles/dft/voting3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 2of3 "B" "C" "D"; +"B" lambda=0.3 dorm=0; +"C" lambda=0.4 dorm=0; +"D" lambda=1 dorm=0; diff --git a/resources/examples/testfiles/dft/voting4.dft b/resources/examples/testfiles/dft/voting4.dft new file mode 100644 index 000000000..412df12e5 --- /dev/null +++ b/resources/examples/testfiles/dft/voting4.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" 2of3 "B" "C" "D"; +"D" or "E"; +"B" lambda=1 dorm=0.0; +"C" lambda=1 dorm=0.0; +"E" lambda=1 dorm=0.0; diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index a2fdd4610..8c57795d6 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -85,7 +85,87 @@ namespace { TYPED_TEST(DftModelCheckerTest, AndMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/and.dft"); - EXPECT_FLOAT_EQ(result, 3.0); + EXPECT_FLOAT_EQ(result, 3); + } + + TYPED_TEST(DftModelCheckerTest, OrMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/or.dft"); + EXPECT_FLOAT_EQ(result, 1); + } + + TYPED_TEST(DftModelCheckerTest, VotingMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting.dft"); + EXPECT_FLOAT_EQ(result, 5/3); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting2.dft"); + EXPECT_FLOAT_EQ(result, 10/17); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting3.dft"); + EXPECT_FLOAT_EQ(result, 1.73562); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting4.dft"); + EXPECT_FLOAT_EQ(result, 5/6); + } + + TYPED_TEST(DftModelCheckerTest, PandMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pand.dft"); + EXPECT_EQ(result, storm::utility::infinity()); + } + + TYPED_TEST(DftModelCheckerTest, PorMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/por.dft"); + EXPECT_EQ(result, storm::utility::infinity()); + } + + TYPED_TEST(DftModelCheckerTest, FdepMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft"); + EXPECT_FLOAT_EQ(result, 2/3); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep2.dft"); + EXPECT_FLOAT_EQ(result, 2); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep3.dft"); + EXPECT_FLOAT_EQ(result, 2.5); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft"); + EXPECT_FLOAT_EQ(result, 1); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"); + EXPECT_FLOAT_EQ(result, 3); + } + + TYPED_TEST(DftModelCheckerTest, PdepMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep.dft"); + EXPECT_FLOAT_EQ(result, 8/3); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); + EXPECT_FLOAT_EQ(result, 38/15); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft"); + EXPECT_FLOAT_EQ(result, 2.79167); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"); + EXPECT_EQ(result, storm::utility::infinity()); + } + TYPED_TEST(DftModelCheckerTest, SpareMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare.dft"); + EXPECT_FLOAT_EQ(result, 3.53846); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare2.dft"); + EXPECT_FLOAT_EQ(result, 1.86957); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare3.dft"); + EXPECT_FLOAT_EQ(result, 1.27273); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare4.dft"); + EXPECT_FLOAT_EQ(result, 4.8459); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft"); + EXPECT_FLOAT_EQ(result, 8/3); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare6.dft"); + EXPECT_FLOAT_EQ(result, 1.4); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare7.dft"); + EXPECT_FLOAT_EQ(result, 3.67333); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare8.dft"); + EXPECT_FLOAT_EQ(result, 4.78846); // DFTCalc says 4.33779 + } + TYPED_TEST(DftModelCheckerTest, SeqMTTF) { + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq.dft"); + EXPECT_FLOAT_EQ(result, 4); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq2.dft"); + EXPECT_FLOAT_EQ(result, 6); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq3.dft"); + EXPECT_FLOAT_EQ(result, 6); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq4.dft"); + EXPECT_FLOAT_EQ(result, 6); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq5.dft"); + EXPECT_EQ(result, storm::utility::infinity()); } } From 263e6ed5f85318fd44da050b5a83c93d7d77e3b7 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 11:23:38 +0100 Subject: [PATCH 189/647] Removed generated files from git --- .gitignore | 2 - resources/3rdparty/cudd-3.0.0/Makefile.in | 3190 ---- resources/3rdparty/cudd-3.0.0/aclocal.m4 | 1256 -- resources/3rdparty/cudd-3.0.0/configure | 19890 -------------------- 4 files changed, 24338 deletions(-) delete mode 100644 resources/3rdparty/cudd-3.0.0/Makefile.in delete mode 100644 resources/3rdparty/cudd-3.0.0/aclocal.m4 delete mode 100755 resources/3rdparty/cudd-3.0.0/configure diff --git a/.gitignore b/.gitignore index 3c761969d..13689e55f 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,5 @@ nbproject/ *.out resources/3rdparty/cudd-3.0.0/Makefile.in resources/3rdparty/cudd-3.0.0/aclocal.m4 -# Python config -stormpy/setup.cfg # Travis helpers travis/mtime_cache/cache.json diff --git a/resources/3rdparty/cudd-3.0.0/Makefile.in b/resources/3rdparty/cudd-3.0.0/Makefile.in deleted file mode 100644 index 7bfa478ae..000000000 --- a/resources/3rdparty/cudd-3.0.0/Makefile.in +++ /dev/null @@ -1,3190 +0,0 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2017 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -@DDDMP_TRUE@am__append_1 = dddmp/dddmp.h -@OBJ_TRUE@am__append_2 = cplusplus/cuddObj.hh -check_PROGRAMS = cudd/testcudd$(EXEEXT) cudd/testextra$(EXEEXT) \ - st/testst$(EXEEXT) mtr/testmtr$(EXEEXT) \ - dddmp/testdddmp$(EXEEXT) cplusplus/testobj$(EXEEXT) \ - cplusplus/testmulti$(EXEEXT) nanotrav/nanotrav$(EXEEXT) -@CROSS_COMPILING_FALSE@am__append_3 = cudd/test_cudd.test \ -@CROSS_COMPILING_FALSE@ st/test_st.test mtr/test_mtr.test \ -@CROSS_COMPILING_FALSE@ dddmp/test_dddmp.test \ -@CROSS_COMPILING_FALSE@ cplusplus/test_obj.test \ -@CROSS_COMPILING_FALSE@ nanotrav/test_ntrv.test -@DDDMP_TRUE@am__append_4 = $(dddmp_sources) -@DDDMP_FALSE@am__append_5 = dddmp/libdddmp.la -@OBJ_TRUE@am__append_6 = $(cplusplus_sources) -@OBJ_FALSE@am__append_7 = cplusplus/libobj.la -@HAVE_PDFLATEX_TRUE@am__append_8 = doc/cudd.pdf doc/cudd.aux doc/cudd.idx doc/cudd.ilg doc/cudd.ind \ -@HAVE_PDFLATEX_TRUE@ doc/cudd.log doc/cudd.out doc/cudd.toc - -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/modern_cxx.m4 $(top_srcdir)/m4/w32.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(dist_check_DATA) \ - $(am__include_HEADERS_DIST) $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = Doxyfile doc/cudd.tex dddmp/exp/test1.sh \ - dddmp/exp/test2.sh dddmp/exp/test3.sh dddmp/exp/test4.sh \ - dddmp/exp/test5.sh dddmp/exp/test6.sh dddmp/exp/test7.sh -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" -LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) -cplusplus_libobj_la_LIBADD = -am__cplusplus_libobj_la_SOURCES_DIST = cplusplus/cuddObj.hh \ - cplusplus/cuddObj.cc -am__dirstamp = $(am__leading_dot)dirstamp -am__objects_1 = cplusplus/cplusplus_libobj_la-cuddObj.lo -@OBJ_FALSE@am_cplusplus_libobj_la_OBJECTS = $(am__objects_1) -cplusplus_libobj_la_OBJECTS = $(am_cplusplus_libobj_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -@OBJ_FALSE@am_cplusplus_libobj_la_rpath = -cudd_libcudd_la_DEPENDENCIES = -am__cudd_libcudd_la_SOURCES_DIST = cudd/cudd.h cudd/cuddInt.h \ - cudd/cuddAddAbs.c cudd/cuddAddApply.c cudd/cuddAddFind.c \ - cudd/cuddAddInv.c cudd/cuddAddIte.c cudd/cuddAddNeg.c \ - cudd/cuddAddWalsh.c cudd/cuddAndAbs.c cudd/cuddAnneal.c \ - cudd/cuddApa.c cudd/cuddAPI.c cudd/cuddApprox.c \ - cudd/cuddBddAbs.c cudd/cuddBddCorr.c cudd/cuddBddIte.c \ - cudd/cuddBridge.c cudd/cuddCache.c cudd/cuddCheck.c \ - cudd/cuddClip.c cudd/cuddCof.c cudd/cuddCompose.c \ - cudd/cuddDecomp.c cudd/cuddEssent.c cudd/cuddExact.c \ - cudd/cuddExport.c cudd/cuddGenCof.c cudd/cuddGenetic.c \ - cudd/cuddGroup.c cudd/cuddHarwell.c cudd/cuddInit.c \ - cudd/cuddInteract.c cudd/cuddLCache.c cudd/cuddLevelQ.c \ - cudd/cuddLinear.c cudd/cuddLiteral.c cudd/cuddMatMult.c \ - cudd/cuddPriority.c cudd/cuddRead.c cudd/cuddRef.c \ - cudd/cuddReorder.c cudd/cuddSat.c cudd/cuddSign.c \ - cudd/cuddSolve.c cudd/cuddSplit.c cudd/cuddSubsetHB.c \ - cudd/cuddSubsetSP.c cudd/cuddSymmetry.c cudd/cuddTable.c \ - cudd/cuddUtil.c cudd/cuddWindow.c cudd/cuddZddCount.c \ - cudd/cuddZddFuncs.c cudd/cuddZddGroup.c cudd/cuddZddIsop.c \ - cudd/cuddZddLin.c cudd/cuddZddMisc.c cudd/cuddZddPort.c \ - cudd/cuddZddReord.c cudd/cuddZddSetop.c cudd/cuddZddSymm.c \ - cudd/cuddZddUtil.c util/util.h util/cstringstream.h \ - util/cpu_stats.c util/cpu_time.c util/cstringstream.c \ - util/datalimit.c util/pathsearch.c util/pipefork.c \ - util/prtime.c util/safe_mem.c util/strsav.c util/texpand.c \ - util/ucbqsort.c st/st.h st/st.c epd/epd.c epd/epdInt.h \ - epd/epd.h mtr/mtr.h mtr/mtrInt.h mtr/mtrBasic.c mtr/mtrGroup.c \ - dddmp/dddmp.h dddmp/dddmpInt.h dddmp/dddmpBinary.c \ - dddmp/dddmpConvert.c dddmp/dddmpDbg.c dddmp/dddmpLoad.c \ - dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c dddmp/dddmpNodeBdd.c \ - dddmp/dddmpNodeCnf.c dddmp/dddmpStoreAdd.c \ - dddmp/dddmpStoreBdd.c dddmp/dddmpStoreCnf.c \ - dddmp/dddmpStoreMisc.c dddmp/dddmpUtil.c cplusplus/cuddObj.hh \ - cplusplus/cuddObj.cc -am__objects_2 = dddmp/cudd_libcudd_la-dddmpBinary.lo \ - dddmp/cudd_libcudd_la-dddmpConvert.lo \ - dddmp/cudd_libcudd_la-dddmpDbg.lo \ - dddmp/cudd_libcudd_la-dddmpLoad.lo \ - dddmp/cudd_libcudd_la-dddmpLoadCnf.lo \ - dddmp/cudd_libcudd_la-dddmpNodeAdd.lo \ - dddmp/cudd_libcudd_la-dddmpNodeBdd.lo \ - dddmp/cudd_libcudd_la-dddmpNodeCnf.lo \ - dddmp/cudd_libcudd_la-dddmpStoreAdd.lo \ - dddmp/cudd_libcudd_la-dddmpStoreBdd.lo \ - dddmp/cudd_libcudd_la-dddmpStoreCnf.lo \ - dddmp/cudd_libcudd_la-dddmpStoreMisc.lo \ - dddmp/cudd_libcudd_la-dddmpUtil.lo -@DDDMP_TRUE@am__objects_3 = $(am__objects_2) -am__objects_4 = cplusplus/cudd_libcudd_la-cuddObj.lo -@OBJ_TRUE@am__objects_5 = $(am__objects_4) -am_cudd_libcudd_la_OBJECTS = cudd/cudd_libcudd_la-cuddAddAbs.lo \ - cudd/cudd_libcudd_la-cuddAddApply.lo \ - cudd/cudd_libcudd_la-cuddAddFind.lo \ - cudd/cudd_libcudd_la-cuddAddInv.lo \ - cudd/cudd_libcudd_la-cuddAddIte.lo \ - cudd/cudd_libcudd_la-cuddAddNeg.lo \ - cudd/cudd_libcudd_la-cuddAddWalsh.lo \ - cudd/cudd_libcudd_la-cuddAndAbs.lo \ - cudd/cudd_libcudd_la-cuddAnneal.lo \ - cudd/cudd_libcudd_la-cuddApa.lo \ - cudd/cudd_libcudd_la-cuddAPI.lo \ - cudd/cudd_libcudd_la-cuddApprox.lo \ - cudd/cudd_libcudd_la-cuddBddAbs.lo \ - cudd/cudd_libcudd_la-cuddBddCorr.lo \ - cudd/cudd_libcudd_la-cuddBddIte.lo \ - cudd/cudd_libcudd_la-cuddBridge.lo \ - cudd/cudd_libcudd_la-cuddCache.lo \ - cudd/cudd_libcudd_la-cuddCheck.lo \ - cudd/cudd_libcudd_la-cuddClip.lo \ - cudd/cudd_libcudd_la-cuddCof.lo \ - cudd/cudd_libcudd_la-cuddCompose.lo \ - cudd/cudd_libcudd_la-cuddDecomp.lo \ - cudd/cudd_libcudd_la-cuddEssent.lo \ - cudd/cudd_libcudd_la-cuddExact.lo \ - cudd/cudd_libcudd_la-cuddExport.lo \ - cudd/cudd_libcudd_la-cuddGenCof.lo \ - cudd/cudd_libcudd_la-cuddGenetic.lo \ - cudd/cudd_libcudd_la-cuddGroup.lo \ - cudd/cudd_libcudd_la-cuddHarwell.lo \ - cudd/cudd_libcudd_la-cuddInit.lo \ - cudd/cudd_libcudd_la-cuddInteract.lo \ - cudd/cudd_libcudd_la-cuddLCache.lo \ - cudd/cudd_libcudd_la-cuddLevelQ.lo \ - cudd/cudd_libcudd_la-cuddLinear.lo \ - cudd/cudd_libcudd_la-cuddLiteral.lo \ - cudd/cudd_libcudd_la-cuddMatMult.lo \ - cudd/cudd_libcudd_la-cuddPriority.lo \ - cudd/cudd_libcudd_la-cuddRead.lo \ - cudd/cudd_libcudd_la-cuddRef.lo \ - cudd/cudd_libcudd_la-cuddReorder.lo \ - cudd/cudd_libcudd_la-cuddSat.lo \ - cudd/cudd_libcudd_la-cuddSign.lo \ - cudd/cudd_libcudd_la-cuddSolve.lo \ - cudd/cudd_libcudd_la-cuddSplit.lo \ - cudd/cudd_libcudd_la-cuddSubsetHB.lo \ - cudd/cudd_libcudd_la-cuddSubsetSP.lo \ - cudd/cudd_libcudd_la-cuddSymmetry.lo \ - cudd/cudd_libcudd_la-cuddTable.lo \ - cudd/cudd_libcudd_la-cuddUtil.lo \ - cudd/cudd_libcudd_la-cuddWindow.lo \ - cudd/cudd_libcudd_la-cuddZddCount.lo \ - cudd/cudd_libcudd_la-cuddZddFuncs.lo \ - cudd/cudd_libcudd_la-cuddZddGroup.lo \ - cudd/cudd_libcudd_la-cuddZddIsop.lo \ - cudd/cudd_libcudd_la-cuddZddLin.lo \ - cudd/cudd_libcudd_la-cuddZddMisc.lo \ - cudd/cudd_libcudd_la-cuddZddPort.lo \ - cudd/cudd_libcudd_la-cuddZddReord.lo \ - cudd/cudd_libcudd_la-cuddZddSetop.lo \ - cudd/cudd_libcudd_la-cuddZddSymm.lo \ - cudd/cudd_libcudd_la-cuddZddUtil.lo \ - util/cudd_libcudd_la-cpu_stats.lo \ - util/cudd_libcudd_la-cpu_time.lo \ - util/cudd_libcudd_la-cstringstream.lo \ - util/cudd_libcudd_la-datalimit.lo \ - util/cudd_libcudd_la-pathsearch.lo \ - util/cudd_libcudd_la-pipefork.lo \ - util/cudd_libcudd_la-prtime.lo \ - util/cudd_libcudd_la-safe_mem.lo \ - util/cudd_libcudd_la-strsav.lo util/cudd_libcudd_la-texpand.lo \ - util/cudd_libcudd_la-ucbqsort.lo st/cudd_libcudd_la-st.lo \ - epd/cudd_libcudd_la-epd.lo mtr/cudd_libcudd_la-mtrBasic.lo \ - mtr/cudd_libcudd_la-mtrGroup.lo $(am__objects_3) \ - $(am__objects_5) -cudd_libcudd_la_OBJECTS = $(am_cudd_libcudd_la_OBJECTS) -cudd_libcudd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ - $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ - $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(cudd_libcudd_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -dddmp_libdddmp_la_LIBADD = -am__dddmp_libdddmp_la_SOURCES_DIST = dddmp/dddmp.h dddmp/dddmpInt.h \ - dddmp/dddmpBinary.c dddmp/dddmpConvert.c dddmp/dddmpDbg.c \ - dddmp/dddmpLoad.c dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c \ - dddmp/dddmpNodeBdd.c dddmp/dddmpNodeCnf.c \ - dddmp/dddmpStoreAdd.c dddmp/dddmpStoreBdd.c \ - dddmp/dddmpStoreCnf.c dddmp/dddmpStoreMisc.c dddmp/dddmpUtil.c -am__objects_6 = dddmp/dddmp_libdddmp_la-dddmpBinary.lo \ - dddmp/dddmp_libdddmp_la-dddmpConvert.lo \ - dddmp/dddmp_libdddmp_la-dddmpDbg.lo \ - dddmp/dddmp_libdddmp_la-dddmpLoad.lo \ - dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo \ - dddmp/dddmp_libdddmp_la-dddmpUtil.lo -@DDDMP_FALSE@am_dddmp_libdddmp_la_OBJECTS = $(am__objects_6) -dddmp_libdddmp_la_OBJECTS = $(am_dddmp_libdddmp_la_OBJECTS) -@DDDMP_FALSE@am_dddmp_libdddmp_la_rpath = -am_cplusplus_testmulti_OBJECTS = \ - cplusplus/cplusplus_testmulti-testmulti.$(OBJEXT) -cplusplus_testmulti_OBJECTS = $(am_cplusplus_testmulti_OBJECTS) -@OBJ_FALSE@cplusplus_testmulti_DEPENDENCIES = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testmulti_DEPENDENCIES = cudd/libcudd.la -cplusplus_testmulti_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ - $(AM_CXXFLAGS) $(CXXFLAGS) $(cplusplus_testmulti_LDFLAGS) \ - $(LDFLAGS) -o $@ -am_cplusplus_testobj_OBJECTS = \ - cplusplus/cplusplus_testobj-testobj.$(OBJEXT) -cplusplus_testobj_OBJECTS = $(am_cplusplus_testobj_OBJECTS) -@OBJ_FALSE@cplusplus_testobj_DEPENDENCIES = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testobj_DEPENDENCIES = cudd/libcudd.la -am_cudd_testcudd_OBJECTS = cudd/cudd_testcudd-testcudd.$(OBJEXT) -cudd_testcudd_OBJECTS = $(am_cudd_testcudd_OBJECTS) -cudd_testcudd_DEPENDENCIES = cudd/libcudd.la -am_cudd_testextra_OBJECTS = cudd/cudd_testextra-testextra.$(OBJEXT) -cudd_testextra_OBJECTS = $(am_cudd_testextra_OBJECTS) -cudd_testextra_DEPENDENCIES = cudd/libcudd.la -am_dddmp_testdddmp_OBJECTS = \ - dddmp/dddmp_testdddmp-testdddmp.$(OBJEXT) -dddmp_testdddmp_OBJECTS = $(am_dddmp_testdddmp_OBJECTS) -@DDDMP_FALSE@dddmp_testdddmp_DEPENDENCIES = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@dddmp_testdddmp_DEPENDENCIES = cudd/libcudd.la -am_mtr_testmtr_OBJECTS = mtr/mtr_testmtr-testmtr.$(OBJEXT) -mtr_testmtr_OBJECTS = $(am_mtr_testmtr_OBJECTS) -mtr_testmtr_DEPENDENCIES = cudd/libcudd.la -am_nanotrav_nanotrav_OBJECTS = \ - nanotrav/nanotrav_nanotrav-bnet.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-chkMterm.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-main.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrBddTest.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntr.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrHeap.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrMflow.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrShort.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrZddTest.$(OBJEXT) -nanotrav_nanotrav_OBJECTS = $(am_nanotrav_nanotrav_OBJECTS) -@DDDMP_FALSE@nanotrav_nanotrav_DEPENDENCIES = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@nanotrav_nanotrav_DEPENDENCIES = cudd/libcudd.la -am_st_testst_OBJECTS = st/st_testst-testst.$(OBJEXT) -st_testst_OBJECTS = $(am_st_testst_OBJECTS) -st_testst_DEPENDENCIES = cudd/libcudd.la -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CXXFLAGS) $(CXXFLAGS) -AM_V_CXX = $(am__v_CXX_@AM_V@) -am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) -am__v_CXX_0 = @echo " CXX " $@; -am__v_CXX_1 = -CXXLD = $(CXX) -CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ - $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) -am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) -am__v_CXXLD_0 = @echo " CXXLD " $@; -am__v_CXXLD_1 = -SOURCES = $(cplusplus_libobj_la_SOURCES) $(cudd_libcudd_la_SOURCES) \ - $(dddmp_libdddmp_la_SOURCES) $(cplusplus_testmulti_SOURCES) \ - $(cplusplus_testobj_SOURCES) $(cudd_testcudd_SOURCES) \ - $(cudd_testextra_SOURCES) $(dddmp_testdddmp_SOURCES) \ - $(mtr_testmtr_SOURCES) $(nanotrav_nanotrav_SOURCES) \ - $(st_testst_SOURCES) -DIST_SOURCES = $(am__cplusplus_libobj_la_SOURCES_DIST) \ - $(am__cudd_libcudd_la_SOURCES_DIST) \ - $(am__dddmp_libdddmp_la_SOURCES_DIST) \ - $(cplusplus_testmulti_SOURCES) $(cplusplus_testobj_SOURCES) \ - $(cudd_testcudd_SOURCES) $(cudd_testextra_SOURCES) \ - $(dddmp_testdddmp_SOURCES) $(mtr_testmtr_SOURCES) \ - $(nanotrav_nanotrav_SOURCES) $(st_testst_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__include_HEADERS_DIST = cudd/cudd.h mtr/mtr.h dddmp/dddmp.h \ - cplusplus/cuddObj.hh -HEADERS = $(include_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ - $(LISP)config.h.in -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope -AM_RECURSIVE_TARGETS = cscope check recheck -am__tty_colors_dummy = \ - mgn= red= grn= lgn= blu= brg= std=; \ - am__color_tests=no -am__tty_colors = { \ - $(am__tty_colors_dummy); \ - if test "X$(AM_COLOR_TESTS)" = Xno; then \ - am__color_tests=no; \ - elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ - am__color_tests=yes; \ - elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ - am__color_tests=yes; \ - fi; \ - if test $$am__color_tests = yes; then \ - red=''; \ - grn=''; \ - lgn=''; \ - blu=''; \ - mgn=''; \ - brg=''; \ - std=''; \ - fi; \ -} -am__recheck_rx = ^[ ]*:recheck:[ ]* -am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* -am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* -# A command that, given a newline-separated list of test names on the -# standard input, print the name of the tests that are to be re-run -# upon "make recheck". -am__list_recheck_tests = $(AWK) '{ \ - recheck = 1; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - { \ - if ((getline line2 < ($$0 ".log")) < 0) \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ - { \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ - { \ - break; \ - } \ - }; \ - if (recheck) \ - print $$0; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# A command that, given a newline-separated list of test names on the -# standard input, create the global log from their .trs and .log files. -am__create_global_log = $(AWK) ' \ -function fatal(msg) \ -{ \ - print "fatal: making $@: " msg | "cat >&2"; \ - exit 1; \ -} \ -function rst_section(header) \ -{ \ - print header; \ - len = length(header); \ - for (i = 1; i <= len; i = i + 1) \ - printf "="; \ - printf "\n\n"; \ -} \ -{ \ - copy_in_global_log = 1; \ - global_test_result = "RUN"; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".trs"); \ - if (line ~ /$(am__global_test_result_rx)/) \ - { \ - sub("$(am__global_test_result_rx)", "", line); \ - sub("[ ]*$$", "", line); \ - global_test_result = line; \ - } \ - else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ - copy_in_global_log = 0; \ - }; \ - if (copy_in_global_log) \ - { \ - rst_section(global_test_result ": " $$0); \ - while ((rc = (getline line < ($$0 ".log"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".log"); \ - print line; \ - }; \ - printf "\n"; \ - }; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# Restructured Text title. -am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } -# Solaris 10 'make', and several other traditional 'make' implementations, -# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it -# by disabling -e (using the XSI extension "set +e") if it's set. -am__sh_e_setup = case $$- in *e*) set +e;; esac -# Default flags passed to test drivers. -am__common_driver_flags = \ - --color-tests "$$am__color_tests" \ - --enable-hard-errors "$$am__enable_hard_errors" \ - --expect-failure "$$am__expect_failure" -# To be inserted before the command running the test. Creates the -# directory for the log if needed. Stores in $dir the directory -# containing $f, in $tst the test, in $log the log. Executes the -# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and -# passes TESTS_ENVIRONMENT. Set up options for the wrapper that -# will run the test scripts (or their associated LOG_COMPILER, if -# thy have one). -am__check_pre = \ -$(am__sh_e_setup); \ -$(am__vpath_adj_setup) $(am__vpath_adj) \ -$(am__tty_colors); \ -srcdir=$(srcdir); export srcdir; \ -case "$@" in \ - */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ - *) am__odir=.;; \ -esac; \ -test "x$$am__odir" = x"." || test -d "$$am__odir" \ - || $(MKDIR_P) "$$am__odir" || exit $$?; \ -if test -f "./$$f"; then dir=./; \ -elif test -f "$$f"; then dir=; \ -else dir="$(srcdir)/"; fi; \ -tst=$$dir$$f; log='$@'; \ -if test -n '$(DISABLE_HARD_ERRORS)'; then \ - am__enable_hard_errors=no; \ -else \ - am__enable_hard_errors=yes; \ -fi; \ -case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ - am__expect_failure=yes;; \ - *) \ - am__expect_failure=no;; \ -esac; \ -$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) -# A shell command to get the names of the tests scripts with any registered -# extension removed (i.e., equivalently, the names of the test logs, with -# the '.log' extension removed). The result is saved in the shell variable -# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, -# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", -# since that might cause problem with VPATH rewrites for suffix-less tests. -# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. -am__set_TESTS_bases = \ - bases='$(TEST_LOGS)'; \ - bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ - bases=`echo $$bases` -RECHECK_LOGS = $(TEST_LOGS) -TEST_SUITE_LOG = test-suite.log -TEST_EXTENSIONS = @EXEEXT@ .test -am__test_logs1 = $(TESTS:=.log) -am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) -TEST_LOGS = $(am__test_logs2:.test.log=.log) -TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ - $(TEST_LOG_FLAGS) -am__set_b = \ - case '$@' in \ - */*) \ - case '$*' in \ - */*) b='$*';; \ - *) b=`echo '$@' | sed 's/\.log$$//'`; \ - esac;; \ - *) \ - b='$*';; \ - esac -am__DIST_COMMON = $(srcdir)/Doxyfile.in $(srcdir)/Makefile.in \ - $(srcdir)/config.h.in $(top_srcdir)/build-aux/ar-lib \ - $(top_srcdir)/build-aux/compile \ - $(top_srcdir)/build-aux/config.guess \ - $(top_srcdir)/build-aux/config.sub \ - $(top_srcdir)/build-aux/depcomp \ - $(top_srcdir)/build-aux/install-sh \ - $(top_srcdir)/build-aux/ltmain.sh \ - $(top_srcdir)/build-aux/missing \ - $(top_srcdir)/build-aux/tap-driver.sh \ - $(top_srcdir)/cplusplus/Included.am \ - $(top_srcdir)/cudd/Included.am $(top_srcdir)/dddmp/Included.am \ - $(top_srcdir)/dddmp/exp/test1.sh.in \ - $(top_srcdir)/dddmp/exp/test2.sh.in \ - $(top_srcdir)/dddmp/exp/test3.sh.in \ - $(top_srcdir)/dddmp/exp/test4.sh.in \ - $(top_srcdir)/dddmp/exp/test5.sh.in \ - $(top_srcdir)/dddmp/exp/test6.sh.in \ - $(top_srcdir)/dddmp/exp/test7.sh.in \ - $(top_srcdir)/doc/Included.am $(top_srcdir)/doc/cudd.tex.in \ - $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am \ - $(top_srcdir)/nanotrav/Included.am \ - $(top_srcdir)/st/Included.am $(top_srcdir)/util/Included.am \ - README build-aux/ar-lib build-aux/compile \ - build-aux/config.guess build-aux/config.sub build-aux/depcomp \ - build-aux/install-sh build-aux/ltmain.sh build-aux/missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -DIST_ARCHIVES = $(distdir).tar.gz -GZIP_ENV = --best -DIST_TARGETS = dist-gzip -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = find . -type f -print -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINDEX = @MAKEINDEX@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PDFLATEX = @PDFLATEX@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -ACLOCAL_AMFLAGS = -I m4 -include_HEADERS = cudd/cudd.h mtr/mtr.h $(am__append_1) \ - $(am__append_2) -check_SCRIPTS = cudd/test_cudd.test st/test_st.test mtr/test_mtr.test \ - dddmp/test_dddmp.test cplusplus/test_obj.test \ - nanotrav/test_ntrv.test -dist_check_DATA = cudd/r7x8.1.mat cudd/r7x8.1.out cudd/extra.out \ - mtr/test.groups mtr/test.out cplusplus/test.out \ - cplusplus/multi.out nanotrav/adj49.blif nanotrav/adj49.out \ - nanotrav/C17.blif nanotrav/C17.out nanotrav/C880.blif \ - nanotrav/C880.out nanotrav/closest.blif nanotrav/closest.out \ - nanotrav/ham01.blif nanotrav/ham01.out nanotrav/mult32a.blif \ - nanotrav/mult32a.out nanotrav/rcn25.blif nanotrav/rcn25.out \ - nanotrav/s27.blif nanotrav/s27.out nanotrav/s27b.blif \ - nanotrav/s27b.out nanotrav/s27c.blif nanotrav/s27c.out \ - nanotrav/s382.blif nanotrav/s382.out nanotrav/s641.blif \ - nanotrav/s641.out nanotrav/miniFirst.blif \ - nanotrav/miniSecond.blif nanotrav/miniFirst.out -EXTRA_DIST = README RELEASE.NOTES LICENSE groups.dox \ - cudd/test_cudd.test.in st/test_st.test.in mtr/test_mtr.test.in \ - dddmp/README.dddmp dddmp/README.testdddmp dddmp/RELEASE_NOTES \ - dddmp/doc dddmp/test_dddmp.test.in dddmp/exp/test1.sh.in \ - dddmp/exp/test2.sh.in dddmp/exp/test3.sh.in \ - dddmp/exp/test4.sh.in dddmp/exp/test5.sh.in \ - dddmp/exp/test6.sh.in dddmp/exp/test7.sh.in dddmp/exp/0.add \ - dddmp/exp/0.bdd dddmp/exp/0or1.bdd dddmp/exp/1.add \ - dddmp/exp/1.bdd dddmp/exp/2and3.bdd dddmp/exp/2.bdd \ - dddmp/exp/3.bdd dddmp/exp/4.bdd dddmp/exp/4.bdd.bis1 \ - dddmp/exp/4.bdd.bis2 dddmp/exp/4.bdd.bis3 dddmp/exp/4.bdd.bis4 \ - dddmp/exp/4bis.bdd dddmp/exp/4.cnf dddmp/exp/4.cnf.bis \ - dddmp/exp/4.max1 dddmp/exp/4.max2 dddmp/exp/4xor5.bdd \ - dddmp/exp/5.bdd dddmp/exp/composeids.txt dddmp/exp/one.bdd \ - dddmp/exp/s27deltaDddmp1.bdd dddmp/exp/s27deltaDddmp1.bdd.bis \ - dddmp/exp/s27deltaDddmp2.bdd dddmp/exp/s27RP1.bdd \ - dddmp/exp/varauxids.ord dddmp/exp/varnames.ord \ - dddmp/exp/zero.bdd cplusplus/test_obj.test.in nanotrav/README \ - nanotrav/nanotrav.1 nanotrav/test_ntrv.test.in doc/phase.pdf -TESTS = $(am__append_3) - -#endif -CLEANFILES = cudd/r7x8.1.tst cudd/extra.tst mtr/test.tst \ - dddmp/exp/test1.sh dddmp/exp/test2.sh dddmp/exp/test3.sh \ - dddmp/exp/test4.sh dddmp/exp/test5.sh dddmp/exp/test6.sh \ - dddmp/exp/test7.sh cplusplus/test.tst cplusplus/multi.tst \ - nanotrav/adj49.tst nanotrav/C17.tst nanotrav/C880.tst \ - nanotrav/closest.tst nanotrav/ham01.tst nanotrav/mult32a.tst \ - nanotrav/rcn25.tst nanotrav/s27.tst nanotrav/s27b.tst \ - nanotrav/s27c.tst nanotrav/s382.tst nanotrav/s641.tst \ - nanotrav/miniFirst.tst $(am__append_8) $(check_SCRIPTS) -noinst_LTLIBRARIES = $(am__append_5) $(am__append_7) -TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ - $(top_srcdir)/build-aux/tap-driver.sh - -do_subst = sed \ - -e 's,[@]EXEEXT[@],$(EXEEXT),g' \ - -e 's,[@]srcdir[@],$(srcdir),g' - -lib_LTLIBRARIES = cudd/libcudd.la -cudd_libcudd_la_SOURCES = cudd/cudd.h cudd/cuddInt.h cudd/cuddAddAbs.c \ - cudd/cuddAddApply.c cudd/cuddAddFind.c cudd/cuddAddInv.c \ - cudd/cuddAddIte.c cudd/cuddAddNeg.c cudd/cuddAddWalsh.c \ - cudd/cuddAndAbs.c cudd/cuddAnneal.c cudd/cuddApa.c \ - cudd/cuddAPI.c cudd/cuddApprox.c cudd/cuddBddAbs.c \ - cudd/cuddBddCorr.c cudd/cuddBddIte.c cudd/cuddBridge.c \ - cudd/cuddCache.c cudd/cuddCheck.c cudd/cuddClip.c \ - cudd/cuddCof.c cudd/cuddCompose.c cudd/cuddDecomp.c \ - cudd/cuddEssent.c cudd/cuddExact.c cudd/cuddExport.c \ - cudd/cuddGenCof.c cudd/cuddGenetic.c cudd/cuddGroup.c \ - cudd/cuddHarwell.c cudd/cuddInit.c cudd/cuddInteract.c \ - cudd/cuddLCache.c cudd/cuddLevelQ.c cudd/cuddLinear.c \ - cudd/cuddLiteral.c cudd/cuddMatMult.c cudd/cuddPriority.c \ - cudd/cuddRead.c cudd/cuddRef.c cudd/cuddReorder.c \ - cudd/cuddSat.c cudd/cuddSign.c cudd/cuddSolve.c \ - cudd/cuddSplit.c cudd/cuddSubsetHB.c cudd/cuddSubsetSP.c \ - cudd/cuddSymmetry.c cudd/cuddTable.c cudd/cuddUtil.c \ - cudd/cuddWindow.c cudd/cuddZddCount.c cudd/cuddZddFuncs.c \ - cudd/cuddZddGroup.c cudd/cuddZddIsop.c cudd/cuddZddLin.c \ - cudd/cuddZddMisc.c cudd/cuddZddPort.c cudd/cuddZddReord.c \ - cudd/cuddZddSetop.c cudd/cuddZddSymm.c cudd/cuddZddUtil.c \ - util/util.h util/cstringstream.h util/cpu_stats.c \ - util/cpu_time.c util/cstringstream.c util/datalimit.c \ - util/pathsearch.c util/pipefork.c util/prtime.c \ - util/safe_mem.c util/strsav.c util/texpand.c util/ucbqsort.c \ - st/st.h st/st.c epd/epd.c epd/epdInt.h epd/epd.h mtr/mtr.h \ - mtr/mtrInt.h mtr/mtrBasic.c mtr/mtrGroup.c $(am__append_4) \ - $(am__append_6) -cudd_libcudd_la_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/st \ - -I$(top_srcdir)/epd -I$(top_srcdir)/mtr -I$(top_srcdir)/util - -@OBJ_TRUE@cudd_libcudd_la_LIBTOOLFLAGS = --tag=CXX -cudd_libcudd_la_LDFLAGS = -release @PACKAGE_VERSION@ -version-info 0:0:0 \ - -no-undefined - -cudd_testcudd_SOURCES = cudd/testcudd.c -cudd_testcudd_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -cudd_testcudd_LDADD = cudd/libcudd.la -cudd_testextra_SOURCES = cudd/testextra.c -cudd_testextra_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -cudd_testextra_LDADD = cudd/libcudd.la -@CROSS_COMPILING_TRUE@@MINGW64_TRUE@cudd_libcudd_la_LIBADD = -lws2_32 -lpsapi -st_testst_SOURCES = st/testst.c -st_testst_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -st_testst_LDADD = cudd/libcudd.la -mtr_testmtr_SOURCES = mtr/testmtr.c -mtr_testmtr_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -mtr_testmtr_LDADD = cudd/libcudd.la -dddmp_sources = dddmp/dddmp.h dddmp/dddmpInt.h \ - dddmp/dddmpBinary.c dddmp/dddmpConvert.c dddmp/dddmpDbg.c \ - dddmp/dddmpLoad.c dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c \ - dddmp/dddmpNodeBdd.c dddmp/dddmpNodeCnf.c dddmp/dddmpStoreAdd.c \ - dddmp/dddmpStoreBdd.c dddmp/dddmpStoreCnf.c dddmp/dddmpStoreMisc.c \ - dddmp/dddmpUtil.c - -@DDDMP_FALSE@dddmp_libdddmp_la_SOURCES = $(dddmp_sources) -@DDDMP_FALSE@dddmp_libdddmp_la_CPPFLAGS = -I$(top_srcdir)/util -I$(top_srcdir)/mtr \ -@DDDMP_FALSE@ -I$(top_srcdir)/epd -I$(top_srcdir)/cudd -I$(top_srcdir)/st - -dddmp_testdddmp_SOURCES = dddmp/testdddmp.c -@DDDMP_FALSE@dddmp_testdddmp_CPPFLAGS = $(dddmp_libdddmp_la_CPPFLAGS) -@DDDMP_TRUE@dddmp_testdddmp_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@DDDMP_FALSE@dddmp_testdddmp_LDADD = dddmp/libdddmp.la cudd/libcudd.la -@DDDMP_TRUE@dddmp_testdddmp_LDADD = cudd/libcudd.la -cplusplus_sources = cplusplus/cuddObj.hh cplusplus/cuddObj.cc -@OBJ_FALSE@cplusplus_libobj_la_SOURCES = $(cplusplus_sources) -@OBJ_FALSE@cplusplus_libobj_la_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/mtr \ -@OBJ_FALSE@ -I$(top_srcdir)/epd -I$(top_srcdir)/st - -cplusplus_testobj_SOURCES = cplusplus/testobj.cc -@OBJ_FALSE@cplusplus_testobj_CPPFLAGS = $(cplusplus_libobj_la_CPPFLAGS) -@OBJ_TRUE@cplusplus_testobj_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@OBJ_FALSE@cplusplus_testobj_LDADD = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testobj_LDADD = cudd/libcudd.la -cplusplus_testmulti_SOURCES = cplusplus/testmulti.cc -@OBJ_FALSE@cplusplus_testmulti_CPPFLAGS = $(cplusplus_libobj_la_CPPFLAGS) -@OBJ_TRUE@cplusplus_testmulti_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@OBJ_FALSE@cplusplus_testmulti_LDADD = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testmulti_LDADD = cudd/libcudd.la -@HAVE_PTHREADS_TRUE@cplusplus_testmulti_LDFLAGS = -pthread -nanotrav_nanotrav_SOURCES = nanotrav/bnet.h nanotrav/ntr.h \ - nanotrav/bnet.c nanotrav/chkMterm.c nanotrav/main.c nanotrav/ntrBddTest.c \ - nanotrav/ntr.c nanotrav/ntrHeap.c nanotrav/ntrMflow.c nanotrav/ntrShort.c \ - nanotrav/ntrZddTest.c - -nanotrav_nanotrav_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/mtr \ - -I$(top_srcdir)/epd -I$(top_srcdir)/st -I$(top_srcdir)/dddmp \ - -I$(top_srcdir)/util - -@DDDMP_FALSE@nanotrav_nanotrav_LDADD = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@nanotrav_nanotrav_LDADD = cudd/libcudd.la -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .cc .lo .log .o .obj .test .test$(EXEEXT) .trs -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/cudd/Included.am $(top_srcdir)/util/Included.am $(top_srcdir)/st/Included.am $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am $(top_srcdir)/dddmp/Included.am $(top_srcdir)/cplusplus/Included.am $(top_srcdir)/nanotrav/Included.am $(top_srcdir)/doc/Included.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; -$(top_srcdir)/cudd/Included.am $(top_srcdir)/util/Included.am $(top_srcdir)/st/Included.am $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am $(top_srcdir)/dddmp/Included.am $(top_srcdir)/cplusplus/Included.am $(top_srcdir)/nanotrav/Included.am $(top_srcdir)/doc/Included.am $(am__empty): - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -@HAVE_DOXYGEN_TRUE@Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in -@HAVE_DOXYGEN_TRUE@ cd $(top_builddir) && $(SHELL) ./config.status $@ -@HAVE_PDFLATEX_TRUE@doc/cudd.tex: $(top_builddir)/config.status $(top_srcdir)/doc/cudd.tex.in -@HAVE_PDFLATEX_TRUE@ cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test1.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test1.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test2.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test2.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test3.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test3.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test4.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test4.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test5.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test5.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test6.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test6.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test7.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test7.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } -cplusplus/$(am__dirstamp): - @$(MKDIR_P) cplusplus - @: > cplusplus/$(am__dirstamp) -cplusplus/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) cplusplus/$(DEPDIR) - @: > cplusplus/$(DEPDIR)/$(am__dirstamp) -cplusplus/cplusplus_libobj_la-cuddObj.lo: cplusplus/$(am__dirstamp) \ - cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/libobj.la: $(cplusplus_libobj_la_OBJECTS) $(cplusplus_libobj_la_DEPENDENCIES) $(EXTRA_cplusplus_libobj_la_DEPENDENCIES) cplusplus/$(am__dirstamp) - $(AM_V_CXXLD)$(CXXLINK) $(am_cplusplus_libobj_la_rpath) $(cplusplus_libobj_la_OBJECTS) $(cplusplus_libobj_la_LIBADD) $(LIBS) -cudd/$(am__dirstamp): - @$(MKDIR_P) cudd - @: > cudd/$(am__dirstamp) -cudd/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) cudd/$(DEPDIR) - @: > cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddApply.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddFind.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddInv.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddIte.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddNeg.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddWalsh.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAndAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAnneal.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddApa.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAPI.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddApprox.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddCorr.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddIte.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBridge.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCache.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCheck.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddClip.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCof.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCompose.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddDecomp.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddEssent.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddExact.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddExport.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGenCof.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGenetic.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGroup.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddHarwell.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddInit.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddInteract.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLCache.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLevelQ.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLinear.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLiteral.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddMatMult.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddPriority.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddRead.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddRef.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddReorder.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSat.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSign.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSolve.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSplit.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSubsetHB.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSubsetSP.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSymmetry.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddTable.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddUtil.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddWindow.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddCount.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddFuncs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddGroup.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddIsop.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddLin.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddMisc.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddPort.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddReord.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddSetop.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddSymm.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddUtil.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -util/$(am__dirstamp): - @$(MKDIR_P) util - @: > util/$(am__dirstamp) -util/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) util/$(DEPDIR) - @: > util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cpu_stats.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cpu_time.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cstringstream.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-datalimit.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-pathsearch.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-pipefork.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-prtime.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-safe_mem.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-strsav.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-texpand.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-ucbqsort.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -st/$(am__dirstamp): - @$(MKDIR_P) st - @: > st/$(am__dirstamp) -st/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) st/$(DEPDIR) - @: > st/$(DEPDIR)/$(am__dirstamp) -st/cudd_libcudd_la-st.lo: st/$(am__dirstamp) \ - st/$(DEPDIR)/$(am__dirstamp) -epd/$(am__dirstamp): - @$(MKDIR_P) epd - @: > epd/$(am__dirstamp) -epd/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) epd/$(DEPDIR) - @: > epd/$(DEPDIR)/$(am__dirstamp) -epd/cudd_libcudd_la-epd.lo: epd/$(am__dirstamp) \ - epd/$(DEPDIR)/$(am__dirstamp) -mtr/$(am__dirstamp): - @$(MKDIR_P) mtr - @: > mtr/$(am__dirstamp) -mtr/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) mtr/$(DEPDIR) - @: > mtr/$(DEPDIR)/$(am__dirstamp) -mtr/cudd_libcudd_la-mtrBasic.lo: mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) -mtr/cudd_libcudd_la-mtrGroup.lo: mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) -dddmp/$(am__dirstamp): - @$(MKDIR_P) dddmp - @: > dddmp/$(am__dirstamp) -dddmp/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) dddmp/$(DEPDIR) - @: > dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpBinary.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpConvert.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpDbg.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpLoad.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpLoadCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreMisc.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpUtil.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -cplusplus/cudd_libcudd_la-cuddObj.lo: cplusplus/$(am__dirstamp) \ - cplusplus/$(DEPDIR)/$(am__dirstamp) - -cudd/libcudd.la: $(cudd_libcudd_la_OBJECTS) $(cudd_libcudd_la_DEPENDENCIES) $(EXTRA_cudd_libcudd_la_DEPENDENCIES) cudd/$(am__dirstamp) - $(AM_V_CXXLD)$(cudd_libcudd_la_LINK) -rpath $(libdir) $(cudd_libcudd_la_OBJECTS) $(cudd_libcudd_la_LIBADD) $(LIBS) -dddmp/dddmp_libdddmp_la-dddmpBinary.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpConvert.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpDbg.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpLoad.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpUtil.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) - -dddmp/libdddmp.la: $(dddmp_libdddmp_la_OBJECTS) $(dddmp_libdddmp_la_DEPENDENCIES) $(EXTRA_dddmp_libdddmp_la_DEPENDENCIES) dddmp/$(am__dirstamp) - $(AM_V_CCLD)$(LINK) $(am_dddmp_libdddmp_la_rpath) $(dddmp_libdddmp_la_OBJECTS) $(dddmp_libdddmp_la_LIBADD) $(LIBS) - -clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -cplusplus/cplusplus_testmulti-testmulti.$(OBJEXT): \ - cplusplus/$(am__dirstamp) cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/testmulti$(EXEEXT): $(cplusplus_testmulti_OBJECTS) $(cplusplus_testmulti_DEPENDENCIES) $(EXTRA_cplusplus_testmulti_DEPENDENCIES) cplusplus/$(am__dirstamp) - @rm -f cplusplus/testmulti$(EXEEXT) - $(AM_V_CXXLD)$(cplusplus_testmulti_LINK) $(cplusplus_testmulti_OBJECTS) $(cplusplus_testmulti_LDADD) $(LIBS) -cplusplus/cplusplus_testobj-testobj.$(OBJEXT): \ - cplusplus/$(am__dirstamp) cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/testobj$(EXEEXT): $(cplusplus_testobj_OBJECTS) $(cplusplus_testobj_DEPENDENCIES) $(EXTRA_cplusplus_testobj_DEPENDENCIES) cplusplus/$(am__dirstamp) - @rm -f cplusplus/testobj$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(cplusplus_testobj_OBJECTS) $(cplusplus_testobj_LDADD) $(LIBS) -cudd/cudd_testcudd-testcudd.$(OBJEXT): cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) - -cudd/testcudd$(EXEEXT): $(cudd_testcudd_OBJECTS) $(cudd_testcudd_DEPENDENCIES) $(EXTRA_cudd_testcudd_DEPENDENCIES) cudd/$(am__dirstamp) - @rm -f cudd/testcudd$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(cudd_testcudd_OBJECTS) $(cudd_testcudd_LDADD) $(LIBS) -cudd/cudd_testextra-testextra.$(OBJEXT): cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) - -cudd/testextra$(EXEEXT): $(cudd_testextra_OBJECTS) $(cudd_testextra_DEPENDENCIES) $(EXTRA_cudd_testextra_DEPENDENCIES) cudd/$(am__dirstamp) - @rm -f cudd/testextra$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(cudd_testextra_OBJECTS) $(cudd_testextra_LDADD) $(LIBS) -dddmp/dddmp_testdddmp-testdddmp.$(OBJEXT): dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) - -dddmp/testdddmp$(EXEEXT): $(dddmp_testdddmp_OBJECTS) $(dddmp_testdddmp_DEPENDENCIES) $(EXTRA_dddmp_testdddmp_DEPENDENCIES) dddmp/$(am__dirstamp) - @rm -f dddmp/testdddmp$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(dddmp_testdddmp_OBJECTS) $(dddmp_testdddmp_LDADD) $(LIBS) -mtr/mtr_testmtr-testmtr.$(OBJEXT): mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) - -mtr/testmtr$(EXEEXT): $(mtr_testmtr_OBJECTS) $(mtr_testmtr_DEPENDENCIES) $(EXTRA_mtr_testmtr_DEPENDENCIES) mtr/$(am__dirstamp) - @rm -f mtr/testmtr$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(mtr_testmtr_OBJECTS) $(mtr_testmtr_LDADD) $(LIBS) -nanotrav/$(am__dirstamp): - @$(MKDIR_P) nanotrav - @: > nanotrav/$(am__dirstamp) -nanotrav/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) nanotrav/$(DEPDIR) - @: > nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-bnet.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-chkMterm.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-main.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrBddTest.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntr.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrHeap.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrMflow.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrShort.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrZddTest.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) - -nanotrav/nanotrav$(EXEEXT): $(nanotrav_nanotrav_OBJECTS) $(nanotrav_nanotrav_DEPENDENCIES) $(EXTRA_nanotrav_nanotrav_DEPENDENCIES) nanotrav/$(am__dirstamp) - @rm -f nanotrav/nanotrav$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(nanotrav_nanotrav_OBJECTS) $(nanotrav_nanotrav_LDADD) $(LIBS) -st/st_testst-testst.$(OBJEXT): st/$(am__dirstamp) \ - st/$(DEPDIR)/$(am__dirstamp) - -st/testst$(EXEEXT): $(st_testst_OBJECTS) $(st_testst_DEPENDENCIES) $(EXTRA_st_testst_DEPENDENCIES) st/$(am__dirstamp) - @rm -f st/testst$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(st_testst_OBJECTS) $(st_testst_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -rm -f cplusplus/*.$(OBJEXT) - -rm -f cplusplus/*.lo - -rm -f cudd/*.$(OBJEXT) - -rm -f cudd/*.lo - -rm -f dddmp/*.$(OBJEXT) - -rm -f dddmp/*.lo - -rm -f epd/*.$(OBJEXT) - -rm -f epd/*.lo - -rm -f mtr/*.$(OBJEXT) - -rm -f mtr/*.lo - -rm -f nanotrav/*.$(OBJEXT) - -rm -f st/*.$(OBJEXT) - -rm -f st/*.lo - -rm -f util/*.$(OBJEXT) - -rm -f util/*.lo - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_testextra-testextra.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@epd/$(DEPDIR)/cudd_libcudd_la-epd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@st/$(DEPDIR)/cudd_libcudd_la-st.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@st/$(DEPDIR)/st_testst-testst.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-datalimit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-pipefork.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-prtime.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-strsav.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-texpand.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -cudd/cudd_libcudd_la-cuddAddAbs.lo: cudd/cuddAddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddAddAbs.lo `test -f 'cudd/cuddAddAbs.c' || echo '$(srcdir)/'`cudd/cuddAddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddAbs.c' object='cudd/cudd_libcudd_la-cuddAddAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddAbs.lo `test -f 'cudd/cuddAddAbs.c' || echo '$(srcdir)/'`cudd/cuddAddAbs.c - -cudd/cudd_libcudd_la-cuddAddApply.lo: cudd/cuddAddApply.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddApply.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Tpo -c -o cudd/cudd_libcudd_la-cuddAddApply.lo `test -f 'cudd/cuddAddApply.c' || echo '$(srcdir)/'`cudd/cuddAddApply.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddApply.c' object='cudd/cudd_libcudd_la-cuddAddApply.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddApply.lo `test -f 'cudd/cuddAddApply.c' || echo '$(srcdir)/'`cudd/cuddAddApply.c - -cudd/cudd_libcudd_la-cuddAddFind.lo: cudd/cuddAddFind.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddFind.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Tpo -c -o cudd/cudd_libcudd_la-cuddAddFind.lo `test -f 'cudd/cuddAddFind.c' || echo '$(srcdir)/'`cudd/cuddAddFind.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddFind.c' object='cudd/cudd_libcudd_la-cuddAddFind.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddFind.lo `test -f 'cudd/cuddAddFind.c' || echo '$(srcdir)/'`cudd/cuddAddFind.c - -cudd/cudd_libcudd_la-cuddAddInv.lo: cudd/cuddAddInv.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddInv.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Tpo -c -o cudd/cudd_libcudd_la-cuddAddInv.lo `test -f 'cudd/cuddAddInv.c' || echo '$(srcdir)/'`cudd/cuddAddInv.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddInv.c' object='cudd/cudd_libcudd_la-cuddAddInv.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddInv.lo `test -f 'cudd/cuddAddInv.c' || echo '$(srcdir)/'`cudd/cuddAddInv.c - -cudd/cudd_libcudd_la-cuddAddIte.lo: cudd/cuddAddIte.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddIte.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Tpo -c -o cudd/cudd_libcudd_la-cuddAddIte.lo `test -f 'cudd/cuddAddIte.c' || echo '$(srcdir)/'`cudd/cuddAddIte.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddIte.c' object='cudd/cudd_libcudd_la-cuddAddIte.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddIte.lo `test -f 'cudd/cuddAddIte.c' || echo '$(srcdir)/'`cudd/cuddAddIte.c - -cudd/cudd_libcudd_la-cuddAddNeg.lo: cudd/cuddAddNeg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddNeg.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Tpo -c -o cudd/cudd_libcudd_la-cuddAddNeg.lo `test -f 'cudd/cuddAddNeg.c' || echo '$(srcdir)/'`cudd/cuddAddNeg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddNeg.c' object='cudd/cudd_libcudd_la-cuddAddNeg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddNeg.lo `test -f 'cudd/cuddAddNeg.c' || echo '$(srcdir)/'`cudd/cuddAddNeg.c - -cudd/cudd_libcudd_la-cuddAddWalsh.lo: cudd/cuddAddWalsh.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddWalsh.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Tpo -c -o cudd/cudd_libcudd_la-cuddAddWalsh.lo `test -f 'cudd/cuddAddWalsh.c' || echo '$(srcdir)/'`cudd/cuddAddWalsh.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddWalsh.c' object='cudd/cudd_libcudd_la-cuddAddWalsh.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddWalsh.lo `test -f 'cudd/cuddAddWalsh.c' || echo '$(srcdir)/'`cudd/cuddAddWalsh.c - -cudd/cudd_libcudd_la-cuddAndAbs.lo: cudd/cuddAndAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAndAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddAndAbs.lo `test -f 'cudd/cuddAndAbs.c' || echo '$(srcdir)/'`cudd/cuddAndAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAndAbs.c' object='cudd/cudd_libcudd_la-cuddAndAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAndAbs.lo `test -f 'cudd/cuddAndAbs.c' || echo '$(srcdir)/'`cudd/cuddAndAbs.c - -cudd/cudd_libcudd_la-cuddAnneal.lo: cudd/cuddAnneal.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAnneal.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Tpo -c -o cudd/cudd_libcudd_la-cuddAnneal.lo `test -f 'cudd/cuddAnneal.c' || echo '$(srcdir)/'`cudd/cuddAnneal.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAnneal.c' object='cudd/cudd_libcudd_la-cuddAnneal.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAnneal.lo `test -f 'cudd/cuddAnneal.c' || echo '$(srcdir)/'`cudd/cuddAnneal.c - -cudd/cudd_libcudd_la-cuddApa.lo: cudd/cuddApa.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddApa.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Tpo -c -o cudd/cudd_libcudd_la-cuddApa.lo `test -f 'cudd/cuddApa.c' || echo '$(srcdir)/'`cudd/cuddApa.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddApa.c' object='cudd/cudd_libcudd_la-cuddApa.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddApa.lo `test -f 'cudd/cuddApa.c' || echo '$(srcdir)/'`cudd/cuddApa.c - -cudd/cudd_libcudd_la-cuddAPI.lo: cudd/cuddAPI.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAPI.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Tpo -c -o cudd/cudd_libcudd_la-cuddAPI.lo `test -f 'cudd/cuddAPI.c' || echo '$(srcdir)/'`cudd/cuddAPI.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAPI.c' object='cudd/cudd_libcudd_la-cuddAPI.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAPI.lo `test -f 'cudd/cuddAPI.c' || echo '$(srcdir)/'`cudd/cuddAPI.c - -cudd/cudd_libcudd_la-cuddApprox.lo: cudd/cuddApprox.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddApprox.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Tpo -c -o cudd/cudd_libcudd_la-cuddApprox.lo `test -f 'cudd/cuddApprox.c' || echo '$(srcdir)/'`cudd/cuddApprox.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddApprox.c' object='cudd/cudd_libcudd_la-cuddApprox.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddApprox.lo `test -f 'cudd/cuddApprox.c' || echo '$(srcdir)/'`cudd/cuddApprox.c - -cudd/cudd_libcudd_la-cuddBddAbs.lo: cudd/cuddBddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddBddAbs.lo `test -f 'cudd/cuddBddAbs.c' || echo '$(srcdir)/'`cudd/cuddBddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddAbs.c' object='cudd/cudd_libcudd_la-cuddBddAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddAbs.lo `test -f 'cudd/cuddBddAbs.c' || echo '$(srcdir)/'`cudd/cuddBddAbs.c - -cudd/cudd_libcudd_la-cuddBddCorr.lo: cudd/cuddBddCorr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddCorr.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Tpo -c -o cudd/cudd_libcudd_la-cuddBddCorr.lo `test -f 'cudd/cuddBddCorr.c' || echo '$(srcdir)/'`cudd/cuddBddCorr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddCorr.c' object='cudd/cudd_libcudd_la-cuddBddCorr.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddCorr.lo `test -f 'cudd/cuddBddCorr.c' || echo '$(srcdir)/'`cudd/cuddBddCorr.c - -cudd/cudd_libcudd_la-cuddBddIte.lo: cudd/cuddBddIte.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddIte.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Tpo -c -o cudd/cudd_libcudd_la-cuddBddIte.lo `test -f 'cudd/cuddBddIte.c' || echo '$(srcdir)/'`cudd/cuddBddIte.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddIte.c' object='cudd/cudd_libcudd_la-cuddBddIte.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddIte.lo `test -f 'cudd/cuddBddIte.c' || echo '$(srcdir)/'`cudd/cuddBddIte.c - -cudd/cudd_libcudd_la-cuddBridge.lo: cudd/cuddBridge.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBridge.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Tpo -c -o cudd/cudd_libcudd_la-cuddBridge.lo `test -f 'cudd/cuddBridge.c' || echo '$(srcdir)/'`cudd/cuddBridge.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBridge.c' object='cudd/cudd_libcudd_la-cuddBridge.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBridge.lo `test -f 'cudd/cuddBridge.c' || echo '$(srcdir)/'`cudd/cuddBridge.c - -cudd/cudd_libcudd_la-cuddCache.lo: cudd/cuddCache.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCache.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Tpo -c -o cudd/cudd_libcudd_la-cuddCache.lo `test -f 'cudd/cuddCache.c' || echo '$(srcdir)/'`cudd/cuddCache.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCache.c' object='cudd/cudd_libcudd_la-cuddCache.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCache.lo `test -f 'cudd/cuddCache.c' || echo '$(srcdir)/'`cudd/cuddCache.c - -cudd/cudd_libcudd_la-cuddCheck.lo: cudd/cuddCheck.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCheck.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Tpo -c -o cudd/cudd_libcudd_la-cuddCheck.lo `test -f 'cudd/cuddCheck.c' || echo '$(srcdir)/'`cudd/cuddCheck.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCheck.c' object='cudd/cudd_libcudd_la-cuddCheck.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCheck.lo `test -f 'cudd/cuddCheck.c' || echo '$(srcdir)/'`cudd/cuddCheck.c - -cudd/cudd_libcudd_la-cuddClip.lo: cudd/cuddClip.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddClip.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Tpo -c -o cudd/cudd_libcudd_la-cuddClip.lo `test -f 'cudd/cuddClip.c' || echo '$(srcdir)/'`cudd/cuddClip.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddClip.c' object='cudd/cudd_libcudd_la-cuddClip.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddClip.lo `test -f 'cudd/cuddClip.c' || echo '$(srcdir)/'`cudd/cuddClip.c - -cudd/cudd_libcudd_la-cuddCof.lo: cudd/cuddCof.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCof.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Tpo -c -o cudd/cudd_libcudd_la-cuddCof.lo `test -f 'cudd/cuddCof.c' || echo '$(srcdir)/'`cudd/cuddCof.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCof.c' object='cudd/cudd_libcudd_la-cuddCof.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCof.lo `test -f 'cudd/cuddCof.c' || echo '$(srcdir)/'`cudd/cuddCof.c - -cudd/cudd_libcudd_la-cuddCompose.lo: cudd/cuddCompose.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCompose.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Tpo -c -o cudd/cudd_libcudd_la-cuddCompose.lo `test -f 'cudd/cuddCompose.c' || echo '$(srcdir)/'`cudd/cuddCompose.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCompose.c' object='cudd/cudd_libcudd_la-cuddCompose.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCompose.lo `test -f 'cudd/cuddCompose.c' || echo '$(srcdir)/'`cudd/cuddCompose.c - -cudd/cudd_libcudd_la-cuddDecomp.lo: cudd/cuddDecomp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddDecomp.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Tpo -c -o cudd/cudd_libcudd_la-cuddDecomp.lo `test -f 'cudd/cuddDecomp.c' || echo '$(srcdir)/'`cudd/cuddDecomp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddDecomp.c' object='cudd/cudd_libcudd_la-cuddDecomp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddDecomp.lo `test -f 'cudd/cuddDecomp.c' || echo '$(srcdir)/'`cudd/cuddDecomp.c - -cudd/cudd_libcudd_la-cuddEssent.lo: cudd/cuddEssent.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddEssent.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Tpo -c -o cudd/cudd_libcudd_la-cuddEssent.lo `test -f 'cudd/cuddEssent.c' || echo '$(srcdir)/'`cudd/cuddEssent.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddEssent.c' object='cudd/cudd_libcudd_la-cuddEssent.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddEssent.lo `test -f 'cudd/cuddEssent.c' || echo '$(srcdir)/'`cudd/cuddEssent.c - -cudd/cudd_libcudd_la-cuddExact.lo: cudd/cuddExact.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddExact.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Tpo -c -o cudd/cudd_libcudd_la-cuddExact.lo `test -f 'cudd/cuddExact.c' || echo '$(srcdir)/'`cudd/cuddExact.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddExact.c' object='cudd/cudd_libcudd_la-cuddExact.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddExact.lo `test -f 'cudd/cuddExact.c' || echo '$(srcdir)/'`cudd/cuddExact.c - -cudd/cudd_libcudd_la-cuddExport.lo: cudd/cuddExport.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddExport.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Tpo -c -o cudd/cudd_libcudd_la-cuddExport.lo `test -f 'cudd/cuddExport.c' || echo '$(srcdir)/'`cudd/cuddExport.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddExport.c' object='cudd/cudd_libcudd_la-cuddExport.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddExport.lo `test -f 'cudd/cuddExport.c' || echo '$(srcdir)/'`cudd/cuddExport.c - -cudd/cudd_libcudd_la-cuddGenCof.lo: cudd/cuddGenCof.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGenCof.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Tpo -c -o cudd/cudd_libcudd_la-cuddGenCof.lo `test -f 'cudd/cuddGenCof.c' || echo '$(srcdir)/'`cudd/cuddGenCof.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGenCof.c' object='cudd/cudd_libcudd_la-cuddGenCof.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGenCof.lo `test -f 'cudd/cuddGenCof.c' || echo '$(srcdir)/'`cudd/cuddGenCof.c - -cudd/cudd_libcudd_la-cuddGenetic.lo: cudd/cuddGenetic.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGenetic.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Tpo -c -o cudd/cudd_libcudd_la-cuddGenetic.lo `test -f 'cudd/cuddGenetic.c' || echo '$(srcdir)/'`cudd/cuddGenetic.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGenetic.c' object='cudd/cudd_libcudd_la-cuddGenetic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGenetic.lo `test -f 'cudd/cuddGenetic.c' || echo '$(srcdir)/'`cudd/cuddGenetic.c - -cudd/cudd_libcudd_la-cuddGroup.lo: cudd/cuddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGroup.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Tpo -c -o cudd/cudd_libcudd_la-cuddGroup.lo `test -f 'cudd/cuddGroup.c' || echo '$(srcdir)/'`cudd/cuddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGroup.c' object='cudd/cudd_libcudd_la-cuddGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGroup.lo `test -f 'cudd/cuddGroup.c' || echo '$(srcdir)/'`cudd/cuddGroup.c - -cudd/cudd_libcudd_la-cuddHarwell.lo: cudd/cuddHarwell.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddHarwell.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Tpo -c -o cudd/cudd_libcudd_la-cuddHarwell.lo `test -f 'cudd/cuddHarwell.c' || echo '$(srcdir)/'`cudd/cuddHarwell.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddHarwell.c' object='cudd/cudd_libcudd_la-cuddHarwell.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddHarwell.lo `test -f 'cudd/cuddHarwell.c' || echo '$(srcdir)/'`cudd/cuddHarwell.c - -cudd/cudd_libcudd_la-cuddInit.lo: cudd/cuddInit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddInit.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Tpo -c -o cudd/cudd_libcudd_la-cuddInit.lo `test -f 'cudd/cuddInit.c' || echo '$(srcdir)/'`cudd/cuddInit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddInit.c' object='cudd/cudd_libcudd_la-cuddInit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddInit.lo `test -f 'cudd/cuddInit.c' || echo '$(srcdir)/'`cudd/cuddInit.c - -cudd/cudd_libcudd_la-cuddInteract.lo: cudd/cuddInteract.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddInteract.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Tpo -c -o cudd/cudd_libcudd_la-cuddInteract.lo `test -f 'cudd/cuddInteract.c' || echo '$(srcdir)/'`cudd/cuddInteract.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddInteract.c' object='cudd/cudd_libcudd_la-cuddInteract.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddInteract.lo `test -f 'cudd/cuddInteract.c' || echo '$(srcdir)/'`cudd/cuddInteract.c - -cudd/cudd_libcudd_la-cuddLCache.lo: cudd/cuddLCache.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLCache.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Tpo -c -o cudd/cudd_libcudd_la-cuddLCache.lo `test -f 'cudd/cuddLCache.c' || echo '$(srcdir)/'`cudd/cuddLCache.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLCache.c' object='cudd/cudd_libcudd_la-cuddLCache.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLCache.lo `test -f 'cudd/cuddLCache.c' || echo '$(srcdir)/'`cudd/cuddLCache.c - -cudd/cudd_libcudd_la-cuddLevelQ.lo: cudd/cuddLevelQ.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLevelQ.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Tpo -c -o cudd/cudd_libcudd_la-cuddLevelQ.lo `test -f 'cudd/cuddLevelQ.c' || echo '$(srcdir)/'`cudd/cuddLevelQ.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLevelQ.c' object='cudd/cudd_libcudd_la-cuddLevelQ.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLevelQ.lo `test -f 'cudd/cuddLevelQ.c' || echo '$(srcdir)/'`cudd/cuddLevelQ.c - -cudd/cudd_libcudd_la-cuddLinear.lo: cudd/cuddLinear.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLinear.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Tpo -c -o cudd/cudd_libcudd_la-cuddLinear.lo `test -f 'cudd/cuddLinear.c' || echo '$(srcdir)/'`cudd/cuddLinear.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLinear.c' object='cudd/cudd_libcudd_la-cuddLinear.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLinear.lo `test -f 'cudd/cuddLinear.c' || echo '$(srcdir)/'`cudd/cuddLinear.c - -cudd/cudd_libcudd_la-cuddLiteral.lo: cudd/cuddLiteral.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLiteral.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Tpo -c -o cudd/cudd_libcudd_la-cuddLiteral.lo `test -f 'cudd/cuddLiteral.c' || echo '$(srcdir)/'`cudd/cuddLiteral.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLiteral.c' object='cudd/cudd_libcudd_la-cuddLiteral.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLiteral.lo `test -f 'cudd/cuddLiteral.c' || echo '$(srcdir)/'`cudd/cuddLiteral.c - -cudd/cudd_libcudd_la-cuddMatMult.lo: cudd/cuddMatMult.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddMatMult.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Tpo -c -o cudd/cudd_libcudd_la-cuddMatMult.lo `test -f 'cudd/cuddMatMult.c' || echo '$(srcdir)/'`cudd/cuddMatMult.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddMatMult.c' object='cudd/cudd_libcudd_la-cuddMatMult.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddMatMult.lo `test -f 'cudd/cuddMatMult.c' || echo '$(srcdir)/'`cudd/cuddMatMult.c - -cudd/cudd_libcudd_la-cuddPriority.lo: cudd/cuddPriority.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddPriority.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Tpo -c -o cudd/cudd_libcudd_la-cuddPriority.lo `test -f 'cudd/cuddPriority.c' || echo '$(srcdir)/'`cudd/cuddPriority.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddPriority.c' object='cudd/cudd_libcudd_la-cuddPriority.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddPriority.lo `test -f 'cudd/cuddPriority.c' || echo '$(srcdir)/'`cudd/cuddPriority.c - -cudd/cudd_libcudd_la-cuddRead.lo: cudd/cuddRead.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddRead.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Tpo -c -o cudd/cudd_libcudd_la-cuddRead.lo `test -f 'cudd/cuddRead.c' || echo '$(srcdir)/'`cudd/cuddRead.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddRead.c' object='cudd/cudd_libcudd_la-cuddRead.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddRead.lo `test -f 'cudd/cuddRead.c' || echo '$(srcdir)/'`cudd/cuddRead.c - -cudd/cudd_libcudd_la-cuddRef.lo: cudd/cuddRef.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddRef.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Tpo -c -o cudd/cudd_libcudd_la-cuddRef.lo `test -f 'cudd/cuddRef.c' || echo '$(srcdir)/'`cudd/cuddRef.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddRef.c' object='cudd/cudd_libcudd_la-cuddRef.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddRef.lo `test -f 'cudd/cuddRef.c' || echo '$(srcdir)/'`cudd/cuddRef.c - -cudd/cudd_libcudd_la-cuddReorder.lo: cudd/cuddReorder.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddReorder.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Tpo -c -o cudd/cudd_libcudd_la-cuddReorder.lo `test -f 'cudd/cuddReorder.c' || echo '$(srcdir)/'`cudd/cuddReorder.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddReorder.c' object='cudd/cudd_libcudd_la-cuddReorder.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddReorder.lo `test -f 'cudd/cuddReorder.c' || echo '$(srcdir)/'`cudd/cuddReorder.c - -cudd/cudd_libcudd_la-cuddSat.lo: cudd/cuddSat.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSat.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Tpo -c -o cudd/cudd_libcudd_la-cuddSat.lo `test -f 'cudd/cuddSat.c' || echo '$(srcdir)/'`cudd/cuddSat.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSat.c' object='cudd/cudd_libcudd_la-cuddSat.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSat.lo `test -f 'cudd/cuddSat.c' || echo '$(srcdir)/'`cudd/cuddSat.c - -cudd/cudd_libcudd_la-cuddSign.lo: cudd/cuddSign.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSign.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Tpo -c -o cudd/cudd_libcudd_la-cuddSign.lo `test -f 'cudd/cuddSign.c' || echo '$(srcdir)/'`cudd/cuddSign.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSign.c' object='cudd/cudd_libcudd_la-cuddSign.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSign.lo `test -f 'cudd/cuddSign.c' || echo '$(srcdir)/'`cudd/cuddSign.c - -cudd/cudd_libcudd_la-cuddSolve.lo: cudd/cuddSolve.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSolve.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Tpo -c -o cudd/cudd_libcudd_la-cuddSolve.lo `test -f 'cudd/cuddSolve.c' || echo '$(srcdir)/'`cudd/cuddSolve.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSolve.c' object='cudd/cudd_libcudd_la-cuddSolve.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSolve.lo `test -f 'cudd/cuddSolve.c' || echo '$(srcdir)/'`cudd/cuddSolve.c - -cudd/cudd_libcudd_la-cuddSplit.lo: cudd/cuddSplit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSplit.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Tpo -c -o cudd/cudd_libcudd_la-cuddSplit.lo `test -f 'cudd/cuddSplit.c' || echo '$(srcdir)/'`cudd/cuddSplit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSplit.c' object='cudd/cudd_libcudd_la-cuddSplit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSplit.lo `test -f 'cudd/cuddSplit.c' || echo '$(srcdir)/'`cudd/cuddSplit.c - -cudd/cudd_libcudd_la-cuddSubsetHB.lo: cudd/cuddSubsetHB.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSubsetHB.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Tpo -c -o cudd/cudd_libcudd_la-cuddSubsetHB.lo `test -f 'cudd/cuddSubsetHB.c' || echo '$(srcdir)/'`cudd/cuddSubsetHB.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSubsetHB.c' object='cudd/cudd_libcudd_la-cuddSubsetHB.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSubsetHB.lo `test -f 'cudd/cuddSubsetHB.c' || echo '$(srcdir)/'`cudd/cuddSubsetHB.c - -cudd/cudd_libcudd_la-cuddSubsetSP.lo: cudd/cuddSubsetSP.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSubsetSP.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Tpo -c -o cudd/cudd_libcudd_la-cuddSubsetSP.lo `test -f 'cudd/cuddSubsetSP.c' || echo '$(srcdir)/'`cudd/cuddSubsetSP.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSubsetSP.c' object='cudd/cudd_libcudd_la-cuddSubsetSP.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSubsetSP.lo `test -f 'cudd/cuddSubsetSP.c' || echo '$(srcdir)/'`cudd/cuddSubsetSP.c - -cudd/cudd_libcudd_la-cuddSymmetry.lo: cudd/cuddSymmetry.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSymmetry.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Tpo -c -o cudd/cudd_libcudd_la-cuddSymmetry.lo `test -f 'cudd/cuddSymmetry.c' || echo '$(srcdir)/'`cudd/cuddSymmetry.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSymmetry.c' object='cudd/cudd_libcudd_la-cuddSymmetry.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSymmetry.lo `test -f 'cudd/cuddSymmetry.c' || echo '$(srcdir)/'`cudd/cuddSymmetry.c - -cudd/cudd_libcudd_la-cuddTable.lo: cudd/cuddTable.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddTable.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Tpo -c -o cudd/cudd_libcudd_la-cuddTable.lo `test -f 'cudd/cuddTable.c' || echo '$(srcdir)/'`cudd/cuddTable.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddTable.c' object='cudd/cudd_libcudd_la-cuddTable.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddTable.lo `test -f 'cudd/cuddTable.c' || echo '$(srcdir)/'`cudd/cuddTable.c - -cudd/cudd_libcudd_la-cuddUtil.lo: cudd/cuddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddUtil.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Tpo -c -o cudd/cudd_libcudd_la-cuddUtil.lo `test -f 'cudd/cuddUtil.c' || echo '$(srcdir)/'`cudd/cuddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddUtil.c' object='cudd/cudd_libcudd_la-cuddUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddUtil.lo `test -f 'cudd/cuddUtil.c' || echo '$(srcdir)/'`cudd/cuddUtil.c - -cudd/cudd_libcudd_la-cuddWindow.lo: cudd/cuddWindow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddWindow.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Tpo -c -o cudd/cudd_libcudd_la-cuddWindow.lo `test -f 'cudd/cuddWindow.c' || echo '$(srcdir)/'`cudd/cuddWindow.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddWindow.c' object='cudd/cudd_libcudd_la-cuddWindow.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddWindow.lo `test -f 'cudd/cuddWindow.c' || echo '$(srcdir)/'`cudd/cuddWindow.c - -cudd/cudd_libcudd_la-cuddZddCount.lo: cudd/cuddZddCount.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddCount.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Tpo -c -o cudd/cudd_libcudd_la-cuddZddCount.lo `test -f 'cudd/cuddZddCount.c' || echo '$(srcdir)/'`cudd/cuddZddCount.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddCount.c' object='cudd/cudd_libcudd_la-cuddZddCount.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddCount.lo `test -f 'cudd/cuddZddCount.c' || echo '$(srcdir)/'`cudd/cuddZddCount.c - -cudd/cudd_libcudd_la-cuddZddFuncs.lo: cudd/cuddZddFuncs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddFuncs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Tpo -c -o cudd/cudd_libcudd_la-cuddZddFuncs.lo `test -f 'cudd/cuddZddFuncs.c' || echo '$(srcdir)/'`cudd/cuddZddFuncs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddFuncs.c' object='cudd/cudd_libcudd_la-cuddZddFuncs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddFuncs.lo `test -f 'cudd/cuddZddFuncs.c' || echo '$(srcdir)/'`cudd/cuddZddFuncs.c - -cudd/cudd_libcudd_la-cuddZddGroup.lo: cudd/cuddZddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddGroup.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Tpo -c -o cudd/cudd_libcudd_la-cuddZddGroup.lo `test -f 'cudd/cuddZddGroup.c' || echo '$(srcdir)/'`cudd/cuddZddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddGroup.c' object='cudd/cudd_libcudd_la-cuddZddGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddGroup.lo `test -f 'cudd/cuddZddGroup.c' || echo '$(srcdir)/'`cudd/cuddZddGroup.c - -cudd/cudd_libcudd_la-cuddZddIsop.lo: cudd/cuddZddIsop.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddIsop.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Tpo -c -o cudd/cudd_libcudd_la-cuddZddIsop.lo `test -f 'cudd/cuddZddIsop.c' || echo '$(srcdir)/'`cudd/cuddZddIsop.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddIsop.c' object='cudd/cudd_libcudd_la-cuddZddIsop.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddIsop.lo `test -f 'cudd/cuddZddIsop.c' || echo '$(srcdir)/'`cudd/cuddZddIsop.c - -cudd/cudd_libcudd_la-cuddZddLin.lo: cudd/cuddZddLin.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddLin.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Tpo -c -o cudd/cudd_libcudd_la-cuddZddLin.lo `test -f 'cudd/cuddZddLin.c' || echo '$(srcdir)/'`cudd/cuddZddLin.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddLin.c' object='cudd/cudd_libcudd_la-cuddZddLin.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddLin.lo `test -f 'cudd/cuddZddLin.c' || echo '$(srcdir)/'`cudd/cuddZddLin.c - -cudd/cudd_libcudd_la-cuddZddMisc.lo: cudd/cuddZddMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddMisc.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Tpo -c -o cudd/cudd_libcudd_la-cuddZddMisc.lo `test -f 'cudd/cuddZddMisc.c' || echo '$(srcdir)/'`cudd/cuddZddMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddMisc.c' object='cudd/cudd_libcudd_la-cuddZddMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddMisc.lo `test -f 'cudd/cuddZddMisc.c' || echo '$(srcdir)/'`cudd/cuddZddMisc.c - -cudd/cudd_libcudd_la-cuddZddPort.lo: cudd/cuddZddPort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddPort.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Tpo -c -o cudd/cudd_libcudd_la-cuddZddPort.lo `test -f 'cudd/cuddZddPort.c' || echo '$(srcdir)/'`cudd/cuddZddPort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddPort.c' object='cudd/cudd_libcudd_la-cuddZddPort.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddPort.lo `test -f 'cudd/cuddZddPort.c' || echo '$(srcdir)/'`cudd/cuddZddPort.c - -cudd/cudd_libcudd_la-cuddZddReord.lo: cudd/cuddZddReord.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddReord.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Tpo -c -o cudd/cudd_libcudd_la-cuddZddReord.lo `test -f 'cudd/cuddZddReord.c' || echo '$(srcdir)/'`cudd/cuddZddReord.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddReord.c' object='cudd/cudd_libcudd_la-cuddZddReord.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddReord.lo `test -f 'cudd/cuddZddReord.c' || echo '$(srcdir)/'`cudd/cuddZddReord.c - -cudd/cudd_libcudd_la-cuddZddSetop.lo: cudd/cuddZddSetop.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddSetop.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Tpo -c -o cudd/cudd_libcudd_la-cuddZddSetop.lo `test -f 'cudd/cuddZddSetop.c' || echo '$(srcdir)/'`cudd/cuddZddSetop.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddSetop.c' object='cudd/cudd_libcudd_la-cuddZddSetop.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddSetop.lo `test -f 'cudd/cuddZddSetop.c' || echo '$(srcdir)/'`cudd/cuddZddSetop.c - -cudd/cudd_libcudd_la-cuddZddSymm.lo: cudd/cuddZddSymm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddSymm.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Tpo -c -o cudd/cudd_libcudd_la-cuddZddSymm.lo `test -f 'cudd/cuddZddSymm.c' || echo '$(srcdir)/'`cudd/cuddZddSymm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddSymm.c' object='cudd/cudd_libcudd_la-cuddZddSymm.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddSymm.lo `test -f 'cudd/cuddZddSymm.c' || echo '$(srcdir)/'`cudd/cuddZddSymm.c - -cudd/cudd_libcudd_la-cuddZddUtil.lo: cudd/cuddZddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddUtil.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Tpo -c -o cudd/cudd_libcudd_la-cuddZddUtil.lo `test -f 'cudd/cuddZddUtil.c' || echo '$(srcdir)/'`cudd/cuddZddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddUtil.c' object='cudd/cudd_libcudd_la-cuddZddUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddUtil.lo `test -f 'cudd/cuddZddUtil.c' || echo '$(srcdir)/'`cudd/cuddZddUtil.c - -util/cudd_libcudd_la-cpu_stats.lo: util/cpu_stats.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cpu_stats.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Tpo -c -o util/cudd_libcudd_la-cpu_stats.lo `test -f 'util/cpu_stats.c' || echo '$(srcdir)/'`util/cpu_stats.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Tpo util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cpu_stats.c' object='util/cudd_libcudd_la-cpu_stats.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cpu_stats.lo `test -f 'util/cpu_stats.c' || echo '$(srcdir)/'`util/cpu_stats.c - -util/cudd_libcudd_la-cpu_time.lo: util/cpu_time.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cpu_time.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Tpo -c -o util/cudd_libcudd_la-cpu_time.lo `test -f 'util/cpu_time.c' || echo '$(srcdir)/'`util/cpu_time.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Tpo util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cpu_time.c' object='util/cudd_libcudd_la-cpu_time.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cpu_time.lo `test -f 'util/cpu_time.c' || echo '$(srcdir)/'`util/cpu_time.c - -util/cudd_libcudd_la-cstringstream.lo: util/cstringstream.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cstringstream.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Tpo -c -o util/cudd_libcudd_la-cstringstream.lo `test -f 'util/cstringstream.c' || echo '$(srcdir)/'`util/cstringstream.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Tpo util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cstringstream.c' object='util/cudd_libcudd_la-cstringstream.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cstringstream.lo `test -f 'util/cstringstream.c' || echo '$(srcdir)/'`util/cstringstream.c - -util/cudd_libcudd_la-datalimit.lo: util/datalimit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-datalimit.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-datalimit.Tpo -c -o util/cudd_libcudd_la-datalimit.lo `test -f 'util/datalimit.c' || echo '$(srcdir)/'`util/datalimit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-datalimit.Tpo util/$(DEPDIR)/cudd_libcudd_la-datalimit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/datalimit.c' object='util/cudd_libcudd_la-datalimit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-datalimit.lo `test -f 'util/datalimit.c' || echo '$(srcdir)/'`util/datalimit.c - -util/cudd_libcudd_la-pathsearch.lo: util/pathsearch.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-pathsearch.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Tpo -c -o util/cudd_libcudd_la-pathsearch.lo `test -f 'util/pathsearch.c' || echo '$(srcdir)/'`util/pathsearch.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Tpo util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/pathsearch.c' object='util/cudd_libcudd_la-pathsearch.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-pathsearch.lo `test -f 'util/pathsearch.c' || echo '$(srcdir)/'`util/pathsearch.c - -util/cudd_libcudd_la-pipefork.lo: util/pipefork.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-pipefork.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-pipefork.Tpo -c -o util/cudd_libcudd_la-pipefork.lo `test -f 'util/pipefork.c' || echo '$(srcdir)/'`util/pipefork.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-pipefork.Tpo util/$(DEPDIR)/cudd_libcudd_la-pipefork.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/pipefork.c' object='util/cudd_libcudd_la-pipefork.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-pipefork.lo `test -f 'util/pipefork.c' || echo '$(srcdir)/'`util/pipefork.c - -util/cudd_libcudd_la-prtime.lo: util/prtime.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-prtime.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-prtime.Tpo -c -o util/cudd_libcudd_la-prtime.lo `test -f 'util/prtime.c' || echo '$(srcdir)/'`util/prtime.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-prtime.Tpo util/$(DEPDIR)/cudd_libcudd_la-prtime.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/prtime.c' object='util/cudd_libcudd_la-prtime.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-prtime.lo `test -f 'util/prtime.c' || echo '$(srcdir)/'`util/prtime.c - -util/cudd_libcudd_la-safe_mem.lo: util/safe_mem.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-safe_mem.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Tpo -c -o util/cudd_libcudd_la-safe_mem.lo `test -f 'util/safe_mem.c' || echo '$(srcdir)/'`util/safe_mem.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Tpo util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/safe_mem.c' object='util/cudd_libcudd_la-safe_mem.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-safe_mem.lo `test -f 'util/safe_mem.c' || echo '$(srcdir)/'`util/safe_mem.c - -util/cudd_libcudd_la-strsav.lo: util/strsav.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-strsav.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-strsav.Tpo -c -o util/cudd_libcudd_la-strsav.lo `test -f 'util/strsav.c' || echo '$(srcdir)/'`util/strsav.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-strsav.Tpo util/$(DEPDIR)/cudd_libcudd_la-strsav.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/strsav.c' object='util/cudd_libcudd_la-strsav.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-strsav.lo `test -f 'util/strsav.c' || echo '$(srcdir)/'`util/strsav.c - -util/cudd_libcudd_la-texpand.lo: util/texpand.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-texpand.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-texpand.Tpo -c -o util/cudd_libcudd_la-texpand.lo `test -f 'util/texpand.c' || echo '$(srcdir)/'`util/texpand.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-texpand.Tpo util/$(DEPDIR)/cudd_libcudd_la-texpand.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/texpand.c' object='util/cudd_libcudd_la-texpand.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-texpand.lo `test -f 'util/texpand.c' || echo '$(srcdir)/'`util/texpand.c - -util/cudd_libcudd_la-ucbqsort.lo: util/ucbqsort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-ucbqsort.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Tpo -c -o util/cudd_libcudd_la-ucbqsort.lo `test -f 'util/ucbqsort.c' || echo '$(srcdir)/'`util/ucbqsort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Tpo util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/ucbqsort.c' object='util/cudd_libcudd_la-ucbqsort.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-ucbqsort.lo `test -f 'util/ucbqsort.c' || echo '$(srcdir)/'`util/ucbqsort.c - -st/cudd_libcudd_la-st.lo: st/st.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/cudd_libcudd_la-st.lo -MD -MP -MF st/$(DEPDIR)/cudd_libcudd_la-st.Tpo -c -o st/cudd_libcudd_la-st.lo `test -f 'st/st.c' || echo '$(srcdir)/'`st/st.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/cudd_libcudd_la-st.Tpo st/$(DEPDIR)/cudd_libcudd_la-st.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/st.c' object='st/cudd_libcudd_la-st.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/cudd_libcudd_la-st.lo `test -f 'st/st.c' || echo '$(srcdir)/'`st/st.c - -epd/cudd_libcudd_la-epd.lo: epd/epd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT epd/cudd_libcudd_la-epd.lo -MD -MP -MF epd/$(DEPDIR)/cudd_libcudd_la-epd.Tpo -c -o epd/cudd_libcudd_la-epd.lo `test -f 'epd/epd.c' || echo '$(srcdir)/'`epd/epd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) epd/$(DEPDIR)/cudd_libcudd_la-epd.Tpo epd/$(DEPDIR)/cudd_libcudd_la-epd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epd/epd.c' object='epd/cudd_libcudd_la-epd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o epd/cudd_libcudd_la-epd.lo `test -f 'epd/epd.c' || echo '$(srcdir)/'`epd/epd.c - -mtr/cudd_libcudd_la-mtrBasic.lo: mtr/mtrBasic.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/cudd_libcudd_la-mtrBasic.lo -MD -MP -MF mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Tpo -c -o mtr/cudd_libcudd_la-mtrBasic.lo `test -f 'mtr/mtrBasic.c' || echo '$(srcdir)/'`mtr/mtrBasic.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Tpo mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/mtrBasic.c' object='mtr/cudd_libcudd_la-mtrBasic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/cudd_libcudd_la-mtrBasic.lo `test -f 'mtr/mtrBasic.c' || echo '$(srcdir)/'`mtr/mtrBasic.c - -mtr/cudd_libcudd_la-mtrGroup.lo: mtr/mtrGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/cudd_libcudd_la-mtrGroup.lo -MD -MP -MF mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Tpo -c -o mtr/cudd_libcudd_la-mtrGroup.lo `test -f 'mtr/mtrGroup.c' || echo '$(srcdir)/'`mtr/mtrGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Tpo mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/mtrGroup.c' object='mtr/cudd_libcudd_la-mtrGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/cudd_libcudd_la-mtrGroup.lo `test -f 'mtr/mtrGroup.c' || echo '$(srcdir)/'`mtr/mtrGroup.c - -dddmp/cudd_libcudd_la-dddmpBinary.lo: dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpBinary.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Tpo -c -o dddmp/cudd_libcudd_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpBinary.c' object='dddmp/cudd_libcudd_la-dddmpBinary.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c - -dddmp/cudd_libcudd_la-dddmpConvert.lo: dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpConvert.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Tpo -c -o dddmp/cudd_libcudd_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpConvert.c' object='dddmp/cudd_libcudd_la-dddmpConvert.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c - -dddmp/cudd_libcudd_la-dddmpDbg.lo: dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpDbg.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Tpo -c -o dddmp/cudd_libcudd_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpDbg.c' object='dddmp/cudd_libcudd_la-dddmpDbg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c - -dddmp/cudd_libcudd_la-dddmpLoad.lo: dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpLoad.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Tpo -c -o dddmp/cudd_libcudd_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoad.c' object='dddmp/cudd_libcudd_la-dddmpLoad.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c - -dddmp/cudd_libcudd_la-dddmpLoadCnf.lo: dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpLoadCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoadCnf.c' object='dddmp/cudd_libcudd_la-dddmpLoadCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c - -dddmp/cudd_libcudd_la-dddmpNodeAdd.lo: dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeAdd.c' object='dddmp/cudd_libcudd_la-dddmpNodeAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c - -dddmp/cudd_libcudd_la-dddmpNodeBdd.lo: dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeBdd.c' object='dddmp/cudd_libcudd_la-dddmpNodeBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c - -dddmp/cudd_libcudd_la-dddmpNodeCnf.lo: dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeCnf.c' object='dddmp/cudd_libcudd_la-dddmpNodeCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c - -dddmp/cudd_libcudd_la-dddmpStoreAdd.lo: dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreAdd.c' object='dddmp/cudd_libcudd_la-dddmpStoreAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c - -dddmp/cudd_libcudd_la-dddmpStoreBdd.lo: dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreBdd.c' object='dddmp/cudd_libcudd_la-dddmpStoreBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c - -dddmp/cudd_libcudd_la-dddmpStoreCnf.lo: dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreCnf.c' object='dddmp/cudd_libcudd_la-dddmpStoreCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c - -dddmp/cudd_libcudd_la-dddmpStoreMisc.lo: dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreMisc.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreMisc.c' object='dddmp/cudd_libcudd_la-dddmpStoreMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c - -dddmp/cudd_libcudd_la-dddmpUtil.lo: dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpUtil.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Tpo -c -o dddmp/cudd_libcudd_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpUtil.c' object='dddmp/cudd_libcudd_la-dddmpUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c - -dddmp/dddmp_libdddmp_la-dddmpBinary.lo: dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpBinary.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpBinary.c' object='dddmp/dddmp_libdddmp_la-dddmpBinary.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c - -dddmp/dddmp_libdddmp_la-dddmpConvert.lo: dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpConvert.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpConvert.c' object='dddmp/dddmp_libdddmp_la-dddmpConvert.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c - -dddmp/dddmp_libdddmp_la-dddmpDbg.lo: dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpDbg.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpDbg.c' object='dddmp/dddmp_libdddmp_la-dddmpDbg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c - -dddmp/dddmp_libdddmp_la-dddmpLoad.lo: dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpLoad.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoad.c' object='dddmp/dddmp_libdddmp_la-dddmpLoad.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c - -dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo: dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoadCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c - -dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo: dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeAdd.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c - -dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo: dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeBdd.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c - -dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo: dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c - -dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo: dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreAdd.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c - -dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo: dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreBdd.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c - -dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo: dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c - -dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo: dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreMisc.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c - -dddmp/dddmp_libdddmp_la-dddmpUtil.lo: dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpUtil.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpUtil.c' object='dddmp/dddmp_libdddmp_la-dddmpUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c - -cudd/cudd_testcudd-testcudd.o: cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testcudd-testcudd.o -MD -MP -MF cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo -c -o cudd/cudd_testcudd-testcudd.o `test -f 'cudd/testcudd.c' || echo '$(srcdir)/'`cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testcudd.c' object='cudd/cudd_testcudd-testcudd.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testcudd-testcudd.o `test -f 'cudd/testcudd.c' || echo '$(srcdir)/'`cudd/testcudd.c - -cudd/cudd_testcudd-testcudd.obj: cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testcudd-testcudd.obj -MD -MP -MF cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo -c -o cudd/cudd_testcudd-testcudd.obj `if test -f 'cudd/testcudd.c'; then $(CYGPATH_W) 'cudd/testcudd.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testcudd.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testcudd.c' object='cudd/cudd_testcudd-testcudd.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testcudd-testcudd.obj `if test -f 'cudd/testcudd.c'; then $(CYGPATH_W) 'cudd/testcudd.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testcudd.c'; fi` - -cudd/cudd_testextra-testextra.o: cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testextra-testextra.o -MD -MP -MF cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo -c -o cudd/cudd_testextra-testextra.o `test -f 'cudd/testextra.c' || echo '$(srcdir)/'`cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo cudd/$(DEPDIR)/cudd_testextra-testextra.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testextra.c' object='cudd/cudd_testextra-testextra.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testextra-testextra.o `test -f 'cudd/testextra.c' || echo '$(srcdir)/'`cudd/testextra.c - -cudd/cudd_testextra-testextra.obj: cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testextra-testextra.obj -MD -MP -MF cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo -c -o cudd/cudd_testextra-testextra.obj `if test -f 'cudd/testextra.c'; then $(CYGPATH_W) 'cudd/testextra.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testextra.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo cudd/$(DEPDIR)/cudd_testextra-testextra.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testextra.c' object='cudd/cudd_testextra-testextra.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testextra-testextra.obj `if test -f 'cudd/testextra.c'; then $(CYGPATH_W) 'cudd/testextra.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testextra.c'; fi` - -dddmp/dddmp_testdddmp-testdddmp.o: dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_testdddmp-testdddmp.o -MD -MP -MF dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo -c -o dddmp/dddmp_testdddmp-testdddmp.o `test -f 'dddmp/testdddmp.c' || echo '$(srcdir)/'`dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/testdddmp.c' object='dddmp/dddmp_testdddmp-testdddmp.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_testdddmp-testdddmp.o `test -f 'dddmp/testdddmp.c' || echo '$(srcdir)/'`dddmp/testdddmp.c - -dddmp/dddmp_testdddmp-testdddmp.obj: dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_testdddmp-testdddmp.obj -MD -MP -MF dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo -c -o dddmp/dddmp_testdddmp-testdddmp.obj `if test -f 'dddmp/testdddmp.c'; then $(CYGPATH_W) 'dddmp/testdddmp.c'; else $(CYGPATH_W) '$(srcdir)/dddmp/testdddmp.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/testdddmp.c' object='dddmp/dddmp_testdddmp-testdddmp.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_testdddmp-testdddmp.obj `if test -f 'dddmp/testdddmp.c'; then $(CYGPATH_W) 'dddmp/testdddmp.c'; else $(CYGPATH_W) '$(srcdir)/dddmp/testdddmp.c'; fi` - -mtr/mtr_testmtr-testmtr.o: mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/mtr_testmtr-testmtr.o -MD -MP -MF mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo -c -o mtr/mtr_testmtr-testmtr.o `test -f 'mtr/testmtr.c' || echo '$(srcdir)/'`mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/testmtr.c' object='mtr/mtr_testmtr-testmtr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/mtr_testmtr-testmtr.o `test -f 'mtr/testmtr.c' || echo '$(srcdir)/'`mtr/testmtr.c - -mtr/mtr_testmtr-testmtr.obj: mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/mtr_testmtr-testmtr.obj -MD -MP -MF mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo -c -o mtr/mtr_testmtr-testmtr.obj `if test -f 'mtr/testmtr.c'; then $(CYGPATH_W) 'mtr/testmtr.c'; else $(CYGPATH_W) '$(srcdir)/mtr/testmtr.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/testmtr.c' object='mtr/mtr_testmtr-testmtr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/mtr_testmtr-testmtr.obj `if test -f 'mtr/testmtr.c'; then $(CYGPATH_W) 'mtr/testmtr.c'; else $(CYGPATH_W) '$(srcdir)/mtr/testmtr.c'; fi` - -nanotrav/nanotrav_nanotrav-bnet.o: nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-bnet.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo -c -o nanotrav/nanotrav_nanotrav-bnet.o `test -f 'nanotrav/bnet.c' || echo '$(srcdir)/'`nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/bnet.c' object='nanotrav/nanotrav_nanotrav-bnet.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-bnet.o `test -f 'nanotrav/bnet.c' || echo '$(srcdir)/'`nanotrav/bnet.c - -nanotrav/nanotrav_nanotrav-bnet.obj: nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-bnet.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo -c -o nanotrav/nanotrav_nanotrav-bnet.obj `if test -f 'nanotrav/bnet.c'; then $(CYGPATH_W) 'nanotrav/bnet.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/bnet.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/bnet.c' object='nanotrav/nanotrav_nanotrav-bnet.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-bnet.obj `if test -f 'nanotrav/bnet.c'; then $(CYGPATH_W) 'nanotrav/bnet.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/bnet.c'; fi` - -nanotrav/nanotrav_nanotrav-chkMterm.o: nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-chkMterm.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo -c -o nanotrav/nanotrav_nanotrav-chkMterm.o `test -f 'nanotrav/chkMterm.c' || echo '$(srcdir)/'`nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/chkMterm.c' object='nanotrav/nanotrav_nanotrav-chkMterm.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-chkMterm.o `test -f 'nanotrav/chkMterm.c' || echo '$(srcdir)/'`nanotrav/chkMterm.c - -nanotrav/nanotrav_nanotrav-chkMterm.obj: nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-chkMterm.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo -c -o nanotrav/nanotrav_nanotrav-chkMterm.obj `if test -f 'nanotrav/chkMterm.c'; then $(CYGPATH_W) 'nanotrav/chkMterm.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/chkMterm.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/chkMterm.c' object='nanotrav/nanotrav_nanotrav-chkMterm.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-chkMterm.obj `if test -f 'nanotrav/chkMterm.c'; then $(CYGPATH_W) 'nanotrav/chkMterm.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/chkMterm.c'; fi` - -nanotrav/nanotrav_nanotrav-main.o: nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-main.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo -c -o nanotrav/nanotrav_nanotrav-main.o `test -f 'nanotrav/main.c' || echo '$(srcdir)/'`nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/main.c' object='nanotrav/nanotrav_nanotrav-main.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-main.o `test -f 'nanotrav/main.c' || echo '$(srcdir)/'`nanotrav/main.c - -nanotrav/nanotrav_nanotrav-main.obj: nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-main.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo -c -o nanotrav/nanotrav_nanotrav-main.obj `if test -f 'nanotrav/main.c'; then $(CYGPATH_W) 'nanotrav/main.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/main.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/main.c' object='nanotrav/nanotrav_nanotrav-main.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-main.obj `if test -f 'nanotrav/main.c'; then $(CYGPATH_W) 'nanotrav/main.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/main.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrBddTest.o: nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrBddTest.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.o `test -f 'nanotrav/ntrBddTest.c' || echo '$(srcdir)/'`nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrBddTest.c' object='nanotrav/nanotrav_nanotrav-ntrBddTest.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.o `test -f 'nanotrav/ntrBddTest.c' || echo '$(srcdir)/'`nanotrav/ntrBddTest.c - -nanotrav/nanotrav_nanotrav-ntrBddTest.obj: nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrBddTest.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.obj `if test -f 'nanotrav/ntrBddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrBddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrBddTest.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrBddTest.c' object='nanotrav/nanotrav_nanotrav-ntrBddTest.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.obj `if test -f 'nanotrav/ntrBddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrBddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrBddTest.c'; fi` - -nanotrav/nanotrav_nanotrav-ntr.o: nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntr.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo -c -o nanotrav/nanotrav_nanotrav-ntr.o `test -f 'nanotrav/ntr.c' || echo '$(srcdir)/'`nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntr.c' object='nanotrav/nanotrav_nanotrav-ntr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntr.o `test -f 'nanotrav/ntr.c' || echo '$(srcdir)/'`nanotrav/ntr.c - -nanotrav/nanotrav_nanotrav-ntr.obj: nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntr.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo -c -o nanotrav/nanotrav_nanotrav-ntr.obj `if test -f 'nanotrav/ntr.c'; then $(CYGPATH_W) 'nanotrav/ntr.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntr.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntr.c' object='nanotrav/nanotrav_nanotrav-ntr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntr.obj `if test -f 'nanotrav/ntr.c'; then $(CYGPATH_W) 'nanotrav/ntr.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntr.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrHeap.o: nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrHeap.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrHeap.o `test -f 'nanotrav/ntrHeap.c' || echo '$(srcdir)/'`nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrHeap.c' object='nanotrav/nanotrav_nanotrav-ntrHeap.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrHeap.o `test -f 'nanotrav/ntrHeap.c' || echo '$(srcdir)/'`nanotrav/ntrHeap.c - -nanotrav/nanotrav_nanotrav-ntrHeap.obj: nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrHeap.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrHeap.obj `if test -f 'nanotrav/ntrHeap.c'; then $(CYGPATH_W) 'nanotrav/ntrHeap.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrHeap.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrHeap.c' object='nanotrav/nanotrav_nanotrav-ntrHeap.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrHeap.obj `if test -f 'nanotrav/ntrHeap.c'; then $(CYGPATH_W) 'nanotrav/ntrHeap.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrHeap.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrMflow.o: nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrMflow.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrMflow.o `test -f 'nanotrav/ntrMflow.c' || echo '$(srcdir)/'`nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrMflow.c' object='nanotrav/nanotrav_nanotrav-ntrMflow.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrMflow.o `test -f 'nanotrav/ntrMflow.c' || echo '$(srcdir)/'`nanotrav/ntrMflow.c - -nanotrav/nanotrav_nanotrav-ntrMflow.obj: nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrMflow.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrMflow.obj `if test -f 'nanotrav/ntrMflow.c'; then $(CYGPATH_W) 'nanotrav/ntrMflow.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrMflow.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrMflow.c' object='nanotrav/nanotrav_nanotrav-ntrMflow.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrMflow.obj `if test -f 'nanotrav/ntrMflow.c'; then $(CYGPATH_W) 'nanotrav/ntrMflow.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrMflow.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrShort.o: nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrShort.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrShort.o `test -f 'nanotrav/ntrShort.c' || echo '$(srcdir)/'`nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrShort.c' object='nanotrav/nanotrav_nanotrav-ntrShort.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrShort.o `test -f 'nanotrav/ntrShort.c' || echo '$(srcdir)/'`nanotrav/ntrShort.c - -nanotrav/nanotrav_nanotrav-ntrShort.obj: nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrShort.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrShort.obj `if test -f 'nanotrav/ntrShort.c'; then $(CYGPATH_W) 'nanotrav/ntrShort.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrShort.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrShort.c' object='nanotrav/nanotrav_nanotrav-ntrShort.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrShort.obj `if test -f 'nanotrav/ntrShort.c'; then $(CYGPATH_W) 'nanotrav/ntrShort.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrShort.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrZddTest.o: nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrZddTest.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.o `test -f 'nanotrav/ntrZddTest.c' || echo '$(srcdir)/'`nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrZddTest.c' object='nanotrav/nanotrav_nanotrav-ntrZddTest.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.o `test -f 'nanotrav/ntrZddTest.c' || echo '$(srcdir)/'`nanotrav/ntrZddTest.c - -nanotrav/nanotrav_nanotrav-ntrZddTest.obj: nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrZddTest.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.obj `if test -f 'nanotrav/ntrZddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrZddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrZddTest.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrZddTest.c' object='nanotrav/nanotrav_nanotrav-ntrZddTest.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.obj `if test -f 'nanotrav/ntrZddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrZddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrZddTest.c'; fi` - -st/st_testst-testst.o: st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/st_testst-testst.o -MD -MP -MF st/$(DEPDIR)/st_testst-testst.Tpo -c -o st/st_testst-testst.o `test -f 'st/testst.c' || echo '$(srcdir)/'`st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/st_testst-testst.Tpo st/$(DEPDIR)/st_testst-testst.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/testst.c' object='st/st_testst-testst.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/st_testst-testst.o `test -f 'st/testst.c' || echo '$(srcdir)/'`st/testst.c - -st/st_testst-testst.obj: st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/st_testst-testst.obj -MD -MP -MF st/$(DEPDIR)/st_testst-testst.Tpo -c -o st/st_testst-testst.obj `if test -f 'st/testst.c'; then $(CYGPATH_W) 'st/testst.c'; else $(CYGPATH_W) '$(srcdir)/st/testst.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/st_testst-testst.Tpo st/$(DEPDIR)/st_testst-testst.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/testst.c' object='st/st_testst-testst.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/st_testst-testst.obj `if test -f 'st/testst.c'; then $(CYGPATH_W) 'st/testst.c'; else $(CYGPATH_W) '$(srcdir)/st/testst.c'; fi` - -.cc.o: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< - -.cc.obj: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.cc.lo: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< - -cplusplus/cplusplus_libobj_la-cuddObj.lo: cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_libobj_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_libobj_la-cuddObj.lo -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Tpo -c -o cplusplus/cplusplus_libobj_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Tpo cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/cuddObj.cc' object='cplusplus/cplusplus_libobj_la-cuddObj.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_libobj_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_libobj_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc - -cplusplus/cudd_libcudd_la-cuddObj.lo: cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cudd_libcudd_la-cuddObj.lo -MD -MP -MF cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Tpo -c -o cplusplus/cudd_libcudd_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Tpo cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/cuddObj.cc' object='cplusplus/cudd_libcudd_la-cuddObj.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cudd_libcudd_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc - -cplusplus/cplusplus_testmulti-testmulti.o: cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testmulti-testmulti.o -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo -c -o cplusplus/cplusplus_testmulti-testmulti.o `test -f 'cplusplus/testmulti.cc' || echo '$(srcdir)/'`cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testmulti.cc' object='cplusplus/cplusplus_testmulti-testmulti.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testmulti-testmulti.o `test -f 'cplusplus/testmulti.cc' || echo '$(srcdir)/'`cplusplus/testmulti.cc - -cplusplus/cplusplus_testmulti-testmulti.obj: cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testmulti-testmulti.obj -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo -c -o cplusplus/cplusplus_testmulti-testmulti.obj `if test -f 'cplusplus/testmulti.cc'; then $(CYGPATH_W) 'cplusplus/testmulti.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testmulti.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testmulti.cc' object='cplusplus/cplusplus_testmulti-testmulti.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testmulti-testmulti.obj `if test -f 'cplusplus/testmulti.cc'; then $(CYGPATH_W) 'cplusplus/testmulti.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testmulti.cc'; fi` - -cplusplus/cplusplus_testobj-testobj.o: cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testobj-testobj.o -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo -c -o cplusplus/cplusplus_testobj-testobj.o `test -f 'cplusplus/testobj.cc' || echo '$(srcdir)/'`cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testobj.cc' object='cplusplus/cplusplus_testobj-testobj.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testobj-testobj.o `test -f 'cplusplus/testobj.cc' || echo '$(srcdir)/'`cplusplus/testobj.cc - -cplusplus/cplusplus_testobj-testobj.obj: cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testobj-testobj.obj -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo -c -o cplusplus/cplusplus_testobj-testobj.obj `if test -f 'cplusplus/testobj.cc'; then $(CYGPATH_W) 'cplusplus/testobj.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testobj.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testobj.cc' object='cplusplus/cplusplus_testobj-testobj.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testobj-testobj.obj `if test -f 'cplusplus/testobj.cc'; then $(CYGPATH_W) 'cplusplus/testobj.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testobj.cc'; fi` - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -rm -rf cplusplus/.libs cplusplus/_libs - -rm -rf cudd/.libs cudd/_libs - -rm -rf dddmp/.libs dddmp/_libs - -rm -rf epd/.libs epd/_libs - -rm -rf mtr/.libs mtr/_libs - -rm -rf nanotrav/.libs nanotrav/_libs - -rm -rf st/.libs st/_libs - -rm -rf util/.libs util/_libs - -distclean-libtool: - -rm -f libtool config.lt -install-includeHEADERS: $(include_HEADERS) - @$(NORMAL_INSTALL) - @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ - $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ - done - -uninstall-includeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - -# Recover from deleted '.trs' file; this should ensure that -# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create -# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells -# to avoid problems with "make -n". -.log.trs: - rm -f $< $@ - $(MAKE) $(AM_MAKEFLAGS) $< - -# Leading 'am--fnord' is there to ensure the list of targets does not -# expand to empty, as could happen e.g. with make check TESTS=''. -am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) -am--force-recheck: - @: - -$(TEST_SUITE_LOG): $(TEST_LOGS) - @$(am__set_TESTS_bases); \ - am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ - redo_bases=`for i in $$bases; do \ - am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ - done`; \ - if test -n "$$redo_bases"; then \ - redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ - redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ - if $(am__make_dryrun); then :; else \ - rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ - fi; \ - fi; \ - if test -n "$$am__remaking_logs"; then \ - echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ - "recursion detected" >&2; \ - elif test -n "$$redo_logs"; then \ - am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ - fi; \ - if $(am__make_dryrun); then :; else \ - st=0; \ - errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ - for i in $$redo_bases; do \ - test -f $$i.trs && test -r $$i.trs \ - || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ - test -f $$i.log && test -r $$i.log \ - || { echo "$$errmsg $$i.log" >&2; st=1; }; \ - done; \ - test $$st -eq 0 || exit 1; \ - fi - @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ - ws='[ ]'; \ - results=`for b in $$bases; do echo $$b.trs; done`; \ - test -n "$$results" || results=/dev/null; \ - all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ - pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ - fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ - skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ - xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ - xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ - error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ - if test `expr $$fail + $$xpass + $$error` -eq 0; then \ - success=true; \ - else \ - success=false; \ - fi; \ - br='==================='; br=$$br$$br$$br$$br; \ - result_count () \ - { \ - if test x"$$1" = x"--maybe-color"; then \ - maybe_colorize=yes; \ - elif test x"$$1" = x"--no-color"; then \ - maybe_colorize=no; \ - else \ - echo "$@: invalid 'result_count' usage" >&2; exit 4; \ - fi; \ - shift; \ - desc=$$1 count=$$2; \ - if test $$maybe_colorize = yes && test $$count -gt 0; then \ - color_start=$$3 color_end=$$std; \ - else \ - color_start= color_end=; \ - fi; \ - echo "$${color_start}# $$desc $$count$${color_end}"; \ - }; \ - create_testsuite_report () \ - { \ - result_count $$1 "TOTAL:" $$all "$$brg"; \ - result_count $$1 "PASS: " $$pass "$$grn"; \ - result_count $$1 "SKIP: " $$skip "$$blu"; \ - result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ - result_count $$1 "FAIL: " $$fail "$$red"; \ - result_count $$1 "XPASS:" $$xpass "$$red"; \ - result_count $$1 "ERROR:" $$error "$$mgn"; \ - }; \ - { \ - echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ - $(am__rst_title); \ - create_testsuite_report --no-color; \ - echo; \ - echo ".. contents:: :depth: 2"; \ - echo; \ - for b in $$bases; do echo $$b; done \ - | $(am__create_global_log); \ - } >$(TEST_SUITE_LOG).tmp || exit 1; \ - mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ - if $$success; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ - fi; \ - echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ - echo "$${col}$$br$${std}"; \ - create_testsuite_report --maybe-color; \ - echo "$$col$$br$$std"; \ - if $$success; then :; else \ - echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ - if test -n "$(PACKAGE_BUGREPORT)"; then \ - echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ - fi; \ - echo "$$col$$br$$std"; \ - fi; \ - $$success || exit 1 - -check-TESTS: - @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list - @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - trs_list=`for i in $$bases; do echo $$i.trs; done`; \ - log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ - exit $$?; -recheck: all $(check_PROGRAMS) $(check_SCRIPTS) $(dist_check_DATA) - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - bases=`for i in $$bases; do echo $$i; done \ - | $(am__list_recheck_tests)` || exit 1; \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - log_list=`echo $$log_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ - am__force_recheck=am--force-recheck \ - TEST_LOGS="$$log_list"; \ - exit $$? -.test.log: - @p='$<'; \ - $(am__set_b); \ - $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -@am__EXEEXT_TRUE@.test$(EXEEXT).log: -@am__EXEEXT_TRUE@ @p='$<'; \ -@am__EXEEXT_TRUE@ $(am__set_b); \ -@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ -@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ -@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ -@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) \ - $(dist_check_DATA) - $(MAKE) $(AM_MAKEFLAGS) check-TESTS -check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) - -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) - -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -rm -f cplusplus/$(DEPDIR)/$(am__dirstamp) - -rm -f cplusplus/$(am__dirstamp) - -rm -f cudd/$(DEPDIR)/$(am__dirstamp) - -rm -f cudd/$(am__dirstamp) - -rm -f dddmp/$(DEPDIR)/$(am__dirstamp) - -rm -f dddmp/$(am__dirstamp) - -rm -f epd/$(DEPDIR)/$(am__dirstamp) - -rm -f epd/$(am__dirstamp) - -rm -f mtr/$(DEPDIR)/$(am__dirstamp) - -rm -f mtr/$(am__dirstamp) - -rm -f nanotrav/$(DEPDIR)/$(am__dirstamp) - -rm -f nanotrav/$(am__dirstamp) - -rm -f st/$(DEPDIR)/$(am__dirstamp) - -rm -f st/$(am__dirstamp) - -rm -f util/$(DEPDIR)/$(am__dirstamp) - -rm -f util/$(am__dirstamp) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ - clean-libtool clean-noinstLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf cplusplus/$(DEPDIR) cudd/$(DEPDIR) dddmp/$(DEPDIR) epd/$(DEPDIR) mtr/$(DEPDIR) nanotrav/$(DEPDIR) st/$(DEPDIR) util/$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-includeHEADERS - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf cplusplus/$(DEPDIR) cudd/$(DEPDIR) dddmp/$(DEPDIR) epd/$(DEPDIR) mtr/$(DEPDIR) nanotrav/$(DEPDIR) st/$(DEPDIR) util/$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES - -.MAKE: all check-am install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \ - check-am clean clean-checkPROGRAMS clean-cscope clean-generic \ - clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ - cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \ - dist-zip distcheck distclean distclean-compile \ - distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-includeHEADERS install-info install-info-am \ - install-libLTLIBRARIES install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - recheck tags tags-am uninstall uninstall-am \ - uninstall-includeHEADERS uninstall-libLTLIBRARIES - -.PRECIOUS: Makefile - - -cudd/test_cudd.test: cudd/test_cudd.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -st/test_st.test: st/test_st.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -mtr/test_mtr.test: mtr/test_mtr.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -dddmp/test_dddmp.test: dddmp/test_dddmp.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -cplusplus/test_obj.test: cplusplus/test_obj.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -nanotrav/test_ntrv.test: nanotrav/test_ntrv.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -@HAVE_PDFLATEX_TRUE@doc/cudd.pdf: doc/cudd.tex $(top_srcdir)/doc/phase.pdf -@HAVE_PDFLATEX_TRUE@ @if $(AM_V_P); then dest='2>&1'; else dest='> /dev/null 2>&1'; fi; \ -@HAVE_PDFLATEX_TRUE@ cd doc && eval "$(PDFLATEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(MAKEINDEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(PDFLATEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(PDFLATEX) cudd $${dest}" - -@HAVE_PDFLATEX_FALSE@doc/cudd.pdf: - -dist-hook: - rm -rf `find $(distdir) -name .svn` - -.PHONY : - -all: html/index.html doc/cudd.pdf - -#if HAVE_DOXYGEN -# -#html/index.html: Doxyfile $(lib_LTLIBRARIES) -# @if $(AM_V_P); then dest='2>&1'; else dest='> /dev/null 2>&1'; fi; \ -# eval "$(DOXYGEN) $< $${dest}" -# -#clean-local: -# rm -rf html doxygen_sqlite3.db -# -#else - -html/index.html: - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/resources/3rdparty/cudd-3.0.0/aclocal.m4 b/resources/3rdparty/cudd-3.0.0/aclocal.m4 deleted file mode 100644 index b1d04ee86..000000000 --- a/resources/3rdparty/cudd-3.0.0/aclocal.m4 +++ /dev/null @@ -1,1256 +0,0 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- - -# Copyright (C) 1996-2017 Free Software Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically 'autoreconf'.])]) - -# Copyright (C) 2002-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.15' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15.1], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15.1])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# Copyright (C) 2011-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_AR([ACT-IF-FAIL]) -# ------------------------- -# Try to determine the archiver interface, and trigger the ar-lib wrapper -# if it is needed. If the detection of archiver interface fails, run -# ACT-IF-FAIL (default is to abort configure with a proper error message). -AC_DEFUN([AM_PROG_AR], -[AC_BEFORE([$0], [LT_INIT])dnl -AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl -AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([ar-lib])dnl -AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) -: ${AR=ar} - -AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], - [AC_LANG_PUSH([C]) - am_cv_ar_interface=ar - AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], - [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' - AC_TRY_EVAL([am_ar_try]) - if test "$ac_status" -eq 0; then - am_cv_ar_interface=ar - else - am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' - AC_TRY_EVAL([am_ar_try]) - if test "$ac_status" -eq 0; then - am_cv_ar_interface=lib - else - am_cv_ar_interface=unknown - fi - fi - rm -f conftest.lib libconftest.a - ]) - AC_LANG_POP([C])]) - -case $am_cv_ar_interface in -ar) - ;; -lib) - # Microsoft lib, so override with the ar-lib wrapper script. - # FIXME: It is wrong to rewrite AR. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__AR in this case, - # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something - # similar. - AR="$am_aux_dir/ar-lib $AR" - ;; -unknown) - m4_default([$1], - [AC_MSG_ERROR([could not determine $AR interface])]) - ;; -esac -AC_SUBST([AR])dnl -]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to -# '$srcdir', '$srcdir/..', or '$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is '.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) - -# AM_COND_IF -*- Autoconf -*- - -# Copyright (C) 2008-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_COND_IF -# _AM_COND_ELSE -# _AM_COND_ENDIF -# -------------- -# These macros are only used for tracing. -m4_define([_AM_COND_IF]) -m4_define([_AM_COND_ELSE]) -m4_define([_AM_COND_ENDIF]) - -# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) -# --------------------------------------- -# If the shell condition COND is true, execute IF-TRUE, otherwise execute -# IF-FALSE. Allow automake to learn about conditional instantiating macros -# (the AC_CONFIG_FOOS). -AC_DEFUN([AM_COND_IF], -[m4_ifndef([_AM_COND_VALUE_$1], - [m4_fatal([$0: no such condition "$1"])])dnl -_AM_COND_IF([$1])dnl -if test -z "$$1_TRUE"; then : - m4_n([$2])[]dnl -m4_ifval([$3], -[_AM_COND_ELSE([$1])dnl -else - $3 -])dnl -_AM_COND_ENDIF([$1])dnl -fi[]dnl -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], - [$1], [CXX], [depcc="$CXX" am_compiler_list=], - [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], - [$1], [UPC], [depcc="$UPC" am_compiler_list=], - [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES. -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE([dependency-tracking], [dnl -AS_HELP_STRING( - [--enable-dependency-tracking], - [do not reject slow dependency extractors]) -AS_HELP_STRING( - [--disable-dependency-tracking], - [speeds up one-time build])]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -AC_SUBST([am__nodep])dnl -_AM_SUBST_NOTMAKE([am__nodep])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[{ - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each '.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. -m4_define([AC_PROG_CC], -m4_defn([AC_PROG_CC]) -[_AM_PROG_CC_C_O -]) - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.65])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[AC_DIAGNOSE([obsolete], - [$0: two- and three-arguments forms are deprecated.]) -m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), - [ok:ok],, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -AM_MISSING_PROG([AUTOCONF], [autoconf]) -AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -AM_MISSING_PROG([AUTOHEADER], [autoheader]) -AM_MISSING_PROG([MAKEINFO], [makeinfo]) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES([CC])], - [m4_define([AC_PROG_CC], - m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES([CXX])], - [m4_define([AC_PROG_CXX], - m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES([OBJC])], - [m4_define([AC_PROG_OBJC], - m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], - [_AM_DEPENDENCIES([OBJCXX])], - [m4_define([AC_PROG_OBJCXX], - m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl -]) -AC_REQUIRE([AM_SILENT_RULES])dnl -dnl The testsuite driver may need to know about EXEEXT, so add the -dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This -dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) - fi -fi -dnl The trailing newline in this macro's definition is deliberate, for -dnl backward compatibility and to allow trailing 'dnl'-style comments -dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. -]) - -dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) - -# Copyright (C) 2003-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it is modern enough. -# If it is, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - AC_MSG_WARN(['missing' script is too old or missing]) -fi -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# -------------------- -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) - -# _AM_SET_OPTIONS(OPTIONS) -# ------------------------ -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Copyright (C) 1999-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_CC_C_O -# --------------- -# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC -# to automatically call this. -AC_DEFUN([_AM_PROG_CC_C_O], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) - -# For backward compatibility. -AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_RUN_LOG(COMMAND) -# ------------------- -# Run COMMAND, save the exit status in ac_status, and log it. -# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) -AC_DEFUN([AM_RUN_LOG], -[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD - ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - (exit $ac_status); }]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken - alias in your environment]) - fi - if test "$[2]" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT([yes]) -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & - am_sleep_pid=$! -fi -AC_CONFIG_COMMANDS_PRE( - [AC_MSG_CHECKING([that generated files are newer than configure]) - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - AC_MSG_RESULT([done])]) -rm -f conftest.file -]) - -# Copyright (C) 2009-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_SILENT_RULES([DEFAULT]) -# -------------------------- -# Enable less verbose build rules; with the default set to DEFAULT -# ("yes" being less verbose, "no" or empty being verbose). -AC_DEFUN([AM_SILENT_RULES], -[AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; -esac -dnl -dnl A few 'make' implementations (e.g., NonStop OS and NextStep) -dnl do not support nested variable expansions. -dnl See automake bug#9928 and bug#10237. -am_make=${MAKE-make} -AC_CACHE_CHECK([whether $am_make supports nested variables], - [am_cv_make_support_nested_variables], - [if AS_ECHO([['TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi]) -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AC_SUBST([AM_V])dnl -AM_SUBST_NOTMAKE([AM_V])dnl -AC_SUBST([AM_DEFAULT_V])dnl -AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl -AC_SUBST([AM_DEFAULT_VERBOSITY])dnl -AM_BACKSLASH='\' -AC_SUBST([AM_BACKSLASH])dnl -_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl -]) - -# Copyright (C) 2001-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor 'install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in "make install-strip", and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# -------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004-2017 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of 'v7', 'ustar', or 'pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -# -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' - -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - - [m4_case([$1], - [ustar], - [# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi - AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi], - - [pax], - [], - - [m4_fatal([Unknown tar format])]) - - AC_MSG_CHECKING([how to create a $1 tar archive]) - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_$1-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) - AC_MSG_RESULT([$am_cv_prog_tar_$1])]) - -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -m4_include([m4/libtool.m4]) -m4_include([m4/ltoptions.m4]) -m4_include([m4/ltsugar.m4]) -m4_include([m4/ltversion.m4]) -m4_include([m4/lt~obsolete.m4]) -m4_include([m4/modern_cxx.m4]) -m4_include([m4/w32.m4]) diff --git a/resources/3rdparty/cudd-3.0.0/configure b/resources/3rdparty/cudd-3.0.0/configure deleted file mode 100755 index 1494802d5..000000000 --- a/resources/3rdparty/cudd-3.0.0/configure +++ /dev/null @@ -1,19890 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for cudd 3.0.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org and Fabio@Colorado.EDU -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - -SHELL=${CONFIG_SHELL-/bin/sh} - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='cudd' -PACKAGE_TARNAME='cudd' -PACKAGE_VERSION='3.0.0' -PACKAGE_STRING='cudd 3.0.0' -PACKAGE_BUGREPORT='Fabio@Colorado.EDU' -PACKAGE_URL='' - -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_unique_file="st/st.c" -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -LIBOBJS -MINGW64_FALSE -MINGW64_TRUE -HAVE_PTHREADS_FALSE -HAVE_PTHREADS_TRUE -HAVE_PDFLATEX_FALSE -HAVE_PDFLATEX_TRUE -MAKEINDEX -PDFLATEX -HAVE_DOXYGEN_FALSE -HAVE_DOXYGEN_TRUE -DOXYGEN -CROSS_COMPILING_FALSE -CROSS_COMPILING_TRUE -CXXCPP -CPP -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -LIBTOOL -OBJDUMP -DLLTOOL -AS -ac_ct_AR -AR -am__fastdepCXX_FALSE -am__fastdepCXX_TRUE -CXXDEPMODE -ac_ct_CXX -CXXFLAGS -CXX -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__quote -am__include -DEPDIR -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -OBJ_FALSE -OBJ_TRUE -DDDMP_FALSE -DDDMP_TRUE -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_silent_rules -enable_dddmp -enable_obj -with_system_qsort -enable_dependency_tracking -enable_shared -enable_static -with_pic -enable_fast_install -with_gnu_ld -with_sysroot -enable_libtool_lock -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CXX -CXXFLAGS -CCC -CPP -CXXCPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures cudd 3.0.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/cudd] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of cudd 3.0.0:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-dddmp include libdddmp in libcudd - --enable-obj include libobj in libcudd - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-shared[=PKGS] build shared libraries [default=no] - --enable-static[=PKGS] build static libraries [default=yes] - --enable-fast-install[=PKGS] - optimize for fast installation [default=yes] - --disable-libtool-lock avoid locking (might break parallel builds) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-system-qsort use system qsort instead of portable one - --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use - both] - --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-sysroot=DIR Search for dependent libraries within DIR - (or the compiler's sysroot if not specified). - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags - CPP C preprocessor - CXXCPP C++ preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -cudd configure 3.0.0 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_cxx_try_cpp LINENO -# ------------------------ -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_cpp - -# ac_fn_cxx_try_link LINENO -# ------------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_link - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## --------------------------------- ## -## Report this to Fabio@Colorado.EDU ## -## --------------------------------- ##" - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type - -# ac_fn_c_find_uintX_t LINENO BITS VAR -# ------------------------------------ -# Finds an unsigned integer type with width BITS, setting cache variable VAR -# accordingly. -ac_fn_c_find_uintX_t () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 -$as_echo_n "checking for uint$2_t... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - # Order is important - never check a type that is potentially smaller - # than half of the expected target width. - for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ - 'unsigned long long int' 'unsigned short int' 'unsigned char'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - case $ac_type in #( - uint$2_t) : - eval "$3=yes" ;; #( - *) : - eval "$3=\$ac_type" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : - -else - break -fi - done -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_find_uintX_t - -# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -# -------------------------------------------- -# Tries to find the compile-time value of EXPR in a program that includes -# INCLUDES, setting VAR accordingly. Returns whether the value could be -# computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in #(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by cudd $as_me 3.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -ac_aux_dir= -for ac_dir in build-aux "$srcdir"/build-aux; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - -am__api_version='1.15' - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -$as_echo_n "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - as_fn_error $? "ls -t appears to fail. Make sure there is not a broken - alias in your environment" "$LINENO" 5 - fi - if test "$2" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$2" = conftest.file - ) -then - # Ok. - : -else - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & - am_sleep_pid=$! -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was `s,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - -fi - - test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - SET_MAKE= -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -# Check whether --enable-silent-rules was given. -if test "${enable_silent_rules+set}" = set; then : - enableval=$enable_silent_rules; -fi - -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=1;; -esac -am_make=${MAKE-make} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -$as_echo_n "checking whether $am_make supports nested variables... " >&6; } -if ${am_cv_make_support_nested_variables+:} false; then : - $as_echo_n "(cached) " >&6 -else - if $as_echo 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -$as_echo "$am_cv_make_support_nested_variables" >&6; } -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AM_BACKSLASH='\' - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='cudd' - VERSION='3.0.0' - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE "$PACKAGE" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define VERSION "$VERSION" -_ACEOF - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar pax cpio none' - -am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' - - - - - - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 - fi -fi - - - -# Check whether --enable-dddmp was given. -if test "${enable_dddmp+set}" = set; then : - enableval=$enable_dddmp; -fi - - if test x$enable_dddmp = xyes; then - DDDMP_TRUE= - DDDMP_FALSE='#' -else - DDDMP_TRUE='#' - DDDMP_FALSE= -fi - - -# Check whether --enable-obj was given. -if test "${enable_obj+set}" = set; then : - enableval=$enable_obj; -fi - - if test x$enable_obj = xyes; then - OBJ_TRUE= - OBJ_FALSE='#' -else - OBJ_TRUE='#' - OBJ_FALSE= -fi - - - -# Check whether --with-system-qsort was given. -if test "${with_system_qsort+set}" = set; then : - withval=$with_system_qsort; -else - with_system_qsort=no -fi - -if test x$with_system_qsort != xno ; then - -$as_echo "#define USE_SYSTEM_QSORT 1" >>confdefs.h - -fi - -# Set our own default (instead of "-g -O2") unless CFLAGS is already defined. -: ${CFLAGS="-Wall -Wextra -g -O3"} -: ${CXXFLAGS="-Wall -Wextra -std=c++0x -g -O3"} - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - - -am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 -$as_echo_n "checking for style of include used by $am_make... " >&6; } -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 -$as_echo "$_am_result" >&6; } -rm -f confinc confmf - -# Check whether --enable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - - -depcc="$CC" am_compiler_list= - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -else - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -depcc="$CXX" am_compiler_list= - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CXX_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CXX_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CXX_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CXX_dependencies_compiler_type=none -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } -CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then - am__fastdepCXX_TRUE= - am__fastdepCXX_FALSE='#' -else - am__fastdepCXX_TRUE='#' - am__fastdepCXX_FALSE= -fi - - - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar lib "link -lib" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar lib "link -lib" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 -$as_echo_n "checking the archiver ($AR) interface... " >&6; } -if ${am_cv_ar_interface+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - am_cv_ar_interface=ar - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int some_variable = 0; -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 - (eval $am_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - am_cv_ar_interface=ar - else - am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 - (eval $am_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - am_cv_ar_interface=lib - else - am_cv_ar_interface=unknown - fi - fi - rm -f conftest.lib libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 -$as_echo "$am_cv_ar_interface" >&6; } - -case $am_cv_ar_interface in -ar) - ;; -lib) - # Microsoft lib, so override with the ar-lib wrapper script. - # FIXME: It is wrong to rewrite AR. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__AR in this case, - # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something - # similar. - AR="$am_aux_dir/ar-lib $AR" - ;; -unknown) - as_fn_error $? "could not determine $AR interface" "$LINENO" 5 - ;; -esac - - -case `pwd` in - *\ * | *\ *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.4.2' -macro_revision='1.3337' - - - - - - - - - - - - - -ltmain="$ac_aux_dir/ltmain.sh" - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -$as_echo_n "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case "$ECHO" in - printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -$as_echo "printf" >&6; } ;; - print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -$as_echo "print -r" >&6; } ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -$as_echo "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -$as_echo_n "checking for fgrep... " >&6; } -if ${ac_cv_path_FGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in fgrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -$as_echo "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if ${lt_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${lt_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if ${lt_cv_path_NM+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS="$lt_save_ifs" - done - : ${lt_cv_path_NM=no} -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -$as_echo "$lt_cv_path_NM" >&6; } -if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DUMPBIN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -$as_echo "$DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -$as_echo "$ac_ct_DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test "$DUMPBIN" != ":"; then - NM="$DUMPBIN" - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -$as_echo_n "checking the name lister ($NM) interface... " >&6; } -if ${lt_cv_nm_interface+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -$as_echo "$lt_cv_nm_interface" >&6; } - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -$as_echo_n "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -$as_echo "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -$as_echo_n "checking the maximum length of command line arguments... " >&6; } -if ${lt_cv_sys_max_cmd_len+:} false; then : - $as_echo_n "(cached) " >&6 -else - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8 ; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - -fi - -if test -n $lt_cv_sys_max_cmd_len ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -$as_echo "$lt_cv_sys_max_cmd_len" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 -$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } -# Try some XSI features -xsi_shell=no -( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,b/c, \ - && eval 'test $(( 1 + 1 )) -eq 2 \ - && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ - && xsi_shell=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 -$as_echo "$xsi_shell" >&6; } - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 -$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } -lt_shell_append=no -( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ - >/dev/null 2>&1 \ - && lt_shell_append=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 -$as_echo "$lt_shell_append" >&6; } - - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -$as_echo_n "checking how to convert $build file names to $host format... " >&6; } -if ${lt_cv_to_host_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -$as_echo "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } -if ${lt_cv_to_tool_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -$as_echo "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -$as_echo_n "checking for $LD option to reload object files... " >&6; } -if ${lt_cv_ld_reload_flag+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_reload_flag='-r' -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -$as_echo "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - if test "$GCC" != yes; then - reload_cmds=false - fi - ;; - darwin*) - if test "$GCC" = yes; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -$as_echo "$OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -$as_echo "$ac_ct_OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -$as_echo_n "checking how to recognize dependent libraries... " >&6; } -if ${lt_cv_deplibs_check_method+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [[regex]]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given extended regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. - if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -$as_echo "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -$as_echo "$DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -$as_echo "$ac_ct_DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -$as_echo_n "checking how to associate runtime and link libraries... " >&6; } -if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh - # decide which to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd="$ECHO" - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} -: ${AR_FLAGS=cru} - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -$as_echo_n "checking for archiver @FILE support... " >&6; } -if ${lt_cv_ar_at_file+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -ne 0; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -$as_echo "$lt_cv_ar_at_file" >&6; } - -if test "x$lt_cv_ar_at_file" = xno; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if ${lt_cv_sys_global_symbol_pipe+:} false; then : - $as_echo_n "(cached) " >&6 -else - -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test "$host_cpu" = ia64; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function - # and D for any global variable. - # Also find C++ and __fastcall symbols from MSVC++, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ -" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ -" s[1]~/^[@?]/{print s[1], s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 - (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -/* DATA imports from DLLs on WIN32 con't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined(__osf__) -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -$as_echo "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -$as_echo_n "checking for sysroot... " >&6; } - -# Check whether --with-sysroot was given. -if test "${with_sysroot+set}" = set; then : - withval=$with_sysroot; -else - with_sysroot=no -fi - - -lt_sysroot= -case ${with_sysroot} in #( - yes) - if test "$GCC" = yes; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 -$as_echo "${with_sysroot}" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -$as_echo "${lt_sysroot:-no}" >&6; } - - - - - -# Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then : - enableval=$enable_libtool_lock; -fi - -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - case `/usr/bin/file conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -$as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if ${lt_cv_cc_needs_belf+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_cc_needs_belf=yes -else - lt_cv_cc_needs_belf=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -$as_echo "$lt_cv_cc_needs_belf" >&6; } - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -*-*solaris*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD="${LD-ld}_sol2" - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks="$enable_libtool_lock" - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -$as_echo "$MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if ${lt_cv_path_mainfest_tool+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_path_mainfest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 -$as_echo "$lt_cv_path_mainfest_tool" >&6; } -if test "x$lt_cv_path_mainfest_tool" != xyes; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DSYMUTIL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -$as_echo "$DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -$as_echo "$ac_ct_DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_NMEDIT+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -$as_echo "$NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -$as_echo "$ac_ct_NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LIPO+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -$as_echo "$LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_LIPO+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -$as_echo "$ac_ct_LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -$as_echo "$OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -$as_echo "$ac_ct_OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OTOOL64+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -$as_echo "$OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -$as_echo "$ac_ct_OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -$as_echo_n "checking for -single_module linker flag... " >&6; } -if ${lt_cv_apple_cc_single_mod+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_apple_cc_single_mod=no - if test -z "${LT_MULTI_MODULE}"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test $_lt_result -eq 0; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -$as_echo "$lt_cv_apple_cc_single_mod" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if ${lt_cv_ld_exported_symbols_list+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_ld_exported_symbols_list=yes -else - lt_cv_ld_exported_symbols_list=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -$as_echo_n "checking for -force_load linker flag... " >&6; } -if ${lt_cv_ld_force_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR cru libconftest.a conftest.o" >&5 - $AR cru libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main() { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -$as_echo "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - darwin*) # darwin 5.x on - # if running on 10.5 or later, the deployment target defaults - # to the OS version, if on x86, and 10.4, the deployment - # target defaults to 10.4. Don't you love it? - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*86*-darwin8*|10.0,*-darwin[91]*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - 10.[012]*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - 10.*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - esac - ;; - esac - if test "$lt_cv_apple_cc_single_mod" = "yes"; then - _lt_dar_single_mod='$single_module' - fi - if test "$lt_cv_ld_exported_symbols_list" = "yes"; then - _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_header in dlfcn.h -do : - ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DLFCN_H 1 -_ACEOF - -fi - -done - - - - -func_stripname_cnf () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; - esac -} # func_stripname_cnf - - - - - -# Set options -enable_win32_dll=yes - -case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. -set dummy ${ac_tool_prefix}as; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AS+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AS"; then - ac_cv_prog_AS="$AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AS="${ac_tool_prefix}as" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AS=$ac_cv_prog_AS -if test -n "$AS"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 -$as_echo "$AS" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AS"; then - ac_ct_AS=$AS - # Extract the first word of "as", so it can be a program name with args. -set dummy as; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AS+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AS"; then - ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AS="as" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AS=$ac_cv_prog_ac_ct_AS -if test -n "$ac_ct_AS"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 -$as_echo "$ac_ct_AS" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AS" = x; then - AS="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AS=$ac_ct_AS - fi -else - AS="$ac_cv_prog_AS" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -$as_echo "$DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -$as_echo "$ac_ct_DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -$as_echo "$OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -$as_echo "$ac_ct_OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - - ;; -esac - -test -z "$AS" && AS=as - - - - - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - -# Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_shared=no -fi - - - - - - - - - - - enable_dlopen=no - - - - - # Check whether --enable-static was given. -if test "${enable_static+set}" = set; then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_static=yes -fi - - - - - - - - - - -# Check whether --with-pic was given. -if test "${with_pic+set}" = set; then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for lt_pkg in $withval; do - IFS="$lt_save_ifs" - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - pic_mode=default -fi - - -test -z "$pic_mode" && pic_mode=default - - - - - - - - # Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_fast_install=yes -fi - - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ltmain" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -$as_echo_n "checking for objdir... " >&6; } -if ${lt_cv_objdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -$as_echo "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -cat >>confdefs.h <<_ACEOF -#define LT_OBJDIR "$lt_cv_objdir/" -_ACEOF - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a - -with_gnu_ld="$lt_cv_prog_gnu_ld" - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if ${lt_cv_path_MAGIC_CMD+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/${ac_tool_prefix}file; then - lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -$as_echo_n "checking for file... " >&6; } -if ${lt_cv_path_MAGIC_CMD+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/file; then - lt_cv_path_MAGIC_CMD="$ac_dir/file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC="$CC" -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test "$GCC" = yes; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test "$GCC" = yes; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64 which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } -if ${lt_cv_prog_compiler_pic+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic=$lt_prog_compiler_pic -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -$as_echo "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if ${lt_cv_prog_compiler_pic_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } - -if test x"$lt_cv_prog_compiler_pic_works" = xyes; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if ${lt_cv_prog_compiler_static_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_static_works=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -$as_echo "$lt_cv_prog_compiler_static_works" >&6; } - -if test x"$lt_cv_prog_compiler_static_works" = xyes; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -$as_echo_n "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -$as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - linux* | k*bsd*-gnu | gnu*) - link_all_deplibs=no - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test "$with_gnu_ld" = yes; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test "$lt_use_gnu_ld_interface" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='${wl}--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - link_all_deplibs=yes - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test "$host_os" = linux-dietlibc; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test "$tmp_diet" = no - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test "$ld_shlibs" = no; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global - # defined symbols, whereas GNU nm marks them as "W". - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='${wl}-f,' - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - link_all_deplibs=no - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - export_dynamic_flag_spec='${wl}-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' ${wl}-bernotok' - allow_undefined_flag=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl*) - # Native MSVC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; - else - sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile="$lt_outputfile.exe" - lt_tool_outputfile="$lt_tool_outputfile.exe" - ;; - esac~ - if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag="$_lt_dar_allow_undefined" - case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -$as_echo_n "checking if $CC understands -b... " >&6; } -if ${lt_cv_prog_compiler__b+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler__b=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -$as_echo "$lt_cv_prog_compiler__b" >&6; } - -if test x"$lt_cv_prog_compiler__b" = xyes; then - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if ${lt_cv_irix_exported_symbol+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_irix_exported_symbol=yes -else - lt_cv_irix_exported_symbol=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -$as_echo "$lt_cv_irix_exported_symbol" >&6; } - if test "$lt_cv_irix_exported_symbol" = yes; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='${wl}' - archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='${wl}-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='${wl}-z,text' - allow_undefined_flag='${wl}-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test x$host_vendor = xsni; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='${wl}-Blargedynsym' - ;; - esac - fi - fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -$as_echo "$ld_shlibs" >&6; } -test "$ld_shlibs" = no && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if ${lt_cv_archive_cmds_need_lc+:} false; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -$as_echo_n "checking dynamic linker characteristics... " >&6; } - -if test "$GCC" = yes; then - case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; - esac - case $host_os in - mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; - *) lt_sed_strip_eq="s,=/,/,g" ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's,/\([A-Za-z]:\),\1,g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - library_names_spec='${libname}.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec="$LIB" - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC wrapper - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if ${lt_cv_shlibpath_overrides_runpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -$as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -$as_echo_n "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test "X$hardcode_automatic" = "Xyes" ; then - - # We can hardcode non-existent directories. - if test "$hardcode_direct" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && - test "$hardcode_minus_L" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -$as_echo "$hardcode_action" >&6; } - -if test "$hardcode_action" = relink || - test "$inherit_rpath" = yes; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32* | cegcc*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - -fi - - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -$as_echo_n "checking for shl_load in -ldld... " >&6; } -if ${ac_cv_lib_dld_shl_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_shl_load=yes -else - ac_cv_lib_dld_shl_load=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -$as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" -else - ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -$as_echo_n "checking for dlopen in -lsvld... " >&6; } -if ${ac_cv_lib_svld_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_svld_dlopen=yes -else - ac_cv_lib_svld_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -$as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -$as_echo_n "checking for dld_link in -ldld... " >&6; } -if ${ac_cv_lib_dld_dld_link+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (); -int -main () -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_dld_link=yes -else - ac_cv_lib_dld_dld_link=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -$as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes; then : - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" -fi - - -fi - - -fi - - -fi - - -fi - - -fi - - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -$as_echo_n "checking whether a program can dlopen itself... " >&6; } -if ${lt_cv_dlopen_self+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -$as_echo "$lt_cv_dlopen_self" >&6; } - - if test "x$lt_cv_dlopen_self" = xyes; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if ${lt_cv_dlopen_self_static+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -$as_echo "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -$as_echo_n "checking whether stripping libraries is possible... " >&6; } -if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ;; - esac -fi - - - - - - - - - - - - - # Report which library types will actually be built - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -$as_echo_n "checking if libtool supports shared libraries... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -$as_echo "$can_build_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -$as_echo_n "checking whether to build shared libraries... " >&6; } - test "$can_build_shared" = "no" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -$as_echo "$enable_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -$as_echo_n "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test "$enable_shared" = yes || enable_static=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -$as_echo "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 -$as_echo_n "checking how to run the C++ preprocessor... " >&6; } -if test -z "$CXXCPP"; then - if ${ac_cv_prog_CXXCPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CXXCPP needs to be expanded - for CXXCPP in "$CXX -E" "/lib/cpp" - do - ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CXXCPP=$CXXCPP - -fi - CXXCPP=$ac_cv_prog_CXXCPP -else - ac_cv_prog_CXXCPP=$CXXCPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 -$as_echo "$CXXCPP" >&6; } -ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -else - _lt_caught_CXX_error=yes -fi - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -archive_cmds_need_lc_CXX=no -allow_undefined_flag_CXX= -always_export_symbols_CXX=no -archive_expsym_cmds_CXX= -compiler_needs_object_CXX=no -export_dynamic_flag_spec_CXX= -hardcode_direct_CXX=no -hardcode_direct_absolute_CXX=no -hardcode_libdir_flag_spec_CXX= -hardcode_libdir_separator_CXX= -hardcode_minus_L_CXX=no -hardcode_shlibpath_var_CXX=unsupported -hardcode_automatic_CXX=no -inherit_rpath_CXX=no -module_cmds_CXX= -module_expsym_cmds_CXX= -link_all_deplibs_CXX=unknown -old_archive_cmds_CXX=$old_archive_cmds -reload_flag_CXX=$reload_flag -reload_cmds_CXX=$reload_cmds -no_undefined_flag_CXX= -whole_archive_flag_spec_CXX= -enable_shared_with_static_runtimes_CXX=no - -# Source file extension for C++ test sources. -ac_ext=cpp - -# Object file extension for compiled C++ test sources. -objext=o -objext_CXX=$objext - -# No sense in running all these tests if we already determined that -# the CXX compiler isn't working. Some variables (like enable_shared) -# are currently assumed to apply to all compilers on this platform, -# and will be corrupted by setting them based on a non-working compiler. -if test "$_lt_caught_CXX_error" != yes; then - # Code to be used in simple compile tests - lt_simple_compile_test_code="int some_variable = 0;" - - # Code to be used in simple link tests - lt_simple_link_test_code='int main(int, char *[]) { return(0); }' - - # ltmain only uses $CC for tagged configurations so make sure $CC is set. - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - - # save warnings/boilerplate of simple test code - ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - - ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - - # Allow CC to be a program name with arguments. - lt_save_CC=$CC - lt_save_CFLAGS=$CFLAGS - lt_save_LD=$LD - lt_save_GCC=$GCC - GCC=$GXX - lt_save_with_gnu_ld=$with_gnu_ld - lt_save_path_LD=$lt_cv_path_LD - if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx - else - $as_unset lt_cv_prog_gnu_ld - fi - if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX - else - $as_unset lt_cv_path_LD - fi - test -z "${LDCXX+set}" || LD=$LDCXX - CC=${CXX-"c++"} - CFLAGS=$CXXFLAGS - compiler=$CC - compiler_CXX=$CC - for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - - - if test -n "$compiler"; then - # We don't want -fno-exception when compiling C++ code, so set the - # no_builtin_flag separately - if test "$GXX" = yes; then - lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' - else - lt_prog_compiler_no_builtin_flag_CXX= - fi - - if test "$GXX" = yes; then - # Set up default GNU C++ configuration - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if ${lt_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${lt_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test "$with_gnu_ld" = yes; then - archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='${wl}' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | - $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec_CXX= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - GXX=no - with_gnu_ld=no - wlarc= - fi - - # PORTME: fill in a description of your system's C++ link characteristics - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - ld_shlibs_CXX=yes - case $host_os in - aix3*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds_CXX='' - hardcode_direct_CXX=yes - hardcode_direct_absolute_CXX=yes - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - file_list_spec_CXX='${wl}-f,' - - if test "$GXX" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct_CXX=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L_CXX=yes - hardcode_libdir_flag_spec_CXX='-L$libdir' - hardcode_libdir_separator_CXX= - fi - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - export_dynamic_flag_spec_CXX='${wl}-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to - # export. - always_export_symbols_CXX=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag_CXX='-berok' - # Determine the default libpath from the value encoded in an empty - # executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath__CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath__CXX -fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - - archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag_CXX="-z nodefs" - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath__CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath__CXX -fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag_CXX=' ${wl}-bernotok' - allow_undefined_flag_CXX=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec_CXX='$convenience' - fi - archive_cmds_need_lc_CXX=yes - # This is similar to how AIX traditionally builds its shared - # libraries. - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag_CXX=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs_CXX=no - fi - ;; - - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - cygwin* | mingw* | pw32* | cegcc*) - case $GXX,$cc_basename in - ,cl* | no,cl*) - # Native MSVC - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec_CXX=' ' - allow_undefined_flag_CXX=unsupported - always_export_symbols_CXX=yes - file_list_spec_CXX='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' - archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; - else - $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' - enable_shared_with_static_runtimes_CXX=yes - # Don't use ranlib - old_postinstall_cmds_CXX='chmod 644 $oldlib' - postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile="$lt_outputfile.exe" - lt_tool_outputfile="$lt_tool_outputfile.exe" - ;; - esac~ - func_to_tool_file "$lt_outputfile"~ - if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # g++ - # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec_CXX='-L$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' - allow_undefined_flag_CXX=unsupported - always_export_symbols_CXX=no - enable_shared_with_static_runtimes_CXX=yes - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs_CXX=no - fi - ;; - esac - ;; - darwin* | rhapsody*) - - - archive_cmds_need_lc_CXX=no - hardcode_direct_CXX=no - hardcode_automatic_CXX=yes - hardcode_shlibpath_var_CXX=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec_CXX='' - fi - link_all_deplibs_CXX=yes - allow_undefined_flag_CXX="$_lt_dar_allow_undefined" - case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=func_echo_all - archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" - if test "$lt_cv_apple_cc_single_mod" != "yes"; then - archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" - archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" - fi - - else - ld_shlibs_CXX=no - fi - - ;; - - dgux*) - case $cc_basename in - ec++*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - ghcx*) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - freebsd2.*) - # C++ shared libraries reported to be fairly broken before - # switch to ELF - ld_shlibs_CXX=no - ;; - - freebsd-elf*) - archive_cmds_need_lc_CXX=no - ;; - - freebsd* | dragonfly*) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - ld_shlibs_CXX=yes - ;; - - haiku*) - archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - link_all_deplibs_CXX=yes - ;; - - hpux9*) - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - export_dynamic_flag_spec_CXX='${wl}-E' - hardcode_direct_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes; then - archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - hpux10*|hpux11*) - if test $with_gnu_ld = no; then - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - case $host_cpu in - hppa*64*|ia64*) - ;; - *) - export_dynamic_flag_spec_CXX='${wl}-E' - ;; - esac - fi - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - ;; - *) - hardcode_direct_CXX=yes - hardcode_direct_absolute_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes; then - if test $with_gnu_ld = no; then - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - interix[3-9]*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - irix5* | irix6*) - case $cc_basename in - CC*) - # SGI C++ - archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test "$GXX" = yes; then - if test "$with_gnu_ld" = no; then - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' - fi - fi - link_all_deplibs_CXX=yes - ;; - esac - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - inherit_rpath_CXX=yes - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc* | ecpc* ) - # Intel C++ - with_gnu_ld=yes - # version 8.0 and above of icpc choke on multiply defined symbols - # if we add $predep_objects and $postdep_objects, however 7.1 and - # earlier do not add the objects themselves. - case `$CC -V 2>&1` in - *"Version 7."*) - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 8.0 or newer - tmp_idyn= - case $host_cpu in - ia64*) tmp_idyn=' -i_dynamic';; - esac - archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - archive_cmds_need_lc_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - case `$CC -V` in - *pgCC\ [1-5].* | *pgcpp\ [1-5].*) - prelink_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ - compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' - old_archive_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ - $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ - $RANLIB $oldlib' - archive_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - archive_expsym_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - ;; - *) # Version 6 and above use weak symbols - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - ;; - esac - - hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - ;; - cxx*) - # Compaq C++ - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' - ;; - xl* | mpixl* | bgxl*) - # IBM XL 8.0 on PPC, with GNU ld - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' - hardcode_libdir_flag_spec_CXX='-R$libdir' - whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object_CXX=yes - - # Not sure whether something based on - # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 - # would be better. - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - esac - ;; - esac - ;; - - lynxos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - m88k*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - mvs*) - case $cc_basename in - cxx*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - - *nto* | *qnx*) - ld_shlibs_CXX=yes - ;; - - openbsd2*) - # C++ shared libraries are fairly broken - ld_shlibs_CXX=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - hardcode_direct_absolute_CXX=yes - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' - export_dynamic_flag_spec_CXX='${wl}-E' - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - fi - output_verbose_link_cmd=func_echo_all - else - ld_shlibs_CXX=no - fi - ;; - - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - hardcode_libdir_separator_CXX=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - case $host in - osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; - *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; - esac - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - cxx*) - case $host in - osf3*) - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - ;; - *) - allow_undefined_flag_CXX=' -expect_unresolved \*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ - $RM $lib.exp' - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - ;; - esac - - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - case $host in - osf3*) - archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - ;; - *) - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - ;; - esac - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - psos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - lcc*) - # Lucid - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - archive_cmds_need_lc_CXX=yes - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_shlibpath_var_CXX=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. - # Supported since Solaris 2.6 (maybe 2.5.1?) - whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' - ;; - esac - link_all_deplibs_CXX=yes - - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - gcx*) - # Green Hills C++ Compiler - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - no_undefined_flag_CXX=' ${wl}-z ${wl}defs' - if $CC --version | $GREP -v '^2\.7' > /dev/null; then - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - else - # g++ 2.7 appears to require `-G' NOT `-shared' on this - # platform. - archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - fi - - hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - ;; - esac - fi - ;; - esac - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag_CXX='${wl}-z,text' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag_CXX='${wl}-z,text' - allow_undefined_flag_CXX='${wl}-z,nodefs' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - export_dynamic_flag_spec_CXX='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ - '"$old_archive_cmds_CXX" - reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ - '"$reload_cmds_CXX" - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - vxworks*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 -$as_echo "$ld_shlibs_CXX" >&6; } - test "$ld_shlibs_CXX" = no && can_build_shared=no - - GCC_CXX="$GXX" - LD_CXX="$LD" - - ## CAVEAT EMPTOR: - ## There is no encapsulation within the following macros, do not change - ## the running order or otherwise move them around unless you know exactly - ## what you are doing... - # Dependencies to place before and after the object being linked: -predep_objects_CXX= -postdep_objects_CXX= -predeps_CXX= -postdeps_CXX= -compiler_lib_search_path_CXX= - -cat > conftest.$ac_ext <<_LT_EOF -class Foo -{ -public: - Foo (void) { a = 0; } -private: - int a; -}; -_LT_EOF - - -_lt_libdeps_save_CFLAGS=$CFLAGS -case "$CC $CFLAGS " in #( -*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; -*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; -*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; -esac - -if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Parse the compiler output and extract the necessary - # objects, libraries and library flags. - - # Sentinel used to keep track of whether or not we are before - # the conftest object file. - pre_test_object_deps_done=no - - for p in `eval "$output_verbose_link_cmd"`; do - case ${prev}${p} in - - -L* | -R* | -l*) - # Some compilers place space between "-{L,R}" and the path. - # Remove the space. - if test $p = "-L" || - test $p = "-R"; then - prev=$p - continue - fi - - # Expand the sysroot to ease extracting the directories later. - if test -z "$prev"; then - case $p in - -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; - -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; - -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; - esac - fi - case $p in - =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; - esac - if test "$pre_test_object_deps_done" = no; then - case ${prev} in - -L | -R) - # Internal compiler library paths should come after those - # provided the user. The postdeps already come after the - # user supplied libs so there is no need to process them. - if test -z "$compiler_lib_search_path_CXX"; then - compiler_lib_search_path_CXX="${prev}${p}" - else - compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" - fi - ;; - # The "-l" case would never come before the object being - # linked, so don't bother handling this case. - esac - else - if test -z "$postdeps_CXX"; then - postdeps_CXX="${prev}${p}" - else - postdeps_CXX="${postdeps_CXX} ${prev}${p}" - fi - fi - prev= - ;; - - *.lto.$objext) ;; # Ignore GCC LTO objects - *.$objext) - # This assumes that the test object file only shows up - # once in the compiler output. - if test "$p" = "conftest.$objext"; then - pre_test_object_deps_done=yes - continue - fi - - if test "$pre_test_object_deps_done" = no; then - if test -z "$predep_objects_CXX"; then - predep_objects_CXX="$p" - else - predep_objects_CXX="$predep_objects_CXX $p" - fi - else - if test -z "$postdep_objects_CXX"; then - postdep_objects_CXX="$p" - else - postdep_objects_CXX="$postdep_objects_CXX $p" - fi - fi - ;; - - *) ;; # Ignore the rest. - - esac - done - - # Clean up. - rm -f a.out a.exe -else - echo "libtool.m4: error: problem compiling CXX test program" -fi - -$RM -f confest.$objext -CFLAGS=$_lt_libdeps_save_CFLAGS - -# PORTME: override above test on systems where it is broken -case $host_os in -interix[3-9]*) - # Interix 3.5 installs completely hosed .la files for C++, so rather than - # hack all around it, let's just trust "g++" to DTRT. - predep_objects_CXX= - postdep_objects_CXX= - postdeps_CXX= - ;; - -linux*) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; - -solaris*) - case $cc_basename in - CC* | sunCC*) - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - # Adding this requires a known-good setup of shared libraries for - # Sun compiler versions before 5.6, else PIC objects from an old - # archive will be linked into the output, leading to subtle bugs. - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; -esac - - -case " $postdeps_CXX " in -*" -lc "*) archive_cmds_need_lc_CXX=no ;; -esac - compiler_lib_search_dirs_CXX= -if test -n "${compiler_lib_search_path_CXX}"; then - compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lt_prog_compiler_wl_CXX= -lt_prog_compiler_pic_CXX= -lt_prog_compiler_static_CXX= - - - # C++ specific cases for pic, static, wl, etc. - if test "$GXX" = yes; then - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic_CXX='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic_CXX='-DDLL_EXPORT' - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic_CXX='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - lt_prog_compiler_pic_CXX= - ;; - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static_CXX= - ;; - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic_CXX=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic_CXX='-fPIC -shared' - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - else - case $host_os in - aix[4-9]*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - else - lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68*) - # Green Hills C++ Compiler - # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic_CXX='-DDLL_EXPORT' - ;; - dgux*) - case $cc_basename in - ec++*) - lt_prog_compiler_pic_CXX='-KPIC' - ;; - ghcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | dragonfly*) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - if test "$host_cpu" != ia64; then - lt_prog_compiler_pic_CXX='+Z' - fi - ;; - aCC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_CXX='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - interix*) - # This is c89, which is MS Visual C++ (no shared libs) - # Anyone wants to do a port? - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # KAI C++ Compiler - lt_prog_compiler_wl_CXX='--backend -Wl,' - lt_prog_compiler_pic_CXX='-fPIC' - ;; - ecpc* ) - # old Intel C++ for x86_64 which still supported -KPIC. - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-static' - ;; - icpc* ) - # Intel C++, used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-fPIC' - lt_prog_compiler_static_CXX='-static' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-fpic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - cxx*) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) - # IBM XL 8.0, 9.0 on PPC and BlueGene - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-qpic' - lt_prog_compiler_static_CXX='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - esac - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx*) - lt_prog_compiler_pic_CXX='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic_CXX='-fPIC -shared' - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - lt_prog_compiler_wl_CXX='--backend -Wl,' - ;; - RCC*) - # Rational C++ 2.4.1 - lt_prog_compiler_pic_CXX='-pic' - ;; - cxx*) - # Digital/Compaq C++ - lt_prog_compiler_wl_CXX='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - gcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - lt_prog_compiler_pic_CXX='-pic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - lcc*) - # Lucid - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - lt_prog_compiler_pic_CXX='-KPIC' - ;; - *) - ;; - esac - ;; - vxworks*) - ;; - *) - lt_prog_compiler_can_build_shared_CXX=no - ;; - esac - fi - -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic_CXX= - ;; - *) - lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" - ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } -if ${lt_cv_prog_compiler_pic_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } -lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 -$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } -if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_works_CXX=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works_CXX=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } - -if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then - case $lt_prog_compiler_pic_CXX in - "" | " "*) ;; - *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; - esac -else - lt_prog_compiler_pic_CXX= - lt_prog_compiler_can_build_shared_CXX=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_static_works_CXX=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works_CXX=yes - fi - else - lt_cv_prog_compiler_static_works_CXX=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } - -if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then - : -else - lt_prog_compiler_static_CXX= -fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o_CXX=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_CXX=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o_CXX=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_CXX=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } - - - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -$as_echo_n "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -$as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - case $host_os in - aix[4-9]*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global defined - # symbols, whereas GNU nm marks them as "W". - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - export_symbols_cmds_CXX="$ltdll_cmds" - ;; - cygwin* | mingw* | cegcc*) - case $cc_basename in - cl*) - exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - ;; - *) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - ;; - esac - ;; - linux* | k*bsd*-gnu | gnu*) - link_all_deplibs_CXX=no - ;; - *) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 -$as_echo "$ld_shlibs_CXX" >&6; } -test "$ld_shlibs_CXX" = no && can_build_shared=no - -with_gnu_ld_CXX=$with_gnu_ld - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc_CXX" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc_CXX=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds_CXX in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl_CXX - pic_flag=$lt_prog_compiler_pic_CXX - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag_CXX - allow_undefined_flag_CXX= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc_CXX=no - else - lt_cv_archive_cmds_need_lc_CXX=yes - fi - allow_undefined_flag_CXX=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } - archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -$as_echo_n "checking dynamic linker characteristics... " >&6; } - -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - library_names_spec='${libname}.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec="$LIB" - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC wrapper - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if ${lt_cv_shlibpath_overrides_runpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -$as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -$as_echo_n "checking how to hardcode library paths into programs... " >&6; } -hardcode_action_CXX= -if test -n "$hardcode_libdir_flag_spec_CXX" || - test -n "$runpath_var_CXX" || - test "X$hardcode_automatic_CXX" = "Xyes" ; then - - # We can hardcode non-existent directories. - if test "$hardcode_direct_CXX" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && - test "$hardcode_minus_L_CXX" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action_CXX=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action_CXX=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action_CXX=unsupported -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 -$as_echo "$hardcode_action_CXX" >&6; } - -if test "$hardcode_action_CXX" = relink || - test "$inherit_rpath_CXX" = yes; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - - fi # test -n "$compiler" - - CC=$lt_save_CC - CFLAGS=$lt_save_CFLAGS - LDCXX=$LD - LD=$lt_save_LD - GCC=$lt_save_GCC - with_gnu_ld=$lt_save_with_gnu_ld - lt_cv_path_LDCXX=$lt_cv_path_LD - lt_cv_path_LD=$lt_save_path_LD - lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld - lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld -fi # test "$_lt_caught_CXX_error" != yes - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - - -ac_config_headers="$ac_config_headers config.h" - - -# Checks for programs. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_bigendian=unknown - # See if we're dealing with a universal compiler. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __APPLE_CC__ - not a universal capable compiler - #endif - typedef int dummy; - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - # Check for potential -arch flags. It is not universal unless - # there are at least two -arch flags with different values. - ac_arch= - ac_prev= - for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do - if test -n "$ac_prev"; then - case $ac_word in - i?86 | x86_64 | ppc | ppc64) - if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then - ac_arch=$ac_word - else - ac_cv_c_bigendian=universal - break - fi - ;; - esac - ac_prev= - elif test "x$ac_word" = "x-arch"; then - ac_prev=arch - fi - done -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test $ac_cv_c_bigendian = unknown; then - # See if sys/param.h defines the BYTE_ORDER macro. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ - && LITTLE_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if BYTE_ORDER != BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to _BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#ifndef _BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # Compile a test program. - if test "$cross_compiling" = yes; then : - # Try to guess by grepping values from an object file. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -short int ascii_mm[] = - { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = - { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; - int use_ascii (int i) { - return ascii_mm[i] + ascii_ii[i]; - } - short int ebcdic_ii[] = - { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = - { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; - int use_ebcdic (int i) { - return ebcdic_mm[i] + ebcdic_ii[i]; - } - extern int foo; - -int -main () -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then - ac_cv_c_bigendian=yes - fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then - if test "$ac_cv_c_bigendian" = unknown; then - ac_cv_c_bigendian=no - else - # finding both strings is unlikely to happen, but who knows? - ac_cv_c_bigendian=unknown - fi - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ - - /* Are we little or big endian? From Harbison&Steele. */ - union - { - long int l; - char c[sizeof (long int)]; - } u; - u.l = 1; - return u.c[sizeof (long int) - 1] == 1; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_bigendian=no -else - ac_cv_c_bigendian=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } - case $ac_cv_c_bigendian in #( - yes) - $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h -;; #( - no) - ;; #( - universal) - -$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h - - ;; #( - *) - as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; - esac - - if test x$cross_compiling = xyes; then - CROSS_COMPILING_TRUE= - CROSS_COMPILING_FALSE='#' -else - CROSS_COMPILING_TRUE='#' - CROSS_COMPILING_FALSE= -fi - - -# Building documentation requires doxygen, pdflatex, and makeindex. -for ac_prog in doxygen -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DOXYGEN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DOXYGEN"; then - ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DOXYGEN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DOXYGEN=$ac_cv_prog_DOXYGEN -if test -n "$DOXYGEN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 -$as_echo "$DOXYGEN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$DOXYGEN" && break -done - -if test -z "$DOXYGEN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Doxygen not found - continuing without Doxygen support" >&5 -$as_echo "$as_me: WARNING: Doxygen not found - continuing without Doxygen support" >&2;} -fi - if test -n "$DOXYGEN"; then - HAVE_DOXYGEN_TRUE= - HAVE_DOXYGEN_FALSE='#' -else - HAVE_DOXYGEN_TRUE='#' - HAVE_DOXYGEN_FALSE= -fi - -if test -z "$HAVE_DOXYGEN_TRUE"; then : - ac_config_files="$ac_config_files Doxyfile" - -fi - -for ac_prog in pdflatex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PDFLATEX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$PDFLATEX"; then - ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_PDFLATEX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PDFLATEX=$ac_cv_prog_PDFLATEX -if test -n "$PDFLATEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 -$as_echo "$PDFLATEX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$PDFLATEX" && break -done - -if test -z "$PDFLATEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pdflatex not found - unable to compile manual to PDF" >&5 -$as_echo "$as_me: WARNING: pdflatex not found - unable to compile manual to PDF" >&2;} -fi -for ac_prog in makeindex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_MAKEINDEX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$MAKEINDEX"; then - ac_cv_prog_MAKEINDEX="$MAKEINDEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_MAKEINDEX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MAKEINDEX=$ac_cv_prog_MAKEINDEX -if test -n "$MAKEINDEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINDEX" >&5 -$as_echo "$MAKEINDEX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$MAKEINDEX" && break -done - -if test -z "$MAKEINDEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: makeindex not found - unable to compile manual to PDF" >&5 -$as_echo "$as_me: WARNING: makeindex not found - unable to compile manual to PDF" >&2;} -fi - if test -n "$PDFLATEX" && test -n "$MAKEINDEX"; then - HAVE_PDFLATEX_TRUE= - HAVE_PDFLATEX_FALSE='#' -else - HAVE_PDFLATEX_TRUE='#' - HAVE_PDFLATEX_FALSE= -fi - -if test -z "$HAVE_PDFLATEX_TRUE"; then : - ac_config_files="$ac_config_files doc/cudd.tex" - -fi - -# Checks for libraries. -#AC_CHECK_LIB([m],[pow]) -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5 -$as_echo_n "checking for library containing pow... " >&6; } -if ${ac_cv_search_pow+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pow (); -int -main () -{ -return pow (); - ; - return 0; -} -_ACEOF -for ac_lib in '' m; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_pow=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_pow+:} false; then : - break -fi -done -if ${ac_cv_search_pow+:} false; then : - -else - ac_cv_search_pow=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5 -$as_echo "$ac_cv_search_pow" >&6; } -ac_res=$ac_cv_search_pow -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_create (); -int -main () -{ -return pthread_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_pthread_pthread_create=yes -else - ac_cv_lib_pthread_pthread_create=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : - have_pthreads=yes -else - have_pthreads=no -fi - - if test x$have_pthreads = xyes; then - HAVE_PTHREADS_TRUE= - HAVE_PTHREADS_FALSE='#' -else - HAVE_PTHREADS_TRUE='#' - HAVE_PTHREADS_FALSE= -fi - -# Check for Windows API functions. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing WSAStartup" >&5 -$as_echo_n "checking for library containing WSAStartup... " >&6; } -if ${ac_cv_search_WSAStartup+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char WSAStartup (); -int -main () -{ -return WSAStartup (); - ; - return 0; -} -_ACEOF -for ac_lib in '' ws2_32; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_WSAStartup=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_WSAStartup+:} false; then : - break -fi -done -if ${ac_cv_search_WSAStartup+:} false; then : - -else - ac_cv_search_WSAStartup=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_WSAStartup" >&5 -$as_echo "$ac_cv_search_WSAStartup" >&6; } -ac_res=$ac_cv_search_WSAStartup -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing GetProcessMemoryInfo" >&5 -$as_echo_n "checking for library containing GetProcessMemoryInfo... " >&6; } -if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char GetProcessMemoryInfo (); -int -main () -{ -return GetProcessMemoryInfo (); - ; - return 0; -} -_ACEOF -for ac_lib in '' psapi; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_GetProcessMemoryInfo=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - break -fi -done -if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - -else - ac_cv_search_GetProcessMemoryInfo=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_GetProcessMemoryInfo" >&5 -$as_echo "$ac_cv_search_GetProcessMemoryInfo" >&6; } -ac_res=$ac_cv_search_GetProcessMemoryInfo -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -# Checks for header files. -# First check for mandatory headers... -for ac_header in float.h inttypes.h limits.h stddef.h stdlib.h string.h assert.h math.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -else - have_mandatory_headers=no -fi - -done - -if test "x${have_mandatory_headers}" = xno; then - as_fn_error $? "One or more mandatory headers missing. Check 'config.log'." "$LINENO" 5 -fi -# ...then check for optional C headers. -for ac_header in unistd.h sys/time.h sys/times.h sys/resource.h sys/wait.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -# Finally, check C++ optional headers. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working C++ thread header" >&5 -$as_echo_n "checking for working C++ thread header... " >&6; } -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - std::thread([] {}).join() - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - have_working_thread=yes -else - have_working_thread=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test x$have_working_thread = xyes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -$as_echo "#define HAVE_WORKING_THREAD 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -# Checks for typedefs, structures, and compiler characteristics. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 -$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } -if ${ac_cv_header_stdbool_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #ifndef bool - "error: bool is not defined" - #endif - #ifndef false - "error: false is not defined" - #endif - #if false - "error: false is not 0" - #endif - #ifndef true - "error: true is not defined" - #endif - #if true != 1 - "error: true is not 1" - #endif - #ifndef __bool_true_false_are_defined - "error: __bool_true_false_are_defined is not defined" - #endif - - struct s { _Bool s: 1; _Bool t; } s; - - char a[true == 1 ? 1 : -1]; - char b[false == 0 ? 1 : -1]; - char c[__bool_true_false_are_defined == 1 ? 1 : -1]; - char d[(bool) 0.5 == true ? 1 : -1]; - /* See body of main program for 'e'. */ - char f[(_Bool) 0.0 == false ? 1 : -1]; - char g[true]; - char h[sizeof (_Bool)]; - char i[sizeof s.t]; - enum { j = false, k = true, l = false * true, m = true * 256 }; - /* The following fails for - HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ - _Bool n[m]; - char o[sizeof n == m * sizeof n[0] ? 1 : -1]; - char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; - /* Catch a bug in an HP-UX C compiler. See - http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html - http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html - */ - _Bool q = true; - _Bool *pq = &q; - -int -main () -{ - - bool e = &s; - *pq |= q; - *pq |= ! q; - /* Refer to every declared value, to avoid compiler optimizations. */ - return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l - + !m + !n + !o + !p + !q + !pq); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdbool_h=yes -else - ac_cv_header_stdbool_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 -$as_echo "$ac_cv_header_stdbool_h" >&6; } - ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" -if test "x$ac_cv_type__Bool" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE__BOOL 1 -_ACEOF - - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -$as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_inline=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -$as_echo "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - -ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" -case $ac_cv_c_uint16_t in #( - no|yes) ;; #( - *) - - -cat >>confdefs.h <<_ACEOF -#define uint16_t $ac_cv_c_uint16_t -_ACEOF -;; - esac - -ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" -case $ac_cv_c_uint32_t in #( - no|yes) ;; #( - *) - -$as_echo "#define _UINT32_T 1" >>confdefs.h - - -cat >>confdefs.h <<_ACEOF -#define uint32_t $ac_cv_c_uint32_t -_ACEOF -;; - esac - -ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_PTRDIFF_T 1 -_ACEOF - - -fi - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_void_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 -$as_echo_n "checking size of long double... " >&6; } -if ${ac_cv_sizeof_long_double+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_double" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long double) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_double=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 -$as_echo "$ac_cv_sizeof_long_double" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double -_ACEOF - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are building for a Win32 host" >&5 -$as_echo_n "checking whether we are building for a Win32 host... " >&6; } -if ${mingw_cv_win32_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef _WIN32 - choke me -#endif -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - mingw_cv_win32_host=no -else - mingw_cv_win32_host=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mingw_cv_win32_host" >&5 -$as_echo "$mingw_cv_win32_host" >&6; } - if test x$mingw_cv_win32_host = xyes; then - MINGW64_TRUE= - MINGW64_FALSE='#' -else - MINGW64_TRUE='#' - MINGW64_FALSE= -fi - -if test x$mingw_cv_win32_host = xyes ; then - -$as_echo "#define __USE_MINGW_ANSI_STDIO 1" >>confdefs.h - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether enough of C++11 is supported" >&5 -$as_echo_n "checking whether enough of C++11 is supported... " >&6; } -if ${ac_cv_have_modern_cxx+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -class Myclass { explicit operator bool() const { return true; } }; -int main() { - void *p = nullptr; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_have_modern_cxx=yes -else - ac_cv_have_modern_cxx=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_modern_cxx" >&5 -$as_echo "$ac_cv_have_modern_cxx" >&6; } -if test x$ac_cv_have_modern_cxx = xyes ; then - -$as_echo "#define HAVE_MODERN_CXX 1" >>confdefs.h - -fi - -# Checks for library functions. -# First the mandatory functions... -for ac_func in pow sqrt strchr strstr -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -else - have_mandatory_functions=no -fi -done - -if test "x${have_mandatory_functions}" = xno; then - as_fn_error $? "One or more mandatory functions missing. Check 'config.log'." "$LINENO" 5 -fi -# ...then check for optional functions. -for ac_func in powl gethostname getrlimit getrusage sysconf -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -# Check for a working implementation of IEEE 754 floating point -# Specifically, check for correct treatment of +Infinity -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for +Infinity (IEEE 754 floating point)" >&5 -$as_echo_n "checking for +Infinity (IEEE 754 floating point)... " >&6; } -if ${ac_cv_have_ieee_754+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_have_ieee_754=maybe -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -main(void) -{ - if (HUGE_VAL != HUGE_VAL * 3 || HUGE_VAL != HUGE_VAL / 3) return 1; - return 0; -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_have_ieee_754=yes -else - ac_cv_have_ieee_754=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -if test x$ac_cv_have_ieee_754 = xmaybe ; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - double x = INFINITY - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_have_ieee_754=yes -else - ac_cv_have_ieee_754=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -if test x$ac_cv_have_ieee_754 = xyes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -$as_echo "#define HAVE_IEEE_754 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -ac_config_files="$ac_config_files Makefile" - -ac_config_files="$ac_config_files dddmp/exp/test1.sh" - -ac_config_files="$ac_config_files dddmp/exp/test2.sh" - -ac_config_files="$ac_config_files dddmp/exp/test3.sh" - -ac_config_files="$ac_config_files dddmp/exp/test4.sh" - -ac_config_files="$ac_config_files dddmp/exp/test5.sh" - -ac_config_files="$ac_config_files dddmp/exp/test6.sh" - -ac_config_files="$ac_config_files dddmp/exp/test7.sh" - - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -$as_echo_n "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 -$as_echo "done" >&6; } - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${DDDMP_TRUE}" && test -z "${DDDMP_FALSE}"; then - as_fn_error $? "conditional \"DDDMP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${OBJ_TRUE}" && test -z "${OBJ_FALSE}"; then - as_fn_error $? "conditional \"OBJ\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -if test -z "${CROSS_COMPILING_TRUE}" && test -z "${CROSS_COMPILING_FALSE}"; then - as_fn_error $? "conditional \"CROSS_COMPILING\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_DOXYGEN_TRUE}" && test -z "${HAVE_DOXYGEN_FALSE}"; then - as_fn_error $? "conditional \"HAVE_DOXYGEN\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_PDFLATEX_TRUE}" && test -z "${HAVE_PDFLATEX_FALSE}"; then - as_fn_error $? "conditional \"HAVE_PDFLATEX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_PTHREADS_TRUE}" && test -z "${HAVE_PTHREADS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_PTHREADS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MINGW64_TRUE}" && test -z "${MINGW64_FALSE}"; then - as_fn_error $? "conditional \"MINGW64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by cudd $as_me 3.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -cudd config.status 3.0.0 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' -predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' -postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' -predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' -postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' -LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' -reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' -reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' -compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' -GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' -archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' -module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' -with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' -no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' -inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' -link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' -always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' -exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' -include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' -prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' -postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' -file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' -predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' -postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' -predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' -postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in AS \ -DLLTOOL \ -OBJDUMP \ -SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -sharedlib_from_linklib_cmd \ -AR \ -AR_FLAGS \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -nm_file_list_spec \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib \ -compiler_lib_search_dirs \ -predep_objects \ -postdep_objects \ -predeps \ -postdeps \ -compiler_lib_search_path \ -LD_CXX \ -reload_flag_CXX \ -compiler_CXX \ -lt_prog_compiler_no_builtin_flag_CXX \ -lt_prog_compiler_pic_CXX \ -lt_prog_compiler_wl_CXX \ -lt_prog_compiler_static_CXX \ -lt_cv_prog_compiler_c_o_CXX \ -export_dynamic_flag_spec_CXX \ -whole_archive_flag_spec_CXX \ -compiler_needs_object_CXX \ -with_gnu_ld_CXX \ -allow_undefined_flag_CXX \ -no_undefined_flag_CXX \ -hardcode_libdir_flag_spec_CXX \ -hardcode_libdir_separator_CXX \ -exclude_expsyms_CXX \ -include_expsyms_CXX \ -file_list_spec_CXX \ -compiler_lib_search_dirs_CXX \ -predep_objects_CXX \ -postdep_objects_CXX \ -predeps_CXX \ -postdeps_CXX \ -compiler_lib_search_path_CXX; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -sys_lib_dlsearch_path_spec \ -reload_cmds_CXX \ -old_archive_cmds_CXX \ -old_archive_from_new_cmds_CXX \ -old_archive_from_expsyms_cmds_CXX \ -archive_cmds_CXX \ -archive_expsym_cmds_CXX \ -module_cmds_CXX \ -module_expsym_cmds_CXX \ -export_symbols_cmds_CXX \ -prelink_cmds_CXX \ -postlink_cmds_CXX; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' -xsi_shell='$xsi_shell' -lt_shell_append='$lt_shell_append' - -# See if we are running on zsh, and set the options which allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - TIMESTAMP='$TIMESTAMP' - RM='$RM' - ofile='$ofile' - - - - - - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;; - "doc/cudd.tex") CONFIG_FILES="$CONFIG_FILES doc/cudd.tex" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "dddmp/exp/test1.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test1.sh" ;; - "dddmp/exp/test2.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test2.sh" ;; - "dddmp/exp/test3.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test3.sh" ;; - "dddmp/exp/test4.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test4.sh" ;; - "dddmp/exp/test5.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test5.sh" ;; - "dddmp/exp/test6.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test6.sh" ;; - "dddmp/exp/test7.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test7.sh" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`$as_dirname -- "$mf" || -$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$mf" : 'X\(//\)[^/]' \| \ - X"$mf" : 'X\(//\)$' \| \ - X"$mf" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`$as_dirname -- "$file" || -$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$file" : 'X\(//\)[^/]' \| \ - X"$file" : 'X\(//\)$' \| \ - X"$file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir=$dirpart/$fdir; as_fn_mkdir_p - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options which allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - - cfgfile="${ofile}T" - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL - -# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008, 2009, 2010, 2011 Free Software -# Foundation, Inc. -# Written by Gordon Matzigkeit, 1996 -# -# This file is part of GNU Libtool. -# -# GNU Libtool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, or -# obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -# The names of the tagged configurations supported by this script. -available_tags="CXX " - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Assembler program. -AS=$lt_AS - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Object dumper program. -OBJDUMP=$lt_OBJDUMP - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive. -AR_FLAGS=$lt_AR_FLAGS - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and in which our libraries should be installed. -lt_sysroot=$lt_sysroot - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# The directories searched by this compiler when creating a shared library. -compiler_lib_search_dirs=$lt_compiler_lib_search_dirs - -# Dependencies to place before and after the objects being linked to -# create a shared library. -predep_objects=$lt_predep_objects -postdep_objects=$lt_postdep_objects -predeps=$lt_predeps -postdeps=$lt_postdeps - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path - -# ### END LIBTOOL CONFIG - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - -ltmain="$ac_aux_dir/ltmain.sh" - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - if test x"$xsi_shell" = xyes; then - sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ -func_dirname ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_basename ()$/,/^} # func_basename /c\ -func_basename ()\ -{\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ -func_dirname_and_basename ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ -func_stripname ()\ -{\ -\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ -\ # positional parameters, so assign one to ordinary parameter first.\ -\ func_stripname_result=${3}\ -\ func_stripname_result=${func_stripname_result#"${1}"}\ -\ func_stripname_result=${func_stripname_result%"${2}"}\ -} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ -func_split_long_opt ()\ -{\ -\ func_split_long_opt_name=${1%%=*}\ -\ func_split_long_opt_arg=${1#*=}\ -} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ -func_split_short_opt ()\ -{\ -\ func_split_short_opt_arg=${1#??}\ -\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ -} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ -func_lo2o ()\ -{\ -\ case ${1} in\ -\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ -\ *) func_lo2o_result=${1} ;;\ -\ esac\ -} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_xform ()$/,/^} # func_xform /c\ -func_xform ()\ -{\ - func_xform_result=${1%.*}.lo\ -} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_arith ()$/,/^} # func_arith /c\ -func_arith ()\ -{\ - func_arith_result=$(( $* ))\ -} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_len ()$/,/^} # func_len /c\ -func_len ()\ -{\ - func_len_result=${#1}\ -} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - -fi - -if test x"$lt_shell_append" = xyes; then - sed -e '/^func_append ()$/,/^} # func_append /c\ -func_append ()\ -{\ - eval "${1}+=\\${2}"\ -} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ -func_append_quoted ()\ -{\ -\ func_quote_for_eval "${2}"\ -\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ -} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - # Save a `func_append' function call where possible by direct use of '+=' - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -else - # Save a `func_append' function call even when '+=' is not available - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -fi - -if test x"$_lt_function_replace_fail" = x":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 -$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} -fi - - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - - cat <<_LT_EOF >> "$ofile" - -# ### BEGIN LIBTOOL TAG CONFIG: CXX - -# The linker used to build libraries. -LD=$lt_LD_CXX - -# How to create reloadable object files. -reload_flag=$lt_reload_flag_CXX -reload_cmds=$lt_reload_cmds_CXX - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds_CXX - -# A language specific compiler. -CC=$lt_compiler_CXX - -# Is the compiler the GNU compiler? -with_gcc=$GCC_CXX - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_CXX - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_CXX - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_CXX - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_CXX - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object_CXX - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds_CXX -archive_expsym_cmds=$lt_archive_expsym_cmds_CXX - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds_CXX -module_expsym_cmds=$lt_module_expsym_cmds_CXX - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld_CXX - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_CXX - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_CXX - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct_CXX - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute_CXX - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L_CXX - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic_CXX - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath_CXX - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_CXX - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols_CXX - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_CXX - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_CXX - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_CXX - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds_CXX - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds_CXX - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec_CXX - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_CXX - -# The directories searched by this compiler when creating a shared library. -compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX - -# Dependencies to place before and after the objects being linked to -# create a shared library. -predep_objects=$lt_predep_objects_CXX -postdep_objects=$lt_postdep_objects_CXX -predeps=$lt_predeps_CXX -postdeps=$lt_postdeps_CXX - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_CXX - -# ### END LIBTOOL TAG CONFIG: CXX -_LT_EOF - - ;; - "dddmp/exp/test1.sh":F) chmod +x dddmp/exp/test1.sh ;; - "dddmp/exp/test2.sh":F) chmod +x dddmp/exp/test2.sh ;; - "dddmp/exp/test3.sh":F) chmod +x dddmp/exp/test3.sh ;; - "dddmp/exp/test4.sh":F) chmod +x dddmp/exp/test4.sh ;; - "dddmp/exp/test5.sh":F) chmod +x dddmp/exp/test5.sh ;; - "dddmp/exp/test6.sh":F) chmod +x dddmp/exp/test6.sh ;; - "dddmp/exp/test7.sh":F) chmod +x dddmp/exp/test7.sh ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -echo \ -"-------------------------------------------------- -Configuration summary for ${PACKAGE_NAME} ${PACKAGE_VERSION} - -Build system : ${build} -Host system : ${host} -Prefix : '${prefix}' -Compilers : '${CC} ${AM_CPPFLAGS} ${CPPFLAGS} ${AM_CFLAGS} ${CFLAGS}' - : '${CXX} ${AM_CPPFLAGS} ${CPPFLAGS} ${AM_CXXFLAGS} ${CXXFLAGS}' -Shared library : ${enable_shared} - dddmp enabled : ${enable_dddmp:-no} - obj enabled : ${enable_obj:-no} ---------------------------------------------------" From 172c5f3657ecdda8045a11a104dc4951f02a5678 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 21 Mar 2018 11:42:12 +0100 Subject: [PATCH 190/647] Making things compile again... --- src/storm/solver/LpMinMaxLinearEquationSolver.cpp | 4 +--- src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp | 4 ---- src/test/storm/solver/LinearEquationSolverTest.cpp | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp index 5143fcdef..78bc75752 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp @@ -120,9 +120,7 @@ namespace storm { requirements.requireNoEndComponents(); } - if (env.solver().minMax().isForceBoundsSet()) { - requirements.requireBounds(); - } + requirements.requireBounds(false); return requirements; } diff --git a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp index b9f8551c3..b599face7 100644 --- a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp @@ -458,10 +458,6 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "The selected min max technique is not supported by this solver."); } - if (env.solver().minMax().isForceBoundsSet()) { - requirements.requireBounds(); - } - return requirements; } diff --git a/src/test/storm/solver/LinearEquationSolverTest.cpp b/src/test/storm/solver/LinearEquationSolverTest.cpp index f96f88e5d..114452ba8 100644 --- a/src/test/storm/solver/LinearEquationSolverTest.cpp +++ b/src/test/storm/solver/LinearEquationSolverTest.cpp @@ -345,7 +345,7 @@ namespace { auto requirements = factory.getRequirements(this->env()); requirements.clearUpperBounds(); requirements.clearLowerBounds(); - ASSERT_TRUE(requirements.empty()); + ASSERT_FALSE(requirements.hasEnabledRequirement()); auto solver = factory.create(this->env(), A); solver->setBounds(this->parseNumber("-100"), this->parseNumber("100")); ASSERT_NO_THROW(solver->solveEquations(this->env(), x, b)); From d9db3f84b6b020c33a4c67fc6a4f15bcb5b3b890 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 13:43:35 +0100 Subject: [PATCH 191/647] Fixed dft tests --- .../storm-dft/api/DftModelCheckerTest.cpp | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index 8c57795d6..902108018 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -95,13 +95,13 @@ namespace { TYPED_TEST(DftModelCheckerTest, VotingMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting.dft"); - EXPECT_FLOAT_EQ(result, 5/3); + EXPECT_FLOAT_EQ(result, 5/3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting2.dft"); - EXPECT_FLOAT_EQ(result, 10/17); + EXPECT_FLOAT_EQ(result, 10/17.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting3.dft"); - EXPECT_FLOAT_EQ(result, 1.73562); + EXPECT_FLOAT_EQ(result, 1.7356173); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/voting4.dft"); - EXPECT_FLOAT_EQ(result, 5/6); + EXPECT_FLOAT_EQ(result, 5/6.0); } TYPED_TEST(DftModelCheckerTest, PandMTTF) { @@ -115,45 +115,59 @@ namespace { } TYPED_TEST(DftModelCheckerTest, FdepMTTF) { - double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft"); - EXPECT_FLOAT_EQ(result, 2/3); - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep2.dft"); + double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep2.dft"); EXPECT_FLOAT_EQ(result, 2); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep3.dft"); EXPECT_FLOAT_EQ(result, 2.5); - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft"); - EXPECT_FLOAT_EQ(result, 1); - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"); - EXPECT_FLOAT_EQ(result, 3); + if (this->getConfig().useMod) { + EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft"), storm::exceptions::NotSupportedException); + EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft"), storm::exceptions::NotSupportedException); + EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"), storm::exceptions::NotSupportedException); + } else { + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft"); + EXPECT_FLOAT_EQ(result, 2/3.0); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft"); + EXPECT_FLOAT_EQ(result, 1); + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft"); + EXPECT_FLOAT_EQ(result, 3); + } } TYPED_TEST(DftModelCheckerTest, PdepMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep.dft"); - EXPECT_FLOAT_EQ(result, 8/3); - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); - EXPECT_FLOAT_EQ(result, 38/15); + EXPECT_FLOAT_EQ(result, 8/3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft"); - EXPECT_FLOAT_EQ(result, 2.79167); - result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"); - EXPECT_EQ(result, storm::utility::infinity()); + EXPECT_FLOAT_EQ(result, 67/24.0); + if (this->getConfig().useMod) { + if (!this->getConfig().useDC) { + EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"), storm::exceptions::NotSupportedException); + } else { + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft"); + EXPECT_FLOAT_EQ(result, 38/15.0); + } + EXPECT_THROW(this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"), storm::exceptions::NotSupportedException); + } else { + result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft"); + EXPECT_EQ(result, storm::utility::infinity()); + } } TYPED_TEST(DftModelCheckerTest, SpareMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare.dft"); - EXPECT_FLOAT_EQ(result, 3.53846); + EXPECT_FLOAT_EQ(result, 46/13.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare2.dft"); - EXPECT_FLOAT_EQ(result, 1.86957); + EXPECT_FLOAT_EQ(result, 43/23.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare3.dft"); - EXPECT_FLOAT_EQ(result, 1.27273); + EXPECT_FLOAT_EQ(result, 14/11.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare4.dft"); - EXPECT_FLOAT_EQ(result, 4.8459); + EXPECT_FLOAT_EQ(result, 4.8458967); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft"); - EXPECT_FLOAT_EQ(result, 8/3); + EXPECT_FLOAT_EQ(result, 8/3.0); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare6.dft"); EXPECT_FLOAT_EQ(result, 1.4); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare7.dft"); - EXPECT_FLOAT_EQ(result, 3.67333); + EXPECT_FLOAT_EQ(result, 3.6733334); result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/spare8.dft"); - EXPECT_FLOAT_EQ(result, 4.78846); // DFTCalc says 4.33779 + EXPECT_FLOAT_EQ(result, 4.78846); // DFTCalc has result of 4.33779 due to different semantics of nested spares } TYPED_TEST(DftModelCheckerTest, SeqMTTF) { double result = this->analyzeMTTF(STORM_TEST_RESOURCES_DIR "/dft/seq.dft"); From 4bdedfbb9a06ca22026435abfdbcd5caff2fbc00 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 16:06:08 +0100 Subject: [PATCH 192/647] Added missing settings --- src/storm-dft/settings/DftSettings.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/storm-dft/settings/DftSettings.cpp b/src/storm-dft/settings/DftSettings.cpp index c1c145a3c..361ccdc8f 100644 --- a/src/storm-dft/settings/DftSettings.cpp +++ b/src/storm-dft/settings/DftSettings.cpp @@ -12,6 +12,8 @@ #include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/GmmxxEquationSolverSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/EliminationSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GameSolverSettings.h" @@ -36,11 +38,13 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(false); // storm::settings::addModule(); storm::settings::addModule(); From 31fa43ab27c71a208777ff66058bd47a30f0c4f9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 21 Mar 2018 16:38:23 +0100 Subject: [PATCH 193/647] some fixes to interpolation in game-based abstraction refinement --- src/storm/abstraction/MenuGameAbstractor.h | 3 + src/storm/abstraction/MenuGameRefiner.cpp | 73 +++++++++++++++++-- .../jani/JaniMenuGameAbstractor.cpp | 5 ++ .../abstraction/jani/JaniMenuGameAbstractor.h | 2 + .../prism/PrismMenuGameAbstractor.cpp | 5 ++ .../prism/PrismMenuGameAbstractor.h | 2 + src/storm/adapters/MathsatExpressionAdapter.h | 14 +++- .../abstraction/GameBasedMdpModelChecker.cpp | 4 +- .../settings/modules/AbstractionSettings.cpp | 2 +- 9 files changed, 98 insertions(+), 12 deletions(-) diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 946fb0a97..e82c1fb31 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -48,6 +48,9 @@ namespace storm { /// Exports a representation of the current abstraction state in the dot format. virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const = 0; + /// Retrieves the number of predicates currently in use. + virtual uint64_t getNumberOfPredicates() const = 0; + protected: void exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const; }; diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 642cb83fb..e139a357f 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -390,7 +390,7 @@ namespace storm { storm::dd::Bdd lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); storm::dd::Bdd lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero(); + bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero(); if (lowerChoicesDifferent) { STORM_LOG_TRACE("Deriving predicate based on lower choice."); predicates = derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); @@ -405,7 +405,7 @@ namespace storm { storm::dd::Bdd upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); storm::dd::Bdd upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero(); + bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero() && !upperChoice1.isZero() && !upperChoice2.isZero(); if (upperChoicesDifferent) { STORM_LOG_TRACE("Deriving predicate based on upper choice."); additionalPredicates = derivePredicatesFromDifferingChoices((pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2); @@ -476,12 +476,26 @@ namespace storm { // Retrieve the variable updates that the predecessor needs to perform to get to the current state. auto variableUpdates = abstractor.get().getVariableUpdates(std::get<1>(decodedPredecessor), std::get<2>(decodedPredecessor)); - for (auto const& update : variableUpdates) { - storm::expressions::Variable newVariable = oldToNewVariables.at(update.first); - if (update.second.hasBooleanType()) { - predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(oldToNewVariables.at(update.first)), update.second.changeManager(expressionManager).substitute(substitution))); + for (auto const& oldNewVariablePair : oldToNewVariables) { + storm::expressions::Variable const& newVariable = oldNewVariablePair.second; + + // If the variable was set, use its update expression. + auto updateIt = variableUpdates.find(oldNewVariablePair.first); + if (updateIt != variableUpdates.end()) { + auto const& update = *updateIt; + + if (update.second.hasBooleanType()) { + predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution))); + } else { + predicates.back().push_back(lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution)); + } } else { - predicates.back().push_back(lastSubstitution.at(oldToNewVariables.at(update.first)) == update.second.changeManager(expressionManager).substitute(substitution)); + // Otherwise, make sure that the new variable maintains the old value. + if (newVariable.hasBooleanType()) { + predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable))); + } else { + predicates.back().push_back(lastSubstitution.at(newVariable) == substitution.at(newVariable)); + } } } @@ -581,6 +595,7 @@ namespace storm { // Redirect all player 1 choices of the min strategy to that of the max strategy if this leads to a player 2 // state that is also a prob 0 state. + auto oldMinPlayer1Strategy = minPlayer1Strategy; minPlayer1Strategy = (maxPlayer1Strategy && qualitativeResult.prob0Min.getPlayer2States()).existsAbstract(game.getPlayer1Variables()).ite(maxPlayer1Strategy, minPlayer1Strategy); // Compute all reached pivot states. @@ -597,7 +612,49 @@ namespace storm { // Now that we have the pivot state candidates, we need to pick one. PivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); - + +// // SANITY CHECK TO MAKE SURE OUR STRATEGIES ARE NOT BROKEN. +// // FIXME. +// auto min1ChoiceInPivot = pivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; +// STORM_LOG_ASSERT(!min1ChoiceInPivot.isZero(), "wth?"); +// bool min1ChoiceInPivotIsProb0Min = !(min1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb0Max = !(min1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb1Min = !(min1ChoiceInPivot && qualitativeResult.prob1Min.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb1Max = !(min1ChoiceInPivot && qualitativeResult.prob1Max.getPlayer2States()).isZero(); +// std::cout << "after redirection (min)" << std::endl; +// std::cout << "min choice is prob0 in min? " << min1ChoiceInPivotIsProb0Min << ", max? " << min1ChoiceInPivotIsProb0Max << std::endl; +// std::cout << "min choice is prob1 in min? " << min1ChoiceInPivotIsProb1Min << ", max? " << min1ChoiceInPivotIsProb1Max << std::endl; +// std::cout << "min" << std::endl; +// for (auto const& e : (min1ChoiceInPivot && minPlayer2Strategy).template toAdd()) { +// std::cout << e.first << " -> " << e.second << std::endl; +// } +// std::cout << "max" << std::endl; +// for (auto const& e : (min1ChoiceInPivot && maxPlayer2Strategy).template toAdd()) { +// std::cout << e.first << " -> " << e.second << std::endl; +// } +// bool different = (min1ChoiceInPivot && minPlayer2Strategy) != (min1ChoiceInPivot && maxPlayer2Strategy); +// std::cout << "min/max choice of player 2 is different? " << different << std::endl; +// bool min1MinPlayer2Choice = !(min1ChoiceInPivot && minPlayer2Strategy).isZero(); +// bool min1MaxPlayer2Choice = !(min1ChoiceInPivot && maxPlayer2Strategy).isZero(); +// std::cout << "max/min choice there? " << min1MinPlayer2Choice << std::endl; +// std::cout << "max/max choice there? " << min1MaxPlayer2Choice << std::endl; +// +// auto max1ChoiceInPivot = pivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; +// STORM_LOG_ASSERT(!max1ChoiceInPivot.isZero(), "wth?"); +// bool max1ChoiceInPivotIsProb0Min = !(max1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb0Max = !(max1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb1Min = !(max1ChoiceInPivot && qualitativeResult.prob1Min.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb1Max = !(max1ChoiceInPivot && qualitativeResult.prob1Max.getPlayer2States()).isZero(); +// std::cout << "after redirection (max)" << std::endl; +// std::cout << "max choice is prob0 in min? " << max1ChoiceInPivotIsProb0Min << ", max? " << max1ChoiceInPivotIsProb0Max << std::endl; +// std::cout << "max choice is prob1 in min? " << max1ChoiceInPivotIsProb1Min << ", max? " << max1ChoiceInPivotIsProb1Max << std::endl; +// different = (max1ChoiceInPivot && minPlayer2Strategy) != (max1ChoiceInPivot && maxPlayer2Strategy); +// std::cout << "min/max choice of player 2 is different? " << different << std::endl; +// bool max1MinPlayer2Choice = !(max1ChoiceInPivot && minPlayer2Strategy).isZero(); +// bool max1MaxPlayer2Choice = !(max1ChoiceInPivot && maxPlayer2Strategy).isZero(); +// std::cout << "max/min choice there? " << max1MinPlayer2Choice << std::endl; +// std::cout << "max/max choice there? " << max1MaxPlayer2Choice << std::endl; + boost::optional predicates; if (useInterpolation) { predicates = derivePredicatesFromInterpolation(game, pivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index b3c7a755a..a3900ab80 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -208,6 +208,11 @@ namespace storm { this->exportToDot(*currentGame, filename, highlightStates, filter); } + template + uint64_t JaniMenuGameAbstractor::getNumberOfPredicates() const { + return abstractionInformation.getNumberOfPredicates(); + } + // Explicitly instantiate the class. template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 3a478fcb0..0a4cc36ed 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -109,6 +109,8 @@ namespace storm { */ void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual uint64_t getNumberOfPredicates() const override; + protected: using MenuGameAbstractor::exportToDot; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 4cb3d46eb..a93e62e67 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -203,6 +203,11 @@ namespace storm { this->exportToDot(*currentGame, filename, highlightStates, filter); } + template + uint64_t PrismMenuGameAbstractor::getNumberOfPredicates() const { + return abstractionInformation.getNumberOfPredicates(); + } + // Explicitly instantiate the class. template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 49dc8e9dc..931170df9 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -109,6 +109,8 @@ namespace storm { */ virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual uint64_t getNumberOfPredicates() const override; + protected: using MenuGameAbstractor::exportToDot; diff --git a/src/storm/adapters/MathsatExpressionAdapter.h b/src/storm/adapters/MathsatExpressionAdapter.h index 357c482b3..4b4d7cb57 100644 --- a/src/storm/adapters/MathsatExpressionAdapter.h +++ b/src/storm/adapters/MathsatExpressionAdapter.h @@ -116,6 +116,8 @@ namespace storm { msat_term leftResult = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); msat_term rightResult = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + msat_term result = leftResult; + int_fast64_t exponent; switch (expression.getOperatorType()) { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: return msat_make_plus(env, leftResult, rightResult); @@ -124,11 +126,21 @@ namespace storm { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Times: return msat_make_times(env, leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Divide: - STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unsupported numerical binary operator: '/' (division) in expression."); + return msat_make_divide(env, leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Min: return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max: return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), rightResult, leftResult); + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power: + exponent = expression.getSecondOperand()->evaluateAsInt(); + STORM_LOG_THROW(exponent >= 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative exponent."); + --exponent; + if (exponent > 0) { + for (; exponent > 0; --exponent) { + result = msat_make_times(env, result, leftResult); + } + } + return result; default: STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast(expression.getOperatorType()) << "' in expression " << expression << "."); } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 36af17be0..6a42b6530 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -131,7 +131,7 @@ namespace storm { std::unique_ptr result; if (checkTask.isBoundSet()) { - // Despite having a bound, we create a quanitative result so that the next layer can perform the comparison. + // Despite having a bound, we create a quantitative result so that the next layer can perform the comparison. if (player2Direction == storm::OptimizationDirection::Minimize) { if (storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { @@ -361,7 +361,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " (player 1) states and " << game.getNumberOfTransitions() << " transitions (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " (player 1) states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare transition matrix BDD and target state BDD for later use. storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 4835019d4..fd384321f 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -25,7 +25,7 @@ namespace storm { AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; this->addOption(storm::settings::OptionBuilder(moduleName, methodOptionName, true, "Sets which abstraction-refinement method to use.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of themethod to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)) .setDefaultValueString("bisim").build()) .build()); From cf478b2984c26fe8b845e71f1c86fb47660826d3 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 17:11:39 +0100 Subject: [PATCH 194/647] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a415b376e..d30d82ad9 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,12 @@ Storm has been developed at RWTH Aachen University. * Christian Dehnert * Sebastian Junges * Joost-Pieter Katoen +* Tim Quatmann * Matthias Volk ###### Developers (lexicographical order) * Philipp Berger * David Korzeniewski -* Tim Quatmann ###### Contributors (lexicographical order) * Dimitri Bohlender From b998b3abf94acb472584c06809eade47eb11c003 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 17:15:05 +0100 Subject: [PATCH 195/647] Cleanup --- pstorm.py | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 pstorm.py diff --git a/pstorm.py b/pstorm.py deleted file mode 100644 index aaa5a6b25..000000000 --- a/pstorm.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import os -import subprocess -prop = ' --prop \"Pmax=? [F<1 \\"goal\\"]\" --ma:technique unifplus' -storm= '/home/timo/ustorm/build/bin/storm' - - -if len(sys.argv)<2: - print("no input file found\n") - exit() - -for a in sys.argv[1:]: - file = " --prism " + a - cmd = storm + file + prop - os.system(cmd) From c35b446926f7664469c94813017af264c481bd88 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 21 Mar 2018 17:16:01 +0100 Subject: [PATCH 196/647] Updated CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2de8e7f05..70d880e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Version 1.2.x ------------- ### Version 1.2.2 (to be released) +- `storm-dft`: improvements in Galileo parser +- `storm-dft`: test cases for DFT analysis ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. From b4d8c209cd26d801fcb1d231f575d4176ac6d9f5 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 21 Mar 2018 21:54:24 +0100 Subject: [PATCH 197/647] optimizations for game-based abstraction refinement --- src/storm/abstraction/ExpressionTranslator.cpp | 11 ++++++++++- src/storm/abstraction/MenuGameAbstractor.h | 7 +++++++ src/storm/abstraction/MenuGameRefiner.cpp | 8 +++++--- .../abstraction/jani/JaniMenuGameAbstractor.cpp | 13 ++++++++++++- .../abstraction/jani/JaniMenuGameAbstractor.h | 5 +++++ .../abstraction/prism/PrismMenuGameAbstractor.cpp | 15 +++++++++++++-- .../abstraction/prism/PrismMenuGameAbstractor.h | 5 +++++ .../abstraction/GameBasedMdpModelChecker.cpp | 4 ++++ .../storage/expressions/EquivalenceChecker.cpp | 10 ++++++++++ .../storage/expressions/EquivalenceChecker.h | 3 +++ 10 files changed, 74 insertions(+), 7 deletions(-) diff --git a/src/storm/abstraction/ExpressionTranslator.cpp b/src/storm/abstraction/ExpressionTranslator.cpp index fe2d28f97..76dd8a2a3 100644 --- a/src/storm/abstraction/ExpressionTranslator.cpp +++ b/src/storm/abstraction/ExpressionTranslator.cpp @@ -17,7 +17,8 @@ namespace storm { template ExpressionTranslator::ExpressionTranslator(AbstractionInformation& abstractionInformation, std::unique_ptr&& smtSolver) : abstractionInformation(abstractionInformation), equivalenceChecker(std::move(smtSolver)), locationVariables(abstractionInformation.getLocationExpressionVariables()), abstractedVariables(abstractionInformation.getAbstractedVariables()) { - // Intentionally left empty. + + equivalenceChecker.addConstraints(abstractionInformation.getConstraints()); } template @@ -51,6 +52,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } @@ -108,6 +111,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } @@ -124,6 +129,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } @@ -154,6 +161,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index e82c1fb31..646292106 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -51,6 +51,13 @@ namespace storm { /// Retrieves the number of predicates currently in use. virtual uint64_t getNumberOfPredicates() const = 0; + /*! + * Adds the expression to the ones characterizing terminal states, i.e. states whose transitions are not + * explored. For this to work, appropriate predicates must have been used to refine the abstraction, + * otherwise this will fail. + */ + virtual void addTerminalStates(storm::expressions::Expression const& expression) = 0; + protected: void exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const; }; diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index e139a357f..cd3522ac0 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -59,6 +59,8 @@ namespace storm { template MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), addedAllGuardsFlag(false), pivotSelectionHeuristic(storm::settings::getModule().getPivotSelectionHeuristic()), splitter(), equivalenceChecker(std::move(smtSolver)) { + equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); + AbstractionSettings::SplitMode splitMode = storm::settings::getModule().getSplitMode(); splitAll = splitMode == AbstractionSettings::SplitMode::All; splitPredicates = splitMode == AbstractionSettings::SplitMode::NonGuard; @@ -325,7 +327,7 @@ namespace storm { } for (auto const& otherPredicate : otherRefinementPredicates) { for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - if (equivalenceChecker.areEquivalent(otherPredicate, possibleRefinementPredicates[index])) { + if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) { ++refinementPredicateIndexToCount[index]; } } @@ -726,13 +728,13 @@ namespace storm { // set or in the set that is to be added. bool addAtom = true; for (auto const& oldPredicate : abstractionInformation.getPredicates()) { - if (equivalenceChecker.areEquivalent(atom, oldPredicate)) { + if (equivalenceChecker.areEquivalent(atom, oldPredicate) || equivalenceChecker.areEquivalent(atom, !oldPredicate)) { addAtom = false; break; } } for (auto const& addedAtom : cleanedAtoms) { - if (equivalenceChecker.areEquivalent(addedAtom, atom)) { + if (equivalenceChecker.areEquivalent(addedAtom, atom) || equivalenceChecker.areEquivalent(addedAtom, !atom)) { addAtom = false; break; } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index a3900ab80..0e63bc0a5 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -154,8 +154,14 @@ namespace storm { auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + // Compute which states are non-terminal. + storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = game.bdd.existsAbstract(variablesToAbstract); + storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); @@ -213,6 +219,11 @@ namespace storm { return abstractionInformation.getNumberOfPredicates(); } + template + void JaniMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { + terminalStateExpressions.emplace_back(expression); + } + // Explicitly instantiate the class. template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 0a4cc36ed..0ef49f908 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -111,6 +111,8 @@ namespace storm { virtual uint64_t getNumberOfPredicates() const override; + virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + protected: using MenuGameAbstractor::exportToDot; @@ -159,6 +161,9 @@ namespace storm { // A flag storing whether a refinement was performed. bool refinementPerformed; + + // A list of terminal state expressions. + std::vector terminalStateExpressions; }; } } diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index a93e62e67..e5f2580b4 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -99,7 +99,7 @@ namespace storm { MenuGame PrismMenuGameAbstractor::abstract() { if (refinementPerformed) { currentGame = buildGame(); - refinementPerformed = true; + refinementPerformed = false; } return *currentGame; } @@ -147,8 +147,14 @@ namespace storm { auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + // Compute which states are non-terminal. + storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = game.bdd.existsAbstract(variablesToAbstract); + storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); @@ -208,6 +214,11 @@ namespace storm { return abstractionInformation.getNumberOfPredicates(); } + template + void PrismMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { + terminalStateExpressions.emplace_back(expression); + } + // Explicitly instantiate the class. template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 931170df9..55845f134 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -111,6 +111,8 @@ namespace storm { virtual uint64_t getNumberOfPredicates() const override; + virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + protected: using MenuGameAbstractor::exportToDot; @@ -156,6 +158,9 @@ namespace storm { // A flag storing whether a refinement was performed. bool refinementPerformed; + + // A list of terminal state expressions. + std::vector terminalStateExpressions; }; } } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 6a42b6530..7a58e4f39 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -342,6 +342,10 @@ namespace storm { } else { abstractor = std::make_shared>(preprocessedModel.asJaniModel(), smtSolverFactory); } + if (!constraintExpression.isTrue()) { + abstractor->addTerminalStates(!constraintExpression); + } + abstractor->addTerminalStates(targetStateExpression); // Create a refiner that can be used to refine the abstraction when needed. storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); diff --git a/src/storm/storage/expressions/EquivalenceChecker.cpp b/src/storm/storage/expressions/EquivalenceChecker.cpp index b8d538656..c00d4fae6 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.cpp +++ b/src/storm/storage/expressions/EquivalenceChecker.cpp @@ -13,6 +13,12 @@ namespace storm { } } + void EquivalenceChecker::addConstraints(std::vector const& constraints) { + for (auto const& constraint : constraints) { + this->smtSolver->add(constraint); + } + } + bool EquivalenceChecker::areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { this->smtSolver->push(); this->smtSolver->add((first && !second) || (!first && second)); @@ -21,5 +27,9 @@ namespace storm { return equivalent; } + bool EquivalenceChecker::areEquivalentModuloNegation(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { + return this->areEquivalent(first, second) || this->areEquivalent(first, !second); + } + } } diff --git a/src/storm/storage/expressions/EquivalenceChecker.h b/src/storm/storage/expressions/EquivalenceChecker.h index 2ec39ba8a..5d60eb50b 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.h +++ b/src/storm/storage/expressions/EquivalenceChecker.h @@ -20,7 +20,10 @@ namespace storm { */ EquivalenceChecker(std::unique_ptr&& smtSolver, boost::optional const& constraint = boost::none); + void addConstraints(std::vector const& constraints); + bool areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second); + bool areEquivalentModuloNegation(storm::expressions::Expression const& first, storm::expressions::Expression const& second); private: std::unique_ptr smtSolver; From efbd899e46023412f3a09d62ddcd34ba4a4e7300 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 22 Mar 2018 14:29:11 +0100 Subject: [PATCH 198/647] update to game-based abstraction refinement --- src/storm/abstraction/MenuGameAbstractor.cpp | 28 +++++++++++++ src/storm/abstraction/MenuGameAbstractor.h | 18 ++++++++ .../jani/JaniMenuGameAbstractor.cpp | 41 ++++++++++++++++--- .../prism/PrismMenuGameAbstractor.cpp | 37 +++++++++++++++-- .../abstraction/GameBasedMdpModelChecker.cpp | 1 + .../settings/modules/AbstractionSettings.cpp | 10 +++++ .../settings/modules/AbstractionSettings.h | 8 ++++ src/storm/utility/dd.cpp | 35 ++++++++++++++++ src/storm/utility/dd.h | 5 ++- 9 files changed, 174 insertions(+), 9 deletions(-) diff --git a/src/storm/abstraction/MenuGameAbstractor.cpp b/src/storm/abstraction/MenuGameAbstractor.cpp index 7ce40950b..f68694c30 100644 --- a/src/storm/abstraction/MenuGameAbstractor.cpp +++ b/src/storm/abstraction/MenuGameAbstractor.cpp @@ -4,6 +4,9 @@ #include "storm/models/symbolic/StandardRewardModel.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/AbstractionSettings.h" + #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" #include "storm/utility/dd.h" @@ -15,6 +18,11 @@ namespace storm { namespace abstraction { + template + MenuGameAbstractor::MenuGameAbstractor() : restrictToRelevantStates(storm::settings::getModule().isRestrictToRelevantStatesSet()) { + // Intentionally left empty. + } + template std::string getStateName(std::pair const& stateValue, std::set const& locationVariables, std::set const& predicateVariables, storm::expressions::Variable const& bottomVariable) { std::stringstream stateName; @@ -45,6 +53,11 @@ namespace storm { return stateName.str(); } + template + bool MenuGameAbstractor::isRestrictToRelevantStatesSet() const { + return restrictToRelevantStates; + } + template void MenuGameAbstractor::exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const { @@ -135,6 +148,21 @@ namespace storm { storm::utility::closeFile(out); } + template + void MenuGameAbstractor::setTargetStates(storm::expressions::Expression const& targetStateExpression) { + this->targetStateExpression = targetStateExpression; + } + + template + storm::expressions::Expression const& MenuGameAbstractor::getTargetStateExpression() const { + return this->targetStateExpression; + } + + template + bool MenuGameAbstractor::hasTargetStateExpression() const { + return this->targetStateExpression.isInitialized(); + } + template class MenuGameAbstractor; template class MenuGameAbstractor; diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 646292106..35fc75c42 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -24,6 +24,7 @@ namespace storm { template class MenuGameAbstractor { public: + MenuGameAbstractor(); virtual ~MenuGameAbstractor() = default; /// Retrieves the abstraction. @@ -58,8 +59,25 @@ namespace storm { */ virtual void addTerminalStates(storm::expressions::Expression const& expression) = 0; + /*! + * Sets the expression characterizing the target states. For this to work, appropriate predicates must have + * been used to refine the abstraction, otherwise this will fail. + */ + void setTargetStates(storm::expressions::Expression const& targetStateExpression); + + storm::expressions::Expression const& getTargetStateExpression() const; + bool hasTargetStateExpression() const; + protected: + bool isRestrictToRelevantStatesSet() const; + void exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const; + + private: + bool restrictToRelevantStates; + + // An expression characterizing the target states. + storm::expressions::Expression targetStateExpression; }; } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 0e63bc0a5..09782e9fd 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -17,6 +17,7 @@ #include "storm/settings/SettingsManager.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/dd.h" #include "storm/utility/macros.h" #include "storm/utility/solver.h" @@ -154,18 +155,48 @@ namespace storm { auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); - // Compute which states are non-terminal. + storm::utility::Stopwatch relevantStatesWatch(true); storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); - for (auto const& expression : this->terminalStateExpressions) { - nonTerminalStates &= !this->getStates(expression); + if (this->isRestrictToRelevantStatesSet()) { + // Compute which states are non-terminal. + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + if (this->hasTargetStateExpression()) { + nonTerminalStates &= !this->getStates(this->getTargetStateExpression()); + } } - + relevantStatesWatch.stop(); + // Do a reachability analysis on the raw transition relation. storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.start(); + if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { + // Cut transition relation to the reachable states for backward search. + transitionRelation &= reachableStates; + + // Get the target state BDD. + storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); + + // In the presence of target states, we keep only states that can reach the target states. + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + + // Cut the transition relation to the 'extended backward reachable states', so we have the appropriate self- + // loops of (now) deadlock states. + transitionRelation &= reachableStates; + + // Include all successors of reachable states, because the backward search otherwise potentially + // cuts probability 0 choices of these states. + reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.stop(); + + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); + } + // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states, // as the bottom states are not contained in the reachable states. storm::dd::Bdd deadlockStates = transitionRelation.existsAbstract(abstractionInformation.getSuccessorVariables()); @@ -223,7 +254,7 @@ namespace storm { void JaniMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { terminalStateExpressions.emplace_back(expression); } - + // Explicitly instantiate the class. template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index e5f2580b4..9da47fee3 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -15,6 +15,7 @@ #include "storm/settings/SettingsManager.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/dd.h" #include "storm/utility/macros.h" #include "storm/utility/solver.h" @@ -147,11 +148,18 @@ namespace storm { auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); - // Compute which states are non-terminal. + storm::utility::Stopwatch relevantStatesWatch(true); storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); - for (auto const& expression : this->terminalStateExpressions) { - nonTerminalStates &= !this->getStates(expression); + if (this->isRestrictToRelevantStatesSet()) { + // Compute which states are non-terminal. + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + if (this->hasTargetStateExpression()) { + nonTerminalStates &= !this->getStates(this->getTargetStateExpression()); + } } + relevantStatesWatch.stop(); // Do a reachability analysis on the raw transition relation. storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); @@ -159,6 +167,29 @@ namespace storm { initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.start(); + if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { + // Cut transition relation to the reachable states for backward search. + transitionRelation &= reachableStates; + + // Get the target state BDD. + storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); + + // In the presence of target states, we keep only states that can reach the target states. + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + + // Cut the transition relation to the 'extended backward reachable states', so we have the appropriate self- + // loops of (now) deadlock states. + transitionRelation &= reachableStates; + + // Include all successors of reachable states, because the backward search otherwise potentially + // cuts probability 0 choices of these states. + reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.stop(); + + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); + } + // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states, // as the bottom states are not contained in the reachable states. storm::dd::Bdd deadlockStates = transitionRelation.existsAbstract(abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 7a58e4f39..f2cb7a3d2 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -346,6 +346,7 @@ namespace storm { abstractor->addTerminalStates(!constraintExpression); } abstractor->addTerminalStates(targetStateExpression); + abstractor->setTargetStates(targetStateExpression); // Create a refiner that can be used to refine the abstraction when needed. storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index fd384321f..9570810f1 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -21,6 +21,7 @@ namespace storm { const std::string AbstractionSettings::precisionOptionName = "precision"; const std::string AbstractionSettings::pivotHeuristicOptionName = "pivot-heuristic"; const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; + const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -64,6 +65,11 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(reuseModes)) .setDefaultValueString("all").build()) .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, restrictToRelevantStatesOptionName, true, "Sets whether to restrict to relevant states during the abstraction.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -104,6 +110,10 @@ namespace storm { return this->getOption(useInterpolationOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isRestrictToRelevantStatesSet() const { + return this->getOption(restrictToRelevantStatesOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + double AbstractionSettings::getPrecision() const { return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 4d5827187..7c2a98f66 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -93,6 +93,13 @@ namespace storm { */ ReuseMode getReuseMode() const; + /*! + * Retrieves whether only relevant states are to be considered. + * + * @return True iff the option was set. + */ + bool isRestrictToRelevantStatesSet() const; + const static std::string moduleName; private: @@ -104,6 +111,7 @@ namespace storm { const static std::string precisionOptionName; const static std::string pivotHeuristicOptionName; const static std::string reuseResultsOptionName; + const static std::string restrictToRelevantStatesOptionName; }; } diff --git a/src/storm/utility/dd.cpp b/src/storm/utility/dd.cpp index 626dc845f..3ecbef7d6 100644 --- a/src/storm/utility/dd.cpp +++ b/src/storm/utility/dd.cpp @@ -45,6 +45,38 @@ namespace storm { return reachableStates; } + template + storm::dd::Bdd computeBackwardsReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables) { + STORM_LOG_TRACE("Computing backwards reachable states: transition matrix BDD has " << transitions.getNodeCount() << " node(s) and " << transitions.getNonZeroCount() << " non-zero(s), " << initialStates.getNonZeroCount() << " initial states)."); + + auto start = std::chrono::high_resolution_clock::now(); + storm::dd::Bdd reachableStates = initialStates; + + // Perform the BFS to discover all reachable states. + bool changed = true; + uint_fast64_t iteration = 0; + do { + changed = false; + storm::dd::Bdd tmp = reachableStates.inverseRelationalProduct(transitions, rowMetaVariables, columnMetaVariables); + storm::dd::Bdd newReachableStates = tmp && (!reachableStates) && constraintStates; + + // Check whether new states were indeed discovered. + if (!newReachableStates.isZero()) { + changed = true; + } + + reachableStates |= newReachableStates; + + ++iteration; + STORM_LOG_TRACE("Iteration " << iteration << " of (backward) reachability computation completed: " << reachableStates.getNonZeroCount() << " reachable states found."); + } while (changed); + + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Backward reachability computation completed in " << iteration << " iterations (" << std::chrono::duration_cast(end - start).count() << "ms)."); + + return reachableStates; + } + template storm::dd::Bdd getRowColumnDiagonal(storm::dd::DdManager const& ddManager, std::vector> const& rowColumnMetaVariablePairs) { return ddManager.getIdentity(rowColumnMetaVariablePairs, false); @@ -53,6 +85,9 @@ namespace storm { template storm::dd::Bdd computeReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); template storm::dd::Bdd computeReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); + template storm::dd::Bdd computeBackwardsReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); + template storm::dd::Bdd computeBackwardsReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); + template storm::dd::Bdd getRowColumnDiagonal(storm::dd::DdManager const& ddManager, std::vector> const& rowColumnMetaVariablePairs); template storm::dd::Bdd getRowColumnDiagonal(storm::dd::DdManager const& ddManager, std::vector> const& rowColumnMetaVariablePairs); diff --git a/src/storm/utility/dd.h b/src/storm/utility/dd.h index 65e079bf3..679e1bd50 100644 --- a/src/storm/utility/dd.h +++ b/src/storm/utility/dd.h @@ -25,7 +25,10 @@ namespace storm { template storm::dd::Bdd computeReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); - + + template + storm::dd::Bdd computeBackwardsReachableStates(storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& transitions, std::set const& rowMetaVariables, std::set const& columnMetaVariables); + template storm::dd::Add getRowColumnDiagonal(storm::dd::DdManager const& ddManager, std::vector> const& rowColumnMetaVariablePairs); From 733bec60bd56efdf2965e7c78f024d0f999432dd Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 22 Mar 2018 16:46:19 +0100 Subject: [PATCH 199/647] started on hybrid solution of abstraction --- .../abstraction/GameBasedMdpModelChecker.cpp | 110 ++++++++++-------- .../abstraction/GameBasedMdpModelChecker.h | 5 + .../settings/modules/AbstractionSettings.cpp | 17 ++- .../settings/modules/AbstractionSettings.h | 10 ++ src/storm/storage/dd/Add.cpp | 25 +++- src/storm/storage/dd/Add.h | 33 +++--- src/storm/storage/dd/cudd/InternalCuddAdd.cpp | 25 ++++ src/storm/storage/dd/cudd/InternalCuddAdd.h | 22 ++++ .../storage/dd/sylvan/InternalSylvanAdd.cpp | 30 +++++ .../storage/dd/sylvan/InternalSylvanAdd.h | 22 ++++ 10 files changed, 232 insertions(+), 67 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index f2cb7a3d2..ea0a72349 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -32,7 +32,6 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" -#include "storm/settings/modules/AbstractionSettings.h" #include "storm/utility/prism.h" #include "storm/utility/macros.h" @@ -50,7 +49,7 @@ namespace storm { using storm::abstraction::QuantitativeGameResultMinMax; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { model.requireNoUndefinedConstants(); if (model.isPrismProgram()) { storm::prism::Program const& originalProgram = model.asPrismProgram(); @@ -424,54 +423,73 @@ namespace storm { // (6) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. if (!qualitativeRefinement) { // At this point, we know that we cannot answer the query without further numeric computation. - - storm::dd::Add initialStatesAdd = initialStates.template toAdd(); - STORM_LOG_TRACE("Starting numerical solution step."); - auto quantitativeStart = std::chrono::high_resolution_clock::now(); - - QuantitativeGameResultMinMax quantitativeResult; - - // (7) Solve the min values and check whether we can give the answer already. - quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); - previousMinQuantitativeResult = quantitativeResult.min; - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; - } - - // (8) Solve the max values and check whether we can give the answer already. - quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; - } - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); - - // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. - result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); - if (result) { - printStatistics(*abstractor, game); - return result; + // Solve abstraction using the selected mode. + if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { + STORM_LOG_TRACE("Using dd-based solving."); + storm::dd::Add initialStatesAdd = initialStates.template toAdd(); + + auto quantitativeStart = std::chrono::high_resolution_clock::now(); + + QuantitativeGameResultMinMax quantitativeResult; + + // (7) Solve the min values and check whether we can give the answer already. + quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); + previousMinQuantitativeResult = quantitativeResult.min; + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); + if (result) { + printStatistics(*abstractor, game); + return result; + } + + // (8) Solve the max values and check whether we can give the answer already. + quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); + if (result) { + printStatistics(*abstractor, game); + return result; + } + + auto quantitativeEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. + result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); + if (result) { + printStatistics(*abstractor, game); + return result; + } + + // Make sure that all strategies are still valid strategies. + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); + + auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. + refiner.refine(game, transitionMatrixBdd, quantitativeResult); + auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + } else { + STORM_LOG_TRACE("Using hybrid solving."); + + storm::dd::Odd odd = (maybeMin || maybeMax || targetStates).createOdd(); + + std::pair, std::vector> transitionMatrixLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), odd, odd, true); + auto const& transitionMatrix = transitionMatrixLabeling.first; + auto const& labeling = transitionMatrixLabeling.second; + + std::cout << transitionMatrix << std::endl; + for (auto const& e : labeling) { + std::cout << e << std::endl; + } + + exit(-1); } - // Make sure that all strategies are still valid strategies. - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); - - auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); - // (10) If we arrived at this point, it means that we have all qualitative and quantitative - // information about the game, but we could not yet answer the query. In this case, we need to refine. - refiner.refine(game, transitionMatrixBdd, quantitativeResult); - auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); - } auto iterationEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 8c105cfc4..dd6c7cb2f 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -14,6 +14,8 @@ #include "storm/logic/Bound.h" +#include "storm/settings/modules/AbstractionSettings.h" + #include "storm/utility/ConstantsComparator.h" #include "storm/utility/solver.h" #include "storm/utility/graph.h" @@ -95,6 +97,9 @@ namespace storm { /// A flag indicating whether to reuse the quantitative results. bool reuseQuantitativeResults; + + /// The mode selected for solving the abstraction. + storm::settings::modules::AbstractionSettings::SolveMode solveMode; }; } } diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 9570810f1..947b7b7ca 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -22,6 +22,7 @@ namespace storm { const std::string AbstractionSettings::pivotHeuristicOptionName = "pivot-heuristic"; const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; + const std::string AbstractionSettings::solveModeOptionName = "solve"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -42,7 +43,13 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(splitModes)) .setDefaultValueString("all").build()) .build()); - + + std::vector solveModes = {"dd", "hybrid"}; + this->addOption(storm::settings::OptionBuilder(moduleName, solveModeOptionName, true, "Sets how the abstractions are solved.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(solveModes)) + .setDefaultValueString("dd").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, addAllGuardsOptionName, true, "Sets whether all guards are added as initial predicates.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("on").build()) @@ -98,6 +105,14 @@ namespace storm { return SplitMode::All; } + AbstractionSettings::SolveMode AbstractionSettings::getSolveMode() const { + std::string solveModeAsString = this->getOption(solveModeOptionName).getArgumentByName("mode").getValueAsString(); + if (solveModeAsString == "dd") { + return SolveMode::Dd; + } + return SolveMode::Hybrid; + } + bool AbstractionSettings::isAddAllGuardsSet() const { return this->getOption(addAllGuardsOptionName).getArgumentByName("value").getValueAsString() == "on"; } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 7c2a98f66..2b361b273 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -27,6 +27,10 @@ namespace storm { All, None, Qualitative, Quantitative }; + enum class SolveMode { + Dd, Hybrid + }; + /*! * Creates a new set of abstraction settings. */ @@ -100,6 +104,11 @@ namespace storm { */ bool isRestrictToRelevantStatesSet() const; + /*! + * Retrieves the mode with which to solve the games. + */ + SolveMode getSolveMode() const; + const static std::string moduleName; private: @@ -112,6 +121,7 @@ namespace storm { const static std::string pivotHeuristicOptionName; const static std::string reuseResultsOptionName; const static std::string restrictToRelevantStatesOptionName; + const static std::string solveModeOptionName; }; } diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 9e91b2123..91c35c67a 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -703,11 +703,11 @@ namespace storm { } // Create the canonical row group sizes and build the matrix. - return toMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd); + return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd).first; } template - storm::storage::SparseMatrix Add::toMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { + std::pair, std::vector> Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling) const { std::vector ddRowVariableIndices; std::vector ddColumnVariableIndices; std::vector ddGroupVariableIndices; @@ -760,12 +760,24 @@ namespace storm { groups.push_back(Add(this->getDdManager(), internalAdd, rowAndColumnMetaVariables)); } + // Create the group labelings if requested. + std::vector groupLabels; + if (buildLabeling) { + groupLabels = internalAdd.decodeGroupLabels(ddGroupVariableIndices); + STORM_LOG_ASSERT(groupLabels.size() == groups.size(), "Mismatching label sizes."); + } + // Create the actual storage for the non-zero entries. std::vector> columnsAndValues(this->getNonZeroCount()); // Now compute the indices at which the individual rows start. std::vector rowIndications(rowGroupIndices.back() + 1); + std::vector labeling; + if (buildLabeling) { + labeling.resize(rowGroupIndices.back()); + } + std::vector> statesWithGroupEnabled(groups.size()); InternalAdd stateToRowGroupCount = this->getDdManager().template getAddZero(); for (uint_fast64_t i = 0; i < groups.size(); ++i) { @@ -779,6 +791,11 @@ namespace storm { statesWithGroupEnabled[i] = groupNotZero.existsAbstract(columnMetaVariables).template toAdd(); statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus()); + + if (buildLabeling) { + uint64_t currentLabel = groupLabels[i]; + statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, labeling, [currentLabel] (uint_fast64_t a, uint_fast64_t l) { return currentLabel; }); + } } // Since we modified the rowGroupIndices, we need to restore the correct values. @@ -812,9 +829,9 @@ namespace storm { } rowIndications[0] = 0; - return storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); + return std::make_pair(storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), labeling); } - + template std::pair, std::vector> Add::toMatrixVector(storm::dd::Add const& vector, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::set rowMetaVariables; diff --git a/src/storm/storage/dd/Add.h b/src/storm/storage/dd/Add.h index 1a4a811d5..c50b4c010 100644 --- a/src/storm/storage/dd/Add.h +++ b/src/storm/storage/dd/Add.h @@ -640,6 +640,23 @@ namespace storm { */ storm::storage::SparseMatrix toMatrix(std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; + /*! + * Converts the ADD to a row-grouped (sparse) matrix. The given offset-labeled DDs are used to determine the + * correct row and column, respectively, for each entry. If requested, it builds a labeling of the rows + * that is derived from the group variable encodings. Note: this function assumes that the meta variables + * used to distinguish different row groups are at the very top of the ADD. + * + * @param rowMetaVariables The meta variables that encode the rows of the matrix. + * @param columnMetaVariables The meta variables that encode the columns of the matrix. + * @param groupMetaVariables The meta variables that are used to distinguish different row groups. + * @param rowOdd The ODD used for determining the correct row. + * @param columnOdd The ODD used for determining the correct column. + * @param buildLabeling If false, no labeling vector is built. + * @return The matrix that is represented by this ADD and a vector corresponding to row labeling + * (if requested). + */ + std::pair, std::vector> toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling = false) const; + /*! * Converts the ADD to a row-grouped (sparse) matrix and the given vector to a row-grouped vector. * The given offset-labeled DDs are used to determine the correct row and column, respectively, for each @@ -721,22 +738,6 @@ namespace storm { */ operator InternalAdd() const; - /*! - * Converts the ADD to a row-grouped (sparse) double matrix. If the optional vector is given, it is also - * translated to an explicit row-grouped vector with the same row-grouping. The given offset-labeled DDs - * are used to determine the correct row and column, respectively, for each entry. Note: this function - * assumes that the meta variables used to distinguish different row groups are at the very top of the ADD. - * - * @param rowMetaVariables The meta variables that encode the rows of the matrix. - * @param columnMetaVariables The meta variables that encode the columns of the matrix. - * @param groupMetaVariables The meta variables that are used to distinguish different row groups. - * @param rowOdd The ODD used for determining the correct row. - * @param columnOdd The ODD used for determining the correct column. - * @return The matrix that is represented by this ADD and and a vector corresponding to the symbolic vector - * (if it was given). - */ - storm::storage::SparseMatrix toMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; - /*! * Converts the ADD to a row-grouped (sparse) double matrix and the given vector to an equally row-grouped * explicit vector. The given offset-labeled DDs are used to determine the correct row and column, diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp index 11c6b12ca..ea0ca6d1f 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp @@ -524,6 +524,31 @@ namespace storm { } } + template + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices) const { + std::vector result; + decodeGroupLabelsRec(this->getCuddDdNode(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size(), 0); + return result; + } + + template + void InternalAdd::decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + // For the empty DD, we do not need to create a group. + if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { + return; + } + + if (currentLevel == maxLevel) { + labels.push_back(label); + } else if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1); + } else { + decodeGroupLabelsRec(Cudd_E(dd), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); + decodeGroupLabelsRec(Cudd_T(dd), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1 ); + } + } + template std::vector> InternalAdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { std::vector> result; diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.h b/src/storm/storage/dd/cudd/InternalCuddAdd.h index 2262d5da0..bb53f68d4 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.h @@ -570,6 +570,15 @@ namespace storm { */ std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + /*! + * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). + * The labeling is then made by interpreting the group encodings as binary encodings. + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices) const; + /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of * the given group variables (given via indices). @@ -661,6 +670,19 @@ namespace storm { */ void splitIntoGroupsRec(DdNode* dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! + * Splits the given matrix DD into the labelings of the gropus using the given group variables. + * + * @param dd The DD to split. + * @param labels A vector that is to be filled with the labels of the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. + * @param label The currently followed label. + */ + void decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; + /*! * Splits the given DDs into the groups using the given group variables. * diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp index 0173f6aac..4a7784015 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp @@ -921,6 +921,36 @@ namespace storm { } } + template + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices) const { + std::vector result; + decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size(), 0); + return result; + } + + template + void InternalAdd::decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + // For the empty DD, we do not need to create a group. + if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { + return; + } + + if (currentLevel == maxLevel) { + labels.push_back(label); + } else if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + MTBDD thenDdNode = mtbdd_gethigh(dd); + MTBDD elseDdNode = mtbdd_getlow(dd); + + decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); + decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1 ); + + } + } + template std::vector> InternalAdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { std::vector> result; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h index 5137caf15..6c3cae256 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h @@ -561,6 +561,15 @@ namespace storm { */ std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + /*! + * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). + * The labeling is then made by interpreting the group encodings as binary encodings. + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices) const; + /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of * the given group variables (given via indices). @@ -651,6 +660,19 @@ namespace storm { */ void composeWithExplicitVectorRec(MTBDD dd, bool negated, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + /*! + * Splits the given matrix DD into the labelings of the gropus using the given group variables. + * + * @param dd The DD to split. + * @param labels A vector that is to be filled with the labels of the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. + * @param label The currently followed label. + */ + void decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; + /*! * Splits the given matrix DD into the groups using the given group variables. * From cedae194e385a2b138599c0305786f11ac1de434 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 22 Mar 2018 19:15:27 +0100 Subject: [PATCH 200/647] towards labeling generation in dd to sparse conversion --- .../abstraction/GameBasedMdpModelChecker.cpp | 7 ++-- src/storm/storage/dd/Add.cpp | 31 ++++++++++++++--- src/storm/storage/dd/Add.h | 2 +- src/storm/storage/dd/cudd/InternalCuddAdd.cpp | 29 +++++++++++----- src/storm/storage/dd/cudd/InternalCuddAdd.h | 6 ++-- .../storage/dd/sylvan/InternalSylvanAdd.cpp | 34 ++++++++++++------- .../storage/dd/sylvan/InternalSylvanAdd.h | 6 ++-- 7 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index ea0a72349..ac3250f19 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -476,9 +476,12 @@ namespace storm { } else { STORM_LOG_TRACE("Using hybrid solving."); - storm::dd::Odd odd = (maybeMin || maybeMax || targetStates).createOdd(); + auto relevantStates = maybeMin || maybeMax || targetStates; + auto relevantStatesAdd = relevantStates.template toAdd(); + storm::dd::Odd odd = relevantStates.createOdd(); - std::pair, std::vector> transitionMatrixLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), odd, odd, true); + auto relevantStatesTransitionMatrix = game.getTransitionMatrix() * relevantStatesAdd * relevantStatesAdd.swapVariables(game.getRowColumnMetaVariablePairs()); + std::pair, std::vector> transitionMatrixLabeling = relevantStatesTransitionMatrix.toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), game.getPlayer1Variables(), odd, odd, true); auto const& transitionMatrix = transitionMatrixLabeling.first; auto const& labeling = transitionMatrixLabeling.second; diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 91c35c67a..80b707639 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -9,6 +9,7 @@ #include "storm/storage/dd/Odd.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" @@ -703,14 +704,15 @@ namespace storm { } // Create the canonical row group sizes and build the matrix. - return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd).first; + return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, groupMetaVariables, rowOdd, columnOdd).first; } template - std::pair, std::vector> Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling) const { + std::pair, std::vector> Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, std::set const& labelMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling) const { std::vector ddRowVariableIndices; std::vector ddColumnVariableIndices; std::vector ddGroupVariableIndices; + storm::storage::BitVector ddLabelVariableIndices; std::set rowAndColumnMetaVariables; for (auto const& variable : rowMetaVariables) { @@ -736,7 +738,25 @@ namespace storm { } } std::sort(ddGroupVariableIndices.begin(), ddGroupVariableIndices.end()); - + if (buildLabeling) { + std::set ddLabelVariableIndicesSet; + for (auto const& variable : labelMetaVariables) { + DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); + for (auto const& ddVariable : metaVariable.getDdVariables()) { + ddLabelVariableIndicesSet.insert(ddVariable.getIndex()); + } + } + + ddLabelVariableIndices = storm::storage::BitVector(ddGroupVariableIndices.size()); + uint64_t position = 0; + for (auto const& index : ddGroupVariableIndices) { + if (ddLabelVariableIndicesSet.find(index) != ddLabelVariableIndicesSet.end()) { + ddLabelVariableIndices.set(position); + } + ++position; + } + } + Bdd columnVariableCube = Bdd::getCube(this->getDdManager(), columnMetaVariables); // Start by computing the offsets (in terms of rows) for each row group. @@ -763,7 +783,7 @@ namespace storm { // Create the group labelings if requested. std::vector groupLabels; if (buildLabeling) { - groupLabels = internalAdd.decodeGroupLabels(ddGroupVariableIndices); + groupLabels = internalAdd.decodeGroupLabels(ddGroupVariableIndices, ddLabelVariableIndices); STORM_LOG_ASSERT(groupLabels.size() == groups.size(), "Mismatching label sizes."); } @@ -794,7 +814,8 @@ namespace storm { if (buildLabeling) { uint64_t currentLabel = groupLabels[i]; - statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, labeling, [currentLabel] (uint_fast64_t a, uint_fast64_t l) { return currentLabel; }); + std::cout << "current label is " << currentLabel << std::endl; + // statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, labeling, [currentLabel] (uint_fast64_t a, uint_fast64_t l) { return currentLabel; }); } } diff --git a/src/storm/storage/dd/Add.h b/src/storm/storage/dd/Add.h index c50b4c010..ba6b5644d 100644 --- a/src/storm/storage/dd/Add.h +++ b/src/storm/storage/dd/Add.h @@ -655,7 +655,7 @@ namespace storm { * @return The matrix that is represented by this ADD and a vector corresponding to row labeling * (if requested). */ - std::pair, std::vector> toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling = false) const; + std::pair, std::vector> toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, std::set const& labelMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling = false) const; /*! * Converts the ADD to a row-grouped (sparse) matrix and the given vector to a row-grouped vector. diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp index ea0ca6d1f..6e5a57e4a 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp @@ -6,6 +6,7 @@ #include "storm/storage/dd/Odd.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" @@ -525,14 +526,15 @@ namespace storm { } template - std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices) const { + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { std::vector result; - decodeGroupLabelsRec(this->getCuddDdNode(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size(), 0); + std::cout << ddLabelVariableIndices << std::endl; + decodeGroupLabelsRec(this->getCuddDdNode(), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); return result; } template - void InternalAdd::decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + void InternalAdd::decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { // For the empty DD, we do not need to create a group. if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { return; @@ -540,12 +542,23 @@ namespace storm { if (currentLevel == maxLevel) { labels.push_back(label); - } else if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { - decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); - decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1); } else { - decodeGroupLabelsRec(Cudd_E(dd), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); - decodeGroupLabelsRec(Cudd_T(dd), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1 ); + uint64_t elseLabel = label; + uint64_t thenLabel = label; + + std::cout << "currentLevel " << currentLevel << " is in labels? " << ddLabelVariableIndices.get(currentLevel) << std::endl; + if (ddLabelVariableIndices.get(currentLevel)) { + elseLabel <<= 1; + thenLabel = (thenLabel << 1) | 1; + } + + if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } else { + decodeGroupLabelsRec(Cudd_E(dd), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(Cudd_T(dd), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } } } diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.h b/src/storm/storage/dd/cudd/InternalCuddAdd.h index bb53f68d4..cab873353 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.h @@ -575,9 +575,10 @@ namespace storm { * The labeling is then made by interpreting the group encodings as binary encodings. * * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @param ddLabelVariableIndices The indices of variables that are considered as labels. * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). */ - std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices) const; + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const; /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of @@ -676,12 +677,13 @@ namespace storm { * @param dd The DD to split. * @param labels A vector that is to be filled with the labels of the individual groups. * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param ddLabelVariableIndices A bit vector indicating which variables are considered label variables. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. * @param label The currently followed label. */ - void decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; + void decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; /*! * Splits the given DDs into the groups using the given group variables. diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp index 4a7784015..96dcbcc75 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp @@ -5,6 +5,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/macros.h" #include "storm/utility/constants.h" @@ -922,14 +923,14 @@ namespace storm { } template - std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices) const { + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { std::vector result; - decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size(), 0); + decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); return result; } template - void InternalAdd::decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + void InternalAdd::decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { // For the empty DD, we do not need to create a group. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; @@ -937,17 +938,26 @@ namespace storm { if (currentLevel == maxLevel) { labels.push_back(label); - } else if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { - decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); - decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1); } else { - // Otherwise, we compute the ODDs for both the then- and else successors. - MTBDD thenDdNode = mtbdd_gethigh(dd); - MTBDD elseDdNode = mtbdd_getlow(dd); - - decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, label << 1); - decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, currentLevel + 1, maxLevel, (label << 1) | 1 ); + uint64_t elseLabel = label; + uint64_t thenLabel = label; + if (ddLabelVariableIndices.get(currentLevel)) { + elseLabel <<= 1; + thenLabel = (thenLabel << 1) | 1; + } + + if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + MTBDD thenDdNode = mtbdd_gethigh(dd); + MTBDD elseDdNode = mtbdd_getlow(dd); + + decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } } } diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h index 6c3cae256..449ba0bbc 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h @@ -566,9 +566,10 @@ namespace storm { * The labeling is then made by interpreting the group encodings as binary encodings. * * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @param ddLabelVariableIndices The indices of variables that are considered as labels. * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). */ - std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices) const; + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const; /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of @@ -666,12 +667,13 @@ namespace storm { * @param dd The DD to split. * @param labels A vector that is to be filled with the labels of the individual groups. * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param ddLabelVariableIndices A bit vector indicating which variables are considered label variables. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. * @param label The currently followed label. */ - void decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; + void decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; /*! * Splits the given matrix DD into the groups using the given group variables. From 51e08bb1a5f8bf941a101c079c3527610c9a7af7 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 23 Mar 2018 09:31:03 +0100 Subject: [PATCH 201/647] removed old inPlaceMultiplier --- src/storm/solver/InPlaceMultiplier.cpp | 138 ------------------------- src/storm/solver/InPlaceMultiplier.h | 41 -------- src/storm/solver/Multiplier.cpp | 1 - 3 files changed, 180 deletions(-) delete mode 100644 src/storm/solver/InPlaceMultiplier.cpp delete mode 100644 src/storm/solver/InPlaceMultiplier.h diff --git a/src/storm/solver/InPlaceMultiplier.cpp b/src/storm/solver/InPlaceMultiplier.cpp deleted file mode 100644 index abfd4463a..000000000 --- a/src/storm/solver/InPlaceMultiplier.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "storm/solver/InPlaceMultiplier.h" - -#include "storm-config.h" - -#include "storm/environment/solver/MultiplierEnvironment.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/CoreSettings.h" - -#include "storm/storage/SparseMatrix.h" - -#include "storm/adapters/RationalNumberAdapter.h" -#include "storm/adapters/RationalFunctionAdapter.h" - -#include "storm/utility/macros.h" - -namespace storm { - namespace solver { - - template - InPlaceMultiplier::InPlaceMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { - // Intentionally left empty. - } - - template - bool InPlaceMultiplier::parallelize(Environment const& env) const { -#ifdef STORM_HAVE_INTELTBB - return storm::settings::getModule().isUseIntelTbbSet(); -#else - return false; -#endif - } - - template - void InPlaceMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { - std::vector* target = &result; - if (&x == &result) { - if (this->cachedVector) { - this->cachedVector->resize(x.size()); - } else { - this->cachedVector = std::make_unique>(x.size()); - } - target = this->cachedVector.get(); - } - if (parallelize(env)) { - multAddParallel(x, b, *target); - } else { - multAdd(x, b, *target); - } - if (&x == &result) { - std::swap(result, *this->cachedVector); - } - } - - template - void InPlaceMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { - this->matrix.multiplyWithVectorBackward(x, x, b); - } - - template - void InPlaceMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - std::vector* target = &result; - if (&x == &result) { - if (this->cachedVector) { - this->cachedVector->resize(x.size()); - } else { - this->cachedVector = std::make_unique>(x.size()); - } - target = this->cachedVector.get(); - } - if (parallelize(env)) { - multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); - } else { - multAddReduce(dir, rowGroupIndices, x, b, *target, choices); - } - if (&x == &result) { - std::swap(result, *this->cachedVector); - } - } - - template - void InPlaceMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); - } - - template - void InPlaceMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { - for (auto const& entry : this->matrix.getRow(rowIndex)) { - value += entry.getValue() * x[entry.getColumn()]; - } - } - - template - void InPlaceMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { - for (auto const& entry : this->matrix.getRow(rowIndex)) { - val1 += entry.getValue() * x1[entry.getColumn()]; - val2 += entry.getValue() * x2[entry.getColumn()]; - } - } - - - template - void InPlaceMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { - this->matrix.multiplyWithVector(x, result, b); - } - - template - void InPlaceMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); - } - - template - void InPlaceMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { -#ifdef STORM_HAVE_INTELTBB - this->matrix.multiplyWithVectorParallel(x, result, b); -#else - STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAdd(x, b, result); -#endif - } - - template - void InPlaceMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { -#ifdef STORM_HAVE_INTELTBB - this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); -#else - STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAddReduce(dir, rowGroupIndices, x, b, result, choices); -#endif - } - - template class InPlaceMultiplier; -#ifdef STORM_HAVE_CARL - template class InPlaceMultiplier; - template class InPlaceMultiplier; -#endif - - } -} diff --git a/src/storm/solver/InPlaceMultiplier.h b/src/storm/solver/InPlaceMultiplier.h deleted file mode 100644 index d02c74bfb..000000000 --- a/src/storm/solver/InPlaceMultiplier.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "storm/solver/Multiplier.h" - -#include "storm/solver/OptimizationDirection.h" - -namespace storm { - namespace storage { - template - class SparseMatrix; - } - - namespace solver { - - template - class InPlaceMultiplier : public Multiplier { - public: - InPlaceMultiplier(storm::storage::SparseMatrix const& matrix); - - virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; - virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const override; - - - private: - bool parallelize(Environment const& env) const; - - void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; - - void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - - void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - - }; - - } -} diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 0da52a06a..26bb4d85b 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -11,7 +11,6 @@ #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/NativeMultiplier.h" #include "storm/solver/GmmxxMultiplier.h" -#include "storm/solver/InPlaceMultiplier.h" #include "storm/environment/solver/MultiplierEnvironment.h" namespace storm { From edbe3b19525bb78d85806b5d9bfa6c5cf9ffe86a Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 24 Mar 2018 22:10:38 +0100 Subject: [PATCH 202/647] more work on explicit game solving --- ... => ExplicitQualitativeGameResultMinMax.h} | 10 +- .../abstraction/ExplicitQualitativeResult.h | 25 ++ .../ExplicitQualitativeResultMinMax.cpp | 29 ++ .../ExplicitQualitativeResultMinMax.h | 28 ++ src/storm/abstraction/QualitativeGameResult.h | 24 -- src/storm/abstraction/QualitativeMdpResult.h | 25 -- .../abstraction/QualitativeMdpResultMinMax.h | 40 --- src/storm/abstraction/QualitativeResult.cpp | 33 +++ src/storm/abstraction/QualitativeResult.h | 25 +- .../abstraction/QualitativeResultMinMax.cpp | 6 +- .../abstraction/QualitativeResultMinMax.h | 3 +- .../abstraction/QuantitativeGameResult.h | 61 ----- .../QuantitativeGameResultMinMax.h | 22 -- .../SymbolicQualitativeGameResult.cpp | 19 ++ .../SymbolicQualitativeGameResult.h | 19 ++ .../SymbolicQualitativeGameResultMinMax.cpp | 29 ++ .../SymbolicQualitativeGameResultMinMax.h | 25 ++ .../SymbolicQualitativeMdpResult.cpp | 20 ++ .../SymbolicQualitativeMdpResult.h | 23 ++ .../SymbolicQualitativeMdpResultMinMax.cpp | 29 ++ .../SymbolicQualitativeMdpResultMinMax.h | 27 ++ .../abstraction/SymbolicQualitativeResult.h | 26 ++ .../SymbolicQualitativeResultMinMax.cpp | 8 +- .../SymbolicQualitativeResultMinMax.h | 14 +- .../SymbolicQuantitativeGameResult.cpp | 61 +++++ .../SymbolicQuantitativeGameResult.h | 41 +++ .../SymbolicQuantitativeGameResultMinMax.cpp | 12 + .../SymbolicQuantitativeGameResultMinMax.h | 20 ++ .../abstraction/GameBasedMdpModelChecker.cpp | 251 ++++++++++-------- .../abstraction/GameBasedMdpModelChecker.h | 12 + .../settings/modules/AbstractionSettings.cpp | 4 +- .../settings/modules/AbstractionSettings.h | 2 +- src/storm/storage/dd/Add.cpp | 6 +- src/storm/storage/dd/cudd/InternalCuddAdd.cpp | 27 +- src/storm/storage/dd/cudd/InternalCuddAdd.h | 22 +- .../storage/dd/sylvan/InternalSylvanAdd.cpp | 29 +- .../storage/dd/sylvan/InternalSylvanAdd.h | 23 +- src/storm/utility/graph.cpp | 16 +- src/storm/utility/graph.h | 12 +- src/test/storm/utility/GraphTest.cpp | 6 +- 40 files changed, 749 insertions(+), 365 deletions(-) rename src/storm/abstraction/{QualitativeGameResultMinMax.h => ExplicitQualitativeGameResultMinMax.h} (85%) create mode 100644 src/storm/abstraction/ExplicitQualitativeResult.h create mode 100644 src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp create mode 100644 src/storm/abstraction/ExplicitQualitativeResultMinMax.h delete mode 100644 src/storm/abstraction/QualitativeGameResult.h delete mode 100644 src/storm/abstraction/QualitativeMdpResult.h delete mode 100644 src/storm/abstraction/QualitativeMdpResultMinMax.h delete mode 100644 src/storm/abstraction/QuantitativeGameResult.h delete mode 100644 src/storm/abstraction/QuantitativeGameResultMinMax.h create mode 100644 src/storm/abstraction/SymbolicQualitativeGameResult.cpp create mode 100644 src/storm/abstraction/SymbolicQualitativeGameResult.h create mode 100644 src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp create mode 100644 src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h create mode 100644 src/storm/abstraction/SymbolicQualitativeMdpResult.cpp create mode 100644 src/storm/abstraction/SymbolicQualitativeMdpResult.h create mode 100644 src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp create mode 100644 src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h create mode 100644 src/storm/abstraction/SymbolicQualitativeResult.h create mode 100644 src/storm/abstraction/SymbolicQuantitativeGameResult.cpp create mode 100644 src/storm/abstraction/SymbolicQuantitativeGameResult.h create mode 100644 src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp create mode 100644 src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h diff --git a/src/storm/abstraction/QualitativeGameResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h similarity index 85% rename from src/storm/abstraction/QualitativeGameResultMinMax.h rename to src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h index c40338185..7764c3383 100644 --- a/src/storm/abstraction/QualitativeGameResultMinMax.h +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h @@ -7,11 +7,10 @@ namespace storm { namespace abstraction { - - template - class QualitativeGameResultMinMax : public SymbolicQualitativeResultMinMax { + + class ExplicitQualitativeGameResultMinMax : public QualitativeResultMinMax { public: - QualitativeGameResultMinMax() = default; + ExplicitQualitativeGameResultMinMax() = default; virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override { if (dir == storm::OptimizationDirection::Minimize) { @@ -34,6 +33,7 @@ namespace storm { QualitativeGameResult prob0Max; QualitativeGameResult prob1Max; }; - + } } + diff --git a/src/storm/abstraction/ExplicitQualitativeResult.h b/src/storm/abstraction/ExplicitQualitativeResult.h new file mode 100644 index 000000000..8f8e6a151 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResult.h @@ -0,0 +1,25 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/QualitativeResult.h" + +namespace storm { + namespace storage { + class BitVector; + } + + namespace abstraction { + + class ExplicitQualitativeResult : public QualitativeResult { + public: + virtual ~ExplicitQualitativeResult() = default; + + virtual storm::storage::BitVector const& getStates() const = 0; + }; + + } +} + + + diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp new file mode 100644 index 000000000..8d3a630f2 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp @@ -0,0 +1,29 @@ +#include "storm/abstraction/ExplicitQualitativeResultMinMax.h" + +#include "storm/abstraction/ExplicitQualitativeResult.h" + +namespace storm { + namespace abstraction { + + bool ExplicitQualitativeResultMinMax::isExplicit() const { + return true; + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb0Min() const { + return getProb0(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb1Min() const { + return getProb1(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb0Max() const { + return getProb0(storm::OptimizationDirection::Maximize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb1Max() const { + return getProb1(storm::OptimizationDirection::Maximize); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h new file mode 100644 index 000000000..2eabe123b --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h @@ -0,0 +1,28 @@ +#pragma once + +#include "storm/solver/OptimizationDirection.h" + +#include "storm/abstraction/QualitativeResultMinMax.h" + +namespace storm { + namespace abstraction { + class ExplicitQualitativeResult; + + class ExplicitQualitativeResultMinMax : public QualitativeResultMinMax { + public: + ExplicitQualitativeResultMinMax() = default; + + virtual bool isExplicit() const override; + + ExplicitQualitativeResult const& getProb0Min() const; + ExplicitQualitativeResult const& getProb1Min() const; + ExplicitQualitativeResult const& getProb0Max() const; + ExplicitQualitativeResult const& getProb1Max() const; + + virtual ExplicitQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; + virtual ExplicitQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; + }; + + } +} + diff --git a/src/storm/abstraction/QualitativeGameResult.h b/src/storm/abstraction/QualitativeGameResult.h deleted file mode 100644 index ff3c6e44c..000000000 --- a/src/storm/abstraction/QualitativeGameResult.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "storm/utility/graph.h" -#include "storm/abstraction/QualitativeResult.h" - -namespace storm { - namespace abstraction { - - template - struct QualitativeGameResult : public storm::utility::graph::GameProb01Result, public QualitativeResult { - QualitativeGameResult() = default; - - QualitativeGameResult(storm::utility::graph::GameProb01Result const& prob01Result) : storm::utility::graph::GameProb01Result(prob01Result) { - // Intentionally left empty. - } - - virtual storm::dd::Bdd const& getStates() const override { - return this->getPlayer1States(); - } - - }; - - } -} diff --git a/src/storm/abstraction/QualitativeMdpResult.h b/src/storm/abstraction/QualitativeMdpResult.h deleted file mode 100644 index 9fc1fcc0e..000000000 --- a/src/storm/abstraction/QualitativeMdpResult.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "storm/abstraction/QualitativeResult.h" - -namespace storm { - namespace abstraction { - - template - struct QualitativeMdpResult : public QualitativeResult { - QualitativeMdpResult() = default; - - QualitativeMdpResult(storm::dd::Bdd const& states) : states(states) { - // Intentionally left empty. - } - - virtual storm::dd::Bdd const& getStates() const override { - return states; - } - - storm::dd::Bdd states; - }; - - } -} - diff --git a/src/storm/abstraction/QualitativeMdpResultMinMax.h b/src/storm/abstraction/QualitativeMdpResultMinMax.h deleted file mode 100644 index 9f2a3c130..000000000 --- a/src/storm/abstraction/QualitativeMdpResultMinMax.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "storm/storage/dd/DdType.h" - -#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeMdpResult.h" - -namespace storm { - namespace abstraction { - - template - class QualitativeMdpResultMinMax : public SymbolicQualitativeResultMinMax { - public: - QualitativeMdpResultMinMax() = default; - - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob0Min; - } else { - return prob0Max; - } - } - - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob1Min; - } else { - return prob1Max; - } - } - - QualitativeMdpResult prob0Min; - QualitativeMdpResult prob1Min; - QualitativeMdpResult prob0Max; - QualitativeMdpResult prob1Max; - }; - - } -} - diff --git a/src/storm/abstraction/QualitativeResult.cpp b/src/storm/abstraction/QualitativeResult.cpp index 68a50d1e5..968b34894 100644 --- a/src/storm/abstraction/QualitativeResult.cpp +++ b/src/storm/abstraction/QualitativeResult.cpp @@ -1,3 +1,36 @@ #include "storm/abstraction/QualitativeResult.h" +#include "storm/abstraction/SymbolicQualitativeResult.h" +#include "storm/abstraction/ExplicitQualitativeResult.h" +namespace storm { + namespace abstraction { + + bool QualitativeResult::isSymbolic() const { + return false; + } + + bool QualitativeResult::isExplicit() const { + return false; + } + + template + SymbolicQualitativeResult& QualitativeResult::asSymbolicQualitativeResult() { + return static_cast&>(*this); + } + + template + SymbolicQualitativeResult const& QualitativeResult::asSymbolicQualitativeResult() const { + return static_cast const&>(*this); + } + + ExplicitQualitativeResult& QualitativeResult::asExplicitQualitativeResult() { + return static_cast(*this); + } + + ExplicitQualitativeResult const& QualitativeResult::asExplicitQualitativeResult() const { + return static_cast(*this); + } + + } +} diff --git a/src/storm/abstraction/QualitativeResult.h b/src/storm/abstraction/QualitativeResult.h index 0d027b3a7..c7eafdc01 100644 --- a/src/storm/abstraction/QualitativeResult.h +++ b/src/storm/abstraction/QualitativeResult.h @@ -3,22 +3,29 @@ #include "storm/storage/dd/DdType.h" namespace storm { - namespace dd { - template - class Bdd; - } - namespace abstraction { - template + template + class SymbolicQualitativeResult; + + class ExplicitQualitativeResult; + class QualitativeResult { public: virtual ~QualitativeResult() = default; + + virtual bool isSymbolic() const; + virtual bool isExplicit() const; + + template + SymbolicQualitativeResult& asSymbolicQualitativeResult(); + template + SymbolicQualitativeResult const& asSymbolicQualitativeResult() const; + + ExplicitQualitativeResult& asExplicitQualitativeResult(); + ExplicitQualitativeResult const& asExplicitQualitativeResult() const; - virtual storm::dd::Bdd const& getStates() const = 0; }; } } - - diff --git a/src/storm/abstraction/QualitativeResultMinMax.cpp b/src/storm/abstraction/QualitativeResultMinMax.cpp index 95465172c..28eee28b1 100644 --- a/src/storm/abstraction/QualitativeResultMinMax.cpp +++ b/src/storm/abstraction/QualitativeResultMinMax.cpp @@ -8,7 +8,11 @@ namespace storm { bool QualitativeResultMinMax::isSymbolic() const { return false; } - + + bool QualitativeResultMinMax::isExplicit() const { + return false; + } + template SymbolicQualitativeResultMinMax const& QualitativeResultMinMax::asSymbolicQualitativeResultMinMax() const { return static_cast const&>(*this); diff --git a/src/storm/abstraction/QualitativeResultMinMax.h b/src/storm/abstraction/QualitativeResultMinMax.h index b6aa96382..3f789eca7 100644 --- a/src/storm/abstraction/QualitativeResultMinMax.h +++ b/src/storm/abstraction/QualitativeResultMinMax.h @@ -13,7 +13,8 @@ namespace storm { virtual ~QualitativeResultMinMax() = default; virtual bool isSymbolic() const; - + virtual bool isExplicit() const; + template SymbolicQualitativeResultMinMax const& asSymbolicQualitativeResultMinMax() const; diff --git a/src/storm/abstraction/QuantitativeGameResult.h b/src/storm/abstraction/QuantitativeGameResult.h deleted file mode 100644 index 2d76a8618..000000000 --- a/src/storm/abstraction/QuantitativeGameResult.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "storm/storage/dd/DdType.h" -#include "storm/storage/dd/Add.h" -#include "storm/storage/dd/Bdd.h" - -namespace storm { - namespace abstraction { - - template - struct QuantitativeGameResult { - QuantitativeGameResult() = default; - - QuantitativeGameResult(storm::dd::Add const& values) : values(values) { - // Intentionally left empty. - } - - QuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy) : initialStatesRange(initialStatesRange), values(values), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { - // Intentionally left empty. - } - - bool hasPlayer1Strategy() const { - return static_cast(player1Strategy); - } - - storm::dd::Bdd const& getPlayer1Strategy() const { - return player1Strategy.get(); - } - - storm::dd::Bdd& getPlayer1Strategy() { - return player1Strategy.get(); - } - - bool hasPlayer2Strategy() const { - return static_cast(player2Strategy); - } - - storm::dd::Bdd const& getPlayer2Strategy() const { - return player2Strategy.get(); - } - - storm::dd::Bdd& getPlayer2Strategy() { - return player2Strategy.get(); - } - - bool hasInitialStatesRange() const { - return static_cast(initialStatesRange); - } - - std::pair const& getInitialStatesRange() const { - return initialStatesRange.get(); - } - - boost::optional> initialStatesRange; - storm::dd::Add values; - boost::optional> player1Strategy; - boost::optional> player2Strategy; - }; - - } -} diff --git a/src/storm/abstraction/QuantitativeGameResultMinMax.h b/src/storm/abstraction/QuantitativeGameResultMinMax.h deleted file mode 100644 index c88c014f3..000000000 --- a/src/storm/abstraction/QuantitativeGameResultMinMax.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "storm/abstraction/QuantitativeGameResult.h" - -namespace storm { - namespace abstraction { - - template - class QuantitativeGameResultMinMax { - public: - QuantitativeGameResultMinMax() = default; - - QuantitativeGameResultMinMax(QuantitativeGameResult const& min, QuantitativeGameResult const& max) : min(min), max(max) { - // Intentionally left empty. - } - - QuantitativeGameResult min; - QuantitativeGameResult max; - }; - - } -} diff --git a/src/storm/abstraction/SymbolicQualitativeGameResult.cpp b/src/storm/abstraction/SymbolicQualitativeGameResult.cpp new file mode 100644 index 000000000..0dfae3145 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResult.cpp @@ -0,0 +1,19 @@ +#include "storm/abstraction/SymbolicQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeGameResult::SymbolicQualitativeGameResult(storm::utility::graph::SymbolicGameProb01Result const& prob01Result) : storm::utility::graph::SymbolicGameProb01Result(prob01Result) { + // Intentionally left empty. + } + + template + storm::dd::Bdd const& SymbolicQualitativeGameResult::getStates() const { + return this->getPlayer1States(); + } + + template class SymbolicQualitativeGameResult; + template class SymbolicQualitativeGameResult; + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeGameResult.h b/src/storm/abstraction/SymbolicQualitativeGameResult.h new file mode 100644 index 000000000..2daea6ae6 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResult.h @@ -0,0 +1,19 @@ +#pragma once + +#include "storm/utility/graph.h" +#include "storm/abstraction/SymbolicQualitativeResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeGameResult : public storm::utility::graph::SymbolicGameProb01Result, public SymbolicQualitativeResult { + SymbolicQualitativeGameResult() = default; + + SymbolicQualitativeGameResult(storm::utility::graph::SymbolicGameProb01Result const& prob01Result); + + virtual storm::dd::Bdd const& getStates() const override; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp new file mode 100644 index 000000000..5a9d34ab5 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp @@ -0,0 +1,29 @@ +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeResult const& SymbolicQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + template + SymbolicQualitativeResult const& SymbolicQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + template class SymbolicQualitativeResultMinMax; + template class SymbolicQualitativeResultMinMax; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h new file mode 100644 index 000000000..beeadd0b0 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h @@ -0,0 +1,25 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeGameResultMinMax : public SymbolicQualitativeResultMinMax { + public: + SymbolicQualitativeGameResultMinMax() = default; + + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override; + + SymbolicQualitativeResult prob0Min; + SymbolicQualitativeResult prob1Min; + SymbolicQualitativeResult prob0Max; + SymbolicQualitativeResult prob1Max; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp b/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp new file mode 100644 index 000000000..418047333 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp @@ -0,0 +1,20 @@ +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeMdpResult::SymbolicQualitativeMdpResult(storm::dd::Bdd const& states) : states(states) { + // Intentionally left empty. + } + + template + storm::dd::Bdd const& SymbolicQualitativeMdpResult::getStates() const { + return states; + } + + template class SymbolicQualitativeMdpResult; + template class SymbolicQualitativeMdpResult; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResult.h b/src/storm/abstraction/SymbolicQualitativeMdpResult.h new file mode 100644 index 000000000..ee44a942e --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResult.h @@ -0,0 +1,23 @@ +#pragma once + +#include "storm/abstraction/SymbolicQualitativeResult.h" + +#include "storm/storage/dd/Bdd.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeMdpResult : public SymbolicQualitativeResult { + SymbolicQualitativeMdpResult() = default; + + SymbolicQualitativeMdpResult(storm::dd::Bdd const& states); + + virtual storm::dd::Bdd const& getStates() const override; + + storm::dd::Bdd states; + }; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp new file mode 100644 index 000000000..87b6f504f --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp @@ -0,0 +1,29 @@ +#include "storm/abstraction/SymbolicQualitativeMdpResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeResult const& SymbolicQualitativeMdpResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + template + SymbolicQualitativeResult const& SymbolicQualitativeMdpResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + template class SymbolicQualitativeMdpResultMinMax; + template class SymbolicQualitativeMdpResultMinMax; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h new file mode 100644 index 000000000..554e0bd3d --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h @@ -0,0 +1,27 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeMdpResultMinMax : public SymbolicQualitativeResultMinMax { + public: + SymbolicQualitativeMdpResultMinMax() = default; + + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override; + + SymbolicQualitativeMdpResult prob0Min; + SymbolicQualitativeMdpResult prob1Min; + SymbolicQualitativeMdpResult prob0Max; + SymbolicQualitativeMdpResult prob1Max; + }; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeResult.h b/src/storm/abstraction/SymbolicQualitativeResult.h new file mode 100644 index 000000000..7703a1033 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeResult.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/QualitativeResult.h" + +namespace storm { + namespace dd { + template + class Bdd; + } + + namespace abstraction { + + template + class SymbolicQualitativeResult : public QualitativeResult { + public: + virtual ~SymbolicQualitativeResult() = default; + + virtual storm::dd::Bdd const& getStates() const = 0; + }; + + } +} + + diff --git a/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp index 772ee645d..51dff167a 100644 --- a/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp +++ b/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp @@ -11,22 +11,22 @@ namespace storm { } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Min() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Min() const { return getProb0(storm::OptimizationDirection::Minimize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Min() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Min() const { return getProb1(storm::OptimizationDirection::Minimize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Max() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Max() const { return getProb0(storm::OptimizationDirection::Maximize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Max() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Max() const { return getProb1(storm::OptimizationDirection::Maximize); } diff --git a/src/storm/abstraction/SymbolicQualitativeResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeResultMinMax.h index 8b9be7e23..fe4d21bf2 100644 --- a/src/storm/abstraction/SymbolicQualitativeResultMinMax.h +++ b/src/storm/abstraction/SymbolicQualitativeResultMinMax.h @@ -14,7 +14,7 @@ namespace storm { namespace abstraction { template - class QualitativeResult; + class SymbolicQualitativeResult; template class SymbolicQualitativeResultMinMax : public QualitativeResultMinMax { @@ -23,13 +23,13 @@ namespace storm { virtual bool isSymbolic() const override; - QualitativeResult const& getProb0Min() const; - QualitativeResult const& getProb1Min() const; - QualitativeResult const& getProb0Max() const; - QualitativeResult const& getProb1Max() const; + SymbolicQualitativeResult const& getProb0Min() const; + SymbolicQualitativeResult const& getProb1Min() const; + SymbolicQualitativeResult const& getProb0Max() const; + SymbolicQualitativeResult const& getProb1Max() const; - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; }; } } diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp new file mode 100644 index 000000000..9c91b1b97 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp @@ -0,0 +1,61 @@ +#include "storm/abstraction/SymbolicQuantitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQuantitativeGameResult::SymbolicQuantitativeGameResult(storm::dd::Add const& values) : values(values) { + // Intentionally left empty. + } + + template + SymbolicQuantitativeGameResult::SymbolicQuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy) : initialStatesRange(initialStatesRange), values(values), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { + // Intentionally left empty. + } + + template + bool SymbolicQuantitativeGameResult::hasPlayer1Strategy() const { + return static_cast(player1Strategy); + } + + template + storm::dd::Bdd const& SymbolicQuantitativeGameResult::getPlayer1Strategy() const { + return player1Strategy.get(); + } + + template + storm::dd::Bdd& SymbolicQuantitativeGameResult::getPlayer1Strategy() { + return player1Strategy.get(); + } + + template + bool SymbolicQuantitativeGameResult::hasPlayer2Strategy() const { + return static_cast(player2Strategy); + } + + template + storm::dd::Bdd const& SymbolicQuantitativeGameResult::getPlayer2Strategy() const { + return player2Strategy.get(); + } + + template + storm::dd::Bdd& SymbolicQuantitativeGameResult::getPlayer2Strategy() { + return player2Strategy.get(); + } + + template + bool SymbolicQuantitativeGameResult::hasInitialStatesRange() const { + return static_cast(initialStatesRange); + } + + template + std::pair const& SymbolicQuantitativeGameResult::getInitialStatesRange() const { + return initialStatesRange.get(); + } + + template class SymbolicQuantitativeGameResult; + template class SymbolicQuantitativeGameResult; + + } +} + diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResult.h b/src/storm/abstraction/SymbolicQuantitativeGameResult.h new file mode 100644 index 000000000..b9dc7eaa2 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResult.h @@ -0,0 +1,41 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" +#include "storm/storage/dd/Add.h" +#include "storm/storage/dd/Bdd.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQuantitativeGameResult { + public: + SymbolicQuantitativeGameResult() = default; + + SymbolicQuantitativeGameResult(storm::dd::Add const& values); + SymbolicQuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy); + + bool hasPlayer1Strategy() const; + + storm::dd::Bdd const& getPlayer1Strategy() const; + + storm::dd::Bdd& getPlayer1Strategy(); + + bool hasPlayer2Strategy() const; + + storm::dd::Bdd const& getPlayer2Strategy() const; + + storm::dd::Bdd& getPlayer2Strategy(); + + bool hasInitialStatesRange() const; + + std::pair const& getInitialStatesRange() const; + + boost::optional> initialStatesRange; + storm::dd::Add values; + boost::optional> player1Strategy; + boost::optional> player2Strategy; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp new file mode 100644 index 000000000..08be6fad6 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp @@ -0,0 +1,12 @@ +#include "storm/abstraction/SymbolicQuantitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQuantitativeGameResultMinMax::SymbolicQuantitativeGameResultMinMax(SymbolicQuantitativeGameResult const& min, SymbolicQuantitativeGameResult const& max) : min(min), max(max) { + // Intentionally left empty. + } + + } +} diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h new file mode 100644 index 000000000..32ec71ce3 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h @@ -0,0 +1,20 @@ +#pragma once + +#include "storm/abstraction/SymbolicQuantitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQuantitativeGameResultMinMax { + public: + SymbolicQuantitativeGameResultMinMax() = default; + + SymbolicQuantitativeGameResultMinMax(SymbolicQuantitativeGameResult const& min, SymbolicQuantitativeGameResult const& max); + + SymbolicQuantitativeGameResult min; + SymbolicQuantitativeGameResult max; + }; + + } +} diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index ac3250f19..6ba963c63 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -367,8 +367,7 @@ namespace storm { auto abstractionEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " (player 1) states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); - // (2) Prepare transition matrix BDD and target state BDD for later use. - storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); + // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); STORM_LOG_THROW(initialStates.getNonZeroCount() == 1 || checkTask.isBoundSet(), storm::exceptions::InvalidPropertyException, "Game-based abstraction refinement requires a bound on the formula for model with " << initialStates.getNonZeroCount() << " initial states."); storm::dd::Bdd constraintStates = globalConstraintStates && game.getReachableStates(); @@ -383,117 +382,18 @@ namespace storm { // game.getReachableStates().template toAdd().exportToDot("reach.dot"); // #endif - // (3) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). - auto qualitativeStart = std::chrono::high_resolution_clock::now(); - QualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); - std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + std::unique_ptr result; + if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { + result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousQualitativeResult, previousMinQuantitativeResult); + } else { + result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner); + } + if (result) { printStatistics(*abstractor, game); return result; } - previousQualitativeResult = qualitativeResult; - auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); - // (4) compute the states for which we have to determine quantitative information. - storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); - storm::dd::Bdd maybeMax = !(qualitativeResult.prob0Max.getPlayer1States() || qualitativeResult.prob1Max.getPlayer1States()) && game.getReachableStates(); - - // (5) if the initial states are not maybe states, then we can refine at this point. - storm::dd::Bdd initialMaybeStates = (initialStates && maybeMin) || (initialStates && maybeMax); - bool qualitativeRefinement = false; - if (initialMaybeStates.isZero()) { - // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. - STORM_LOG_TRACE("No initial state is a 'maybe' state."); - - STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); - - // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) - // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. - auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); - qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); - auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); - } else if (initialMaybeStates == initialStates && checkTask.isQualitativeSet()) { - // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, - // we can return the result here. - return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); - } - - // (6) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. - if (!qualitativeRefinement) { - // At this point, we know that we cannot answer the query without further numeric computation. - STORM_LOG_TRACE("Starting numerical solution step."); - - // Solve abstraction using the selected mode. - if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { - STORM_LOG_TRACE("Using dd-based solving."); - storm::dd::Add initialStatesAdd = initialStates.template toAdd(); - - auto quantitativeStart = std::chrono::high_resolution_clock::now(); - - QuantitativeGameResultMinMax quantitativeResult; - - // (7) Solve the min values and check whether we can give the answer already. - quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); - previousMinQuantitativeResult = quantitativeResult.min; - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; - } - - // (8) Solve the max values and check whether we can give the answer already. - quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; - } - - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); - - // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. - result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); - if (result) { - printStatistics(*abstractor, game); - return result; - } - - // Make sure that all strategies are still valid strategies. - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); - - auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); - // (10) If we arrived at this point, it means that we have all qualitative and quantitative - // information about the game, but we could not yet answer the query. In this case, we need to refine. - refiner.refine(game, transitionMatrixBdd, quantitativeResult); - auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); - } else { - STORM_LOG_TRACE("Using hybrid solving."); - - auto relevantStates = maybeMin || maybeMax || targetStates; - auto relevantStatesAdd = relevantStates.template toAdd(); - storm::dd::Odd odd = relevantStates.createOdd(); - - auto relevantStatesTransitionMatrix = game.getTransitionMatrix() * relevantStatesAdd * relevantStatesAdd.swapVariables(game.getRowColumnMetaVariablePairs()); - std::pair, std::vector> transitionMatrixLabeling = relevantStatesTransitionMatrix.toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), game.getPlayer1Variables(), odd, odd, true); - auto const& transitionMatrix = transitionMatrixLabeling.first; - auto const& labeling = transitionMatrixLabeling.second; - - std::cout << transitionMatrix << std::endl; - for (auto const& e : labeling) { - std::cout << e << std::endl; - } - - exit(-1); - } - - } auto iterationEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); } @@ -502,6 +402,141 @@ namespace storm { return nullptr; } + template + std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { + + STORM_LOG_TRACE("Using dd-based solving."); + + // Prepare transition matrix BDD. + storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); + + // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). + auto qualitativeStart = std::chrono::high_resolution_clock::now(); + QualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + if (result) { + return result; + } + previousQualitativeResult = qualitativeResult; + auto qualitativeEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); + + // (2) compute the states for which we have to determine quantitative information. + storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); + storm::dd::Bdd maybeMax = !(qualitativeResult.prob0Max.getPlayer1States() || qualitativeResult.prob1Max.getPlayer1States()) && game.getReachableStates(); + + // (3) if the initial states are not maybe states, then we can refine at this point. + storm::dd::Bdd initialMaybeStates = (initialStates && maybeMin) || (initialStates && maybeMax); + bool qualitativeRefinement = false; + if (initialMaybeStates.isZero()) { + // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. + STORM_LOG_TRACE("No initial state is a 'maybe' state."); + + STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + + // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) + // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. + auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); + qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); + auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + } else if (initialMaybeStates == initialStates && checkTask.isQualitativeSet()) { + // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, + // we can return the result here. + return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); + } + + // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. + if (!qualitativeRefinement) { + // At this point, we know that we cannot answer the query without further numeric computation. + STORM_LOG_TRACE("Starting numerical solution step."); + + STORM_LOG_TRACE("Using dd-based solving."); + storm::dd::Add initialStatesAdd = initialStates.template toAdd(); + + auto quantitativeStart = std::chrono::high_resolution_clock::now(); + + QuantitativeGameResultMinMax quantitativeResult; + + // (7) Solve the min values and check whether we can give the answer already. + quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); + previousMinQuantitativeResult = quantitativeResult.min; + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); + if (result) { + return result; + } + + // (8) Solve the max values and check whether we can give the answer already. + quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); + if (result) { + return result; + } + + auto quantitativeEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. + result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); + if (result) { + return result; + } + + // Make sure that all strategies are still valid strategies. + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); + + auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); + + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. + refiner.refine(game, transitionMatrixBdd, quantitativeResult); + auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + } + + // Return null to indicate no result has been found yet. + return nullptr; + } + + template + std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner) { + STORM_LOG_TRACE("Using hybrid solving."); + + // (0) Start by transforming the necessary symbolic elements to explicit ones. + storm::dd::Odd odd = game.getReachableStates().createOdd(); + + std::pair, std::vector> transitionMatrixAndLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), game.getPlayer1Variables(), odd, odd, true); + auto const& transitionMatrix = transitionMatrixAndLabeling.first; + auto const& labeling = transitionMatrixAndLabeling.second; + + storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); + storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); + storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); + + // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). + auto qualitativeStart = std::chrono::high_resolution_clock::now(); + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(game, player1Direction, transitionMatrix, constraintStates, targetStates); + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + if (result) { + return result; + } + auto qualitativeEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); + + + + std::cout << transitionMatrix << std::endl; + std::cout << labeling.size() << std::endl; + std::cout << initialStates << std::endl; + std::cout << constraintStates << std::endl; + std::cout << targetStates << std::endl; + + exit(-1); + } + template std::vector GameBasedMdpModelChecker::getInitialPredicates(storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { std::vector initialPredicates; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index dd6c7cb2f..8556edc71 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -27,6 +27,15 @@ namespace storm { template class MenuGameAbstractor; + + template + class MenuGameRefiner; + + template + class QualitativeGameResultMinMax; + + template + struct QuantitativeGameResult; } namespace modelchecker { @@ -59,6 +68,9 @@ namespace storm { */ std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); + std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); + std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner); + /*! * Retrieves the initial predicates for the abstraction. */ diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 947b7b7ca..455cb7da8 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -44,7 +44,7 @@ namespace storm { .setDefaultValueString("all").build()) .build()); - std::vector solveModes = {"dd", "hybrid"}; + std::vector solveModes = {"dd", "sparse"}; this->addOption(storm::settings::OptionBuilder(moduleName, solveModeOptionName, true, "Sets how the abstractions are solved.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(solveModes)) .setDefaultValueString("dd").build()) @@ -110,7 +110,7 @@ namespace storm { if (solveModeAsString == "dd") { return SolveMode::Dd; } - return SolveMode::Hybrid; + return SolveMode::Sparse; } bool AbstractionSettings::isAddAllGuardsSet() const { diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 2b361b273..f8b2e5c93 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -28,7 +28,7 @@ namespace storm { }; enum class SolveMode { - Dd, Hybrid + Dd, Sparse }; /*! diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 80b707639..75552108e 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -810,13 +810,11 @@ namespace storm { } statesWithGroupEnabled[i] = groupNotZero.existsAbstract(columnMetaVariables).template toAdd(); - statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus()); - if (buildLabeling) { uint64_t currentLabel = groupLabels[i]; - std::cout << "current label is " << currentLabel << std::endl; - // statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, labeling, [currentLabel] (uint_fast64_t a, uint_fast64_t l) { return currentLabel; }); + statesWithGroupEnabled[i].forEach(rowOdd, ddRowVariableIndices, [currentLabel, &rowGroupIndices, &labeling] (uint64_t const& offset, uint_fast64_t const& value) { labeling[rowGroupIndices[offset]] = currentLabel; }); } + statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus()); } // Since we modified the rowGroupIndices, we need to restore the correct values. diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp index 6e5a57e4a..9ed21a92a 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp @@ -494,16 +494,24 @@ namespace storm { template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(this->getCuddDdNode(), nullptr, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector] (uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); }); + } + + template + void InternalAdd::forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function); } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(this->getCuddDdNode(), &offsets, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector, &offsets] (uint64_t const& offset, ValueType const& value) { + ValueType& targetValue = targetVector[offsets[offset]]; + targetValue = function(targetValue, value); + }); } template - void InternalAdd::composeWithExplicitVectorRec(DdNode const* dd, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { + void InternalAdd::forEachRec(DdNode const* dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { // For the empty DD, we do not need to add any entries. if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { return; @@ -511,24 +519,22 @@ namespace storm { // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentLevel == maxLevel) { - ValueType& targetValue = targetVector[offsets != nullptr ? (*offsets)[currentOffset] : currentOffset]; - targetValue = function(targetValue, storm::utility::convertNumber(Cudd_V(dd))); + function(currentOffset, storm::utility::convertNumber(Cudd_V(dd))); } else if (ddVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set // and for the one in which it is not set. - composeWithExplicitVectorRec(dd, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(dd, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } else { // Otherwise, we simply recursively call the function for both (different) cases. - composeWithExplicitVectorRec(Cudd_E_const(dd), offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(Cudd_T_const(dd), offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(Cudd_E_const(dd), currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(Cudd_T_const(dd), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } } template std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { std::vector result; - std::cout << ddLabelVariableIndices << std::endl; decodeGroupLabelsRec(this->getCuddDdNode(), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); return result; } @@ -546,7 +552,6 @@ namespace storm { uint64_t elseLabel = label; uint64_t thenLabel = label; - std::cout << "currentLevel " << currentLevel << " is in labels? " << ddLabelVariableIndices.get(currentLevel) << std::endl; if (ddLabelVariableIndices.get(currentLevel)) { elseLabel <<= 1; thenLabel = (thenLabel << 1) | 1; diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.h b/src/storm/storage/dd/cudd/InternalCuddAdd.h index cab873353..e5af927e8 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.h @@ -549,6 +549,18 @@ namespace storm { */ void composeWithExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + /*! + * Composes the ADD with an explicit vector by performing a specified function between the entries of this + * ADD and the explicit vector. + * + * @param odd The ODD to use for the translation from symbolic to explicit positions. + * @param ddVariableIndices The indices of the DD variables present in this ADD. + * @param targetVector The explicit vector that is to be composed with the ADD. The results are written to + * this vector again. + * @param function The function to perform in the composition. + */ + void forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; + /*! * Composes the (row-grouped) ADD with an explicit vector by performing a specified function between the * entries of this ADD and the explicit vector. @@ -646,18 +658,18 @@ namespace storm { private: /*! - * Performs a recursive step to perform the given function between the given DD-based vector and the given - * explicit vector. + * Performs a recursive step for forEach. * - * @param dd The DD to add to the explicit vector. + * @param dd The DD to traverse. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param currentOffset The current offset. * @param odd The ODD used for the translation. * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param targetVector The vector to which the translated DD-based vector is to be added. + * @param function The callback invoked for every element. The first argument is the offset and the second + * is the value. */ - void composeWithExplicitVectorRec(DdNode const* dd, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + void forEachRec(DdNode const* dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; /*! * Splits the given matrix DD into the groups using the given group variables. diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp index 96dcbcc75..fc0829f22 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp @@ -884,16 +884,24 @@ namespace storm { template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), nullptr, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector] (uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); }); } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), &offsets, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector, &offsets] (uint64_t const& offset, ValueType const& value) { + ValueType& targetValue = targetVector[offsets[offset]]; + targetValue = function(targetValue, value); + }); } template - void InternalAdd::composeWithExplicitVectorRec(MTBDD dd, bool negated, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { + void InternalAdd::forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function); + } + + template + void InternalAdd::forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { // For the empty DD, we do not need to add any entries. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; @@ -901,24 +909,19 @@ namespace storm { // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentLevel == maxLevel) { - ValueType& targetValue = targetVector[offsets != nullptr ? (*offsets)[currentOffset] : currentOffset]; - targetValue = function(targetValue, getValue(dd)); + function(currentOffset, getValue(dd)); } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) { // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set // and for the one in which it is not set. - composeWithExplicitVectorRec(dd, negated, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(dd, negated, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } else { // Otherwise, we simply recursively call the function for both (different) cases. MTBDD thenNode = mtbdd_gethigh(dd); MTBDD elseNode = mtbdd_getlow(dd); - // Determine whether we have to evaluate the successors as if they were complemented. - bool elseComplemented = mtbdd_hascomp(elseNode) ^ negated; - bool thenComplemented = mtbdd_hascomp(thenNode) ^ negated; - - composeWithExplicitVectorRec(mtbdd_regular(elseNode), elseComplemented, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(mtbdd_regular(thenNode), thenComplemented, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(elseNode, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(thenNode, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } } diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h index 449ba0bbc..ccdc61414 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h @@ -553,6 +553,18 @@ namespace storm { */ void composeWithExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const; + /*! + * Composes the ADD with an explicit vector by performing a specified function between the entries of this + * ADD and the explicit vector. + * + * @param odd The ODD to use for the translation from symbolic to explicit positions. + * @param ddVariableIndices The indices of the DD variables present in this ADD. + * @param targetVector The explicit vector that is to be composed with the ADD. The results are written to + * this vector again. + * @param function The function to perform in the composition. + */ + void forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; + /*! * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). * @@ -647,19 +659,18 @@ namespace storm { static std::shared_ptr createOddRec(BDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector const& ddVariableIndices, std::vector>>& uniqueTableForLevels); /*! - * Performs a recursive step to perform the given function between the given DD-based vector and the given - * explicit vector. + * Performs a recursive step for forEach. * - * @param dd The DD to add to the explicit vector. - * @param negated A flag indicating whether the DD node is to be interpreted as being negated. + * @param dd The DD to traverse. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param currentOffset The current offset. * @param odd The ODD used for the translation. * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param targetVector The vector to which the translated DD-based vector is to be added. + * @param function The callback invoked for every element. The first argument is the offset and the second + * is the value. */ - void composeWithExplicitVectorRec(MTBDD dd, bool negated, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + void forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; /*! * Splits the given matrix DD into the labelings of the gropus using the given group variables. diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 5bb8cc758..c720483fc 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1084,7 +1084,7 @@ namespace storm { } template - GameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { + SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { // The solution sets. storm::dd::Bdd player1States = psiStates; @@ -1147,11 +1147,11 @@ namespace storm { player1StrategyBdd = onlyProb0Successors.existsAbstractRepresentative(model.getPlayer1Variables()); } - return GameProb01Result(player1States, player2States, player1StrategyBdd, player2StrategyBdd); + return SymbolicGameProb01Result(player1States, player2States, player1StrategyBdd, player2StrategyBdd); } template - GameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates) { + SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates) { // Create the potential prob1 states of player 1. storm::dd::Bdd maybePlayer1States = model.getReachableStates(); @@ -1284,7 +1284,7 @@ namespace storm { } } - return GameProb01Result(maybePlayer1States, maybePlayer2States, player1StrategyBdd, player2StrategyBdd); + return SymbolicGameProb01Result(maybePlayer1States, maybePlayer2States, player1StrategyBdd, player2StrategyBdd); } template @@ -1568,9 +1568,9 @@ namespace storm { template std::pair, storm::dd::Bdd> performProb01Min(storm::models::symbolic::NondeterministicModel const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates); - template GameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); + template SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); - template GameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); + template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); // Instantiations for Sylvan (double). @@ -1608,9 +1608,9 @@ namespace storm { template std::pair, storm::dd::Bdd> performProb01Min(storm::models::symbolic::NondeterministicModel const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates); - template GameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); + template SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); - template GameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); + template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); // Instantiations for Sylvan (rational number). diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index 79103700b..cff5887fc 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -10,7 +10,9 @@ #include "storm/storage/Scheduler.h" #include "storm/models/sparse/NondeterministicModel.h" #include "storm/models/sparse/DeterministicModel.h" + #include "storm/storage/dd/DdType.h" +#include "storm/storage/dd/Bdd.h" #include "storm/solver/OptimizationDirection.h" @@ -542,9 +544,9 @@ namespace storm { std::pair, storm::dd::Bdd> performProb01Min(storm::models::symbolic::NondeterministicModel const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates); template - struct GameProb01Result { - GameProb01Result() = default; - GameProb01Result(storm::dd::Bdd const& player1States, storm::dd::Bdd const& player2States, boost::optional> const& player1Strategy = boost::none, boost::optional> const& player2Strategy = boost::none) : player1States(player1States), player2States(player2States), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { + struct SymbolicGameProb01Result { + SymbolicGameProb01Result() = default; + SymbolicGameProb01Result(storm::dd::Bdd const& player1States, storm::dd::Bdd const& player2States, boost::optional> const& player1Strategy = boost::none, boost::optional> const& player2Strategy = boost::none) : player1States(player1States), player2States(player2States), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { // Intentionally left empty. } @@ -597,7 +599,7 @@ namespace storm { * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. */ template - GameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); + SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); /*! * Computes the set of states that have probability 1 given the strategies of the two players. @@ -611,7 +613,7 @@ namespace storm { * @param player1Candidates If given, this set constrains the candidates of player 1 states that are considered. */ template - GameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional> const& player1Candidates = boost::none); + SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional> const& player1Candidates = boost::none); /*! * Performs a topological sort of the states of the system according to the given transitions. diff --git a/src/test/storm/utility/GraphTest.cpp b/src/test/storm/utility/GraphTest.cpp index ac646d99a..b3a7c6ef4 100644 --- a/src/test/storm/utility/GraphTest.cpp +++ b/src/test/storm/utility/GraphTest.cpp @@ -227,7 +227,7 @@ TEST(GraphTest, SymbolicProb01StochasticGameDieSmall) { // The target states are those states where !(s < 3). storm::dd::Bdd targetStates = !abstractor.getStates(initialPredicates[0]) && game.getReachableStates(); - storm::utility::graph::GameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); + storm::utility::graph::SymbolicGameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); EXPECT_EQ(0ull, result.getPlayer1States().getNonZeroCount()); EXPECT_TRUE(result.hasPlayer1Strategy()); EXPECT_TRUE(result.hasPlayer2Strategy()); @@ -366,7 +366,7 @@ TEST(GraphTest, SymbolicProb01StochasticGameTwoDice) { // The target states are those states where s1 == 7 & s2 == 7 & d1 + d2 == 2. storm::dd::Bdd targetStates = abstractor.getStates(initialPredicates[7]) && abstractor.getStates(initialPredicates[22]) && abstractor.getStates(initialPredicates[9]) && abstractor.getStates(initialPredicates[24]) && game.getReachableStates(); - storm::utility::graph::GameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); + storm::utility::graph::SymbolicGameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); EXPECT_EQ(153ull, result.getPlayer1States().getNonZeroCount()); ASSERT_TRUE(result.hasPlayer1Strategy()); ASSERT_TRUE(result.hasPlayer2Strategy()); @@ -538,7 +538,7 @@ TEST(GraphTest, SymbolicProb01StochasticGameWlan) { // The target states are those states where col == 2. storm::dd::Bdd targetStates = abstractor.getStates(initialPredicates[2]) && game.getReachableStates(); - storm::utility::graph::GameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); + storm::utility::graph::SymbolicGameProb01Result result = storm::utility::graph::performProb0(game, game.getQualitativeTransitionMatrix(), game.getReachableStates(), targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize, true, true); EXPECT_EQ(2831ull, result.getPlayer1States().getNonZeroCount()); EXPECT_TRUE(result.hasPlayer1Strategy()); EXPECT_TRUE(result.hasPlayer2Strategy()); From 9665f4fa307f0ea79b9ab7c470784e4ee00bc70d Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 25 Mar 2018 20:55:43 +0200 Subject: [PATCH 203/647] sparse qualitative solving of menu games --- .../ExplicitQualitativeGameResult.cpp | 16 ++ .../ExplicitQualitativeGameResult.h | 20 ++ .../ExplicitQualitativeGameResultMinMax.cpp | 25 ++ .../ExplicitQualitativeGameResultMinMax.h | 33 +-- src/storm/abstraction/MenuGameRefiner.cpp | 8 +- src/storm/abstraction/MenuGameRefiner.h | 8 +- .../SymbolicQualitativeGameResult.h | 1 + .../SymbolicQualitativeGameResultMinMax.cpp | 4 +- .../SymbolicQualitativeGameResultMinMax.h | 9 +- .../SymbolicQualitativeMdpResult.h | 1 + ...tractAbstractionRefinementModelChecker.cpp | 48 ++-- ...bstractAbstractionRefinementModelChecker.h | 6 +- .../abstraction/GameBasedMdpModelChecker.cpp | 176 +++++++++--- .../abstraction/GameBasedMdpModelChecker.h | 28 +- .../settings/modules/AbstractionSettings.cpp | 7 + .../settings/modules/AbstractionSettings.h | 8 + src/storm/storage/SparseMatrix.cpp | 10 + src/storm/storage/SparseMatrix.h | 6 + src/storm/utility/graph.cpp | 270 ++++++++++++++++++ src/storm/utility/graph.h | 79 +++++ 20 files changed, 649 insertions(+), 114 deletions(-) create mode 100644 src/storm/abstraction/ExplicitQualitativeGameResult.cpp create mode 100644 src/storm/abstraction/ExplicitQualitativeGameResult.h create mode 100644 src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp diff --git a/src/storm/abstraction/ExplicitQualitativeGameResult.cpp b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp new file mode 100644 index 000000000..8ff41f18a --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp @@ -0,0 +1,16 @@ +#include "storm/abstraction/ExplicitQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult::ExplicitQualitativeGameResult(storm::utility::graph::ExplicitGameProb01Result const& prob01Result) : storm::utility::graph::ExplicitGameProb01Result(prob01Result) { + // Intentionally left empty. + } + + + storm::storage::BitVector const& ExplicitQualitativeGameResult::getStates() const { + return this->getPlayer1States(); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeGameResult.h b/src/storm/abstraction/ExplicitQualitativeGameResult.h new file mode 100644 index 000000000..45b97964a --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResult.h @@ -0,0 +1,20 @@ +#pragma once + +#include "storm/utility/graph.h" +#include "storm/abstraction/ExplicitQualitativeResult.h" + +namespace storm { + namespace abstraction { + + class ExplicitQualitativeGameResult : public storm::utility::graph::ExplicitGameProb01Result, public ExplicitQualitativeResult { + public: + ExplicitQualitativeGameResult() = default; + + ExplicitQualitativeGameResult(storm::utility::graph::ExplicitGameProb01Result const& prob01Result); + + virtual storm::storage::BitVector const& getStates() const override; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp new file mode 100644 index 000000000..ef1538c50 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp @@ -0,0 +1,25 @@ +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult const& ExplicitQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + ExplicitQualitativeGameResult const& ExplicitQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + } +} + + diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h index 7764c3383..8551a3c47 100644 --- a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h @@ -1,37 +1,22 @@ #pragma once -#include "storm/storage/dd/DdType.h" - -#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeGameResult.h" +#include "storm/abstraction/ExplicitQualitativeResultMinMax.h" +#include "storm/abstraction/ExplicitQualitativeGameResult.h" namespace storm { namespace abstraction { - class ExplicitQualitativeGameResultMinMax : public QualitativeResultMinMax { + class ExplicitQualitativeGameResultMinMax : public ExplicitQualitativeResultMinMax { public: ExplicitQualitativeGameResultMinMax() = default; - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob0Min; - } else { - return prob0Max; - } - } - - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob1Min; - } else { - return prob1Max; - } - } + virtual ExplicitQualitativeGameResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual ExplicitQualitativeGameResult const& getProb1(storm::OptimizationDirection const& dir) const override; - QualitativeGameResult prob0Min; - QualitativeGameResult prob1Min; - QualitativeGameResult prob0Max; - QualitativeGameResult prob1Max; + ExplicitQualitativeGameResult prob0Min; + ExplicitQualitativeGameResult prob1Min; + ExplicitQualitativeGameResult prob0Max; + ExplicitQualitativeGameResult prob1Max; }; } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index cd3522ac0..d97973bd6 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -3,6 +3,8 @@ #include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/MenuGameAbstractor.h" +#include "storm/storage/BitVector.h" + #include "storm/storage/dd/DdManager.h" #include "storm/utility/dd.h" #include "storm/utility/solver.h" @@ -122,7 +124,7 @@ namespace storm { } template - PivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { + PivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { // Get easy access to strategies. storm::dd::Bdd minPlayer1Strategy; @@ -587,7 +589,7 @@ namespace storm { } template - bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QualitativeGameResultMinMax const& qualitativeResult) const { + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const { STORM_LOG_TRACE("Trying refinement after qualitative check."); // Get all relevant strategies. storm::dd::Bdd minPlayer1Strategy = qualitativeResult.prob0Min.getPlayer1Strategy(); @@ -675,7 +677,7 @@ namespace storm { } template - bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QuantitativeGameResultMinMax const& quantitativeResult) const { + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQuantitativeGameResultMinMax const& quantitativeResult) const { STORM_LOG_TRACE("Refining after quantitative check."); // Get all relevant strategies. storm::dd::Bdd minPlayer1Strategy = quantitativeResult.min.getPlayer1Strategy(); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index c0a4b8f8a..ed3589ac6 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -7,8 +7,8 @@ #include #include "storm/abstraction/RefinementCommand.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" -#include "storm/abstraction/QuantitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQuantitativeGameResultMinMax.h" #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/FullPredicateSplitter.h" @@ -85,14 +85,14 @@ namespace storm { * * @param True if predicates for refinement could be derived, false otherwise. */ - bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QualitativeGameResultMinMax const& qualitativeResult) const; + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const; /*! * Refines the abstractor based on the quantitative result by trying to derive suitable predicates. * * @param True if predicates for refinement could be derived, false otherwise. */ - bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QuantitativeGameResultMinMax const& quantitativeResult) const; + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQuantitativeGameResultMinMax const& quantitativeResult) const; /*! * Retrieves whether all guards were added. diff --git a/src/storm/abstraction/SymbolicQualitativeGameResult.h b/src/storm/abstraction/SymbolicQualitativeGameResult.h index 2daea6ae6..968e7d51d 100644 --- a/src/storm/abstraction/SymbolicQualitativeGameResult.h +++ b/src/storm/abstraction/SymbolicQualitativeGameResult.h @@ -8,6 +8,7 @@ namespace storm { template class SymbolicQualitativeGameResult : public storm::utility::graph::SymbolicGameProb01Result, public SymbolicQualitativeResult { + public: SymbolicQualitativeGameResult() = default; SymbolicQualitativeGameResult(storm::utility::graph::SymbolicGameProb01Result const& prob01Result); diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp index 5a9d34ab5..9768cab16 100644 --- a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp @@ -21,8 +21,8 @@ namespace storm { } } - template class SymbolicQualitativeResultMinMax; - template class SymbolicQualitativeResultMinMax; + template class SymbolicQualitativeGameResultMinMax; + template class SymbolicQualitativeGameResultMinMax; } } diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h index beeadd0b0..4f58660a9 100644 --- a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h @@ -3,6 +3,7 @@ #include "storm/storage/dd/DdType.h" #include "storm/abstraction/SymbolicQualitativeResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResult.h" namespace storm { namespace abstraction { @@ -15,10 +16,10 @@ namespace storm { virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override; virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override; - SymbolicQualitativeResult prob0Min; - SymbolicQualitativeResult prob1Min; - SymbolicQualitativeResult prob0Max; - SymbolicQualitativeResult prob1Max; + SymbolicQualitativeGameResult prob0Min; + SymbolicQualitativeGameResult prob1Min; + SymbolicQualitativeGameResult prob0Max; + SymbolicQualitativeGameResult prob1Max; }; } diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResult.h b/src/storm/abstraction/SymbolicQualitativeMdpResult.h index ee44a942e..ba854fff7 100644 --- a/src/storm/abstraction/SymbolicQualitativeMdpResult.h +++ b/src/storm/abstraction/SymbolicQualitativeMdpResult.h @@ -9,6 +9,7 @@ namespace storm { template class SymbolicQualitativeMdpResult : public SymbolicQualitativeResult { + public: SymbolicQualitativeMdpResult() = default; SymbolicQualitativeMdpResult(storm::dd::Bdd const& states); diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp index 1fdcf2907..e6cdf6ddd 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp @@ -25,9 +25,9 @@ #include "storm/abstraction/StateSet.h" #include "storm/abstraction/SymbolicStateSet.h" #include "storm/abstraction/QualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeMdpResult.h" -#include "storm/abstraction/QualitativeMdpResultMinMax.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" +#include "storm/abstraction/SymbolicQualitativeMdpResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/AbstractionSettings.h" @@ -470,18 +470,18 @@ namespace storm { template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for DTMC."); - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr> result = std::make_unique>(); auto start = std::chrono::high_resolution_clock::now(); bool isRewardFormula = checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward; storm::dd::Bdd transitionMatrixBdd = abstractModel.getTransitionMatrix().notZero(); if (isRewardFormula) { auto prob1 = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob1Min = result->prob1Max = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Min = result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob1); } else { auto prob01 = storm::utility::graph::performProb01(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = result->prob0Max = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Min = result->prob1Max = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Min = result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Min = result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); } auto end = std::chrono::high_resolution_clock::now(); @@ -494,7 +494,7 @@ namespace storm { template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for MDP."); - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr> result = std::make_unique>(); auto start = std::chrono::high_resolution_clock::now(); bool isRewardFormula = checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward; @@ -505,13 +505,13 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto states = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(states); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(states); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto states = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(states); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(states); if (!computedMin) { result->prob1Min = result->prob1Max; } @@ -523,18 +523,18 @@ namespace storm { bool computedMax = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto states = storm::utility::graph::performProb0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Max = storm::abstraction::QualitativeMdpResult(states); + result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(states); states = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(states); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(states); computedMax = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto states = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(states); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(states); states = storm::utility::graph::performProb0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = storm::abstraction::QualitativeMdpResult(states); + result->prob0Min = storm::abstraction::SymbolicQualitativeMdpResult(states); if (!computedMax) { result->prob0Max = result->prob0Min; @@ -550,13 +550,13 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto prob1 = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(prob1); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto prob1 = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob1); if (!computedMin) { result->prob1Min = result->prob1Max; } @@ -567,15 +567,15 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto prob01 = storm::utility::graph::performProb01Min(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Min = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Min = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto prob01 = storm::utility::graph::performProb01Max(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Max = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Max = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); if (!computedMin) { result->prob0Min = result->prob0Max; result->prob1Min = result->prob1Max; @@ -604,7 +604,7 @@ namespace storm { template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for S2PG."); - std::unique_ptr> result; + std::unique_ptr> result; // Obtain the player optimization directions. uint64_t abstractionPlayer = this->getAbstractionPlayer(); @@ -622,7 +622,7 @@ namespace storm { if (this->getReuseQualitativeResults()) { result = computeQualitativeResultReuse(abstractModel, transitionMatrixBdd, constraintStates, targetStates, abstractionPlayer, modelNondeterminismDirection, requiresSchedulers); } else { - result = std::make_unique>(); + result = std::make_unique>(); result->prob0Min = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, requiresSchedulers, requiresSchedulers); result->prob1Min = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, requiresSchedulers, requiresSchedulers); @@ -648,8 +648,8 @@ namespace storm { } template - std::unique_ptr::DdType>> AbstractAbstractionRefinementModelChecker::computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers) { - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr::DdType>> AbstractAbstractionRefinementModelChecker::computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers) { + std::unique_ptr> result = std::make_unique>(); // Depending on the model nondeterminism direction, we choose a different order of operations. if (modelNondeterminismDirection == storm::OptimizationDirection::Minimize) { diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h index 5fdabe05e..83a2d35a6 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h @@ -41,10 +41,10 @@ namespace storm { class SymbolicQualitativeResultMinMax; template - class QualitativeMdpResultMinMax; + class SymbolicQualitativeMdpResultMinMax; template - class QualitativeGameResultMinMax; + class SymbolicQualitativeGameResultMinMax; class StateSet; @@ -124,7 +124,7 @@ namespace storm { std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); - std::unique_ptr> computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers); + std::unique_ptr> computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::Model const& abstractModel); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::symbolic::Model const& abstractModel); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 6ba963c63..4b64daac9 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -10,7 +10,6 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/VariableSetPredicateSplitter.h" - #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/EdgeDestination.h" #include "storm/storage/jani/Model.h" @@ -26,6 +25,8 @@ #include "storm/abstraction/jani/JaniMenuGameAbstractor.h" #include "storm/abstraction/MenuGameRefiner.h" +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" + #include "storm/logic/FragmentSpecification.h" #include "storm/solver/SymbolicGameSolver.h" @@ -45,8 +46,8 @@ namespace storm { namespace modelchecker { - using storm::abstraction::QuantitativeGameResult; - using storm::abstraction::QuantitativeGameResultMinMax; + using storm::abstraction::SymbolicQuantitativeGameResult; + using storm::abstraction::SymbolicQuantitativeGameResultMinMax; template GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { @@ -71,9 +72,11 @@ namespace storm { preprocessedModel = model.asJaniModel().flattenComposition(); } - storm::settings::modules::AbstractionSettings::ReuseMode reuseMode = storm::settings::getModule().getReuseMode(); + auto const& abstractionSettings = storm::settings::getModule(); + storm::settings::modules::AbstractionSettings::ReuseMode reuseMode = abstractionSettings.getReuseMode(); reuseQualitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Qualitative; reuseQuantitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Quantitative; + maximalNumberOfAbstractions = abstractionSettings.getMaximalAbstractionCount(); } template @@ -159,7 +162,7 @@ namespace storm { } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, QualitativeGameResultMinMax const& qualitativeResult) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, SymbolicQualitativeGameResultMinMax const& qualitativeResult) { // Check whether we can already give the answer based on the current information. std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); if (result) { @@ -232,7 +235,7 @@ namespace storm { } template - QuantitativeGameResult solveMaybeStates(Environment const& env, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& prob1States, boost::optional> const& startInfo = boost::none) { + SymbolicQuantitativeGameResult solveMaybeStates(Environment const& env, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& prob1States, boost::optional> const& startInfo = boost::none) { STORM_LOG_TRACE("Performing quantative solution step. Player 1: " << player1Direction << ", player 2: " << player2Direction << "."); @@ -259,14 +262,14 @@ namespace storm { std::unique_ptr> solver = solverFactory.create(submatrix, maybeStates, game.getIllegalPlayer1Mask(), game.getIllegalPlayer2Mask(), game.getRowVariables(), game.getColumnVariables(), game.getRowColumnMetaVariablePairs(), game.getPlayer1Variables(), game.getPlayer2Variables()); solver->setGeneratePlayersStrategies(true); auto values = solver->solveGame(env, player1Direction, player2Direction, startVector, subvector, startInfo ? boost::make_optional(startInfo.get().getPlayer1Strategy()) : boost::none, startInfo ? boost::make_optional(startInfo.get().getPlayer2Strategy()) : boost::none); - return QuantitativeGameResult(std::make_pair(storm::utility::zero(), storm::utility::one()), values, solver->getPlayer1Strategy(), solver->getPlayer2Strategy()); + return SymbolicQuantitativeGameResult(std::make_pair(storm::utility::zero(), storm::utility::one()), values, solver->getPlayer1Strategy(), solver->getPlayer2Strategy()); } template - QuantitativeGameResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::abstraction::MenuGame const& game, QualitativeGameResultMinMax const& qualitativeResult, storm::dd::Add const& initialStatesAdd, storm::dd::Bdd const& maybeStates, boost::optional> const& startInfo = boost::none) { + SymbolicQuantitativeGameResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::abstraction::MenuGame const& game, SymbolicQualitativeGameResultMinMax const& qualitativeResult, storm::dd::Add const& initialStatesAdd, storm::dd::Bdd const& maybeStates, boost::optional> const& startInfo = boost::none) { bool min = player2Direction == storm::OptimizationDirection::Minimize; - QuantitativeGameResult result; + SymbolicQuantitativeGameResult result; // We fix the strategies. That is, we take the decisions of the strategies obtained in the qualitiative // preprocessing if possible. @@ -355,9 +358,11 @@ namespace storm { storm::dd::Bdd globalTargetStates = abstractor->getStates(targetStateExpression); // Enter the main-loop of abstraction refinement. - boost::optional> previousQualitativeResult = boost::none; - boost::optional> previousMinQuantitativeResult = boost::none; - for (uint_fast64_t iterations = 0; iterations < 10000; ++iterations) { + boost::optional> previousSymbolicQualitativeResult = boost::none; + boost::optional> previousSymbolicMinQuantitativeResult = boost::none; + boost::optional previousExplicitQualitativeResult = boost::none; + // boost::optional> previousExplicitMinQuantitativeResult = boost::none; + for (uint_fast64_t iterations = 0; iterations < maximalNumberOfAbstractions; ++iterations) { auto iterationStart = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Starting iteration " << iterations << "."); @@ -384,9 +389,9 @@ namespace storm { std::unique_ptr result; if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { - result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousQualitativeResult, previousMinQuantitativeResult); + result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousSymbolicQualitativeResult, previousSymbolicMinQuantitativeResult); } else { - result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner); + result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousExplicitQualitativeResult); } if (result) { @@ -397,13 +402,14 @@ namespace storm { auto iterationEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); } - - STORM_LOG_ASSERT(false, "This point must not be reached."); + + // If this point is reached, we have given up on abstraction. + STORM_LOG_WARN("Could not derive result, maximal number of abstractions exceeded."); return nullptr; } template - std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { + std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { STORM_LOG_TRACE("Using dd-based solving."); @@ -412,7 +418,7 @@ namespace storm { // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). auto qualitativeStart = std::chrono::high_resolution_clock::now(); - QualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); + SymbolicQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); if (result) { return result; @@ -456,7 +462,7 @@ namespace storm { auto quantitativeStart = std::chrono::high_resolution_clock::now(); - QuantitativeGameResultMinMax quantitativeResult; + SymbolicQuantitativeGameResultMinMax quantitativeResult; // (7) Solve the min values and check whether we can give the answer already. quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); @@ -502,39 +508,64 @@ namespace storm { } template - std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner) { - STORM_LOG_TRACE("Using hybrid solving."); + std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional& previousQualitativeResult) { + STORM_LOG_TRACE("Using sparse solving."); // (0) Start by transforming the necessary symbolic elements to explicit ones. storm::dd::Odd odd = game.getReachableStates().createOdd(); std::pair, std::vector> transitionMatrixAndLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), game.getPlayer1Variables(), odd, odd, true); - auto const& transitionMatrix = transitionMatrixAndLabeling.first; - auto const& labeling = transitionMatrixAndLabeling.second; - + auto& transitionMatrix = transitionMatrixAndLabeling.first; + auto& labeling = transitionMatrixAndLabeling.second; + + // Create the player 2 row grouping from the labeling. + std::vector tmpPlayer2RowGrouping; + for (uint64_t player1State = 0; player1State < transitionMatrix.getRowGroupCount(); ++player1State) { + uint64_t lastLabel = std::numeric_limits::max(); + for (uint64_t row = transitionMatrix.getRowGroupIndices()[player1State]; row < transitionMatrix.getRowGroupIndices()[player1State + 1]; ++row) { + if (labeling[row] != lastLabel) { + tmpPlayer2RowGrouping.emplace_back(row); + lastLabel = labeling[row]; + } + } + } + tmpPlayer2RowGrouping.emplace_back(labeling.size()); + + std::vector player1RowGrouping = transitionMatrix.swapRowGroupIndices(std::move(tmpPlayer2RowGrouping)); + auto const& player2RowGrouping = transitionMatrix.getRowGroupIndices(); + + // Create the backward transitions for both players. + storm::storage::SparseMatrix player1BackwardTransitions = transitionMatrix.transpose(true); + std::vector player2BackwardTransitions(transitionMatrix.getRowGroupCount()); + uint64_t player2State = 0; + for (uint64_t player1State = 0; player1State < player2RowGrouping.size() - 1; ++player1State) { + while (player1RowGrouping[player1State + 1] > player2RowGrouping[player2State]) { + player2BackwardTransitions[player2State] = player1State; + ++player2State; + } + } + storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). auto qualitativeStart = std::chrono::high_resolution_clock::now(); - ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(game, player1Direction, transitionMatrix, constraintStates, targetStates); - std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); - if (result) { - return result; - } + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates); +// std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); +// if (result) { +// return result; +// } auto qualitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); +// std::cout << transitionMatrix << std::endl; +// std::cout << labeling.size() << std::endl; +// std::cout << initialStates << std::endl; +// std::cout << constraintStates << std::endl; +// std::cout << targetStates << std::endl; - - std::cout << transitionMatrix << std::endl; - std::cout << labeling.size() << std::endl; - std::cout << initialStates << std::endl; - std::cout << constraintStates << std::endl; - std::cout << targetStates << std::endl; - - exit(-1); + return nullptr; } template @@ -573,7 +604,7 @@ namespace storm { } template - bool checkQualitativeStrategies(bool prob0, QualitativeGameResult const& result, storm::dd::Bdd const& targetStates) { + bool checkQualitativeStrategies(bool prob0, SymbolicQualitativeGameResult const& result, storm::dd::Bdd const& targetStates) { if (prob0) { STORM_LOG_ASSERT(result.hasPlayer1Strategy() && (result.getPlayer1States().isZero() || !result.getPlayer1Strategy().isZero()), "Unable to proceed without strategy."); } else { @@ -586,7 +617,7 @@ namespace storm { } template - bool checkQualitativeStrategies(QualitativeGameResultMinMax const& qualitativeResult, storm::dd::Bdd const& targetStates) { + bool checkQualitativeStrategies(SymbolicQualitativeGameResultMinMax const& qualitativeResult, storm::dd::Bdd const& targetStates) { bool result = true; result &= checkQualitativeStrategies(true, qualitativeResult.prob0Min, targetStates); result &= checkQualitativeStrategies(false, qualitativeResult.prob1Min, targetStates); @@ -596,9 +627,72 @@ namespace storm { } template - QualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates) { + ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates) { + + ExplicitQualitativeGameResultMinMax result; + +// if (reuseQualitativeResults) { +// // Depending on the player 1 direction, we choose a different order of operations. +// if (player1Direction == storm::OptimizationDirection::Minimize) { +// // (1) min/min: compute prob0 using the game functions +// result.prob0Min = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); +// +// // (2) min/min: compute prob1 using the MDP functions +// storm::dd::Bdd candidates = game.getReachableStates() && !result.prob0Min.player1States; +// storm::dd::Bdd prob1MinMinMdp = storm::utility::graph::performProb1A(game, transitionMatrixBdd, previousQualitativeResult ? previousQualitativeResult.get().prob1Min.player1States : targetStates, candidates); +// +// // (3) min/min: compute prob1 using the game functions +// result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MinMinMdp)); +// +// // (4) min/max: compute prob 0 using the game functions +// result.prob0Max = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); +// +// // (5) min/max: compute prob 1 using the game functions +// // We know that only previous prob1 states can now be prob 1 states again, because the upper bound +// // values can only decrease over iterations. +// boost::optional> prob1Candidates; +// if (previousQualitativeResult) { +// prob1Candidates = previousQualitativeResult.get().prob1Max.player1States; +// } +// result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true, prob1Candidates); +// } else { +// // (1) max/max: compute prob0 using the game functions +// result.prob0Max = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); +// +// // (2) max/max: compute prob1 using the MDP functions, reuse prob1 states of last iteration to constrain the candidate states. +// storm::dd::Bdd candidates = game.getReachableStates() && !result.prob0Max.player1States; +// if (previousQualitativeResult) { +// candidates &= previousQualitativeResult.get().prob1Max.player1States; +// } +// storm::dd::Bdd prob1MaxMaxMdp = storm::utility::graph::performProb1E(game, transitionMatrixBdd, constraintStates, targetStates, candidates); +// +// // (3) max/max: compute prob1 using the game functions, reuse prob1 states from the MDP precomputation +// result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true, boost::make_optional(prob1MaxMaxMdp)); +// +// // (4) max/min: compute prob0 using the game functions +// result.prob0Min = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); +// +// // (5) max/min: compute prob1 using the game functions, use prob1 from max/max as the candidate set +// result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MaxMaxMdp)); +// } +// } else { + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); + result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); + result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); + result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); +// } + + STORM_LOG_TRACE("Qualitative precomputation completed."); + STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); + STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); + + return result; + } + + template + SymbolicQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates) { - QualitativeGameResultMinMax result; + SymbolicQualitativeGameResultMinMax result; if (reuseQualitativeResults) { // Depending on the player 1 direction, we choose a different order of operations. diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 8556edc71..933e0bf5d 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -9,8 +9,8 @@ #include "storm/storage/SymbolicModelDescription.h" -#include "storm/abstraction/QualitativeGameResult.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResult.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" #include "storm/logic/Bound.h" @@ -32,16 +32,21 @@ namespace storm { class MenuGameRefiner; template - class QualitativeGameResultMinMax; + class SymbolicQualitativeGameResultMinMax; template - struct QuantitativeGameResult; + class SymbolicQuantitativeGameResult; + + class ExplicitQualitativeGameResult; + class ExplicitQualitativeGameResultMinMax; } namespace modelchecker { - using storm::abstraction::QualitativeGameResult; - using storm::abstraction::QualitativeGameResultMinMax; + using storm::abstraction::SymbolicQualitativeGameResult; + using storm::abstraction::SymbolicQualitativeGameResultMinMax; + using storm::abstraction::ExplicitQualitativeGameResult; + using storm::abstraction::ExplicitQualitativeGameResultMinMax; template class GameBasedMdpModelChecker : public AbstractModelChecker { @@ -68,8 +73,8 @@ namespace storm { */ std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); - std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); - std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner); + std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); + std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional& previousQualitativeResult); /*! * Retrieves the initial predicates for the abstraction. @@ -85,7 +90,9 @@ namespace storm { * Performs a qualitative check on the the given game to compute the (player 1) states that have probability * 0 or 1, respectively, to reach a target state and only visiting constraint states before. */ - QualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); + SymbolicQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); + + ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates); void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const; @@ -110,6 +117,9 @@ namespace storm { /// A flag indicating whether to reuse the quantitative results. bool reuseQuantitativeResults; + /// The maximal number of abstractions to perform. + uint64_t maximalNumberOfAbstractions; + /// The mode selected for solving the abstraction. storm::settings::modules::AbstractionSettings::SolveMode solveMode; }; diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 455cb7da8..341571ef6 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -23,6 +23,7 @@ namespace storm { const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; const std::string AbstractionSettings::solveModeOptionName = "solve"; + const std::string AbstractionSettings::maximalAbstractionOptionName = "maxabs"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -31,6 +32,8 @@ namespace storm { .setDefaultValueString("bisim").build()) .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalAbstractionOptionName, false, "The maximal number of abstraction to perform before solving is aborted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal abstraction count.").setDefaultValueUnsignedInteger(20000).build()).build()); + std::vector onOff = {"on", "off"}; this->addOption(storm::settings::OptionBuilder(moduleName, useDecompositionOptionName, true, "Sets whether to apply decomposition during the abstraction.") @@ -159,6 +162,10 @@ namespace storm { return ReuseMode::All; } + uint_fast64_t AbstractionSettings::getMaximalAbstractionCount() const { + return this->getOption(maximalAbstractionOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index f8b2e5c93..90a7ea668 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -109,6 +109,13 @@ namespace storm { */ SolveMode getSolveMode() const; + /*! + * Retrieves the maximal number of abstractions to perform until giving up on converging. + * + * @return The maximal abstraction count. + */ + uint_fast64_t getMaximalAbstractionCount() const; + const static std::string moduleName; private: @@ -122,6 +129,7 @@ namespace storm { const static std::string reuseResultsOptionName; const static std::string restrictToRelevantStatesOptionName; const static std::string solveModeOptionName; + const static std::string maximalAbstractionOptionName; }; } diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 729b85b46..d909b76b2 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -603,6 +603,16 @@ namespace storm { return rowGroupIndices.get(); } + template + std::vector::index_type> SparseMatrix::swapRowGroupIndices(std::vector&& newRowGrouping) { + std::vector result; + if (this->rowGroupIndices) { + result = std::move(rowGroupIndices.get()); + rowGroupIndices = std::move(newRowGrouping); + } + return result; + } + template void SparseMatrix::setRowGroupIndices(std::vector const& newRowGroupIndices) { trivialRowGrouping = false; diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index 4013a7cbf..917ed92e2 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -579,6 +579,12 @@ namespace storm { */ std::vector const& getRowGroupIndices() const; + /*! + * Swaps the grouping of rows of this matrix. + * + * @return The old grouping of rows of this matrix. + */ + std::vector swapRowGroupIndices(std::vector&& newRowGrouping); /*! * Sets the row grouping to the given one. diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index c720483fc..d5d2b408b 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1083,6 +1083,145 @@ namespace storm { return result; } + template + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { + + ExplicitGameProb01Result result(psiStates, storm::storage::BitVector(transitionMatrix.getRowGroupCount())); + + // Initialize the stack used for the DFS with the states + std::vector stack(psiStates.begin(), psiStates.end()); + + // Perform the actual DFS. + uint_fast64_t currentState; + while (!stack.empty()) { + currentState = stack.back(); + stack.pop_back(); + + // Check which player 2 predecessors of the current player 1 state to add. + for (auto const& player2PredecessorEntry : player1BackwardTransitions.getRow(currentState)) { + uint64_t player2Predecessor = player2PredecessorEntry.getColumn(); + if (!result.player2States.get(player2Predecessor)) { + bool addPlayer2State = false; + if (player2Strategy == OptimizationDirection::Minimize) { + bool allChoicesHavePlayer1State = true; + for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2Predecessor]; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { + bool choiceHasPlayer1State = false; + for (auto const& entry : transitionMatrix.getRow(row)) { + if (result.player1States.get(entry.getColumn())) { + choiceHasPlayer1State = true; + break; + } + } + if (!choiceHasPlayer1State) { + allChoicesHavePlayer1State = false; + } + } + if (allChoicesHavePlayer1State) { + addPlayer2State = true; + } + } else { + addPlayer2State = true; + } + + if (addPlayer2State) { + result.player2States.set(player2Predecessor); + + // Now check whether adding the player 2 state changes something with respect to the + // (single) player 1 predecessor. + uint64_t player1Predecessor = player2BackwardTransitions[player2Predecessor]; + + if (!result.player1States.get(player1Predecessor)) { + bool addPlayer1State = false; + if (player1Strategy == OptimizationDirection::Minimize) { + bool allPlayer2Successors = true; + for (uint64_t player2State = player1RowGrouping[player1Predecessor]; player2State < player1RowGrouping[player1Predecessor + 1]; ++player2State) { + if (!result.player2States.get(player2State)) { + allPlayer2Successors = false; + break; + } + } + if (allPlayer2Successors) { + addPlayer1State = true; + } + } else { + addPlayer1State = true; + } + + if (addPlayer1State) { + result.player1States.set(player1Predecessor); + stack.emplace_back(player1Predecessor); + } + } + } + } + } + } + + // Since we have determined the complements of the desired sets, we need to complement it now. + result.player1States.complement(); + result.player2States.complement(); + + // Generate player 1 strategy if required. + if (producePlayer1Strategy) { + result.player1Strategy = std::vector(result.player1States.size()); + + for (auto player1State : result.player1States) { + if (player1Strategy == storm::OptimizationDirection::Minimize) { + // At least one player 2 successor is a state with probability 0, find it. + bool foundProb0Successor = false; + uint64_t player2State; + for (player2State = player1RowGrouping[player1State]; player2State < player1RowGrouping[player1State + 1]; ++player2State) { + if (result.player2States.get(player2State)) { + result.player1Strategy.get()[player1State] = player2State - player1RowGrouping[player1State]; + foundProb0Successor = true; + break; + } + } + STORM_LOG_ASSERT(foundProb0Successor, "Expected at least one state 2 successor with probability 0."); + result.player1Strategy.get()[player1State] = player2State - player1RowGrouping[player1State]; + } else { + // Since all player 2 successors are states with probability 0, just pick any. + result.player1Strategy.get()[player1State] = 0; + } + } + } + + // Generate player 2 strategy if required. + if (producePlayer2Strategy) { + result.player2Strategy = std::vector(result.player2States.size()); + + for (auto player2State : result.player2States) { + if (player2Strategy == storm::OptimizationDirection::Minimize) { + // At least one distribution only has successors with probability 0, find it. + bool foundProb0SuccessorDistribution = false; + + uint64_t row; + for (row = transitionMatrix.getRowGroupIndices()[player2State]; row < transitionMatrix.getRowGroupIndices()[player2State + 1]; ++row) { + bool distributionHasOnlyProb0Successors = true; + for (auto const& player1SuccessorEntry : transitionMatrix.getRow(row)) { + if (!result.player1States.get(player1SuccessorEntry.getColumn())) { + distributionHasOnlyProb0Successors = false; + break; + } + } + if (distributionHasOnlyProb0Successors) { + foundProb0SuccessorDistribution = true; + break; + } + } + + STORM_LOG_ASSERT(foundProb0SuccessorDistribution, "Expected at least one distribution with only successors with probability 0."); + result.player2Strategy.get()[player2State] = row - transitionMatrix.getRowGroupIndices()[player2State]; + } else { + // Since all player 1 successors are states with probability 0, just pick any. + result.player2Strategy.get()[player2State] = 0; + } + } + } + + return result; + } + template SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { @@ -1150,6 +1289,133 @@ namespace storm { return SymbolicGameProb01Result(player1States, player2States, player1StrategyBdd, player2StrategyBdd); } + template + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates) { + + // During the execution, the two state sets in the result hold the potential player 1/2 states. + ExplicitGameProb01Result result; + if (player1Candidates) { + result = ExplicitGameProb01Result(player1Candidates.get(), storm::storage::BitVector(transitionMatrix.getRowGroupCount())); + } else { + result = ExplicitGameProb01Result(storm::storage::BitVector(phiStates.size(), true), storm::storage::BitVector(transitionMatrix.getRowGroupCount())); + } + + // A flag that governs whether strategies are produced in the current iteration. + bool produceStrategiesInIteration = false; + + // Initialize the stack used for the DFS with the states + std::vector stack; + bool maybeStatesDone = false; + uint_fast64_t maybeStateIterations = 0; + while (!maybeStatesDone || produceStrategiesInIteration) { + storm::storage::BitVector player1Solution = psiStates; + storm::storage::BitVector player2Solution(result.player2States.size()); + + stack.clear(); + stack.insert(stack.end(), psiStates.begin(), psiStates.end()); + + // If we are to produce strategies in this iteration, we prepare some storage. + if (produceStrategiesInIteration) { + if (producePlayer1Strategy) { + result.player1Strategy = std::vector(result.player1States.size()); + } + if (producePlayer2Strategy) { + result.player2Strategy = std::vector(result.player2States.size()); + } + } + + // Perform the actual DFS. + uint_fast64_t currentState; + while (!stack.empty()) { + currentState = stack.back(); + stack.pop_back(); + + for (auto player2PredecessorEntry : player1BackwardTransitions.getRow(currentState)) { + uint64_t player2Predecessor = player2PredecessorEntry.getColumn(); + if (!player2Solution.get(player2PredecessorEntry.getColumn())) { + bool addPlayer2State = player2Strategy == storm::OptimizationDirection::Minimize ? true : false; + + uint64_t validChoice = 0; + for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2Predecessor]; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { + bool choiceHasSolutionSuccessor = false; + bool choiceStaysInMaybeStates = true; + for (auto const& entry : transitionMatrix.getRow(row)) { + if (player1Solution.get(entry.getColumn())) { + choiceHasSolutionSuccessor = true; + } + if (!result.player1States.get(entry.getColumn())) { + choiceStaysInMaybeStates = false; + break; + } + } + + if (choiceHasSolutionSuccessor && choiceStaysInMaybeStates) { + if (player2Strategy == storm::OptimizationDirection::Maximize) { + validChoice = row - transitionMatrix.getRowGroupIndices()[player2Predecessor]; + addPlayer2State = true; + break; + } + } else if (player2Strategy == storm::OptimizationDirection::Minimize) { + addPlayer2State = false; + break; + } + } + + if (addPlayer2State) { + player2Solution.set(player2Predecessor); + if (produceStrategiesInIteration && producePlayer2Strategy) { + result.player2Strategy.get()[player2Predecessor] = validChoice; + } + + // Check whether the addition of the player 2 state changes the state of the (single) + // player 1 predecessor. + uint64_t player1Predecessor = player2BackwardTransitions[player2Predecessor]; + + if (!player1Solution.get(player1Predecessor)) { + bool addPlayer1State = player1Strategy == storm::OptimizationDirection::Minimize ? true : false; + + validChoice = 0; + for (uint64_t player2Successor = player1RowGrouping[player1Predecessor]; player2Successor < player1RowGrouping[player1Predecessor + 1]; ++player2Successor) { + if (player2Solution.get(player2Successor)) { + if (player1Strategy == storm::OptimizationDirection::Maximize) { + validChoice = player2Successor - player1RowGrouping[player1Predecessor]; + addPlayer1State = true; + break; + } + } else if (player1Strategy == storm::OptimizationDirection::Minimize) { + addPlayer1State = false; + break; + } + } + + if (addPlayer1State) { + player1Solution.set(player1Predecessor); + + if (produceStrategiesInIteration && producePlayer1Strategy) { + result.player1Strategy.get()[player1Predecessor] = validChoice; + } + + stack.emplace_back(); + } + } + } + } + } + } + + if (result.player1States == player1Solution) { + maybeStatesDone = true; + result.player2States = player2Solution; + } else { + result.player1States = player1Solution; + result.player2States = player2Solution; + } + ++maybeStateIterations; + } + + return result; + } + template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates) { @@ -1424,6 +1690,10 @@ namespace storm { template std::pair performProb01Min(storm::models::sparse::NondeterministicModel> const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); #endif + template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); + + template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates); + template std::vector getTopologicalSort(storm::storage::SparseMatrix const& matrix) ; // Instantiations for storm::RationalNumber. diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index cff5887fc..5e1fae518 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -615,6 +615,85 @@ namespace storm { template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional> const& player1Candidates = boost::none); + struct ExplicitGameProb01Result { + ExplicitGameProb01Result() = default; + ExplicitGameProb01Result(uint64_t numberOfPlayer1States, uint64_t numberOfPlayer2States) : player1States(numberOfPlayer1States), player2States(numberOfPlayer2States) { + // Intentionally left empty. + } + + ExplicitGameProb01Result(storm::storage::BitVector const& player1States, storm::storage::BitVector const& player2States, boost::optional> const& player1Strategy = boost::none, boost::optional> const& player2Strategy = boost::none) : player1States(player1States), player2States(player2States), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { + // Intentionally left empty. + } + + bool hasPlayer1Strategy() const { + return static_cast(player1Strategy); + } + + std::vector const& getPlayer1Strategy() const { + return player1Strategy.get(); + } + + boost::optional> const& getOptionalPlayer1Strategy() { + return player1Strategy; + } + + bool hasPlayer2Strategy() const { + return static_cast(player2Strategy); + } + + std::vector const& getPlayer2Strategy() const { + return player2Strategy.get(); + } + + boost::optional> const& getOptionalPlayer2Strategy() { + return player2Strategy; + } + + storm::storage::BitVector const& getPlayer1States() const { + return player1States; + } + + storm::storage::BitVector const& getPlayer2States() const { + return player2States; + } + + storm::storage::BitVector player1States; + storm::storage::BitVector player2States; + boost::optional> player1Strategy; + boost::optional> player2Strategy; + }; + + /*! + * Computes the set of states that have probability 0 given the strategies of the two players. + * + * @param transitionMatrix The transition matrix of the model as a BDD. + * @param player1RowGrouping The row grouping of player 1 states. + * @param player1BackwardTransitions The backward transitions (player 1 to player 2). + * @param player2BackwardTransitions The backward transitions (player 2 to player 1). + * @param phiStates The phi states of the model. + * @param psiStates The psi states of the model. + * @param producePlayer1Strategy A flag indicating whether the strategy of player 1 shall be produced. + * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. + */ + template + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); + + /*! + * Computes the set of states that have probability 1 given the strategies of the two players. + * + * @param transitionMatrix The transition matrix of the model as a BDD. + * @param player1RowGrouping The row grouping of player 1 states. + * @param player1BackwardTransitions The backward transitions (player 1 to player 2). + * @param player2BackwardTransitions The backward transitions (player 2 to player 1). + * @param phiStates The phi states of the model. + * @param psiStates The psi states of the model. + * @param producePlayer1Strategy A flag indicating whether the strategy of player 1 shall be produced. + * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. + * @param player1Candidates If given, this set constrains the candidates of player 1 states that are considered. + */ + template + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional const& player1Candidates = boost::none); + /*! * Performs a topological sort of the states of the system according to the given transitions. * From 3f6a8fed92924c5db97191932b10d0590fa26407 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 25 Mar 2018 21:58:19 +0200 Subject: [PATCH 204/647] fixed some issues in qualitative sparse solution of game-based abstraction --- .../abstraction/GameBasedMdpModelChecker.cpp | 17 ++++++---- src/storm/utility/graph.cpp | 34 +++++++++---------- src/storm/utility/graph.h | 8 ++--- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 4b64daac9..9119c498f 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -534,15 +534,18 @@ namespace storm { std::vector player1RowGrouping = transitionMatrix.swapRowGroupIndices(std::move(tmpPlayer2RowGrouping)); auto const& player2RowGrouping = transitionMatrix.getRowGroupIndices(); - // Create the backward transitions for both players. + // Create the player 1 groups and backward transitions (for both players). + std::vector player1Groups(player1RowGrouping.size()); storm::storage::SparseMatrix player1BackwardTransitions = transitionMatrix.transpose(true); std::vector player2BackwardTransitions(transitionMatrix.getRowGroupCount()); + uint64_t player2State = 0; for (uint64_t player1State = 0; player1State < player2RowGrouping.size() - 1; ++player1State) { while (player1RowGrouping[player1State + 1] > player2RowGrouping[player2State]) { player2BackwardTransitions[player2State] = player1State; ++player2State; } + player1Groups[player1State + 1] = player2State; } storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); @@ -551,7 +554,7 @@ namespace storm { // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). auto qualitativeStart = std::chrono::high_resolution_clock::now(); - ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates); + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates); // std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); // if (result) { // return result; @@ -627,7 +630,7 @@ namespace storm { } template - ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates) { + ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates) { ExplicitQualitativeGameResultMinMax result; @@ -676,10 +679,10 @@ namespace storm { // result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MaxMaxMdp)); // } // } else { - result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); - result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); - result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); - result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1RowGrouping, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); + result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); + result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); + result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); // } STORM_LOG_TRACE("Qualitative precomputation completed."); diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index d5d2b408b..423641dc2 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1084,7 +1084,7 @@ namespace storm { } template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { ExplicitGameProb01Result result(psiStates, storm::storage::BitVector(transitionMatrix.getRowGroupCount())); @@ -1134,7 +1134,7 @@ namespace storm { bool addPlayer1State = false; if (player1Strategy == OptimizationDirection::Minimize) { bool allPlayer2Successors = true; - for (uint64_t player2State = player1RowGrouping[player1Predecessor]; player2State < player1RowGrouping[player1Predecessor + 1]; ++player2State) { + for (uint64_t player2State = player1Groups[player1Predecessor]; player2State < player1Groups[player1Predecessor + 1]; ++player2State) { if (!result.player2States.get(player2State)) { allPlayer2Successors = false; break; @@ -1170,18 +1170,18 @@ namespace storm { // At least one player 2 successor is a state with probability 0, find it. bool foundProb0Successor = false; uint64_t player2State; - for (player2State = player1RowGrouping[player1State]; player2State < player1RowGrouping[player1State + 1]; ++player2State) { + for (player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) { if (result.player2States.get(player2State)) { - result.player1Strategy.get()[player1State] = player2State - player1RowGrouping[player1State]; + result.player1Strategy.get()[player1State] = player2State; foundProb0Successor = true; break; } } STORM_LOG_ASSERT(foundProb0Successor, "Expected at least one state 2 successor with probability 0."); - result.player1Strategy.get()[player1State] = player2State - player1RowGrouping[player1State]; + result.player1Strategy.get()[player1State] = player2State; } else { // Since all player 2 successors are states with probability 0, just pick any. - result.player1Strategy.get()[player1State] = 0; + result.player1Strategy.get()[player1State] = player1Groups[player1State]; } } } @@ -1211,10 +1211,10 @@ namespace storm { } STORM_LOG_ASSERT(foundProb0SuccessorDistribution, "Expected at least one distribution with only successors with probability 0."); - result.player2Strategy.get()[player2State] = row - transitionMatrix.getRowGroupIndices()[player2State]; + result.player2Strategy.get()[player2State] = row; } else { // Since all player 1 successors are states with probability 0, just pick any. - result.player2Strategy.get()[player2State] = 0; + result.player2Strategy.get()[player2State] = transitionMatrix.getRowGroupIndices()[player2State]; } } } @@ -1290,8 +1290,8 @@ namespace storm { } template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates) { - + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates) { + // During the execution, the two state sets in the result hold the potential player 1/2 states. ExplicitGameProb01Result result; if (player1Candidates) { @@ -1335,8 +1335,8 @@ namespace storm { if (!player2Solution.get(player2PredecessorEntry.getColumn())) { bool addPlayer2State = player2Strategy == storm::OptimizationDirection::Minimize ? true : false; - uint64_t validChoice = 0; - for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2Predecessor]; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { + uint64_t validChoice = transitionMatrix.getRowGroupIndices()[player2Predecessor]; + for (uint64_t row = validChoice; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { bool choiceHasSolutionSuccessor = false; bool choiceStaysInMaybeStates = true; for (auto const& entry : transitionMatrix.getRow(row)) { @@ -1351,7 +1351,7 @@ namespace storm { if (choiceHasSolutionSuccessor && choiceStaysInMaybeStates) { if (player2Strategy == storm::OptimizationDirection::Maximize) { - validChoice = row - transitionMatrix.getRowGroupIndices()[player2Predecessor]; + validChoice = row; addPlayer2State = true; break; } @@ -1374,11 +1374,11 @@ namespace storm { if (!player1Solution.get(player1Predecessor)) { bool addPlayer1State = player1Strategy == storm::OptimizationDirection::Minimize ? true : false; - validChoice = 0; - for (uint64_t player2Successor = player1RowGrouping[player1Predecessor]; player2Successor < player1RowGrouping[player1Predecessor + 1]; ++player2Successor) { + validChoice = player1Groups[player1Predecessor]; + for (uint64_t player2Successor = validChoice; player2Successor < player1Groups[player1Predecessor + 1]; ++player2Successor) { if (player2Solution.get(player2Successor)) { if (player1Strategy == storm::OptimizationDirection::Maximize) { - validChoice = player2Successor - player1RowGrouping[player1Predecessor]; + validChoice = player2Successor; addPlayer1State = true; break; } @@ -1395,7 +1395,7 @@ namespace storm { result.player1Strategy.get()[player1Predecessor] = validChoice; } - stack.emplace_back(); + stack.emplace_back(player1Predecessor); } } } diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index 5e1fae518..2e37d0318 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -667,7 +667,7 @@ namespace storm { * Computes the set of states that have probability 0 given the strategies of the two players. * * @param transitionMatrix The transition matrix of the model as a BDD. - * @param player1RowGrouping The row grouping of player 1 states. + * @param player1Groups The grouping of player 1 states (in terms of player 2 states). * @param player1BackwardTransitions The backward transitions (player 1 to player 2). * @param player2BackwardTransitions The backward transitions (player 2 to player 1). * @param phiStates The phi states of the model. @@ -676,13 +676,13 @@ namespace storm { * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. */ template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); /*! * Computes the set of states that have probability 1 given the strategies of the two players. * * @param transitionMatrix The transition matrix of the model as a BDD. - * @param player1RowGrouping The row grouping of player 1 states. + * @param player1Groups The grouping of player 1 states (in terms of player 2 states). * @param player1BackwardTransitions The backward transitions (player 1 to player 2). * @param player2BackwardTransitions The backward transitions (player 2 to player 1). * @param phiStates The phi states of the model. @@ -692,7 +692,7 @@ namespace storm { * @param player1Candidates If given, this set constrains the candidates of player 1 states that are considered. */ template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional const& player1Candidates = boost::none); + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional const& player1Candidates = boost::none); /*! * Performs a topological sort of the states of the system according to the given transitions. From a03f9c80d283c6d7fdc0e4e17dd915efb80f28dd Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 26 Mar 2018 11:13:01 +0200 Subject: [PATCH 205/647] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d30d82ad9..6dcf702a0 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Authors Storm has been developed at RWTH Aachen University. ###### Principal developers -* Christian Dehnert +* Christian Hensel * Sebastian Junges * Joost-Pieter Katoen * Tim Quatmann From 6fa88b1c14e68c49f64ca55b59bf3a1d9b68ffb0 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 26 Mar 2018 11:14:00 +0200 Subject: [PATCH 206/647] Disable unnecessary output for DFT model checking --- src/storm-dft-cli/storm-dft.cpp | 4 +- src/storm-dft/api/storm-dft.h | 16 ++++--- .../modelchecker/dft/DFTModelChecker.cpp | 48 +++++++++---------- .../storm-dft/api/DftModelCheckerTest.cpp | 2 +- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index f051570dc..9923330d0 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -107,9 +107,9 @@ void processOptions() { // Carry out the actual analysis if (faultTreeSettings.isApproximationErrorSet()) { // Approximate analysis - storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), faultTreeSettings.getApproximationError()); + storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), faultTreeSettings.getApproximationError(), true); } else { - storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC()); + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), true); } } diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index 003c03f14..db6d7b3e4 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -53,11 +53,13 @@ namespace storm { * @return Result. */ template - typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC) { + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, bool printOutput) { storm::modelchecker::DFTModelChecker modelChecker; typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, 0.0); - modelChecker.printTimings(); - modelChecker.printResults(); + if (printOutput) { + modelChecker.printTimings(); + modelChecker.printResults(); + } return results; } @@ -75,11 +77,13 @@ namespace storm { * @return Result. */ template - typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, bool printOutput) { storm::modelchecker::DFTModelChecker modelChecker; typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError); - modelChecker.printTimings(); - modelChecker.printResults(); + if (printOutput) { + modelChecker.printTimings(); + modelChecker.printResults(); + } return results; } diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index c3e7996c7..31ba6789d 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -176,7 +176,7 @@ namespace storm { bool firstTime = true; std::shared_ptr> composedModel; for (auto const ft : dfts) { - STORM_LOG_INFO("Building Model via parallel composition..."); + STORM_LOG_DEBUG("Building Model via parallel composition..."); explorationTimer.start(); // Find symmetries @@ -185,12 +185,12 @@ namespace storm { if(symred) { auto colouring = ft.colourDFT(); symmetries = ft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } // Build a single CTMC - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); @@ -226,7 +226,7 @@ namespace storm { } } - composedModel->printModelInformationToStream(std::cout); + //composedModel->printModelInformationToStream(std::cout); return composedModel; } else { // No composition was possible @@ -237,17 +237,17 @@ namespace storm { if(symred) { auto colouring = dft.colourDFT(); symmetries = dft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } // Build a single CTMC - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); explorationTimer.stop(); STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Ctmc), storm::exceptions::NotSupportedException, "Parallel composition only applicable for CTMCs"); return model->template as>(); @@ -264,7 +264,7 @@ namespace storm { if(symred) { auto colouring = dft.colourDFT(); symmetries = dft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } @@ -292,7 +292,7 @@ namespace storm { if (iteration > 0) { explorationTimer.start(); } - STORM_LOG_INFO("Building model..."); + STORM_LOG_DEBUG("Building model..."); // TODO Matthias refine model using existing model and MC results builder.buildModel(labeloptions, iteration, approximationError); explorationTimer.stop(); @@ -301,10 +301,10 @@ namespace storm { // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one? // Build model for lower bound - STORM_LOG_INFO("Getting model for lower bound..."); + STORM_LOG_DEBUG("Getting model for lower bound..."); model = builder.getModelApproximation(true, !probabilityFormula); // We only output the info from the lower bound as the info for the upper bound is the same - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); buildingTimer.stop(); // Check lower bounds @@ -314,7 +314,7 @@ namespace storm { approxResult.first = newResult[0]; // Build model for upper bound - STORM_LOG_INFO("Getting model for upper bound..."); + STORM_LOG_DEBUG("Getting model for upper bound..."); buildingTimer.start(); model = builder.getModelApproximation(false, !probabilityFormula); buildingTimer.stop(); @@ -326,25 +326,25 @@ namespace storm { ++iteration; STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second), "Under-approximation " << approxResult.first << " is greater than over-approximation " << approxResult.second); - STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")"); + //STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")"); totalTimer.stop(); printTimings(); totalTimer.start(); STORM_LOG_THROW(!storm::utility::isInfinity(approxResult.first) && !storm::utility::isInfinity(approxResult.second), storm::exceptions::NotSupportedException, "Approximation does not work if result might be infinity."); } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula)); - STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : ".")); + //STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : ".")); dft_results results; results.push_back(approxResult); return results; } else { // Build a single Markov Automaton - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, storm::settings::getModule().isExportExplicitSet()); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); explorationTimer.stop(); // Export the model if required @@ -373,15 +373,15 @@ namespace storm { // Bisimulation if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule().isBisimulationSet()) { bisimulationTimer.start(); - STORM_LOG_INFO("Bisimulation..."); + STORM_LOG_DEBUG("Bisimulation..."); model = storm::api::performDeterministicSparseBisimulationMinimization>(model->template as>(), properties, storm::storage::BisimulationType::Weak)->template as>(); - STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates()); - STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions()); + STORM_LOG_DEBUG("No. states (Bisimulation): " << model->getNumberOfStates()); + STORM_LOG_DEBUG("No. transitions (Bisimulation): " << model->getNumberOfTransitions()); bisimulationTimer.stop(); } // Check the model - STORM_LOG_INFO("Model checking..."); + STORM_LOG_DEBUG("Model checking..."); modelCheckingTimer.start(); std::vector results; @@ -390,18 +390,18 @@ namespace storm { for (auto property : properties) { singleModelCheckingTimer.reset(); singleModelCheckingTimer.start(); - STORM_PRINT_AND_LOG("Model checking property " << *property << " ..." << std::endl); + //STORM_PRINT_AND_LOG("Model checking property " << *property << " ..." << std::endl); std::unique_ptr result(storm::api::verifyWithSparseEngine(model, storm::api::createTask(property, true))); STORM_LOG_ASSERT(result, "Result does not exist."); result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); ValueType resultValue = result->asExplicitQuantitativeCheckResult().getValueMap().begin()->second; - STORM_PRINT_AND_LOG("Result (initial states): " << resultValue << std::endl); + //STORM_PRINT_AND_LOG("Result (initial states): " << resultValue << std::endl); results.push_back(resultValue); singleModelCheckingTimer.stop(); - STORM_PRINT_AND_LOG("Time for model checking: " << singleModelCheckingTimer << "." << std::endl); + //STORM_PRINT_AND_LOG("Time for model checking: " << singleModelCheckingTimer << "." << std::endl); } modelCheckingTimer.stop(); - STORM_LOG_INFO("Model checking done."); + STORM_LOG_DEBUG("Model checking done."); return results; } diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index 902108018..5db58d60d 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -65,7 +65,7 @@ namespace { std::shared_ptr> dft = storm::api::loadDFTGalileo(file); std::string property = "Tmin=? [F \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); - typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, config.useDC); + typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, config.useDC, false); return boost::get(results[0]); } From c6a5d5a74d90e7cabc75e192d9995dca80737a74 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 26 Mar 2018 16:42:15 +0200 Subject: [PATCH 207/647] started on refining menu games based on explicit results --- .../abstraction/ExplicitGameStrategy.cpp | 39 ++++ src/storm/abstraction/ExplicitGameStrategy.h | 27 +++ .../abstraction/ExplicitGameStrategyPair.cpp | 31 +++ .../abstraction/ExplicitGameStrategyPair.h | 26 +++ .../ExplicitQualitativeGameResultMinMax.cpp | 15 ++ .../ExplicitQualitativeGameResultMinMax.h | 4 +- .../abstraction/ExplicitQualitativeResult.cpp | 17 ++ .../abstraction/ExplicitQualitativeResult.h | 5 + .../ExplicitQualitativeResultMinMax.cpp | 16 ++ .../ExplicitQualitativeResultMinMax.h | 9 +- src/storm/abstraction/MenuGameRefiner.cpp | 183 +++++++++++++++--- src/storm/abstraction/MenuGameRefiner.h | 56 +++++- .../jani/JaniMenuGameAbstractor.cpp | 4 +- .../prism/PrismMenuGameAbstractor.cpp | 4 +- .../abstraction/GameBasedMdpModelChecker.cpp | 116 +++++++++-- .../abstraction/GameBasedMdpModelChecker.h | 4 +- src/storm/storage/dd/Add.cpp | 61 +++--- src/storm/storage/dd/Add.h | 17 +- src/storm/storage/dd/Bdd.cpp | 5 + src/storm/storage/dd/Bdd.h | 10 + src/storm/utility/graph.cpp | 64 +++--- src/storm/utility/graph.h | 51 ++--- 22 files changed, 605 insertions(+), 159 deletions(-) create mode 100644 src/storm/abstraction/ExplicitGameStrategy.cpp create mode 100644 src/storm/abstraction/ExplicitGameStrategy.h create mode 100644 src/storm/abstraction/ExplicitGameStrategyPair.cpp create mode 100644 src/storm/abstraction/ExplicitGameStrategyPair.h create mode 100644 src/storm/abstraction/ExplicitQualitativeResult.cpp diff --git a/src/storm/abstraction/ExplicitGameStrategy.cpp b/src/storm/abstraction/ExplicitGameStrategy.cpp new file mode 100644 index 000000000..642c274b7 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategy.cpp @@ -0,0 +1,39 @@ +#include "storm/abstraction/ExplicitGameStrategy.h" + +namespace storm { + namespace abstraction { + + const uint64_t ExplicitGameStrategy::UNDEFINED = std::numeric_limits::max(); + + ExplicitGameStrategy::ExplicitGameStrategy(uint64_t numberOfStates) : choices(numberOfStates, UNDEFINED) { + // Intentionally left empty. + } + + ExplicitGameStrategy::ExplicitGameStrategy(std::vector&& choices) : choices(std::move(choices)) { + // Intentionally left empty. + } + + uint64_t ExplicitGameStrategy::getNumberOfStates() const { + return choices.size(); + } + + uint64_t ExplicitGameStrategy::getChoice(uint64_t state) const { + return choices[state]; + } + + void ExplicitGameStrategy::setChoice(uint64_t state, uint64_t choice) { + choices[state] = choice; + } + + bool ExplicitGameStrategy::hasDefinedChoice(uint64_t state) const { + return choices[state] != UNDEFINED; + } + + void ExplicitGameStrategy::undefineAll() { + for (auto& e : choices) { + e = UNDEFINED; + } + } + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategy.h b/src/storm/abstraction/ExplicitGameStrategy.h new file mode 100644 index 000000000..8315e9101 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategy.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace storm { + namespace abstraction { + + class ExplicitGameStrategy { + public: + static const uint64_t UNDEFINED; + + ExplicitGameStrategy(uint64_t numberOfStates); + ExplicitGameStrategy(std::vector&& choices); + + uint64_t getNumberOfStates() const; + uint64_t getChoice(uint64_t state) const; + void setChoice(uint64_t state, uint64_t choice); + bool hasDefinedChoice(uint64_t state) const; + void undefineAll(); + + private: + std::vector choices; + }; + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.cpp b/src/storm/abstraction/ExplicitGameStrategyPair.cpp new file mode 100644 index 000000000..d773f9ec5 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategyPair.cpp @@ -0,0 +1,31 @@ +#include "storm/abstraction/ExplicitGameStrategyPair.h" + +namespace storm { + namespace abstraction { + + ExplicitGameStrategyPair::ExplicitGameStrategyPair(uint64_t numberOfPlayer1States, uint64_t numberOfPlayer2States) : player1Strategy(numberOfPlayer1States), player2Strategy(numberOfPlayer2States) { + // Intentionally left empty. + } + + ExplicitGameStrategyPair::ExplicitGameStrategyPair(ExplicitGameStrategy&& player1Strategy, ExplicitGameStrategy&& player2Strategy) : player1Strategy(std::move(player1Strategy)), player2Strategy(std::move(player2Strategy)) { + // Intentionally left empty. + } + + ExplicitGameStrategy& ExplicitGameStrategyPair::getPlayer1Strategy() { + return player1Strategy; + } + + ExplicitGameStrategy const& ExplicitGameStrategyPair::getPlayer1Strategy() const { + return player1Strategy; + } + + ExplicitGameStrategy& ExplicitGameStrategyPair::getPlayer2Strategy() { + return player2Strategy; + } + + ExplicitGameStrategy const& ExplicitGameStrategyPair::getPlayer2Strategy() const { + return player2Strategy; + } + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.h b/src/storm/abstraction/ExplicitGameStrategyPair.h new file mode 100644 index 000000000..6449c3ddd --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategyPair.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "storm/abstraction/ExplicitGameStrategy.h" + +namespace storm { + namespace abstraction { + + class ExplicitGameStrategyPair { + public: + ExplicitGameStrategyPair(uint64_t numberOfPlayer1States, uint64_t numberOfPlayer2States); + ExplicitGameStrategyPair(ExplicitGameStrategy&& player1Strategy, ExplicitGameStrategy&& player2Strategy); + + ExplicitGameStrategy& getPlayer1Strategy(); + ExplicitGameStrategy const& getPlayer1Strategy() const; + ExplicitGameStrategy& getPlayer2Strategy(); + ExplicitGameStrategy const& getPlayer2Strategy() const; + + private: + ExplicitGameStrategy player1Strategy; + ExplicitGameStrategy player2Strategy; + }; + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp index ef1538c50..7a5456bd5 100644 --- a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp @@ -19,6 +19,21 @@ namespace storm { } } + ExplicitQualitativeGameResult& ExplicitQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + ExplicitQualitativeGameResult& ExplicitQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } } } diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h index 8551a3c47..5612ac9e7 100644 --- a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h @@ -12,7 +12,9 @@ namespace storm { virtual ExplicitQualitativeGameResult const& getProb0(storm::OptimizationDirection const& dir) const override; virtual ExplicitQualitativeGameResult const& getProb1(storm::OptimizationDirection const& dir) const override; - + virtual ExplicitQualitativeGameResult& getProb0(storm::OptimizationDirection const& dir) override; + virtual ExplicitQualitativeGameResult& getProb1(storm::OptimizationDirection const& dir) override; + ExplicitQualitativeGameResult prob0Min; ExplicitQualitativeGameResult prob1Min; ExplicitQualitativeGameResult prob0Max; diff --git a/src/storm/abstraction/ExplicitQualitativeResult.cpp b/src/storm/abstraction/ExplicitQualitativeResult.cpp new file mode 100644 index 000000000..b1237350e --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResult.cpp @@ -0,0 +1,17 @@ +#include "storm/abstraction/ExplicitQualitativeResult.h" + +#include "storm/abstraction/ExplicitQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult& ExplicitQualitativeResult::asExplicitQualitativeGameResult() { + return static_cast(*this); + } + + ExplicitQualitativeGameResult const& ExplicitQualitativeResult::asExplicitQualitativeGameResult() const { + return static_cast(*this); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeResult.h b/src/storm/abstraction/ExplicitQualitativeResult.h index 8f8e6a151..d275fe91c 100644 --- a/src/storm/abstraction/ExplicitQualitativeResult.h +++ b/src/storm/abstraction/ExplicitQualitativeResult.h @@ -10,11 +10,16 @@ namespace storm { } namespace abstraction { + + class ExplicitQualitativeGameResult; class ExplicitQualitativeResult : public QualitativeResult { public: virtual ~ExplicitQualitativeResult() = default; + ExplicitQualitativeGameResult& asExplicitQualitativeGameResult(); + ExplicitQualitativeGameResult const& asExplicitQualitativeGameResult() const; + virtual storm::storage::BitVector const& getStates() const = 0; }; diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp index 8d3a630f2..382a435f6 100644 --- a/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp @@ -25,5 +25,21 @@ namespace storm { return getProb1(storm::OptimizationDirection::Maximize); } + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb0Min() { + return getProb0(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb1Min() { + return getProb1(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb0Max() { + return getProb0(storm::OptimizationDirection::Maximize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb1Max() { + return getProb1(storm::OptimizationDirection::Maximize); + } + } } diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h index 2eabe123b..acccab839 100644 --- a/src/storm/abstraction/ExplicitQualitativeResultMinMax.h +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h @@ -7,6 +7,7 @@ namespace storm { namespace abstraction { class ExplicitQualitativeResult; + class ExplicitQualitativeGameResultMinMax; class ExplicitQualitativeResultMinMax : public QualitativeResultMinMax { public: @@ -18,9 +19,15 @@ namespace storm { ExplicitQualitativeResult const& getProb1Min() const; ExplicitQualitativeResult const& getProb0Max() const; ExplicitQualitativeResult const& getProb1Max() const; - + ExplicitQualitativeResult& getProb0Min(); + ExplicitQualitativeResult& getProb1Min(); + ExplicitQualitativeResult& getProb0Max(); + ExplicitQualitativeResult& getProb1Max(); + virtual ExplicitQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; virtual ExplicitQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; + virtual ExplicitQualitativeResult& getProb0(storm::OptimizationDirection const& dir) = 0; + virtual ExplicitQualitativeResult& getProb1(storm::OptimizationDirection const& dir) = 0; }; } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index d97973bd6..6b83338e7 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -4,8 +4,11 @@ #include "storm/abstraction/MenuGameAbstractor.h" #include "storm/storage/BitVector.h" +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitGameStrategyPair.h" #include "storm/storage/dd/DdManager.h" +#include "storm/storage/dd/Odd.h" #include "storm/utility/dd.h" #include "storm/utility/solver.h" @@ -42,7 +45,7 @@ namespace storm { } template - MostProbablePathsResult::MostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree) : maxProbabilities(maxProbabilities), spanningTree(spanningTree) { + SymbolicMostProbablePathsResult::SymbolicMostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree) : maxProbabilities(maxProbabilities), spanningTree(spanningTree) { // Intentionally left empty. } @@ -54,7 +57,7 @@ namespace storm { }; template - PivotStateResult::PivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& mostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), mostProbablePathsResult(mostProbablePathsResult) { + SymbolicPivotStateResult::SymbolicPivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& symbolicMostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), symbolicMostProbablePathsResult(symbolicMostProbablePathsResult) { // Intentionally left empty. } @@ -89,7 +92,7 @@ namespace storm { } template - MostProbablePathsResult getMostProbablePathSpanningTree(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionFilter) { + SymbolicMostProbablePathsResult getMostProbablePathSpanningTree(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionFilter) { storm::dd::Add maxProbabilities = game.getInitialStates().template toAdd(); storm::dd::Bdd border = game.getInitialStates(); @@ -120,11 +123,11 @@ namespace storm { border = updateStates; } - return MostProbablePathsResult(maxProbabilities, spanningTree); + return SymbolicMostProbablePathsResult(maxProbabilities, spanningTree); } template - PivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { + SymbolicPivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { // Get easy access to strategies. storm::dd::Bdd minPlayer1Strategy; @@ -163,7 +166,7 @@ namespace storm { bool foundPivotState = !frontierPivotStates.isZero(); if (foundPivotState) { STORM_LOG_TRACE("Picked pivot state from " << frontierPivotStates.getNonZeroCount() << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); - return PivotStateResult(frontierPivotStates.existsAbstractRepresentative(rowVariables), storm::OptimizationDirection::Minimize); + return SymbolicPivotStateResult(frontierPivotStates.existsAbstractRepresentative(rowVariables), storm::OptimizationDirection::Minimize); } else { // Otherwise, we perform a simulatenous BFS in the sense that we make one step in both the min and max // transitions and check for pivot states we encounter. @@ -195,7 +198,7 @@ namespace storm { } STORM_LOG_TRACE("Picked pivot state with difference " << diffValue << " from " << numberOfPivotStateCandidatesOnLevel << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); - return PivotStateResult(direction == storm::OptimizationDirection::Minimize ? diffMin.maxAbstractRepresentative(rowVariables) : diffMax.maxAbstractRepresentative(rowVariables), direction); + return SymbolicPivotStateResult(direction == storm::OptimizationDirection::Minimize ? diffMin.maxAbstractRepresentative(rowVariables) : diffMax.maxAbstractRepresentative(rowVariables), direction); } else { STORM_LOG_TRACE("Picked pivot state from " << numberOfPivotStateCandidatesOnLevel << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); @@ -206,18 +209,18 @@ namespace storm { direction = storm::OptimizationDirection::Maximize; } - return PivotStateResult(direction == storm::OptimizationDirection::Minimize ? frontierMinPivotStates.existsAbstractRepresentative(rowVariables) : frontierMaxPivotStates.existsAbstractRepresentative(rowVariables), direction); + return SymbolicPivotStateResult(direction == storm::OptimizationDirection::Minimize ? frontierMinPivotStates.existsAbstractRepresentative(rowVariables) : frontierMaxPivotStates.existsAbstractRepresentative(rowVariables), direction); } } } } } else { // Compute the most probable paths to the reachable states and the corresponding spanning trees. - MostProbablePathsResult minMostProbablePathsResult = getMostProbablePathSpanningTree(game, minPlayer1Strategy && minPlayer2Strategy); - MostProbablePathsResult maxMostProbablePathsResult = getMostProbablePathSpanningTree(game, maxPlayer1Strategy && maxPlayer2Strategy); + SymbolicMostProbablePathsResult minSymbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, minPlayer1Strategy && minPlayer2Strategy); + SymbolicMostProbablePathsResult maxSymbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, maxPlayer1Strategy && maxPlayer2Strategy); storm::dd::Bdd selectedPivotState; - storm::dd::Add score = pivotStates.template toAdd() * minMostProbablePathsResult.maxProbabilities.maximum(maxMostProbablePathsResult.maxProbabilities); + storm::dd::Add score = pivotStates.template toAdd() * minSymbolicMostProbablePathsResult.maxProbabilities.maximum(maxSymbolicMostProbablePathsResult.maxProbabilities); if (heuristic == AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation && quantitativeResult) { score = score * (quantitativeResult.get().max.values - quantitativeResult.get().min.values); @@ -227,15 +230,15 @@ namespace storm { storm::OptimizationDirection fromDirection = storm::OptimizationDirection::Minimize; storm::dd::Add selectedPivotStateAsAdd = selectedPivotState.template toAdd(); - if ((selectedPivotStateAsAdd * maxMostProbablePathsResult.maxProbabilities).getMax() > (selectedPivotStateAsAdd * minMostProbablePathsResult.maxProbabilities).getMax()) { + if ((selectedPivotStateAsAdd * maxSymbolicMostProbablePathsResult.maxProbabilities).getMax() > (selectedPivotStateAsAdd * minSymbolicMostProbablePathsResult.maxProbabilities).getMax()) { fromDirection = storm::OptimizationDirection::Maximize; } - return PivotStateResult(selectedPivotState, fromDirection, fromDirection == storm::OptimizationDirection::Minimize ? minMostProbablePathsResult : maxMostProbablePathsResult); + return SymbolicPivotStateResult(selectedPivotState, fromDirection, fromDirection == storm::OptimizationDirection::Minimize ? minSymbolicMostProbablePathsResult : maxSymbolicMostProbablePathsResult); } STORM_LOG_ASSERT(false, "This point must not be reached, because then no pivot state could be found."); - return PivotStateResult(storm::dd::Bdd(), storm::OptimizationDirection::Minimize); + return SymbolicPivotStateResult(storm::dd::Bdd(), storm::OptimizationDirection::Minimize); } template @@ -522,23 +525,23 @@ namespace storm { } template - boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, PivotStateResult const& pivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { + boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); // Compute the most probable path from any initial state to the pivot state. - MostProbablePathsResult mostProbablePathsResult; - if (!pivotStateResult.mostProbablePathsResult) { - mostProbablePathsResult = getMostProbablePathSpanningTree(game, pivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); + SymbolicMostProbablePathsResult symbolicMostProbablePathsResult; + if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) { + symbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); } else { - mostProbablePathsResult = pivotStateResult.mostProbablePathsResult.get(); + symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get(); } // Create a new expression manager that we can use for the interpolation. std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); // Build the trace of the most probable path in terms of which predicates hold in each step. - std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, mostProbablePathsResult.spanningTree, pivotStateResult.pivotState); + std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState); auto const& trace = traceAndVariableSubstitution.first; auto const& variableSubstitution = traceAndVariableSubstitution.second; @@ -615,11 +618,11 @@ namespace storm { STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to proceed without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - PivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); + SymbolicPivotStateResult SymbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); // // SANITY CHECK TO MAKE SURE OUR STRATEGIES ARE NOT BROKEN. // // FIXME. -// auto min1ChoiceInPivot = pivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; +// auto min1ChoiceInPivot = SymbolicPivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; // STORM_LOG_ASSERT(!min1ChoiceInPivot.isZero(), "wth?"); // bool min1ChoiceInPivotIsProb0Min = !(min1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); // bool min1ChoiceInPivotIsProb0Max = !(min1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); @@ -643,7 +646,7 @@ namespace storm { // std::cout << "max/min choice there? " << min1MinPlayer2Choice << std::endl; // std::cout << "max/max choice there? " << min1MaxPlayer2Choice << std::endl; // -// auto max1ChoiceInPivot = pivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; +// auto max1ChoiceInPivot = SymbolicPivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; // STORM_LOG_ASSERT(!max1ChoiceInPivot.isZero(), "wth?"); // bool max1ChoiceInPivotIsProb0Min = !(max1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); // bool max1ChoiceInPivotIsProb0Max = !(max1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); @@ -661,12 +664,12 @@ namespace storm { boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, pivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, SymbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, pivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, SymbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); @@ -676,6 +679,130 @@ namespace storm { return true; } + template + ExplicitMostProbablePathsResult::ExplicitMostProbablePathsResult(ValueType const& maxProbability, std::vector>&& predecessors) : maxProbability(maxProbability), predecessors(std::move(predecessors)) { + // Intentionally left empty. + } + + template + ExplicitPivotStateResult::ExplicitPivotStateResult(uint64_t pivotState, storm::OptimizationDirection fromDirection, boost::optional>&& explicitMostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), explicitMostProbablePathsResult(std::move(explicitMostProbablePathsResult)) { + // Intentionally left empty. + } + + template + ExplicitPivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) { + + // Perform Dijkstra search that stays within the relevant states and searches for a state in which the + // strategies for the (commonly chosen) player 1 action leads to a player 2 state in which the choices differ. + ExplicitPivotStateResult explicitPivotStateResult; + explicitPivotStateResult.explicitMostProbablePathsResult = ExplicitMostProbablePathsResult(); + auto& explicitMostProbablePathsResult = explicitPivotStateResult.explicitMostProbablePathsResult.get(); + + bool probabilityDistances = pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MostProbablePath; + uint64_t numberOfStates = initialStates.size(); + ValueType inftyDistance = probabilityDistances ? storm::utility::zero() : storm::utility::infinity(); + ValueType zeroDistance = probabilityDistances ? storm::utility::one() : storm::utility::zero(); + std::vector distances(numberOfStates, inftyDistance); + explicitMostProbablePathsResult.predecessors.resize(numberOfStates, std::make_pair(0, 0)); + + // Use set as priority queue with unique membership; default comparison on pair works fine if distance is + // the first entry. + std::set, std::greater>> dijkstraQueue; + + for (auto initialState : initialStates) { + if (!relevantStates.get(initialState)) { + continue; + } + + distances[initialState] = zeroDistance; + dijkstraQueue.emplace(zeroDistance, initialState); + } + + while (!dijkstraQueue.empty()) { + uint64_t currentState = (*dijkstraQueue.begin()).second; + dijkstraQueue.erase(dijkstraQueue.begin()); + + // Determine whether the current state is a pivot state. + bool isPivotState = false; + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor)) { + isPivotState = true; + } + } else if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor)) { + isPivotState = true; + } + } + + // If it is indeed a pivot state, we can abort the search here. + if (isPivotState) { + explicitPivotStateResult.pivotState = currentState; + return explicitPivotStateResult; + } + + // Otherwise, we explore all its relevant successors. + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t minPlayer2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t minPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor); + + for (auto const& entry : transitionMatrix.getRow(minPlayer2Choice)) { + uint64_t player1Successor = entry.getColumn(); + if (!relevantStates.get(player1Successor)) { + continue; + } + + ValueType alternateDistance = probabilityDistances ? distances[currentState] * entry.getValue() : distances[currentState] + storm::utility::one(); + if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { + distances[player1Successor] = alternateDistance; + explicitMostProbablePathsResult.predecessors[player1Successor] = std::make_pair(currentState, minPlayer2Successor); + dijkstraQueue.emplace(alternateDistance, player1Successor); + } + } + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t maxPlayer2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t maxPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor); + + for (auto const& entry : transitionMatrix.getRow(maxPlayer2Choice)) { + uint64_t player1Successor = entry.getColumn(); + if (!relevantStates.get(player1Successor)) { + continue; + } + + ValueType alternateDistance = probabilityDistances ? distances[currentState] * entry.getValue() : distances[currentState] + storm::utility::one(); + if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { + distances[player1Successor] = alternateDistance; + explicitMostProbablePathsResult.predecessors[player1Successor] = std::make_pair(currentState, maxPlayer2Successor); + dijkstraQueue.emplace(alternateDistance, player1Successor); + } + } + } + } + + // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, + // which can happen when trying to refine using the qualitative result only. + return explicitPivotStateResult; + } + + template + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + + // Compute the set of states whose result we have for the min and max case. + storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); + + ExplicitPivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, transitionMatrix, player1Grouping, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + + // If there was no pivot state, continue the search. + if (!pivotStateResult.pivotState) { + return false; + } + + // Otherwise, we can refine. + storm::dd::Bdd pivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotStateResult.pivotState.get(), odd, game.getRowVariables()); + } + template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQuantitativeGameResultMinMax const& quantitativeResult) const { STORM_LOG_TRACE("Refining after quantitative check."); @@ -691,16 +818,16 @@ namespace storm { STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to refine without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - PivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); + SymbolicPivotStateResult SymbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, pivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, SymbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, pivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, SymbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index ed3589ac6..7a912e947 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -21,6 +21,14 @@ #include "storm/utility/solver.h" namespace storm { + namespace dd { + class Odd; + } + + namespace storage { + class BitVector; + } + namespace abstraction { template @@ -48,23 +56,48 @@ namespace storm { }; template - struct MostProbablePathsResult { - MostProbablePathsResult() = default; - MostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree); + struct SymbolicMostProbablePathsResult { + SymbolicMostProbablePathsResult() = default; + SymbolicMostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree); storm::dd::Add maxProbabilities; storm::dd::Bdd spanningTree; }; template - struct PivotStateResult { - PivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& mostProbablePathsResult = boost::none); + struct SymbolicPivotStateResult { + SymbolicPivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& symbolicMostProbablePathsResult = boost::none); storm::dd::Bdd pivotState; storm::OptimizationDirection fromDirection; - boost::optional> mostProbablePathsResult; + boost::optional> symbolicMostProbablePathsResult; + }; + + template + struct ExplicitMostProbablePathsResult { + ExplicitMostProbablePathsResult() = default; + ExplicitMostProbablePathsResult(ValueType const& maxProbability, std::vector>&& predecessors); + + /// The maximal probability with which the state in question is reached. + ValueType maxProbability; + + /// The predecessors for the states to obtain this probability. + std::vector> predecessors; + }; + + template + struct ExplicitPivotStateResult { + ExplicitPivotStateResult() = default; + ExplicitPivotStateResult(uint64_t pivotState, storm::OptimizationDirection fromDirection, boost::optional>&& explicitMostProbablePathsResult = boost::none); + + boost::optional pivotState; + storm::OptimizationDirection fromDirection; + boost::optional> explicitMostProbablePathsResult; }; + class ExplicitQualitativeGameResultMinMax; + class ExplicitGameStrategyPair; + template class MenuGameRefiner { public: @@ -86,7 +119,14 @@ namespace storm { * @param True if predicates for refinement could be derived, false otherwise. */ bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const; - + + /*! + * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. + * + * @param True if predicates for refinement could be derived, false otherwise. + */ + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const; + /*! * Refines the abstractor based on the quantitative result by trying to derive suitable predicates. * @@ -113,7 +153,7 @@ namespace storm { */ std::vector createGlobalRefinement(std::vector const& predicates) const; - boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, PivotStateResult const& pivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; + boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& spanningTree, storm::dd::Bdd const& pivotState) const; void performRefinement(std::vector const& refinementCommands) const; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 09782e9fd..215aeb780 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -61,10 +61,10 @@ namespace storm { totalNumberOfCommands += automaton.getNumberOfEdges(); } - // NOTE: currently we assume that 100 player 2 variables suffice, which corresponds to 2^100 possible + // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible // choices. If for some reason this should not be enough, we could grow this vector dynamically, but // odds are that it's impossible to treat such models in any event. - abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 100, static_cast(std::ceil(std::log2(maximalUpdateCount)))); + abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 64, static_cast(std::ceil(std::log2(maximalUpdateCount)))); // For each module of the concrete program, we create an abstract counterpart. bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 9da47fee3..99dc2c5a2 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -58,10 +58,10 @@ namespace storm { totalNumberOfCommands += module.getNumberOfCommands(); } - // NOTE: currently we assume that 100 player 2 variables suffice, which corresponds to 2^100 possible + // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible // choices. If for some reason this should not be enough, we could grow this vector dynamically, but // odds are that it's impossible to treat such models in any event. - abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 100, static_cast(std::ceil(std::log2(maximalUpdateCount)))); + abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 64, static_cast(std::ceil(std::log2(maximalUpdateCount)))); // For each module of the concrete program, we create an abstract counterpart. bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 9119c498f..2b2980e95 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -24,6 +24,7 @@ #include "storm/abstraction/prism/PrismMenuGameAbstractor.h" #include "storm/abstraction/jani/JaniMenuGameAbstractor.h" #include "storm/abstraction/MenuGameRefiner.h" +#include "storm/abstraction/ExplicitGameStrategyPair.h" #include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" @@ -174,6 +175,53 @@ namespace storm { } return result; } + + template + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& prob0, storm::storage::BitVector const& prob1) { + std::unique_ptr result; + + if (checkTask.isBoundSet()) { + // Despite having a bound, we create a quantitative result so that the next layer can perform the comparison. + + if (player2Direction == storm::OptimizationDirection::Minimize) { + if (storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { + if (initialStates.isSubsetOf(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } + } else { + if (!initialStates.isDisjointFrom(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } + } + } else if (player2Direction == storm::OptimizationDirection::Maximize) { + if (!storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { + if (initialStates.isSubsetOf(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } + } else { + if (!initialStates.isDisjointFrom(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } + } + } + } + + return result; + } + + template + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::storage::BitVector const& initialStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult) { + // Check whether we can already give the answer based on the current information. + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); + if (result) { + return result; + } + result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Maximize, initialStates, qualitativeResult.prob0Max.getPlayer1States(), qualitativeResult.prob1Max.getPlayer1States()); + if (result) { + return result; + } + return result; + } template std::unique_ptr checkForResultAfterQuantitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection const& player2Direction, std::pair const& initialValueRange) { @@ -506,7 +554,7 @@ namespace storm { // Return null to indicate no result has been found yet. return nullptr; } - + template std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional& previousQualitativeResult) { STORM_LOG_TRACE("Using sparse solving."); @@ -514,22 +562,24 @@ namespace storm { // (0) Start by transforming the necessary symbolic elements to explicit ones. storm::dd::Odd odd = game.getReachableStates().createOdd(); - std::pair, std::vector> transitionMatrixAndLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), game.getPlayer1Variables(), odd, odd, true); - auto& transitionMatrix = transitionMatrixAndLabeling.first; - auto& labeling = transitionMatrixAndLabeling.second; - + std::vector> labelingVariableSets = {game.getPlayer1Variables(), game.getPlayer2Variables()}; + typename storm::dd::Add::MatrixAndLabeling matrixAndLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), odd, odd, labelingVariableSets); + auto& transitionMatrix = matrixAndLabeling.matrix; + auto& player1Labeling = matrixAndLabeling.labelings.front(); + auto& player2Labeling = matrixAndLabeling.labelings.back(); + // Create the player 2 row grouping from the labeling. std::vector tmpPlayer2RowGrouping; for (uint64_t player1State = 0; player1State < transitionMatrix.getRowGroupCount(); ++player1State) { uint64_t lastLabel = std::numeric_limits::max(); for (uint64_t row = transitionMatrix.getRowGroupIndices()[player1State]; row < transitionMatrix.getRowGroupIndices()[player1State + 1]; ++row) { - if (labeling[row] != lastLabel) { + if (player1Labeling[row] != lastLabel) { tmpPlayer2RowGrouping.emplace_back(row); - lastLabel = labeling[row]; + lastLabel = player1Labeling[row]; } } } - tmpPlayer2RowGrouping.emplace_back(labeling.size()); + tmpPlayer2RowGrouping.emplace_back(player1Labeling.size()); std::vector player1RowGrouping = transitionMatrix.swapRowGroupIndices(std::move(tmpPlayer2RowGrouping)); auto const& player2RowGrouping = transitionMatrix.getRowGroupIndices(); @@ -548,17 +598,22 @@ namespace storm { player1Groups[player1State + 1] = player2State; } + // Create explicit representations of important state sets. storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); + // Prepare the two strategies. + abstraction::ExplicitGameStrategyPair minStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); + abstraction::ExplicitGameStrategyPair maxStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); + // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). auto qualitativeStart = std::chrono::high_resolution_clock::now(); - ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates); -// std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); -// if (result) { -// return result; -// } + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, minStrategyPair, maxStrategyPair); + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + if (result) { + return result; + } auto qualitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); @@ -568,6 +623,31 @@ namespace storm { // std::cout << constraintStates << std::endl; // std::cout << targetStates << std::endl; + // (2) compute the states for which we have to determine quantitative information. + storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()); + storm::storage::BitVector maybeMax = ~(qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); + + // (3) if the initial states are not maybe states, then we can refine at this point. + storm::storage::BitVector initialMaybeStates = initialStates & (maybeMin | maybeMax); + bool qualitativeRefinement = false; + if (initialMaybeStates.empty()) { + // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. + STORM_LOG_TRACE("No initial state is a 'maybe' state."); + + STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + + // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) + // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. + auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); + qualitativeRefinement = refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + } else if (initialStates.isSubsetOf(initialMaybeStates) && checkTask.isQualitativeSet()) { + // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, + // we can return the result here. + return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); + } + return nullptr; } @@ -630,7 +710,7 @@ namespace storm { } template - ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates) { + ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair) { ExplicitQualitativeGameResultMinMax result; @@ -679,10 +759,10 @@ namespace storm { // result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MaxMaxMdp)); // } // } else { - result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); - result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); - result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); - result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair.getPlayer1Strategy(), &minStrategyPair.getPlayer2Strategy()); + result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair.getPlayer1Strategy(), &minStrategyPair.getPlayer2Strategy()); + result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair.getPlayer1Strategy(), &maxStrategyPair.getPlayer2Strategy()); + result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair.getPlayer1Strategy(), &maxStrategyPair.getPlayer2Strategy()); // } STORM_LOG_TRACE("Qualitative precomputation completed."); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 933e0bf5d..a2f4e53f0 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -39,6 +39,8 @@ namespace storm { class ExplicitQualitativeGameResult; class ExplicitQualitativeGameResultMinMax; + class ExplicitGameStrategy; + class ExplicitGameStrategyPair; } namespace modelchecker { @@ -92,7 +94,7 @@ namespace storm { */ SymbolicQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); - ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates); + ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const; diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 75552108e..7f1cb1517 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -704,16 +704,18 @@ namespace storm { } // Create the canonical row group sizes and build the matrix. - return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, groupMetaVariables, rowOdd, columnOdd).first; + return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd).matrix; } template - std::pair, std::vector> Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, std::set const& labelMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling) const { + typename Add::MatrixAndLabeling Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, std::vector> const& labelMetaVariables) const { std::vector ddRowVariableIndices; std::vector ddColumnVariableIndices; std::vector ddGroupVariableIndices; - storm::storage::BitVector ddLabelVariableIndices; + std::vector ddLabelVariableIndicesVector; std::set rowAndColumnMetaVariables; + bool buildLabeling = !labelMetaVariables.empty(); + MatrixAndLabeling result; for (auto const& variable : rowMetaVariables) { DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); @@ -739,21 +741,23 @@ namespace storm { } std::sort(ddGroupVariableIndices.begin(), ddGroupVariableIndices.end()); if (buildLabeling) { - std::set ddLabelVariableIndicesSet; - for (auto const& variable : labelMetaVariables) { - DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); - for (auto const& ddVariable : metaVariable.getDdVariables()) { - ddLabelVariableIndicesSet.insert(ddVariable.getIndex()); + for (auto const& labelMetaVariableSet : labelMetaVariables) { + std::set ddLabelVariableIndicesSet; + for (auto const& variable : labelMetaVariableSet) { + DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); + for (auto const& ddVariable : metaVariable.getDdVariables()) { + ddLabelVariableIndicesSet.insert(ddVariable.getIndex()); + } } - } - - ddLabelVariableIndices = storm::storage::BitVector(ddGroupVariableIndices.size()); - uint64_t position = 0; - for (auto const& index : ddGroupVariableIndices) { - if (ddLabelVariableIndicesSet.find(index) != ddLabelVariableIndicesSet.end()) { - ddLabelVariableIndices.set(position); + + ddLabelVariableIndicesVector.emplace_back(ddGroupVariableIndices.size()); + uint64_t position = 0; + for (auto const& index : ddGroupVariableIndices) { + if (ddLabelVariableIndicesSet.find(index) != ddLabelVariableIndicesSet.end()) { + ddLabelVariableIndicesVector.back().set(position); + } + ++position; } - ++position; } } @@ -781,10 +785,12 @@ namespace storm { } // Create the group labelings if requested. - std::vector groupLabels; + std::vector> groupLabelings; if (buildLabeling) { - groupLabels = internalAdd.decodeGroupLabels(ddGroupVariableIndices, ddLabelVariableIndices); - STORM_LOG_ASSERT(groupLabels.size() == groups.size(), "Mismatching label sizes."); + for (auto const& ddLabelVariableIndices : ddLabelVariableIndicesVector) { + groupLabelings.emplace_back(internalAdd.decodeGroupLabels(ddGroupVariableIndices, ddLabelVariableIndices)); + STORM_LOG_ASSERT(groupLabelings.back().size() == groups.size(), "Mismatching label sizes."); + } } // Create the actual storage for the non-zero entries. @@ -793,9 +799,10 @@ namespace storm { // Now compute the indices at which the individual rows start. std::vector rowIndications(rowGroupIndices.back() + 1); - std::vector labeling; if (buildLabeling) { - labeling.resize(rowGroupIndices.back()); + for (uint64_t i = 0; i < labelMetaVariables.size(); ++i) { + result.labelings.emplace_back(rowGroupIndices.back()); + } } std::vector> statesWithGroupEnabled(groups.size()); @@ -811,8 +818,10 @@ namespace storm { statesWithGroupEnabled[i] = groupNotZero.existsAbstract(columnMetaVariables).template toAdd(); if (buildLabeling) { - uint64_t currentLabel = groupLabels[i]; - statesWithGroupEnabled[i].forEach(rowOdd, ddRowVariableIndices, [currentLabel, &rowGroupIndices, &labeling] (uint64_t const& offset, uint_fast64_t const& value) { labeling[rowGroupIndices[offset]] = currentLabel; }); + for (uint64_t j = 0; j < labelMetaVariables.size(); ++j) { + uint64_t currentLabel = groupLabelings[j][i]; + statesWithGroupEnabled[i].forEach(rowOdd, ddRowVariableIndices, [currentLabel, &rowGroupIndices, &result, j] (uint64_t const& offset, uint_fast64_t const& value) { result.labelings[j][rowGroupIndices[offset]] = currentLabel; }); + } } statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus()); } @@ -847,8 +856,10 @@ namespace storm { rowIndications[i] = rowIndications[i - 1]; } rowIndications[0] = 0; - - return std::make_pair(storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)), labeling); + + // Move-construct matrix and return. + result.matrix = storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); + return result; } template diff --git a/src/storm/storage/dd/Add.h b/src/storm/storage/dd/Add.h index ba6b5644d..94a512482 100644 --- a/src/storm/storage/dd/Add.h +++ b/src/storm/storage/dd/Add.h @@ -655,7 +655,22 @@ namespace storm { * @return The matrix that is represented by this ADD and a vector corresponding to row labeling * (if requested). */ - std::pair, std::vector> toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, std::set const& labelMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, bool buildLabeling = false) const; + struct MatrixAndLabeling { + MatrixAndLabeling() = default; + + MatrixAndLabeling(storm::storage::SparseMatrix const& matrix) : matrix(matrix) { + // Intentionally left empty. + } + + MatrixAndLabeling(storm::storage::SparseMatrix&& matrix) : matrix(std::move(matrix)) { + // Intentionally left empty. + } + + storm::storage::SparseMatrix matrix; + std::vector> labelings; + }; + + MatrixAndLabeling toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, std::vector> const& labelMetaVariables = std::vector>()) const; /*! * Converts the ADD to a row-grouped (sparse) matrix and the given vector to a row-grouped vector. diff --git a/src/storm/storage/dd/Bdd.cpp b/src/storm/storage/dd/Bdd.cpp index c2452ed3b..5271a628a 100644 --- a/src/storm/storage/dd/Bdd.cpp +++ b/src/storm/storage/dd/Bdd.cpp @@ -63,6 +63,11 @@ namespace storm { return Bdd(ddManager, InternalBdd::fromVector(&ddManager.getInternalDdManager(), odd, ddManager.getSortedVariableIndices(metaVariables), [&truthValues] (uint64_t offset) { return truthValues[offset]; } ), metaVariables); } + template + Bdd Bdd::getEncoding(DdManager const& ddManager, uint64_t targetOffset, storm::dd::Odd const& odd, std::set const& metaVariables) { + return Bdd(ddManager, InternalBdd::fromVector(&ddManager.getInternalDdManager(), odd, ddManager.getSortedVariableIndices(metaVariables), [targetOffset] (uint64_t offset) { return offset == targetOffset; }), metaVariables); + } + template bool Bdd::operator==(Bdd const& other) const { return internalBdd == other.internalBdd; diff --git a/src/storm/storage/dd/Bdd.h b/src/storm/storage/dd/Bdd.h index bfb845c70..9e36ba52b 100644 --- a/src/storm/storage/dd/Bdd.h +++ b/src/storm/storage/dd/Bdd.h @@ -45,6 +45,16 @@ namespace storm { Bdd(Bdd&& other) = default; Bdd& operator=(Bdd&& other) = default; + /*! + * Constructs the BDD representation of the encoding with the given offset. + * + * @param ddManager The DD manager responsible for the resulting BDD. + * @param targetOffset The offset to encode (interpreted within the ODD). + * @param odd The ODD used for the translation from the explicit representation to a symbolic one. + * @param metaVariables The meta variables to use for the symbolic encoding. + */ + static Bdd getEncoding(DdManager const& ddManager, uint64_t targetOffset, storm::dd::Odd const& odd, std::set const& metaVariables); + /*! * Constructs a BDD representation of all encodings whose value is true in the given list of truth values. * diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 423641dc2..9fcd19b74 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -9,6 +9,7 @@ #include "storm/storage/dd/Add.h" #include "storm/storage/dd/DdManager.h" +#include "storm/abstraction/ExplicitGameStrategy.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/models/symbolic/DeterministicModel.h" @@ -1084,7 +1085,7 @@ namespace storm { } template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy) { + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy) { ExplicitGameProb01Result result(psiStates, storm::storage::BitVector(transitionMatrix.getRowGroupCount())); @@ -1102,7 +1103,7 @@ namespace storm { uint64_t player2Predecessor = player2PredecessorEntry.getColumn(); if (!result.player2States.get(player2Predecessor)) { bool addPlayer2State = false; - if (player2Strategy == OptimizationDirection::Minimize) { + if (player2Direction == OptimizationDirection::Minimize) { bool allChoicesHavePlayer1State = true; for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2Predecessor]; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { bool choiceHasPlayer1State = false; @@ -1132,7 +1133,7 @@ namespace storm { if (!result.player1States.get(player1Predecessor)) { bool addPlayer1State = false; - if (player1Strategy == OptimizationDirection::Minimize) { + if (player1Direction == OptimizationDirection::Minimize) { bool allPlayer2Successors = true; for (uint64_t player2State = player1Groups[player1Predecessor]; player2State < player1Groups[player1Predecessor + 1]; ++player2State) { if (!result.player2States.get(player2State)) { @@ -1162,36 +1163,31 @@ namespace storm { result.player2States.complement(); // Generate player 1 strategy if required. - if (producePlayer1Strategy) { - result.player1Strategy = std::vector(result.player1States.size()); - + if (player1Strategy) { for (auto player1State : result.player1States) { - if (player1Strategy == storm::OptimizationDirection::Minimize) { + if (player1Direction == storm::OptimizationDirection::Minimize) { // At least one player 2 successor is a state with probability 0, find it. bool foundProb0Successor = false; uint64_t player2State; for (player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) { if (result.player2States.get(player2State)) { - result.player1Strategy.get()[player1State] = player2State; foundProb0Successor = true; break; } } STORM_LOG_ASSERT(foundProb0Successor, "Expected at least one state 2 successor with probability 0."); - result.player1Strategy.get()[player1State] = player2State; + player1Strategy->setChoice(player1State, player2State); } else { // Since all player 2 successors are states with probability 0, just pick any. - result.player1Strategy.get()[player1State] = player1Groups[player1State]; + player1Strategy->setChoice(player1State, player1Groups[player1State]); } } } // Generate player 2 strategy if required. - if (producePlayer2Strategy) { - result.player2Strategy = std::vector(result.player2States.size()); - + if (player2Strategy) { for (auto player2State : result.player2States) { - if (player2Strategy == storm::OptimizationDirection::Minimize) { + if (player2Direction == storm::OptimizationDirection::Minimize) { // At least one distribution only has successors with probability 0, find it. bool foundProb0SuccessorDistribution = false; @@ -1211,10 +1207,10 @@ namespace storm { } STORM_LOG_ASSERT(foundProb0SuccessorDistribution, "Expected at least one distribution with only successors with probability 0."); - result.player2Strategy.get()[player2State] = row; + player2Strategy->setChoice(player2State, row); } else { // Since all player 1 successors are states with probability 0, just pick any. - result.player2Strategy.get()[player2State] = transitionMatrix.getRowGroupIndices()[player2State]; + player2Strategy->setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State]); } } } @@ -1290,7 +1286,7 @@ namespace storm { } template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates) { + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy, boost::optional const& player1Candidates) { // During the execution, the two state sets in the result hold the potential player 1/2 states. ExplicitGameProb01Result result; @@ -1314,16 +1310,6 @@ namespace storm { stack.clear(); stack.insert(stack.end(), psiStates.begin(), psiStates.end()); - // If we are to produce strategies in this iteration, we prepare some storage. - if (produceStrategiesInIteration) { - if (producePlayer1Strategy) { - result.player1Strategy = std::vector(result.player1States.size()); - } - if (producePlayer2Strategy) { - result.player2Strategy = std::vector(result.player2States.size()); - } - } - // Perform the actual DFS. uint_fast64_t currentState; while (!stack.empty()) { @@ -1333,7 +1319,7 @@ namespace storm { for (auto player2PredecessorEntry : player1BackwardTransitions.getRow(currentState)) { uint64_t player2Predecessor = player2PredecessorEntry.getColumn(); if (!player2Solution.get(player2PredecessorEntry.getColumn())) { - bool addPlayer2State = player2Strategy == storm::OptimizationDirection::Minimize ? true : false; + bool addPlayer2State = player2Direction == storm::OptimizationDirection::Minimize ? true : false; uint64_t validChoice = transitionMatrix.getRowGroupIndices()[player2Predecessor]; for (uint64_t row = validChoice; row < transitionMatrix.getRowGroupIndices()[player2Predecessor + 1]; ++row) { @@ -1350,12 +1336,12 @@ namespace storm { } if (choiceHasSolutionSuccessor && choiceStaysInMaybeStates) { - if (player2Strategy == storm::OptimizationDirection::Maximize) { + if (player2Direction == storm::OptimizationDirection::Maximize) { validChoice = row; addPlayer2State = true; break; } - } else if (player2Strategy == storm::OptimizationDirection::Minimize) { + } else if (player2Direction == storm::OptimizationDirection::Minimize) { addPlayer2State = false; break; } @@ -1363,8 +1349,8 @@ namespace storm { if (addPlayer2State) { player2Solution.set(player2Predecessor); - if (produceStrategiesInIteration && producePlayer2Strategy) { - result.player2Strategy.get()[player2Predecessor] = validChoice; + if (produceStrategiesInIteration && player2Strategy) { + player2Strategy->setChoice(player2Predecessor, validChoice); } // Check whether the addition of the player 2 state changes the state of the (single) @@ -1372,17 +1358,17 @@ namespace storm { uint64_t player1Predecessor = player2BackwardTransitions[player2Predecessor]; if (!player1Solution.get(player1Predecessor)) { - bool addPlayer1State = player1Strategy == storm::OptimizationDirection::Minimize ? true : false; + bool addPlayer1State = player1Direction == storm::OptimizationDirection::Minimize ? true : false; validChoice = player1Groups[player1Predecessor]; for (uint64_t player2Successor = validChoice; player2Successor < player1Groups[player1Predecessor + 1]; ++player2Successor) { if (player2Solution.get(player2Successor)) { - if (player1Strategy == storm::OptimizationDirection::Maximize) { + if (player1Direction == storm::OptimizationDirection::Maximize) { validChoice = player2Successor; addPlayer1State = true; break; } - } else if (player1Strategy == storm::OptimizationDirection::Minimize) { + } else if (player1Direction == storm::OptimizationDirection::Minimize) { addPlayer1State = false; break; } @@ -1391,8 +1377,8 @@ namespace storm { if (addPlayer1State) { player1Solution.set(player1Predecessor); - if (produceStrategiesInIteration && producePlayer1Strategy) { - result.player1Strategy.get()[player1Predecessor] = validChoice; + if (produceStrategiesInIteration && player1Strategy) { + player1Strategy->setChoice(player1Predecessor, validChoice); } stack.emplace_back(player1Predecessor); @@ -1690,9 +1676,9 @@ namespace storm { template std::pair performProb01Min(storm::models::sparse::NondeterministicModel> const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); #endif - template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); + template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy); - template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional const& player1Candidates); + template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy, boost::optional const& player1Candidates); template std::vector getTopologicalSort(storm::storage::SparseMatrix const& matrix) ; diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index 2e37d0318..e99fd0ba6 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -49,6 +49,9 @@ namespace storm { } + namespace abstraction { + class ExplicitGameStrategy; + } namespace utility { namespace graph { @@ -621,34 +624,10 @@ namespace storm { // Intentionally left empty. } - ExplicitGameProb01Result(storm::storage::BitVector const& player1States, storm::storage::BitVector const& player2States, boost::optional> const& player1Strategy = boost::none, boost::optional> const& player2Strategy = boost::none) : player1States(player1States), player2States(player2States), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { + ExplicitGameProb01Result(storm::storage::BitVector const& player1States, storm::storage::BitVector const& player2States) : player1States(player1States), player2States(player2States) { // Intentionally left empty. } - bool hasPlayer1Strategy() const { - return static_cast(player1Strategy); - } - - std::vector const& getPlayer1Strategy() const { - return player1Strategy.get(); - } - - boost::optional> const& getOptionalPlayer1Strategy() { - return player1Strategy; - } - - bool hasPlayer2Strategy() const { - return static_cast(player2Strategy); - } - - std::vector const& getPlayer2Strategy() const { - return player2Strategy.get(); - } - - boost::optional> const& getOptionalPlayer2Strategy() { - return player2Strategy; - } - storm::storage::BitVector const& getPlayer1States() const { return player1States; } @@ -659,8 +638,6 @@ namespace storm { storm::storage::BitVector player1States; storm::storage::BitVector player2States; - boost::optional> player1Strategy; - boost::optional> player2Strategy; }; /*! @@ -672,11 +649,15 @@ namespace storm { * @param player2BackwardTransitions The backward transitions (player 2 to player 1). * @param phiStates The phi states of the model. * @param psiStates The psi states of the model. - * @param producePlayer1Strategy A flag indicating whether the strategy of player 1 shall be produced. - * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. + * @param player1Direction The optimization direction of player 1. + * @param player2Direction The optimization direction of player 2. + * @param player1Strategy If not null, a player 1 strategy is synthesized and the corresponding choices + * are written to this strategy. + * @param player2Strategy If not null, a player 2 strategy is synthesized and the corresponding choices + * are written to this strategy. */ template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false); + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy = nullptr, storm::abstraction::ExplicitGameStrategy* player2Strategy = nullptr); /*! * Computes the set of states that have probability 1 given the strategies of the two players. @@ -687,12 +668,16 @@ namespace storm { * @param player2BackwardTransitions The backward transitions (player 2 to player 1). * @param phiStates The phi states of the model. * @param psiStates The psi states of the model. - * @param producePlayer1Strategy A flag indicating whether the strategy of player 1 shall be produced. - * @param producePlayer2Strategy A flag indicating whether the strategy of player 2 shall be produced. + * @param player1Direction The optimization direction of player 1. + * @param player2Direction The optimization direction of player 2. + * @param player1Strategy If not null, a player 1 strategy is synthesized and the corresponding choices + * are written to this strategy. + * @param player2Strategy If not null, a player 2 strategy is synthesized and the corresponding choices + * are written to this strategy. * @param player1Candidates If given, this set constrains the candidates of player 1 states that are considered. */ template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy = false, bool producePlayer2Strategy = false, boost::optional const& player1Candidates = boost::none); + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy = nullptr, storm::abstraction::ExplicitGameStrategy* player2Strategy = nullptr, boost::optional const& player1Candidates = boost::none); /*! * Performs a topological sort of the states of the system according to the given transitions. From c2e646b887c05dda312a498360f360dbe76ecc4d Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 26 Mar 2018 22:30:36 +0200 Subject: [PATCH 208/647] working towards predicate synthesis from explicit (qualitative) result for game-based abstraction --- .../abstraction/ExplicitGameStrategy.cpp | 19 ++ src/storm/abstraction/ExplicitGameStrategy.h | 5 +- .../abstraction/ExplicitGameStrategyPair.cpp | 6 + .../abstraction/ExplicitGameStrategyPair.h | 3 + src/storm/abstraction/MenuGameRefiner.cpp | 189 ++++++++++++------ src/storm/abstraction/MenuGameRefiner.h | 26 +-- .../abstraction/GameBasedMdpModelChecker.cpp | 12 ++ src/storm/storage/dd/Odd.cpp | 22 ++ src/storm/storage/dd/Odd.h | 13 ++ src/storm/utility/graph.cpp | 6 +- 10 files changed, 225 insertions(+), 76 deletions(-) diff --git a/src/storm/abstraction/ExplicitGameStrategy.cpp b/src/storm/abstraction/ExplicitGameStrategy.cpp index 642c274b7..2703ac3a5 100644 --- a/src/storm/abstraction/ExplicitGameStrategy.cpp +++ b/src/storm/abstraction/ExplicitGameStrategy.cpp @@ -35,5 +35,24 @@ namespace storm { } } + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategy const& strategy) { + std::vector undefinedStates; + for (uint64_t state = 0; state < strategy.getNumberOfStates(); ++state) { + uint64_t choice = strategy.getChoice(state); + if (choice == ExplicitGameStrategy::UNDEFINED) { + undefinedStates.emplace_back(state); + } else { + out << state << " -> " << choice << std::endl; + } + } + out << "undefined states: "; + for (auto state : undefinedStates) { + out << state << ", "; + } + out << std::endl; + + return out; + } + } } diff --git a/src/storm/abstraction/ExplicitGameStrategy.h b/src/storm/abstraction/ExplicitGameStrategy.h index 8315e9101..aabe6226f 100644 --- a/src/storm/abstraction/ExplicitGameStrategy.h +++ b/src/storm/abstraction/ExplicitGameStrategy.h @@ -2,6 +2,7 @@ #include #include +#include namespace storm { namespace abstraction { @@ -18,10 +19,12 @@ namespace storm { void setChoice(uint64_t state, uint64_t choice); bool hasDefinedChoice(uint64_t state) const; void undefineAll(); - + private: std::vector choices; }; + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategy const& strategy); + } } diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.cpp b/src/storm/abstraction/ExplicitGameStrategyPair.cpp index d773f9ec5..9f42ea642 100644 --- a/src/storm/abstraction/ExplicitGameStrategyPair.cpp +++ b/src/storm/abstraction/ExplicitGameStrategyPair.cpp @@ -27,5 +27,11 @@ namespace storm { return player2Strategy; } + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategyPair const& strategyPair) { + out << "player 1 strategy: " << std::endl << strategyPair.getPlayer1Strategy() << std::endl; + out << "player 2 strategy: " << std::endl << strategyPair.getPlayer2Strategy() << std::endl; + return out; + } + } } diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.h b/src/storm/abstraction/ExplicitGameStrategyPair.h index 6449c3ddd..e5774d7e1 100644 --- a/src/storm/abstraction/ExplicitGameStrategyPair.h +++ b/src/storm/abstraction/ExplicitGameStrategyPair.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "storm/abstraction/ExplicitGameStrategy.h" @@ -22,5 +23,7 @@ namespace storm { ExplicitGameStrategy player2Strategy; }; + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategyPair const& strategyPair); + } } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 6b83338e7..a5d1f647e 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -394,9 +394,12 @@ namespace storm { // Derive predicates from lower choice. storm::dd::Bdd lowerChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; + lowerChoice.template toAdd().exportToDot("lower.dot"); storm::dd::Bdd lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); + lowerChoice1.template toAdd().exportToDot("lower1.dot"); storm::dd::Bdd lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - + lowerChoice2.template toAdd().exportToDot("lower2.dot"); + bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero(); if (lowerChoicesDifferent) { STORM_LOG_TRACE("Deriving predicate based on lower choice."); @@ -523,30 +526,12 @@ namespace storm { predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution)); return std::make_pair(predicates, stepVariableToCopiedVariableMap); } - - template - boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { - - AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); - - // Compute the most probable path from any initial state to the pivot state. - SymbolicMostProbablePathsResult symbolicMostProbablePathsResult; - if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) { - symbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); - } else { - symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get(); - } - - // Create a new expression manager that we can use for the interpolation. - std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); - - // Build the trace of the most probable path in terms of which predicates hold in each step. - std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState); - auto const& trace = traceAndVariableSubstitution.first; - auto const& variableSubstitution = traceAndVariableSubstitution.second; + + template + boost::optional derivePredicatesFromInterpolation(storm::expressions::ExpressionManager& interpolationManager, AbstractionInformation const& abstractionInformation, std::vector> const& trace, std::map const& variableSubstitution) { // Create solver and interpolation groups. - storm::solver::MathsatSmtSolver interpolatingSolver(*interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); + storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); uint64_t stepCounter = 0; auto traceIt = trace.rbegin(); auto traceIte = trace.rend(); @@ -559,7 +544,7 @@ namespace storm { interpolatingSolver.add(predicate); } ++stepCounter; - + storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); // If the result already became unsatisfiable if (result == storm::solver::SmtSolver::CheckResult::Unsat) { @@ -591,6 +576,33 @@ namespace storm { return boost::none; } + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { + + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + + // Compute the most probable path from any initial state to the pivot state. + SymbolicMostProbablePathsResult symbolicMostProbablePathsResult; + if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) { + symbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); + } else { + symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get(); + } + + // Create a new expression manager that we can use for the interpolation. + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Build the trace of the most probable path in terms of which predicates hold in each step. + std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState); + + return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const { + // TODO. + } + template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const { STORM_LOG_TRACE("Trying refinement after qualitative check."); @@ -613,6 +625,7 @@ namespace storm { // strategies and they differ. Hence, it is possible that we arrive at a point where no suitable pivot state // is found. In this case, we abort the qualitative refinement here. if (pivotStateCandidatesResult.pivotStates.isZero()) { + STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); return false; } STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to proceed without pivot state candidates."); @@ -680,35 +693,25 @@ namespace storm { } template - ExplicitMostProbablePathsResult::ExplicitMostProbablePathsResult(ValueType const& maxProbability, std::vector>&& predecessors) : maxProbability(maxProbability), predecessors(std::move(predecessors)) { - // Intentionally left empty. - } - - template - ExplicitPivotStateResult::ExplicitPivotStateResult(uint64_t pivotState, storm::OptimizationDirection fromDirection, boost::optional>&& explicitMostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), explicitMostProbablePathsResult(std::move(explicitMostProbablePathsResult)) { - // Intentionally left empty. - } - - template - ExplicitPivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) { + boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) { // Perform Dijkstra search that stays within the relevant states and searches for a state in which the // strategies for the (commonly chosen) player 1 action leads to a player 2 state in which the choices differ. - ExplicitPivotStateResult explicitPivotStateResult; - explicitPivotStateResult.explicitMostProbablePathsResult = ExplicitMostProbablePathsResult(); - auto& explicitMostProbablePathsResult = explicitPivotStateResult.explicitMostProbablePathsResult.get(); + ExplicitPivotStateResult result; bool probabilityDistances = pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MostProbablePath; uint64_t numberOfStates = initialStates.size(); ValueType inftyDistance = probabilityDistances ? storm::utility::zero() : storm::utility::infinity(); ValueType zeroDistance = probabilityDistances ? storm::utility::one() : storm::utility::zero(); std::vector distances(numberOfStates, inftyDistance); - explicitMostProbablePathsResult.predecessors.resize(numberOfStates, std::make_pair(0, 0)); + if (generatePredecessors) { + result.predecessors.resize(numberOfStates, std::make_pair(0, 0)); + } // Use set as priority queue with unique membership; default comparison on pair works fine if distance is // the first entry. std::set, std::greater>> dijkstraQueue; - + for (auto initialState : initialStates) { if (!relevantStates.get(initialState)) { continue; @@ -718,28 +721,44 @@ namespace storm { dijkstraQueue.emplace(zeroDistance, initialState); } + // For some heuristics, we need to potentially find more than just one pivot. + bool foundPivotState = false; + ValueType maximalDeviation = storm::utility::zero(); + while (!dijkstraQueue.empty()) { - uint64_t currentState = (*dijkstraQueue.begin()).second; + auto distanceStatePair = *dijkstraQueue.begin(); + uint64_t currentState = distanceStatePair.second; + ValueType currentDistance = distanceStatePair.first; dijkstraQueue.erase(dijkstraQueue.begin()); + if (foundPivotState && currentDistance > result.distance) { + return result; + } + // Determine whether the current state is a pivot state. bool isPivotState = false; if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t player2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); - if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor)) { + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } } else if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); - if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor)) { + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } } // If it is indeed a pivot state, we can abort the search here. if (isPivotState) { - explicitPivotStateResult.pivotState = currentState; - return explicitPivotStateResult; + if (foundPivotState && haveQuantitativeResults && deviationOfCurrentState > currentPivotState) { + result.pivotState = currentState; + maximalDeviation = deviationForCurrentState; + } else if (!foundPivotState) { + result.pivotState = currentState; + result.distance = distances[currentState]; + foundPivotState = true; + } } // Otherwise, we explore all its relevant successors. @@ -753,10 +772,12 @@ namespace storm { continue; } - ValueType alternateDistance = probabilityDistances ? distances[currentState] * entry.getValue() : distances[currentState] + storm::utility::one(); + ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { distances[player1Successor] = alternateDistance; - explicitMostProbablePathsResult.predecessors[player1Successor] = std::make_pair(currentState, minPlayer2Successor); + if (generatePredecessors) { + result.predecessors[player1Successor] = std::make_pair(currentState, minPlayer2Successor); + } dijkstraQueue.emplace(alternateDistance, player1Successor); } } @@ -771,10 +792,12 @@ namespace storm { continue; } - ValueType alternateDistance = probabilityDistances ? distances[currentState] * entry.getValue() : distances[currentState] + storm::utility::one(); + ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { distances[player1Successor] = alternateDistance; - explicitMostProbablePathsResult.predecessors[player1Successor] = std::make_pair(currentState, maxPlayer2Successor); + if (generatePredecessors) { + result.predecessors[player1Successor] = std::make_pair(currentState, maxPlayer2Successor); + } dijkstraQueue.emplace(alternateDistance, player1Successor); } } @@ -783,24 +806,76 @@ namespace storm { // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, // which can happen when trying to refine using the qualitative result only. - return explicitPivotStateResult; + return boost::none; } template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + STORM_LOG_THROW(heuristic != AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation, storm::exceptions::NotImplementedException, "The pivot selection heuristic 'maximal weighted deviation' is not supported by the sparse solution strategy."); + // Compute the set of states whose result we have for the min and max case. storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); - - ExplicitPivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, transitionMatrix, player1Grouping, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); // If there was no pivot state, continue the search. - if (!pivotStateResult.pivotState) { + if (!optionalPivotStateResult) { + STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); return false; } // Otherwise, we can refine. - storm::dd::Bdd pivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotStateResult.pivotState.get(), odd, game.getRowVariables()); + auto const& pivotStateResult = optionalPivotStateResult.get(); + STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << "."); + + // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques. + auto const& abstractionInformation = abstractor.get().getAbstractionInformation(); + uint64_t pivotState = pivotStateResult.pivotState; + storm::dd::Bdd symbolicPivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables()); + storm::dd::Bdd minPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd minPlayer2Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer2Strategy = game.getManager().getBddZero(); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState); + minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[transitionMatrix.getRowGroupIndices()[player2State]], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState); + maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[transitionMatrix.getRowGroupIndices()[player2State]], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + boost::optional predicates; + if (useInterpolation) { + predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); + + } + if (!predicates) { + predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + } + STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); + + std::vector preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource()); + performRefinement(createGlobalRefinement(preparedPredicates)); + return true; } template @@ -818,16 +893,16 @@ namespace storm { STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to refine without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - SymbolicPivotStateResult SymbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); + SymbolicPivotStateResult symbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, SymbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, SymbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 7a912e947..d4d913a1f 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -73,26 +73,17 @@ namespace storm { boost::optional> symbolicMostProbablePathsResult; }; - template - struct ExplicitMostProbablePathsResult { - ExplicitMostProbablePathsResult() = default; - ExplicitMostProbablePathsResult(ValueType const& maxProbability, std::vector>&& predecessors); - - /// The maximal probability with which the state in question is reached. - ValueType maxProbability; - - /// The predecessors for the states to obtain this probability. - std::vector> predecessors; - }; - template struct ExplicitPivotStateResult { ExplicitPivotStateResult() = default; - ExplicitPivotStateResult(uint64_t pivotState, storm::OptimizationDirection fromDirection, boost::optional>&& explicitMostProbablePathsResult = boost::none); - boost::optional pivotState; - storm::OptimizationDirection fromDirection; - boost::optional> explicitMostProbablePathsResult; + uint64_t pivotState; + + /// The distance with which the state in question is reached. + ValueType distance; + + /// The predecessors for the states to obtain the given distance. + std::vector> predecessors; }; class ExplicitQualitativeGameResultMinMax; @@ -155,7 +146,8 @@ namespace storm { boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& spanningTree, storm::dd::Bdd const& pivotState) const; - + boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; + void performRefinement(std::vector const& refinementCommands) const; /// The underlying abstractor to refine. diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 2b2980e95..25b110e06 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -157,6 +157,12 @@ namespace storm { } } } + } else { + if (player2Direction == storm::OptimizationDirection::Minimize && (prob1 && initialStates) == initialStates) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } else if (player2Direction == storm::OptimizationDirection::Maximize && (prob0 && initialStates) == initialStates) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } } return result; @@ -204,6 +210,12 @@ namespace storm { } } } + } else { + if (player2Direction == storm::OptimizationDirection::Minimize && initialStates.isSubsetOf(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } else if (player2Direction == storm::OptimizationDirection::Maximize && initialStates.isSubsetOf(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } } return result; diff --git a/src/storm/storage/dd/Odd.cpp b/src/storm/storage/dd/Odd.cpp index b94295f0e..0a0712b2b 100644 --- a/src/storm/storage/dd/Odd.cpp +++ b/src/storm/storage/dd/Odd.cpp @@ -4,6 +4,8 @@ #include #include +#include "storm/storage/BitVector.h" + #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/utility/file.h" @@ -130,6 +132,26 @@ namespace storm { storm::utility::closeFile(dotFile); } + void getEncodingRec(Odd const& odd, uint64_t index, uint64_t offset, storm::storage::BitVector& result) { + if (odd.isTerminalNode()) { + return; + } + + bool thenPath = false; + if (odd.getElseOffset() <= offset) { + thenPath = true; + offset -= odd.getElseOffset(); + result.set(index); + } + getEncodingRec(thenPath ? odd.getThenSuccessor() : odd.getElseSuccessor(), index + 1, offset, result); + } + + storm::storage::BitVector Odd::getEncoding(uint64_t offset, uint64_t variableCount) const { + storm::storage::BitVector result(variableCount > 0 ? variableCount : this->getHeight()); + getEncodingRec(*this, 0, offset, result); + return result; + } + void Odd::addToLevelToOddNodesMap(std::map>& levelToOddNodesMap, uint_fast64_t level) const { levelToOddNodesMap[level].emplace(this); if (!this->isTerminalNode()) { diff --git a/src/storm/storage/dd/Odd.h b/src/storm/storage/dd/Odd.h index 0cb4a307c..d62bf1844 100644 --- a/src/storm/storage/dd/Odd.h +++ b/src/storm/storage/dd/Odd.h @@ -7,6 +7,10 @@ #include namespace storm { + namespace storage { + class BitVector; + } + namespace dd { class Odd { public: @@ -119,6 +123,15 @@ namespace storm { */ void exportToDot(std::string const& filename) const; + /*! + * Retrieves the encoding for the given offset. + * + * @param offset The target offset. + * @param variableCount If not null, this indicates how many variables are contained in the encoding. If 0, + * this number is automatically determined. + */ + storm::storage::BitVector getEncoding(uint64_t offset, uint64_t variableCount = 0) const; + private: /*! * Adds all nodes below the current one to the given mapping. diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 9fcd19b74..eb582f980 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1315,7 +1315,7 @@ namespace storm { while (!stack.empty()) { currentState = stack.back(); stack.pop_back(); - + for (auto player2PredecessorEntry : player1BackwardTransitions.getRow(currentState)) { uint64_t player2Predecessor = player2PredecessorEntry.getColumn(); if (!player2Solution.get(player2PredecessorEntry.getColumn())) { @@ -1392,6 +1392,10 @@ namespace storm { if (result.player1States == player1Solution) { maybeStatesDone = true; result.player2States = player2Solution; + + // If we were asked to produce strategies, we propagate that by triggering another iteration. + // We only do this if at least one strategy will be produced. + produceStrategiesInIteration = !produceStrategiesInIteration && ((player1Strategy && player1Direction == OptimizationDirection::Maximize) || (player2Strategy && player2Direction == OptimizationDirection::Maximize)); } else { result.player1States = player1Solution; result.player2States = player2Solution; From d3bbe4df10637ae50afc6449cce2a4be841e348b Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 27 Mar 2018 16:44:19 +0200 Subject: [PATCH 209/647] explicit interpolation and started on explicit quantitative solution --- .../abstraction/AbstractionInformation.cpp | 16 ++ .../abstraction/AbstractionInformation.h | 8 +- .../ExplicitQuantiativeResultMinMax.cpp | 48 +++++ .../ExplicitQuantitativeResult.cpp | 54 ++++++ .../abstraction/ExplicitQuantitativeResult.h | 31 +++ .../ExplicitQuantitativeResultMinMax.cpp | 61 ++++++ .../ExplicitQuantitativeResultMinMax.h | 32 ++++ src/storm/abstraction/MenuGameAbstractor.cpp | 9 + src/storm/abstraction/MenuGameAbstractor.h | 2 + src/storm/abstraction/MenuGameRefiner.cpp | 177 ++++++++++++++++-- src/storm/abstraction/MenuGameRefiner.h | 5 + .../abstraction/jani/AutomatonAbstractor.cpp | 5 + .../abstraction/jani/AutomatonAbstractor.h | 5 + src/storm/abstraction/jani/EdgeAbstractor.cpp | 5 + src/storm/abstraction/jani/EdgeAbstractor.h | 5 + .../jani/JaniMenuGameAbstractor.cpp | 5 + .../abstraction/jani/JaniMenuGameAbstractor.h | 5 + .../abstraction/prism/CommandAbstractor.cpp | 5 + .../abstraction/prism/CommandAbstractor.h | 5 + .../abstraction/prism/ModuleAbstractor.cpp | 5 + .../abstraction/prism/ModuleAbstractor.h | 5 + .../prism/PrismMenuGameAbstractor.cpp | 5 + .../prism/PrismMenuGameAbstractor.h | 5 + .../abstraction/GameBasedMdpModelChecker.cpp | 89 ++++++++- .../abstraction/GameBasedMdpModelChecker.h | 7 + .../symbolic/StochasticTwoPlayerGame.cpp | 5 + .../models/symbolic/StochasticTwoPlayerGame.h | 5 + 27 files changed, 585 insertions(+), 24 deletions(-) create mode 100644 src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp create mode 100644 src/storm/abstraction/ExplicitQuantitativeResult.cpp create mode 100644 src/storm/abstraction/ExplicitQuantitativeResult.h create mode 100644 src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp create mode 100644 src/storm/abstraction/ExplicitQuantitativeResultMinMax.h diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 5e25b5530..d6d375544 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -138,6 +138,22 @@ namespace storm { return result; } + template + std::vector AbstractionInformation::getPredicatesExcludingBottom(storm::storage::BitVector const& predicateValuation) const { + STORM_LOG_ASSERT(predicateValuation.size() == this->getNumberOfPredicates() + 1, "Size of predicate valuation does not match number of predicates."); + + std::vector result; + for (uint64_t index = 0; index < this->getNumberOfPredicates(); ++index) { + if (predicateValuation[index + 1]) { + result.push_back(this->getPredicateByIndex(index)); + } else { + result.push_back(!this->getPredicateByIndex(index)); + } + } + + return result; + } + template storm::expressions::Expression const& AbstractionInformation::getPredicateByIndex(uint_fast64_t index) const { return predicates[index]; diff --git a/src/storm/abstraction/AbstractionInformation.h b/src/storm/abstraction/AbstractionInformation.h index 093342993..fa1a1927a 100644 --- a/src/storm/abstraction/AbstractionInformation.h +++ b/src/storm/abstraction/AbstractionInformation.h @@ -139,7 +139,13 @@ namespace storm { * Retrieves a list of expression that corresponds to the given predicate valuation. */ std::vector getPredicates(storm::storage::BitVector const& predicateValuation) const; - + + /*! + * Retrieves a list of expression that corresponds to the given predicate valuation that mentions all of the + * predicates' truth values *and* the value of the bottom variable (at the first index). + */ + std::vector getPredicatesExcludingBottom(storm::storage::BitVector const& predicateValuation) const; + /*! * Retrieves the predicate with the given index. * diff --git a/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp new file mode 100644 index 000000000..35237f4d5 --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp @@ -0,0 +1,48 @@ +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + ExplicitQuantitativeResultMinMax::ExplicitQuantitativeResultMinMax(uint64_t numberOfStates) = default; + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMin() const { + return min; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMin() { + return min; + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMax() const { + return max; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMax() { + return max; + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + } +} diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.cpp b/src/storm/abstraction/ExplicitQuantitativeResult.cpp new file mode 100644 index 000000000..4b996483d --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResult.cpp @@ -0,0 +1,54 @@ +#include "storm/abstraction/ExplicitQuantitativeResult.h" + +#include "storm/storage/BitVector.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace abstraction { + + template + ExplicitQuantitativeResult::ExplicitQuantitativeResult(uint64_t numberOfStates) : values(numberOfStates) { + // Intentionally left empty. + } + + template + std::vector const& ExplicitQuantitativeResult::getValues() const { + return values; + } + + template + std::vector& ExplicitQuantitativeResult::getValues() { + return values; + } + + template + void ExplicitQuantitativeResult::setValue(uint64_t state, ValueType const& value) { + values[state] = value; + } + + template + std::pair ExplicitQuantitativeResult::getRange(storm::storage::BitVector const& states) const { + STORM_LOG_THROW(!states.empty(), storm::exceptions::InvalidArgumentException, "Expected non-empty set of states."); + + auto stateIt = states.begin(); + std::pair result = std::make_pair(values[*stateIt], values[*stateIt]); + ++stateIt; + + while (stateIt != states.end()) { + if (values[*stateIt] < result.first) { + result.first = values[*stateIt]; + } else if (values[*stateIt] < result.first) { + result.second = values[*stateIt]; + } + + ++stateIt; + } + + return result; + } + + template class ExplicitQuantitativeResult; + } +} diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.h b/src/storm/abstraction/ExplicitQuantitativeResult.h new file mode 100644 index 000000000..7604655d8 --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResult.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +namespace storm { + namespace storage { + class BitVector; + } + + namespace abstraction { + + template + class ExplicitQuantitativeResult { + public: + ExplicitQuantitativeResult() = default; + ExplicitQuantitativeResult(uint64_t numberOfStates); + + std::vector const& getValues() const; + std::vector& getValues(); + void setValue(uint64_t state, ValueType const& value); + + std::pair getRange(storm::storage::BitVector const& states) const; + + private: + std::vector values; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp new file mode 100644 index 000000000..fe8799a9f --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp @@ -0,0 +1,61 @@ +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + ExplicitQuantitativeResultMinMax::ExplicitQuantitativeResultMinMax(uint64_t numberOfStates) : min(numberOfStates), max(numberOfStates) { + // Intentionally left empty. + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMin() const { + return min; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMin() { + return min; + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMax() const { + return max; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMax() { + return max; + } + + template + void ExplicitQuantitativeResultMinMax::setMin(ExplicitQuantitativeResult&& newMin) { + min = std::move(newMin); + } + + template + void ExplicitQuantitativeResultMinMax::setMax(ExplicitQuantitativeResult&& newMax) { + max = std::move(newMax); + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + template class ExplicitQuantitativeResultMinMax; + } +} diff --git a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h new file mode 100644 index 000000000..f22ff4edb --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h @@ -0,0 +1,32 @@ +#pragma once + +#include "storm/abstraction/ExplicitQuantitativeResult.h" + +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + namespace abstraction { + + template + class ExplicitQuantitativeResultMinMax { + public: + ExplicitQuantitativeResultMinMax() = default; + ExplicitQuantitativeResultMinMax(uint64_t numberOfStates); + + ExplicitQuantitativeResult const& getMin() const; + ExplicitQuantitativeResult& getMin(); + ExplicitQuantitativeResult const& getMax() const; + ExplicitQuantitativeResult& getMax(); + ExplicitQuantitativeResult const& get(storm::OptimizationDirection const& dir) const; + ExplicitQuantitativeResult& get(storm::OptimizationDirection const& dir); + + void setMin(ExplicitQuantitativeResult&& newMin); + void setMax(ExplicitQuantitativeResult&& newMax); + + private: + ExplicitQuantitativeResult min; + ExplicitQuantitativeResult max; + }; + + } +} diff --git a/src/storm/abstraction/MenuGameAbstractor.cpp b/src/storm/abstraction/MenuGameAbstractor.cpp index f68694c30..c999b9316 100644 --- a/src/storm/abstraction/MenuGameAbstractor.cpp +++ b/src/storm/abstraction/MenuGameAbstractor.cpp @@ -23,6 +23,15 @@ namespace storm { // Intentionally left empty. } + template + std::vector> MenuGameAbstractor::getVariableUpdates(uint64_t player1Choice) const { + std::vector> result(this->getNumberOfUpdates(player1Choice)); + for (uint64_t i = 0; i < result.size(); ++i) { + result[i] = this->getVariableUpdates(player1Choice, i); + } + return result; + } + template std::string getStateName(std::pair const& stateValue, std::set const& locationVariables, std::set const& predicateVariables, storm::expressions::Variable const& bottomVariable) { std::stringstream stateName; diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 35fc75c42..ee753bebc 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -34,6 +34,8 @@ namespace storm { virtual AbstractionInformation const& getAbstractionInformation() const = 0; virtual storm::expressions::Expression const& getGuard(uint64_t player1Choice) const = 0; virtual std::pair getPlayer1ChoiceRange() const = 0; + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const = 0; + std::vector> getVariableUpdates(uint64_t player1Choice) const; virtual std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const = 0; virtual storm::expressions::Expression getInitialExpression() const = 0; diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index a5d1f647e..76e528ee7 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -526,6 +526,112 @@ namespace storm { predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution)); return std::make_pair(predicates, stepVariableToCopiedVariableMap); } + + template + const uint64_t ExplicitPivotStateResult::NO_PREDECESSOR = std::numeric_limits::max(); + + template + std::pair>, std::map> MenuGameRefiner::buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const { + + std::vector> predicates; + + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression(); + + std::set oldVariables = initialExpression.getVariables(); + for (auto const& predicate : abstractionInformation.getPredicates()) { + std::set usedVariables = predicate.getVariables(); + oldVariables.insert(usedVariables.begin(), usedVariables.end()); + } + + std::map oldToNewVariables; + for (auto const& variable : oldVariables) { + oldToNewVariables[variable] = expressionManager.getVariable(variable.getName()); + } + std::map lastSubstitution; + for (auto const& variable : oldToNewVariables) { + lastSubstitution[variable.second] = variable.second; + } + std::map stepVariableToCopiedVariableMap; + + // The state valuation also includes the bottom state, so we need to reserve one more than the number of + // predicates here. + storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(pivotStateResult.pivotState, abstractionInformation.getNumberOfPredicates() + 1); + + // Decode pivot state. + predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation)); + for (auto& predicate : predicates.back()) { + predicate = predicate.changeManager(expressionManager); + } + + // Perform a backward traversal from the pivot state along the chosen predecessors until there is no more + // predecessors. + uint64_t currentState = pivotStateResult.predecessors[pivotStateResult.pivotState].first; + uint64_t currentAction = pivotStateResult.predecessors[pivotStateResult.pivotState].second; + while (currentState != ExplicitPivotStateResult::NO_PREDECESSOR) { + // Create a new copy of each variable to use for this step. + std::map substitution; + for (auto const& variablePair : oldToNewVariables) { + storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variablePair.second); + substitution[variablePair.second] = variableCopy; + stepVariableToCopiedVariableMap[variableCopy] = variablePair.second; + } + + // Retrieve the variable updates that the predecessor needs to perform to get to the current state. + auto variableUpdateVector = abstractor.get().getVariableUpdates(currentAction); + storm::expressions::Expression allVariableUpdateExpression; + for (auto const& variableUpdates : variableUpdateVector) { + storm::expressions::Expression variableUpdateExpression; + for (auto const& oldNewVariablePair : oldToNewVariables) { + storm::expressions::Variable const& newVariable = oldNewVariablePair.second; + + // If the variable was set, use its update expression. + auto updateIt = variableUpdates.find(oldNewVariablePair.first); + if (updateIt != variableUpdates.end()) { + auto const& update = *updateIt; + + if (update.second.hasBooleanType()) { + variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution)); + } else { + variableUpdateExpression = variableUpdateExpression && lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution); + } + } else { + // Otherwise, make sure that the new variable maintains the old value. + if (newVariable.hasBooleanType()) { + variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable)); + } else { + variableUpdateExpression = variableUpdateExpression && lastSubstitution.at(newVariable) == substitution.at(newVariable); + } + } + } + + allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression; + } + + // Add variable update expression. + predicates.back().emplace_back(allVariableUpdateExpression); + + // Add the guard of the choice. + predicates.back().emplace_back(abstractor.get().getGuard(currentAction).changeManager(expressionManager).substitute(substitution)); + + // Retrieve the predicate valuation in the predecessor. + extendedPredicateValuation = odd.getEncoding(currentState, abstractionInformation.getNumberOfPredicates() + 1); + predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation)); + for (auto& predicate : predicates.back()) { + predicate = predicate.changeManager(expressionManager).substitute(substitution); + } + + // Move backwards one step. + lastSubstitution = std::move(substitution); + + std::pair predecessorPair = pivotStateResult.predecessors[currentState]; + currentState = predecessorPair.first; + currentAction = predecessorPair.second; + } + + predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution)); + return std::make_pair(predicates, stepVariableToCopiedVariableMap); + } template boost::optional derivePredicatesFromInterpolation(storm::expressions::ExpressionManager& interpolationManager, AbstractionInformation const& abstractionInformation, std::vector> const& trace, std::map const& variableSubstitution) { @@ -579,8 +685,6 @@ namespace storm { template boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { - AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); - // Compute the most probable path from any initial state to the pivot state. SymbolicMostProbablePathsResult symbolicMostProbablePathsResult; if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) { @@ -590,6 +694,7 @@ namespace storm { } // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); // Build the trace of the most probable path in terms of which predicates hold in each step. @@ -600,7 +705,15 @@ namespace storm { template boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const { - // TODO. + + // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Build the trace of the most probable path in terms of which predicates hold in each step. + std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, pivotStateResult, odd); + + return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } template @@ -631,7 +744,7 @@ namespace storm { STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to proceed without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - SymbolicPivotStateResult SymbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); + SymbolicPivotStateResult symbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); // // SANITY CHECK TO MAKE SURE OUR STRATEGIES ARE NOT BROKEN. // // FIXME. @@ -677,12 +790,12 @@ namespace storm { boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, SymbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, SymbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); @@ -693,8 +806,11 @@ namespace storm { } template - boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) { + boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair, std::vector const* lowerValues = nullptr, std::vector const* upperValues = nullptr) { + STORM_LOG_ASSERT(!lowerValues || upperValues, "Expected none or both value results."); + STORM_LOG_ASSERT(!upperValues || lowerValues, "Expected none or both value results."); + // Perform Dijkstra search that stays within the relevant states and searches for a state in which the // strategies for the (commonly chosen) player 1 action leads to a player 2 state in which the choices differ. ExplicitPivotStateResult result; @@ -705,7 +821,7 @@ namespace storm { ValueType zeroDistance = probabilityDistances ? storm::utility::one() : storm::utility::zero(); std::vector distances(numberOfStates, inftyDistance); if (generatePredecessors) { - result.predecessors.resize(numberOfStates, std::make_pair(0, 0)); + result.predecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); } // Use set as priority queue with unique membership; default comparison on pair works fine if distance is @@ -722,8 +838,9 @@ namespace storm { } // For some heuristics, we need to potentially find more than just one pivot. + bool considerDeviation = (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::NearestMaximalDeviation || pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) && lowerValues && upperValues; bool foundPivotState = false; - ValueType maximalDeviation = storm::utility::zero(); + ValueType pivotStateDeviation = storm::utility::zero(); while (!dijkstraQueue.empty()) { auto distanceStatePair = *dijkstraQueue.begin(); @@ -731,8 +848,17 @@ namespace storm { ValueType currentDistance = distanceStatePair.first; dijkstraQueue.erase(dijkstraQueue.begin()); - if (foundPivotState && currentDistance > result.distance) { - return result; + if (foundPivotState && (probabilityDistances ? currentDistance < result.distance : currentDistance > result.distance)) { + if (pivotSelectionHeuristic != storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { + // For the nearest maximal deviation and most probable path heuristics, future pivot states are + // not important any more, because their distance will be strictly larger, so we can return the + // current pivot state. + return result; + } else if (pivotStateDeviation >= currentDistance) { + // If the heuristic is maximal weighted deviation and the weighted deviation for any future pivot + // state is necessarily at most as high as the current one, we can abort the search. + return result; + } } // Determine whether the current state is a pivot state. @@ -751,14 +877,26 @@ namespace storm { // If it is indeed a pivot state, we can abort the search here. if (isPivotState) { - if (foundPivotState && haveQuantitativeResults && deviationOfCurrentState > currentPivotState) { - result.pivotState = currentState; - maximalDeviation = deviationForCurrentState; + if (considerDeviation && foundPivotState) { + ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState]; + if (deviationOfCurrentState > pivotStateDeviation) { + result.pivotState = currentState; + pivotStateDeviation = deviationOfCurrentState; + if (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { + // Scale the deviation with the distance (probability) for this heuristic. + pivotStateDeviation *= currentDistance; + } + } } else if (!foundPivotState) { result.pivotState = currentState; result.distance = distances[currentState]; foundPivotState = true; } + + // If there is no need to look at other deviations, stop here. + if (!considerDeviation) { + return result; + } } // Otherwise, we explore all its relevant successors. @@ -776,7 +914,7 @@ namespace storm { if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { - result.predecessors[player1Successor] = std::make_pair(currentState, minPlayer2Successor); + result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[minPlayer2Successor]); } dijkstraQueue.emplace(alternateDistance, player1Successor); } @@ -812,12 +950,10 @@ namespace storm { template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { - STORM_LOG_THROW(heuristic != AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation, storm::exceptions::NotImplementedException, "The pivot selection heuristic 'maximal weighted deviation' is not supported by the sparse solution strategy."); - // Compute the set of states whose result we have for the min and max case. storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); - boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); // If there was no pivot state, continue the search. if (!optionalPivotStateResult) { @@ -866,7 +1002,6 @@ namespace storm { boost::optional predicates; if (useInterpolation) { predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); - } if (!predicates) { predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); @@ -972,7 +1107,9 @@ namespace storm { for (auto const& predicate : command.getPredicates()) { STORM_LOG_TRACE(predicate); } - abstractor.get().refine(command); + if (!command.getPredicates().empty()) { + abstractor.get().refine(command); + } } STORM_LOG_TRACE("Current set of predicates:"); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index d4d913a1f..5e7be4d2d 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -82,6 +82,9 @@ namespace storm { /// The distance with which the state in question is reached. ValueType distance; + /// The value filled in for states without predecessors in the search. + static const uint64_t NO_PREDECESSOR; + /// The predecessors for the states to obtain the given distance. std::vector> predecessors; }; @@ -146,6 +149,8 @@ namespace storm { boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& spanningTree, storm::dd::Bdd const& pivotState) const; + + std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; void performRefinement(std::vector const& refinementCommands) const; diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index b97ad6002..5ab326657 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -51,6 +51,11 @@ namespace storm { return edges[player1Choice].getGuard(); } + template + uint64_t AutomatonAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return edges[player1Choice].getNumberOfUpdates(player1Choice); + } + template std::map AutomatonAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return edges[player1Choice].getVariableUpdates(auxiliaryChoice); diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index ac010a0d9..e9ff1d76a 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -57,6 +57,11 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index eaaafe266..8f0ab300e 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -65,6 +65,11 @@ namespace storm { return edge.get().getGuard(); } + template + uint64_t EdgeAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return edge.get().getNumberOfDestinations(); + } + template std::map EdgeAbstractor::getVariableUpdates(uint64_t auxiliaryChoice) const { return edge.get().getDestination(auxiliaryChoice).getAsVariableToExpressionMap(); diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index ac88b6b04..f3dfa531c 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -72,6 +72,11 @@ namespace storm { */ storm::expressions::Expression const& getGuard() const; + /*! + * Retrieves the number of updates of this edge. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given * auxiliary choice. diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 215aeb780..a5bc90ed0 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -119,6 +119,11 @@ namespace storm { return automata.front().getGuard(player1Choice); } + template + uint64_t JaniMenuGameAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return automata.front().getNumberOfUpdates(player1Choice); + } + template std::map JaniMenuGameAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return automata.front().getVariableUpdates(player1Choice, auxiliaryChoice); diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 0ef49f908..0a366c625 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -75,6 +75,11 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const override; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const override; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index afc859e01..15b68685e 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -65,6 +65,11 @@ namespace storm { return command.get().getGuardExpression(); } + template + uint64_t CommandAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return command.get().getNumberOfUpdates(); + } + template std::map CommandAbstractor::getVariableUpdates(uint64_t auxiliaryChoice) const { return command.get().getUpdate(auxiliaryChoice).getAsVariableToExpressionMap(); diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index b26492125..d5c725921 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -70,6 +70,11 @@ namespace storm { */ storm::expressions::Expression const& getGuard() const; + /*! + * Retrieves the number of updates of this command. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given * auxiliary choice. diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index 6ba51b062..b5180ecf4 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -45,6 +45,11 @@ namespace storm { return commands[player1Choice].getGuard(); } + template + uint64_t ModuleAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return commands[player1Choice].getNumberOfUpdates(player1Choice); + } + template std::map ModuleAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return commands[player1Choice].getVariableUpdates(auxiliaryChoice); diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index 3cfb21ca7..8aef43562 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -60,6 +60,11 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 99dc2c5a2..718207120 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -115,6 +115,11 @@ namespace storm { return modules.front().getGuard(player1Choice); } + template + uint64_t PrismMenuGameAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return modules.front().getNumberOfUpdates(player1Choice); + } + template std::map PrismMenuGameAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return modules.front().getVariableUpdates(player1Choice, auxiliaryChoice); diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 55845f134..ce5f7ac42 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -74,6 +74,11 @@ namespace storm { * @return The guard of the player 1 choice. */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const override; + + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const override; /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 25b110e06..004d7993d 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -27,6 +27,7 @@ #include "storm/abstraction/ExplicitGameStrategyPair.h" #include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" #include "storm/logic/FragmentSpecification.h" @@ -49,7 +50,10 @@ namespace storm { using storm::abstraction::SymbolicQuantitativeGameResult; using storm::abstraction::SymbolicQuantitativeGameResultMinMax; - + using storm::abstraction::ExplicitQuantitativeResult; + using storm::abstraction::ExplicitQuantitativeResultMinMax; + using storm::abstraction::ExplicitGameStrategyPair; + template GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { model.requireNoUndefinedConstants(); @@ -385,6 +389,35 @@ namespace storm { return result; } + template + ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& minStrategyPair) { + + bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; + auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); + auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); + + // Determine which rows to keep. + storm::storage::BitVector rows(transitionMatrix.getRowCount()); + for (uint64_t player2State = 0; player2State < transitionMatrix.getRowGroupCount(); ++player2State) { + if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) { + // Mark all rows that have a maybe state as a successor. + for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2State]; row < transitionMatrix.getRowGroupIndices()[player2State + 1]; ++row) { + bool hasMaybeStateSuccessor = false; + for (auto const& entry : transitionMatrix.getRow(row)) { + if (maybeStates.get(entry.getColumn())) { + hasMaybeStateSuccessor = true; + } + } + if (!hasMaybeStateSuccessor) { + rows.set(row); + } + } + } + } + + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, <#const storm::storage::BitVector &columnConstraint#>) + } + template std::unique_ptr GameBasedMdpModelChecker::performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException, "The game-based abstraction refinement model checker can only compute the result for the initial states."); @@ -430,7 +463,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " (player 1) states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -517,7 +550,6 @@ namespace storm { // At this point, we know that we cannot answer the query without further numeric computation. STORM_LOG_TRACE("Starting numerical solution step."); - STORM_LOG_TRACE("Using dd-based solving."); storm::dd::Add initialStatesAdd = initialStates.template toAdd(); auto quantitativeStart = std::chrono::high_resolution_clock::now(); @@ -660,6 +692,57 @@ namespace storm { return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); } + // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. + if (!qualitativeRefinement) { + // At this point, we know that we cannot answer the query without further numeric computation. + STORM_LOG_TRACE("Starting numerical solution step."); + + auto quantitativeStart = std::chrono::high_resolution_clock::now(); + + ExplicitQuantitativeResultMinMax quantitativeResult; + quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair)); + +// SymbolicQuantitativeGameResultMinMax quantitativeResult; +// +// // (7) Solve the min values and check whether we can give the answer already. +// quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); +// previousMinQuantitativeResult = quantitativeResult.min; +// result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); +// if (result) { +// return result; +// } +// +// // (8) Solve the max values and check whether we can give the answer already. +// quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); +// result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); +// if (result) { +// return result; +// } +// + auto quantitativeEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); +// +// // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. +// result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); +// if (result) { +// return result; +// } +// +// // Make sure that all strategies are still valid strategies. +// STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); +// STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); +// STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); +// STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); +// + auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); +// +// // (10) If we arrived at this point, it means that we have all qualitative and quantitative +// // information about the game, but we could not yet answer the query. In this case, we need to refine. +// refiner.refine(game, transitionMatrixBdd, quantitativeResult); + auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + } + return nullptr; } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index a2f4e53f0..b54a510c8 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -39,6 +39,13 @@ namespace storm { class ExplicitQualitativeGameResult; class ExplicitQualitativeGameResultMinMax; + + template + class ExplicitQuantitativeResult; + + template + class ExplicitQuantitativeResultMinMax; + class ExplicitGameStrategy; class ExplicitGameStrategyPair; } diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp index 677d80912..8695c57d8 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp @@ -100,6 +100,11 @@ namespace storm { } + template + uint64_t StochasticTwoPlayerGame::getNumberOfPlayer2States() const { + return this->getQualitativeTransitionMatrix().existsAbstract(this->getColumnVariables()).getNonZeroCount(); + } + // Explicitly instantiate the template class. template class StochasticTwoPlayerGame; template class StochasticTwoPlayerGame; diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.h b/src/storm/models/symbolic/StochasticTwoPlayerGame.h index 569d258dd..1a243eff5 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.h +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.h @@ -120,6 +120,11 @@ namespace storm { template std::shared_ptr> toValueType() const; + /*! + * Retrieves the number of player 2 states in the game. + */ + uint64_t getNumberOfPlayer2States() const; + private: /*! * Prepare all illegal masks. From d557ef10753a050b0831a7dfd7938be3c9342eb9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 27 Mar 2018 22:21:02 +0200 Subject: [PATCH 210/647] started to make game solver flexible enough to also solve the (explicit) games of game-based abstraction --- .../SparseMdpParameterLiftingModelChecker.cpp | 6 +- .../abstraction/GameBasedMdpModelChecker.cpp | 29 +- src/storm/solver/GameSolver.cpp | 2 +- src/storm/solver/GameSolver.h | 14 +- src/storm/solver/MinMaxLinearEquationSolver.h | 2 +- src/storm/solver/StandardGameSolver.cpp | 266 ++++++++++++------ src/storm/solver/StandardGameSolver.h | 22 +- src/storm/storage/SparseMatrix.h | 2 +- 8 files changed, 233 insertions(+), 110 deletions(-) diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp index 0aa70d974..c58426f79 100644 --- a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp @@ -275,8 +275,8 @@ namespace storm { } // Invoke the solver - if(stepBound) { - assert(*stepBound > 0); + if (stepBound) { + STORM_LOG_ASSERT(*stepBound > 0, "Expected positive step bound."); solver->repeatedMultiply(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound); } else { solver->solveGame(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector()); @@ -293,7 +293,7 @@ namespace storm { // Get the result for the complete model (including maybestates) std::vector result = resultsForNonMaybeStates; auto maybeStateResIt = x.begin(); - for(auto const& maybeState : maybeStates) { + for (auto const& maybeState : maybeStates) { result[maybeState] = *maybeStateResIt; ++maybeStateResIt; } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 004d7993d..2c10f2f2d 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -391,31 +391,30 @@ namespace storm { template ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& minStrategyPair) { - + + bool player1Min = player1Direction == storm::OptimizationDirection::Minimize; bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; + auto const& player1Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer1States(); + auto const& player1Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer1States(); auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); // Determine which rows to keep. - storm::storage::BitVector rows(transitionMatrix.getRowCount()); + storm::storage::BitVector player2MaybeStates(transitionMatrix.getRowCount()); for (uint64_t player2State = 0; player2State < transitionMatrix.getRowGroupCount(); ++player2State) { if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) { - // Mark all rows that have a maybe state as a successor. - for (uint64_t row = transitionMatrix.getRowGroupIndices()[player2State]; row < transitionMatrix.getRowGroupIndices()[player2State + 1]; ++row) { - bool hasMaybeStateSuccessor = false; - for (auto const& entry : transitionMatrix.getRow(row)) { - if (maybeStates.get(entry.getColumn())) { - hasMaybeStateSuccessor = true; - } - } - if (!hasMaybeStateSuccessor) { - rows.set(row); - } - } + player2MaybeStates.set(player2State); } } - storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, <#const storm::storage::BitVector &columnConstraint#>) + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); + std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, maybeStates); + + auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); + + + env. } template diff --git a/src/storm/solver/GameSolver.cpp b/src/storm/solver/GameSolver.cpp index 9c3e5ad8e..0710cc9f2 100644 --- a/src/storm/solver/GameSolver.cpp +++ b/src/storm/solver/GameSolver.cpp @@ -10,7 +10,7 @@ namespace storm { namespace solver { template - GameSolver::GameSolver() : trackSchedulers(false), cachingEnabled(false) { + GameSolver::GameSolver() : trackSchedulers(false), uniqueSolution(false), cachingEnabled(false) { // Intentionally left empty } diff --git a/src/storm/solver/GameSolver.h b/src/storm/solver/GameSolver.h index fd9e63667..07cb16e88 100644 --- a/src/storm/solver/GameSolver.h +++ b/src/storm/solver/GameSolver.h @@ -111,6 +111,16 @@ namespace storm { * Clears the currently cached data that has been stored during previous calls of the solver. */ virtual void clearCache() const; + + /*! + * Sets whether the solution to the min max equation system is known to be unique. + */ + void setHasUniqueSolution(bool value = true); + + /*! + * Retrieves whether the solution to the min max equation system is assumed to be unique + */ + bool hasUniqueSolution() const; protected: @@ -128,9 +138,11 @@ namespace storm { boost::optional> player2ChoicesHint; private: + /// Whether the solver can assume that the min-max equation system has a unique solution + bool uniqueSolution; + /// Whether some of the generated data during solver calls should be cached. bool cachingEnabled; - }; template diff --git a/src/storm/solver/MinMaxLinearEquationSolver.h b/src/storm/solver/MinMaxLinearEquationSolver.h index 00788089c..9ea9ac90a 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.h +++ b/src/storm/solver/MinMaxLinearEquationSolver.h @@ -170,7 +170,7 @@ namespace storm { boost::optional> initialScheduler; private: - // Whether the solver can assume that the min-max equation system has a unique solution + /// Whether the solver can assume that the min-max equation system has a unique solution bool uniqueSolution; /// Whether some of the generated data during solver calls should be cached. diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 6140a5c15..07512b23d 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -16,12 +16,22 @@ namespace storm { namespace solver { template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localP1Matrix(nullptr), localP2Matrix(nullptr), player1Matrix(player1Matrix), player2Matrix(player2Matrix) { + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(nullptr), player1Matrix(&player1Matrix), player2Matrix(player2Matrix) { // Intentionally left empty. } template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localP1Matrix(std::make_unique>(std::move(player1Matrix))), localP2Matrix(std::make_unique>(std::move(player2Matrix))), player1Matrix(*localP1Matrix), player2Matrix(*localP2Matrix) { + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(std::make_unique>(std::move(player1Matrix))), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(nullptr), player1Matrix(localPlayer1Matrix.get()), player2Matrix(*localPlayer2Matrix) { + // Intentionally left empty. + } + + template + StandardGameSolver::StandardGameSolver(std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(&player1Grouping), player1Matrix(nullptr), player2Matrix(player2Matrix) { + + } + + template + StandardGameSolver::StandardGameSolver(std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(std::make_unique>(std::move(player1Grouping))), localPlayer1Matrix(nullptr), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(localPlayer1Grouping.get()), player1Matrix(nullptr), player2Matrix(*localPlayer2Matrix) { // Intentionally left empty. } @@ -63,20 +73,30 @@ namespace storm { bool StandardGameSolver::solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { // Create the initial choice selections. - std::vector player1Choices = this->hasSchedulerHints() ? this->player1ChoicesHint.get() : std::vector(this->player1Matrix.getRowGroupCount(), 0); + std::vector player1Choices; + if (this->hasSchedulerHints()) { + player1Choices = this->player1ChoicesHint.get(); + } else if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + player1Choices = std::vector(this->getPlayer1Matrix().getRowGroupCount(), 0); + } else { + // Player 1 represented by grouping of player 2 states. + player1Choices = this->getPlayer1Grouping(); + player1Choices.resize(player1Choices.size() - 1); + } std::vector player2Choices = this->hasSchedulerHints() ? this->player2ChoicesHint.get() : std::vector(this->player2Matrix.getRowGroupCount(), 0); - if(!auxiliaryP2RowGroupVector) { + if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(this->player2Matrix.getRowGroupCount()); } - if(!auxiliaryP1RowGroupVector) { - auxiliaryP1RowGroupVector = std::make_unique>(this->player1Matrix.getRowGroupCount()); + if (!auxiliaryP1RowGroupVector) { + auxiliaryP1RowGroupVector = std::make_unique>(this->player1Matrix->getRowGroupCount()); } std::vector& subB = *auxiliaryP1RowGroupVector; uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); - // The linear equation solver should be at least as precise as this solver + // The linear equation solver should be at least as precise as this solver. std::unique_ptr environmentOfSolverStorage; auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); if (!storm::NumberTraits::IsExact) { @@ -104,8 +124,13 @@ namespace storm { submatrix.convertToEquationSystem(); } auto submatrixSolver = linearEquationSolverFactory->create(environmentOfSolver, std::move(submatrix)); - if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); } - if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); } + if (this->lowerBound) { + submatrixSolver->setLowerBound(this->lowerBound.get()); + + } + if (this->upperBound) { + submatrixSolver->setUpperBound(this->upperBound.get()); + } submatrixSolver->setCachingEnabled(true); Status status = Status::InProgress; @@ -140,7 +165,7 @@ namespace storm { this->player2SchedulerChoices = std::move(player2Choices); } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } @@ -163,25 +188,21 @@ namespace storm { multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } - if (!auxiliaryP2RowVector) { - auxiliaryP2RowVector = std::make_unique>(player2Matrix.getRowCount()); - } - if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(player2Matrix.getRowGroupCount()); } if (!auxiliaryP1RowGroupVector) { - auxiliaryP1RowGroupVector = std::make_unique>(player1Matrix.getRowGroupCount()); + auxiliaryP1RowGroupVector = std::make_unique>(this->getNumberOfPlayer1States()); } ValueType precision = storm::utility::convertNumber(env.solver().game().getPrecision()); bool relative = env.solver().game().getRelativeTerminationCriterion(); uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); - std::vector& multiplyResult = *auxiliaryP2RowVector; - std::vector& reducedMultiplyResult = *auxiliaryP2RowGroupVector; - + std::vector& reducedPlayer2Result = *auxiliaryP2RowGroupVector; + + bool trackSchedulersInValueIteration = this->isTrackSchedulersSet() && !this->hasUniqueSolution(); if (this->hasSchedulerHints()) { // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; @@ -190,9 +211,25 @@ namespace storm { submatrix.convertToEquationSystem(); } auto submatrixSolver = linearEquationSolverFactory->create(env, std::move(submatrix)); - if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); } - if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); } + if (this->lowerBound) { + submatrixSolver->setLowerBound(this->lowerBound.get()); + + } + if (this->upperBound) { + submatrixSolver->setUpperBound(this->upperBound.get()); + } submatrixSolver->solveEquations(env, x, *auxiliaryP1RowGroupVector); + + // If requested, we store the scheduler for retrieval. Initialize the schedulers to the hint we have. + if (trackSchedulersInValueIteration) { + this->player1SchedulerChoices = this->player1ChoicesHint.get(); + this->player2SchedulerChoices = this->player2ChoicesHint.get(); + } + } else if (trackSchedulersInValueIteration) { + // If requested, we store the scheduler for retrieval. Create empty schedulers here so we can fill them + // during VI. + this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); + this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); } std::vector* newX = auxiliaryP1RowGroupVector.get(); @@ -203,7 +240,7 @@ namespace storm { Status status = Status::InProgress; while (status == Status::InProgress) { - multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, multiplyResult, reducedMultiplyResult, *newX); + multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, trackSchedulersInValueIteration ? &this->getPlayer1SchedulerChoices() : nullptr, trackSchedulersInValueIteration ? &this->getPlayer2SchedulerChoices() : nullptr); // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { @@ -225,13 +262,13 @@ namespace storm { } // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulersSet()) { - this->player1SchedulerChoices = std::vector(player1Matrix.getRowGroupCount(), 0); - this->player2SchedulerChoices = std::vector(player2Matrix.getRowGroupCount(), 0); + if (this->isTrackSchedulersSet() && this->hasUniqueSolution()) { + this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); + this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } @@ -245,54 +282,53 @@ namespace storm { multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } - if (!auxiliaryP2RowVector) { - auxiliaryP2RowVector = std::make_unique>(player2Matrix.getRowCount()); - } - if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(player2Matrix.getRowGroupCount()); } - std::vector& multiplyResult = *auxiliaryP2RowVector; - std::vector& reducedMultiplyResult = *auxiliaryP2RowGroupVector; + std::vector& reducedPlayer2Result = *auxiliaryP2RowGroupVector; for (uint_fast64_t iteration = 0; iteration < n; ++iteration) { - multiplyAndReduce(env, player1Dir, player2Dir, x, b, *multiplierPlayer2Matrix, multiplyResult, reducedMultiplyResult, x); + multiplyAndReduce(env, player1Dir, player2Dir, x, b, *multiplierPlayer2Matrix, reducedPlayer2Result, x); } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } } template - void StandardGameSolver::multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const { + void StandardGameSolver::multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& player2ReducedResult, std::vector& player1ReducedResult, std::vector* player1SchedulerChoices, std::vector* player2SchedulerChoices) const { - multiplier.multiply(env, x, b, multiplyResult); + multiplier.multiplyAndReduce(env, player2Dir, x, b, player2ReducedResult, player2SchedulerChoices); - storm::utility::vector::reduceVectorMinOrMax(player2Dir, multiplyResult, p2ReducedMultiplyResult, player2Matrix.getRowGroupIndices()); - - uint_fast64_t pl1State = 0; - for (auto& result : p1ReducedMultiplyResult) { - storm::storage::SparseMatrix::const_rows relevantRows = player1Matrix.getRowGroup(pl1State); - STORM_LOG_ASSERT(relevantRows.getNumberOfEntries() != 0, "There is a choice of player 1 that does not lead to any player 2 choice"); - auto it = relevantRows.begin(); - auto ite = relevantRows.end(); - - // Set the first value. - result = p2ReducedMultiplyResult[it->getColumn()]; - ++it; - - // Now iterate through the different values and pick the extremal one. - if (player1Dir == OptimizationDirection::Minimize) { - for (; it != ite; ++it) { - result = std::min(result, p2ReducedMultiplyResult[it->getColumn()]); - } - } else { - for (; it != ite; ++it) { - result = std::max(result, p2ReducedMultiplyResult[it->getColumn()]); + if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + uint_fast64_t player1State = 0; + for (auto& result : player1ReducedResult) { + storm::storage::SparseMatrix::const_rows relevantRows = this->getPlayer1Matrix().getRowGroup(player1State); + STORM_LOG_ASSERT(relevantRows.getNumberOfEntries() != 0, "There is a choice of player 1 that does not lead to any player 2 choice"); + auto it = relevantRows.begin(); + auto ite = relevantRows.end(); + + // Set the first value. + result = player2ReducedResult[it->getColumn()]; + ++it; + + // Now iterate through the different values and pick the extremal one. + if (player1Dir == OptimizationDirection::Minimize) { + for (; it != ite; ++it) { + result = std::min(result, player2ReducedResult[it->getColumn()]); + } + } else { + for (; it != ite; ++it) { + result = std::max(result, player2ReducedResult[it->getColumn()]); + } } + ++player1State; } - ++pl1State; + } else { + // Player 1 represented by grouping of player 2 states (vector). + storm::utility::vector::reduceVectorMinOrMax(player1Dir, player2ReducedResult, player1ReducedResult, this->getPlayer1Grouping(), player1SchedulerChoices); } } @@ -333,22 +369,45 @@ namespace storm { } } - // Now extract the choices of player 1 - for (uint_fast64_t p1Group = 0; p1Group < this->player1Matrix.getRowGroupCount(); ++p1Group) { - uint_fast64_t firstRowInGroup = this->player1Matrix.getRowGroupIndices()[p1Group]; - uint_fast64_t rowGroupSize = this->player1Matrix.getRowGroupIndices()[p1Group + 1] - firstRowInGroup; - uint_fast64_t currentChoice = player1Choices[p1Group]; - ValueType currentValue = player2ChoiceValues[this->player1Matrix.getRow(firstRowInGroup + currentChoice).begin()->getColumn()]; - for (uint_fast64_t p1Choice = 0; p1Choice < rowGroupSize; ++p1Choice) { - // If the choice is the currently selected one, we can skip it. - if (p1Choice == currentChoice) { - continue; + // Now extract the choices of player 1. + if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + for (uint_fast64_t p1Group = 0; p1Group < this->getPlayer1Matrix().getRowGroupCount(); ++p1Group) { + uint_fast64_t firstRowInGroup = this->getPlayer1Matrix().getRowGroupIndices()[p1Group]; + uint_fast64_t rowGroupSize = this->getPlayer1Matrix().getRowGroupIndices()[p1Group + 1] - firstRowInGroup; + uint_fast64_t currentChoice = player1Choices[p1Group]; + ValueType currentValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + currentChoice).begin()->getColumn()]; + for (uint_fast64_t p1Choice = 0; p1Choice < rowGroupSize; ++p1Choice) { + // If the choice is the currently selected one, we can skip it. + if (p1Choice == currentChoice) { + continue; + } + ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; + if (valueImproved(player1Dir, currentValue, choiceValue)) { + schedulerImproved = true; + player1Choices[p1Group] = p1Choice; + currentValue = choiceValue; + } } - ValueType const& choiceValue = player2ChoiceValues[this->player1Matrix.getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; - if (valueImproved(player1Dir, currentValue, choiceValue)) { - schedulerImproved = true; - player1Choices[p1Group] = p1Choice; - currentValue = choiceValue; + } + } else { + // Player 1 represented by grouping of player 2 states (vector). + for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { + uint64_t currentChoice = player1Choices[player1State]; + ValueType currentValue = player2ChoiceValues[currentChoice]; + uint64_t numberOfPlayer2Successors = this->getPlayer1Grouping()[player1State + 1] - this->getPlayer1Grouping()[player1State]; + for (uint64_t player2State = 0; player2State < numberOfPlayer2Successors; ++player2State) { + // If the choice is the currently selected one, we can skip it. + if (currentChoice == player2State + this->getPlayer1Grouping()[player1State]) { + continue; + } + + ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + player2State]; + if (valueImproved(player1Dir, currentValue, choiceValue)) { + schedulerImproved = true; + player1Choices[player1State] = player2State; + currentValue = choiceValue; + } } } } @@ -358,25 +417,66 @@ namespace storm { template void StandardGameSolver::getInducedMatrixVector(std::vector& x, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const { - //Get the rows of the player2matrix that are selected by the schedulers - //Note that rows can be selected more then once and in an arbitrary order. + // Get the rows of the player 2 matrix that are selected by the schedulers. + // Note that rows can be selected more than once and in an arbitrary order. std::vector selectedRows; - selectedRows.reserve(player1Matrix.getRowGroupCount()); - uint_fast64_t pl1State = 0; - for (auto const& pl1Choice : player1Choices){ - auto const& pl1Row = player1Matrix.getRow(pl1State, pl1Choice); - STORM_LOG_ASSERT(pl1Row.getNumberOfEntries() == 1, "It is assumed that rows of player one have one entry, but this is not the case."); - uint_fast64_t const& pl2State = pl1Row.begin()->getColumn(); - selectedRows.push_back(player2Matrix.getRowGroupIndices()[pl2State] + player2Choices[pl2State]); - ++pl1State; + if (this->player1RepresentedByMatrix()) { + // Player 1 is represented by a matrix. + selectedRows.reserve(this->getPlayer1Matrix().getRowGroupCount()); + uint_fast64_t player1State = 0; + for (auto const& player1Choice : player1Choices) { + auto const& player1Row = this->getPlayer1Matrix().getRow(player1State, player1Choice); + STORM_LOG_ASSERT(player1Row.getNumberOfEntries() == 1, "It is assumed that rows of player one have one entry, but this is not the case."); + uint_fast64_t player2State = player1Row.begin()->getColumn(); + selectedRows.push_back(player2Matrix.getRowGroupIndices()[player2State] + player2Choices[player2State]); + ++player1State; + } + } else { + // Player 1 is represented by the grouping of player 2 states (vector). + selectedRows.reserve(this->player2Matrix.getRowGroupCount()); + for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { + uint64_t player2State = player1Choices[player1State]; + selectedRows.emplace_back(player2Matrix.getRowGroupIndices()[player2State] + player2Choices[player2State]); + } } - //Get the matrix and the vector induced by this selection. Note that we add entries at the diagonal + // Get the matrix and the vector induced by this selection and add entries on the diagonal in the process. inducedMatrix = player2Matrix.selectRowsFromRowIndexSequence(selectedRows, true); inducedVector.resize(inducedMatrix.getRowCount()); storm::utility::vector::selectVectorValues(inducedVector, selectedRows, b); } + template + bool StandardGameSolver::player1RepresentedByMatrix() const { + return player1Matrix != nullptr; + } + + template + storm::storage::SparseMatrix const& StandardGameSolver::getPlayer1Matrix() const { + STORM_LOG_ASSERT(player1RepresentedByMatrix(), "Player 1 is represented by a matrix."); + return *player1Matrix; + } + + template + std::vector const& StandardGameSolver::getPlayer1Grouping() const { + STORM_LOG_ASSERT(!player1RepresentedByMatrix(), "Player 1 is represented by a matrix."); + return *player1Grouping; + } + + template + uint64_t StandardGameSolver::getNumberOfPlayer1States() const { + if (this->player1RepresentedByMatrix()) { + return this->getPlayer1Matrix().getRowGroupCount(); + } else { + return this->getPlayer1Grouping().size() - 1; + } + } + + template + uint64_t StandardGameSolver::getNumberOfPlayer2States() const { + return this->player2Matrix.getRowGroupCount(); + } + template typename StandardGameSolver::Status StandardGameSolver::updateStatusIfNotConverged(Status status, std::vector const& x, uint64_t iterations, uint64_t maximalNumberOfIterations) const { if (status != Status::Converged) { diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index e9e8060a7..e0a800ea2 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -11,10 +11,14 @@ namespace storm { template class StandardGameSolver : public GameSolver { public: + // Constructors for when the first player is represented using a matrix. StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); - StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); + // Constructor for when the first player is represented by a grouping of the player 2 states (row groups). + StandardGameSolver(std::vector const& player1Groups, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); + StandardGameSolver(std::vector&& player1Groups, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); + virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const override; virtual void repeatedMultiply(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; @@ -27,7 +31,7 @@ namespace storm { bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; // Computes p2Matrix * x + b, reduces the result w.r.t. player 2 choices, and then reduces the result w.r.t. player 1 choices. - void multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const; + void multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& player2ReducedResult, std::vector& player1ReducedResult, std::vector* player1SchedulerChoices = nullptr, std::vector* player2SchedulerChoices = nullptr) const; // Solves the equation system given by the two choice selections void getInducedMatrixVector(std::vector& x, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const; @@ -38,6 +42,12 @@ namespace storm { bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; + bool player1RepresentedByMatrix() const; + storm::storage::SparseMatrix const& getPlayer1Matrix() const; + std::vector const& getPlayer1Grouping() const; + uint64_t getNumberOfPlayer1States() const; + uint64_t getNumberOfPlayer2States() const; + enum class Status { Converged, TerminatedEarly, MaximalIterationsExceeded, InProgress }; @@ -56,12 +66,14 @@ namespace storm { // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted // when the solver is destructed. - std::unique_ptr> localP1Matrix; - std::unique_ptr> localP2Matrix; + std::unique_ptr> localPlayer1Grouping; + std::unique_ptr> localPlayer1Matrix; + std::unique_ptr> localPlayer2Matrix; // A reference to the original sparse matrix given to this solver. If the solver takes posession of the matrix // the reference refers to localA. - storm::storage::SparseMatrix const& player1Matrix; + std::vector const* player1Grouping; + storm::storage::SparseMatrix const* player1Matrix; storm::storage::SparseMatrix const& player2Matrix; }; diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index 917ed92e2..1ec88e34e 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -756,7 +756,7 @@ namespace storm { /*! * Selects the rows that are given by the sequence of row indices, allowing to select rows arbitrarily often and with an arbitrary order - * The resulting matrix will have a trivial row grouping + * The resulting matrix will have a trivial row grouping. * * @param rowIndexSequence the sequence of row indices which specifies, which rows are contained in the new matrix * @param insertDiagonalEntries If set to true, the resulting matrix will have zero entries in column i for From 3952b47d1b2c7e4bf5bbaf883685619f3f177930 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 28 Mar 2018 11:03:12 +0200 Subject: [PATCH 211/647] fix some compile issues --- .../abstraction/GameBasedMdpModelChecker.cpp | 10 +++++----- src/storm/solver/GameSolver.cpp | 10 ++++++++++ src/storm/solver/NativeMultiplier.cpp | 1 - src/storm/solver/StandardGameSolver.cpp | 2 +- src/storm/storage/SparseMatrix.h | 4 +++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 2c10f2f2d..43df463ae 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -410,11 +410,11 @@ namespace storm { storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, maybeStates); - auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); - multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); - - - env. +// auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); +// multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); +// +// +// env. } template diff --git a/src/storm/solver/GameSolver.cpp b/src/storm/solver/GameSolver.cpp index 0710cc9f2..bb27cb4fa 100644 --- a/src/storm/solver/GameSolver.cpp +++ b/src/storm/solver/GameSolver.cpp @@ -99,6 +99,16 @@ namespace storm { // Intentionally left empty. } + template + void GameSolver::setHasUniqueSolution(bool value) { + this->uniqueSolution = value; + } + + template + bool GameSolver::hasUniqueSolution() const { + return this->uniqueSolution; + } + template GameSolverFactory::GameSolverFactory() { // Intentionally left empty. diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index 13b27c617..7dd2457df 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -97,7 +97,6 @@ namespace storm { } } - template void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { this->matrix.multiplyWithVector(x, result, b); diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 07512b23d..4d4cfd03c 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -240,7 +240,7 @@ namespace storm { Status status = Status::InProgress; while (status == Status::InProgress) { - multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, trackSchedulersInValueIteration ? &this->getPlayer1SchedulerChoices() : nullptr, trackSchedulersInValueIteration ? &this->getPlayer2SchedulerChoices() : nullptr); + multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, trackSchedulersInValueIteration ? &this->player1SchedulerChoices.get() : nullptr, trackSchedulersInValueIteration ? &this->player2SchedulerChoices.get() : nullptr); // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index 1ec88e34e..c6b51b981 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -851,7 +851,9 @@ namespace storm { * @param vector The vector with which to multiply the matrix. * @param summand If given, this summand will be added to the result of the multiplication. * @param result The vector that is supposed to hold the result of the multiplication after the operation. - * @param choices If given, the choices made in the reduction process will be written to this vector. + * @param choices If given, the choices made in the reduction process will be written to this vector. Note + * that if the direction is maximize, the choice for a row group is only updated if the value obtained with + * the 'new' choice has a value strictly better (wrt. to the optimization direction) value. * @return The resulting vector the content of the given result vector. */ void multiplyAndReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const; From 0725b5e59024481813dd726d2bc0f0f9e70eb594 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 28 Mar 2018 14:02:49 +0200 Subject: [PATCH 212/647] changes to tracking values in mult-and-reduce functions of matrix --- src/storm/solver/Multiplier.h | 2 - src/storm/storage/SparseMatrix.cpp | 120 ++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h index a94934ae0..5f9036022 100644 --- a/src/storm/solver/Multiplier.h +++ b/src/storm/solver/Multiplier.h @@ -144,8 +144,6 @@ namespace storm { ~MultiplierFactory() = default; std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix); - - }; } diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index d909b76b2..3f0f25828 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -1501,7 +1501,7 @@ namespace storm { multiplyWithVectorParallel(vector, tmpVector); result = std::move(tmpVector); } else { - tbb::parallel_for(tbb::blocked_range(0, result.size(), 10), TbbMultAddFunctor(columnsAndValues, rowIndications, vector, result, summand)); + tbb::parallel_for(tbb::blocked_range(0, result.size(), 100), TbbMultAddFunctor(columnsAndValues, rowIndications, vector, result, summand)); } } #endif @@ -1586,6 +1586,7 @@ namespace storm { template void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + bool min = dir == OptimizationDirection::Minimize; auto elementIt = this->begin(); auto rowGroupIt = rowGroupIndices.begin(); auto rowIt = rowIndications.begin(); @@ -1597,13 +1598,15 @@ namespace storm { if (choices) { choiceIt = choices->begin(); } + + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + uint64_t currentRow = 0; for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++choiceIt, ++rowGroupIt) { ValueType currentValue = storm::utility::zero(); - if (choices) { - *choiceIt = 0; - } - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { @@ -1615,30 +1618,43 @@ namespace storm { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = currentValue; + } + } + ++rowIt; + ++currentRow; - for (; static_cast(std::distance(rowIndications.begin(), rowIt)) < *(rowGroupIt + 1); ++rowIt) { + for (; currentRow < *(rowGroupIt + 1); ++rowIt, ++currentRow) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (choices && currentRow == *choiceIt + *rowGroupIt) { + oldSelectedChoiceValue = newValue; + } + + if (min ? newValue < currentValue : newValue > currentValue) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; } } if (summand) { ++summandIt; } } - } else if (choices) { - *choiceIt = 0; + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } @@ -1651,6 +1667,7 @@ namespace storm { template void SparseMatrix::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + bool min = dir == OptimizationDirection::Minimize; auto elementIt = this->end() - 1; auto rowGroupIt = rowGroupIndices.end() - 2; auto rowIt = rowIndications.end() - 2; @@ -1662,13 +1679,15 @@ namespace storm { if (choices) { choiceIt = choices->end() - 1; } - + + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = this->getRowCount() - 1; for (auto resultIt = result.end() - 1, resultIte = result.begin() - 1; resultIt != resultIte; --resultIt, --choiceIt, --rowGroupIt) { - if (choices) { - *choiceIt = 0; - } ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { @@ -1680,27 +1699,38 @@ namespace storm { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; + if (*choiceIt == selectedChoice) { + oldSelectedChoiceValue = currentValue; + } } --rowIt; + --currentRow; - for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, ++i, --summandIt) { + for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, --currentRow, ++i, --summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (choices && currentRow == *choiceIt + *rowGroupIt) { + oldSelectedChoiceValue = newValue; + } + + if (min ? newValue < currentValue : newValue > currentValue) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; } } } + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } @@ -1724,6 +1754,8 @@ namespace storm { } void operator()(tbb::blocked_range const& range) const { + bool min = dir == storm::OptimizationDirection::Minimize; + auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); @@ -1740,11 +1772,12 @@ namespace storm { auto resultIt = result.begin() + range.begin(); + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { - if (choices) { - *choiceIt = 0; - } - ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if there is at least one row in the group. @@ -1758,25 +1791,40 @@ namespace storm { currentValue += elementIt->getValue() * x[elementIt->getColumn()]; } + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = currentValue; + } + } + ++rowIt; + ++currentRow; - for (; static_cast(std::distance(rowIndications.begin(), rowIt)) < *(groupIt + 1); ++rowIt, ++summandIt) { + for (; currentRow < *(groupIt + 1); ++rowIt, ++currentRow, ++summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * x[elementIt->getColumn()]; } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (choices && currentRow == *choiceIt + *groupIt) { + oldSelectedChoiceValue = newValue; + } + + if (min ? newValue < currentValue : newValue > currentValue) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *groupIt; + selectedChoice = currentRow - *groupIt; } } } + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } @@ -1793,7 +1841,7 @@ namespace storm { template void SparseMatrix::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor(dir, rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); } #ifdef STORM_HAVE_CARL From e205b1bf6add3dc65eccc7e14592ad07f89ec894 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 28 Mar 2018 15:36:13 +0200 Subject: [PATCH 213/647] check task API slightly extended for scheduler extraction --- src/storm/modelchecker/CheckTask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/CheckTask.h b/src/storm/modelchecker/CheckTask.h index 093c40ca8..45f2a9bc3 100644 --- a/src/storm/modelchecker/CheckTask.h +++ b/src/storm/modelchecker/CheckTask.h @@ -211,7 +211,7 @@ namespace storm { /*! * Sets whether to produce schedulers (if supported). */ - void setProduceSchedulers(bool produceSchedulers) { + void setProduceSchedulers(bool produceSchedulers = true) { this->produceSchedulers = produceSchedulers; } From 5159afc3485a53503868de2a0df187c82e8f4ee1 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 28 Mar 2018 16:45:03 +0200 Subject: [PATCH 214/647] further work towards proper scheduler extraction for games --- .../abstraction/GameBasedMdpModelChecker.cpp | 9 ++-- .../modules/MinMaxEquationSolverSettings.cpp | 2 +- src/storm/solver/GameSolver.cpp | 10 ++++ src/storm/solver/GameSolver.h | 5 +- src/storm/solver/GmmxxMultiplier.cpp | 49 ++++++++++--------- src/storm/solver/StandardGameSolver.h | 1 - src/storm/utility/vector.h | 33 +++++++++---- 7 files changed, 68 insertions(+), 41 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 43df463ae..af0c46121 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -32,6 +32,7 @@ #include "storm/logic/FragmentSpecification.h" #include "storm/solver/SymbolicGameSolver.h" +#include "storm/solver/StandardGameSolver.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" @@ -410,11 +411,9 @@ namespace storm { storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, maybeStates); -// auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); -// multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); -// -// -// env. + auto gameSolver = storm::solver::GameSolverFactory().create(env, player1Groups, transitionMatrix); + exit(-1); + } template diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 186f0caf9..8ee45ab20 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -38,7 +38,7 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a long run average computation method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(lraMethods)).setDefaultValueString("vi").build()).build()); std::vector maMethods = {"imca", "unifplus"}; - this->addOption(storm::settings::OptionBuilder(moduleName, markovAutomatonBoundedReachabilityMethodOptionName, true, "The method to use to solve bounded reachability queries on MAs.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, markovAutomatonBoundedReachabilityMethodOptionName, false, "The method to use to solve bounded reachability queries on MAs.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.") diff --git a/src/storm/solver/GameSolver.cpp b/src/storm/solver/GameSolver.cpp index bb27cb4fa..f5ccce0ad 100644 --- a/src/storm/solver/GameSolver.cpp +++ b/src/storm/solver/GameSolver.cpp @@ -124,6 +124,16 @@ namespace storm { return std::make_unique>(std::move(player1Matrix), std::move(player2Matrix), std::make_unique>()); } + template + std::unique_ptr> GameSolverFactory::create(Environment const& env, std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix) const { + return std::make_unique>(player1Grouping, player2Matrix, std::make_unique>()); + } + + template + std::unique_ptr> GameSolverFactory::create(Environment const& env, std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix) const { + return std::make_unique>(std::move(player1Grouping), std::move(player2Matrix), std::make_unique>()); + } + template class GameSolver; template class GameSolver; diff --git a/src/storm/solver/GameSolver.h b/src/storm/solver/GameSolver.h index 07cb16e88..6c724e33c 100644 --- a/src/storm/solver/GameSolver.h +++ b/src/storm/solver/GameSolver.h @@ -154,9 +154,8 @@ namespace storm { virtual std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix) const; virtual std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix) const; - private: - bool trackScheduler; - + virtual std::unique_ptr> create(Environment const& env, std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix) const; + virtual std::unique_ptr> create(Environment const& env, std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix) const; }; } // namespace solver diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 9618e2495..939a4b61e 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -119,6 +119,7 @@ namespace storm { template void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + bool min = dir == OptimizationDirection::Minimize; typedef std::vector VectorType; typedef gmm::csr_matrix MatrixType; @@ -133,13 +134,13 @@ namespace storm { if (choices) { choice_it = choices->end() - 1; } - - uint64_t choice; - for (auto row_group_it = rowGroupIndices.end() - 2, row_group_ite = rowGroupIndices.begin() - 1; row_group_it != row_group_ite; --row_group_it, --choice_it, --target_it) { - if (choices) { - *choice_it = 0; - } + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = gmmMatrix.nrows() - 1; + for (auto row_group_it = rowGroupIndices.end() - 2, row_group_ite = rowGroupIndices.begin() - 1; row_group_it != row_group_ite; --row_group_it, --choice_it, --target_it) { ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. @@ -150,35 +151,39 @@ namespace storm { } currentValue += vect_sp(gmm::linalg_traits::row(itr), x); - + if (choices) { - choice = *(row_group_it + 1) - 1 - *row_group_it; - *choice_it = choice; + selectedChoice = currentRow - *row_group_it; + if (*choice_it == selectedChoice) { + oldSelectedChoiceValue = currentValue; + } } - + --itr; + --currentRow; - for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, --itr, --add_it) { + for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, ++currentRow, --itr, --add_it) { ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); - if (choices) { - --choice; + if (choices && currentRow == *choice_it + *row_group_it) { + oldSelectedChoiceValue = newValue; } - - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + + if (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue) { currentValue = newValue; if (choices) { - *choice_it = choice; + selectedChoice = currentRow - *row_group_it; } } } - } else if (choices) { - *choice_it = 0; + + // Finally write value to target vector. + *target_it = currentValue; + if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + *choice_it = selectedChoice; + } } - - // Write back final value. - *target_it = currentValue; } } @@ -275,7 +280,7 @@ namespace storm { template void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor(dir, rowGroupIndices, this->gmmMatrix, x, b, result, choices)); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices); diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index e0a800ea2..338966d27 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -75,7 +75,6 @@ namespace storm { std::vector const* player1Grouping; storm::storage::SparseMatrix const* player1Matrix; storm::storage::SparseMatrix const& player2Matrix; - }; } } diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index ac73e48d5..c283d7495 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -672,28 +672,43 @@ namespace storm { typename std::vector::const_iterator sourceIt = source.begin(); typename std::vector::const_iterator sourceIte; typename std::vector::iterator choiceIt; - uint_fast64_t localChoice; - if (choices != nullptr) { + if (choices) { choiceIt = choices->begin(); } + // Variables for correctly tracking choices (only update if new choice is strictly better). + T oldSelectedChoiceValue; + uint64_t selectedChoice; + for (; targetIt != targetIte; ++targetIt, ++rowGroupingIt, ++choiceIt) { // Only traverse elements if the row group is non-empty. if (*rowGroupingIt != *(rowGroupingIt + 1)) { *targetIt = *sourceIt; - ++sourceIt; - localChoice = 1; - if (choices != nullptr) { - *choiceIt = 0; + + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = *targetIt; + } } - for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt, ++localChoice) { + + ++sourceIt; + for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt) { + if (choices && selectedChoice == std::distance(source.begin(), sourceIt) - *rowGroupingIt) { + oldSelectedChoiceValue = *sourceIt; + } + if (f(*sourceIt, *targetIt)) { *targetIt = *sourceIt; - if (choices != nullptr) { - *choiceIt = localChoice; + if (choices) { + selectedChoice = std::distance(source.begin(), sourceIt) - *rowGroupingIt; } } } + + if (choices && f(*targetIt, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } else { *targetIt = storm::utility::zero(); } From 0534216a85fc0fa8709d4e26728817ff4dbd7857 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 28 Mar 2018 17:14:36 +0200 Subject: [PATCH 215/647] preparations for scheduler extraction support --- src/storm/modelchecker/results/CheckResult.cpp | 4 ++++ src/storm/modelchecker/results/CheckResult.h | 4 +++- .../modelchecker/results/ExplicitQuantitativeCheckResult.h | 2 +- src/storm/storage/Scheduler.h | 6 +++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/storm/modelchecker/results/CheckResult.cpp b/src/storm/modelchecker/results/CheckResult.cpp index 9155057d3..26eb24946 100644 --- a/src/storm/modelchecker/results/CheckResult.cpp +++ b/src/storm/modelchecker/results/CheckResult.cpp @@ -162,6 +162,10 @@ namespace storm { SymbolicParetoCurveCheckResult const& CheckResult::asSymbolicParetoCurveCheckResult() const { return dynamic_cast const&>(*this); } + + bool CheckResult::hasScheduler() const { + return false; + } // Explicitly instantiate the template functions. template QuantitativeCheckResult& CheckResult::asQuantitativeCheckResult(); diff --git a/src/storm/modelchecker/results/CheckResult.h b/src/storm/modelchecker/results/CheckResult.h index 4edd2cb19..740a8269d 100644 --- a/src/storm/modelchecker/results/CheckResult.h +++ b/src/storm/modelchecker/results/CheckResult.h @@ -111,7 +111,9 @@ namespace storm { template SymbolicParetoCurveCheckResult const& asSymbolicParetoCurveCheckResult() const; - + + virtual bool hasScheduler() const; + virtual std::ostream& writeToStream(std::ostream& out) const = 0; }; diff --git a/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h b/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h index 131cf0cea..57be3266f 100644 --- a/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h +++ b/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h @@ -65,7 +65,7 @@ namespace storm { virtual ValueType average() const override; virtual ValueType sum() const override; - bool hasScheduler() const; + virtual bool hasScheduler() const override; void setScheduler(std::unique_ptr>&& scheduler); storm::storage::Scheduler const& getScheduler() const; storm::storage::Scheduler& getScheduler(); diff --git a/src/storm/storage/Scheduler.h b/src/storm/storage/Scheduler.h index b51e308b9..f3777cf55 100644 --- a/src/storm/storage/Scheduler.h +++ b/src/storm/storage/Scheduler.h @@ -44,10 +44,10 @@ namespace storm { void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0); /*! - * Sets the choice defined by the scheduler for the given model and memory state. + * Gets the choice defined by the scheduler for the given model and memory state. * - * @param state The state for which to set the choice. - * @param choice The choice to set for the given state. + * @param state The state for which to get the choice. + * @param memoryState the memory state which we consider. */ SchedulerChoice const& getChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0) const; From 25853f08f1b1100b4f13abf058f365eee2d60f70 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 28 Mar 2018 18:57:17 +0200 Subject: [PATCH 216/647] fixed newly introduced issues with more restrictive choice updates --- src/storm/solver/GmmxxMultiplier.cpp | 4 +-- src/storm/utility/vector.h | 47 +++++++++++++++++++--------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 939a4b61e..e992e4457 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -162,7 +162,7 @@ namespace storm { --itr; --currentRow; - for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, ++currentRow, --itr, --add_it) { + for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, --currentRow, --itr, --add_it) { ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); @@ -170,7 +170,7 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue) { + if (min ? newValue < currentValue : newValue > currentValue) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index c283d7495..56494dc03 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -615,31 +615,46 @@ namespace storm { typename std::vector::const_iterator sourceIt = source.begin() + *rowGroupingIt; typename std::vector::const_iterator sourceIte; typename std::vector::iterator choiceIt; - uint_fast64_t localChoice; - if (choices != nullptr) { + if (choices) { choiceIt = choices->begin() + startRow; } - + + // Variables for correctly tracking choices (only update if new choice is strictly better). + T oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = 0; for (; targetIt != targetIte; ++targetIt, ++rowGroupingIt, ++choiceIt) { // Only traverse elements if the row group is non-empty. if (*rowGroupingIt != *(rowGroupingIt + 1)) { *targetIt = *sourceIt; - ++sourceIt; - localChoice = 1; - if (choices != nullptr) { - *choiceIt = 0; + + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = *targetIt; + } } - for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt, ++localChoice) { + ++sourceIt; + ++currentRow; + + for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt, ++currentRow) { + if (choices && *choiceIt + *rowGroupingIt == currentRow) { + oldSelectedChoiceValue = *sourceIt; + } + if (f(*sourceIt, *targetIt)) { *targetIt = *sourceIt; - if (choices != nullptr) { - *choiceIt = localChoice; + if (choices) { + selectedChoice = std::distance(source.begin(), sourceIt) - *rowGroupingIt; } } } - } else { - *targetIt = storm::utility::zero(); + + if (choices && f(*targetIt, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } } } @@ -680,6 +695,7 @@ namespace storm { T oldSelectedChoiceValue; uint64_t selectedChoice; + uint64_t currentRow = 0; for (; targetIt != targetIte; ++targetIt, ++rowGroupingIt, ++choiceIt) { // Only traverse elements if the row group is non-empty. if (*rowGroupingIt != *(rowGroupingIt + 1)) { @@ -693,8 +709,10 @@ namespace storm { } ++sourceIt; - for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt) { - if (choices && selectedChoice == std::distance(source.begin(), sourceIt) - *rowGroupingIt) { + ++currentRow; + + for (sourceIte = source.begin() + *(rowGroupingIt + 1); sourceIt != sourceIte; ++sourceIt, ++currentRow) { + if (choices && *rowGroupingIt + *choiceIt == currentRow) { oldSelectedChoiceValue = *sourceIt; } @@ -710,6 +728,7 @@ namespace storm { *choiceIt = selectedChoice; } } else { + *choiceIt = 0; *targetIt = storm::utility::zero(); } } From c3e66f2dec27cba4ef8c8aaa6d6599b4626fda59 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 28 Mar 2018 22:34:27 +0200 Subject: [PATCH 217/647] more work on solving the abstractions explicitly --- .../abstraction/GameBasedMdpModelChecker.cpp | 44 +++++++++++++++---- src/storm/solver/StandardGameSolver.cpp | 2 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index af0c46121..9d1229b34 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -391,7 +391,7 @@ namespace storm { } template - ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& minStrategyPair) { + ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair) { bool player1Min = player1Direction == storm::OptimizationDirection::Minimize; bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; @@ -400,18 +400,44 @@ namespace storm { auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); - // Determine which rows to keep. - storm::storage::BitVector player2MaybeStates(transitionMatrix.getRowCount()); - for (uint64_t player2State = 0; player2State < transitionMatrix.getRowGroupCount(); ++player2State) { - if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) { - player2MaybeStates.set(player2State); + // Determine which row groups to keep. + storm::storage::BitVector player2MaybeStates = ~(player2Prob0States | player2Prob1States); + + // Create the sub-game. + std::cout << "maybe: " << maybeStates << std::endl; + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); + std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, player1Prob1States); + std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); + uint64_t position = 0; + uint64_t previousPlayer2States = 0; + for (auto state : maybeStates) { + subPlayer1Groups[position] = previousPlayer2States; + + bool hasMaybePlayer2Successor = false; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player2MaybeStates.get(player2State)) { + hasMaybePlayer2Successor = true; + ++previousPlayer2States; + } } + STORM_LOG_ASSERT(hasMaybePlayer2Successor, "Player 1 maybe state has no player2 maybe successor."); + ++position; } + subPlayer1Groups.back() = previousPlayer2States; + + // Solve the sub-game. + auto gameSolver = storm::solver::GameSolverFactory().create(env, subPlayer1Groups, submatrix); + std::vector lowerValues(maybeStates.getNumberOfSetBits()); + gameSolver->solveGame(env, player1Direction, player2Direction, lowerValues, b); + + // Create combined result for all states. + ExplicitQuantitativeResult result(maybeStates.size()); + storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); + storm::utility::vector::setVectorValues(result.getValues(), maybeStates, lowerValues); + + // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. - storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); - std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, maybeStates); - auto gameSolver = storm::solver::GameSolverFactory().create(env, player1Groups, transitionMatrix); exit(-1); } diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 4d4cfd03c..3d9e4975d 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -234,7 +234,7 @@ namespace storm { std::vector* newX = auxiliaryP1RowGroupVector.get(); std::vector* currentX = &x; - + // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = 0; From cbc72468854fbc9b314d0f1388f4c9b61628d27a Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 29 Mar 2018 09:35:03 +0200 Subject: [PATCH 218/647] min/max sparse game solving alpha version in game-based abstraction --- .../abstraction/ExplicitGameStrategy.cpp | 4 + src/storm/abstraction/ExplicitGameStrategy.h | 4 +- .../abstraction/ExplicitGameStrategyPair.cpp | 8 ++ .../abstraction/ExplicitGameStrategyPair.h | 3 + .../abstraction/GameBasedMdpModelChecker.cpp | 90 +++++++++++-------- 5 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/storm/abstraction/ExplicitGameStrategy.cpp b/src/storm/abstraction/ExplicitGameStrategy.cpp index 2703ac3a5..29748aa92 100644 --- a/src/storm/abstraction/ExplicitGameStrategy.cpp +++ b/src/storm/abstraction/ExplicitGameStrategy.cpp @@ -35,6 +35,10 @@ namespace storm { } } + uint64_t ExplicitGameStrategy::getNumberOfUndefinedStates() const { + return std::count_if(choices.begin(), choices.end(), [] (uint64_t choice) { return choice == UNDEFINED; }); + } + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategy const& strategy) { std::vector undefinedStates; for (uint64_t state = 0; state < strategy.getNumberOfStates(); ++state) { diff --git a/src/storm/abstraction/ExplicitGameStrategy.h b/src/storm/abstraction/ExplicitGameStrategy.h index aabe6226f..af96a1f69 100644 --- a/src/storm/abstraction/ExplicitGameStrategy.h +++ b/src/storm/abstraction/ExplicitGameStrategy.h @@ -19,7 +19,9 @@ namespace storm { void setChoice(uint64_t state, uint64_t choice); bool hasDefinedChoice(uint64_t state) const; void undefineAll(); - + + uint64_t getNumberOfUndefinedStates() const; + private: std::vector choices; }; diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.cpp b/src/storm/abstraction/ExplicitGameStrategyPair.cpp index 9f42ea642..eed00f455 100644 --- a/src/storm/abstraction/ExplicitGameStrategyPair.cpp +++ b/src/storm/abstraction/ExplicitGameStrategyPair.cpp @@ -27,6 +27,14 @@ namespace storm { return player2Strategy; } + uint64_t ExplicitGameStrategyPair::getNumberOfUndefinedPlayer1States() const { + return player1Strategy.getNumberOfUndefinedStates(); + } + + uint64_t ExplicitGameStrategyPair::getNumberOfUndefinedPlayer2States() const { + return player2Strategy.getNumberOfUndefinedStates(); + } + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategyPair const& strategyPair) { out << "player 1 strategy: " << std::endl << strategyPair.getPlayer1Strategy() << std::endl; out << "player 2 strategy: " << std::endl << strategyPair.getPlayer2Strategy() << std::endl; diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.h b/src/storm/abstraction/ExplicitGameStrategyPair.h index e5774d7e1..b7428d987 100644 --- a/src/storm/abstraction/ExplicitGameStrategyPair.h +++ b/src/storm/abstraction/ExplicitGameStrategyPair.h @@ -18,6 +18,9 @@ namespace storm { ExplicitGameStrategy& getPlayer2Strategy(); ExplicitGameStrategy const& getPlayer2Strategy() const; + uint64_t getNumberOfUndefinedPlayer1States() const; + uint64_t getNumberOfUndefinedPlayer2States() const; + private: ExplicitGameStrategy player1Strategy; ExplicitGameStrategy player2Strategy; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 9d1229b34..7dd306a81 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -404,7 +404,6 @@ namespace storm { storm::storage::BitVector player2MaybeStates = ~(player2Prob0States | player2Prob1States); // Create the sub-game. - std::cout << "maybe: " << maybeStates << std::endl; storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, player1Prob1States); std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); @@ -427,6 +426,7 @@ namespace storm { // Solve the sub-game. auto gameSolver = storm::solver::GameSolverFactory().create(env, subPlayer1Groups, submatrix); + gameSolver->setTrackSchedulers(true); std::vector lowerValues(maybeStates.getNumberOfSetBits()); gameSolver->solveGame(env, player1Direction, player2Direction, lowerValues, b); @@ -435,11 +435,33 @@ namespace storm { storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); storm::utility::vector::setVectorValues(result.getValues(), maybeStates, lowerValues); - // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. - + STORM_LOG_ASSERT(gameSolver->hasSchedulers(), "Expected to have schedulers available after solving game."); - exit(-1); + std::vector const& player1Scheduler = gameSolver->getPlayer1SchedulerChoices(); + std::vector const& player2Scheduler = gameSolver->getPlayer2SchedulerChoices(); + + // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. + uint64_t previousPlayer1MaybeStates = 0; + uint64_t previousPlayer2MaybeStates = 0; + for (auto state : maybeStates) { + uint64_t previousPlayer2StatesForState = 0; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2StatesForState) { + strategyPair.getPlayer1Strategy().setChoice(state, player2State); + } + + if (player2MaybeStates.get(player2State)) { + strategyPair.getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]); + + ++previousPlayer2StatesForState; + ++previousPlayer2MaybeStates; + } + } + + ++previousPlayer1MaybeStates; + } + return result; } template @@ -663,6 +685,7 @@ namespace storm { player2BackwardTransitions[player2State] = player1State; ++player2State; } + player1Groups[player1State + 1] = player2State; } @@ -724,42 +747,37 @@ namespace storm { auto quantitativeStart = std::chrono::high_resolution_clock::now(); ExplicitQuantitativeResultMinMax quantitativeResult; + + // (7) Solve the min values and check whether we can give the answer already. quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair)); - -// SymbolicQuantitativeGameResultMinMax quantitativeResult; -// -// // (7) Solve the min values and check whether we can give the answer already. -// quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); -// previousMinQuantitativeResult = quantitativeResult.min; -// result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); -// if (result) { -// return result; -// } -// -// // (8) Solve the max values and check whether we can give the answer already. -// quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); -// result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); -// if (result) { -// return result; -// } -// + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); + if (result) { + return result; + } + + // (8) Solve the max values and check whether we can give the answer already. + quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair)); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); + if (result) { + return result; + } + auto quantitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); -// -// // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. -// result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); -// if (result) { -// return result; -// } -// -// // Make sure that all strategies are still valid strategies. -// STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); -// STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); -// STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); -// STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); -// + + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. + result = checkForResultAfterQuantitativeCheck(quantitativeResult.getMin().getRange(initialStates).first, quantitativeResult.getMax().getRange(initialStates).second, comparator); + if (result) { + return result; + } + + // Make sure that all strategies are still valid strategies. + STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() == targetStates.getNumberOfSetBits() && minStrategyPair.getNumberOfUndefinedPlayer2States() == 0, "Minimal strategy pair has undefined choices for some relevant states."); + STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() == targetStates.getNumberOfSetBits() && maxStrategyPair.getNumberOfUndefinedPlayer2States() == 0, "Maximal strategy pair has undefined choices for some relevant states."); + + exit(-1); + auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); -// // // (10) If we arrived at this point, it means that we have all qualitative and quantitative // // information about the game, but we could not yet answer the query. In this case, we need to refine. // refiner.refine(game, transitionMatrixBdd, quantitativeResult); From 0a68d8afa290e41472b9697b403c3f68b7a1b5f0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 29 Mar 2018 09:44:58 +0200 Subject: [PATCH 219/647] fixed out-of-bounds access in symbolic to explicit conversion of game-based abstraction --- src/storm/abstraction/MenuGameRefiner.cpp | 2 ++ .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 76e528ee7..f8209ee99 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -672,6 +672,8 @@ namespace storm { if (!interpolant.isTrue() && !interpolant.isFalse()) { STORM_LOG_DEBUG("Derived new predicate (based on interpolation): " << interpolant); interpolants.push_back(interpolant); + } else { + STORM_LOG_TRACE("Found interpolant is '" << interpolant << "'."); } } return boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 7dd306a81..35d838d55 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -680,12 +680,12 @@ namespace storm { std::vector player2BackwardTransitions(transitionMatrix.getRowGroupCount()); uint64_t player2State = 0; - for (uint64_t player1State = 0; player1State < player2RowGrouping.size() - 1; ++player1State) { + for (uint64_t player1State = 0; player1State < player1RowGrouping.size() - 1; ++player1State) { while (player1RowGrouping[player1State + 1] > player2RowGrouping[player2State]) { player2BackwardTransitions[player2State] = player1State; ++player2State; } - + player1Groups[player1State + 1] = player2State; } From 76d5ddad3032d33fa7397362ab997f236ab781b6 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 13:42:56 +0200 Subject: [PATCH 220/647] Minor improvements in DRN parser --- src/storm/parser/DirectEncodingParser.cpp | 35 +++++++++++--------- src/storm/utility/DirectEncodingExporter.cpp | 31 +++++++++-------- src/storm/utility/DirectEncodingExporter.h | 4 +-- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm/parser/DirectEncodingParser.cpp index 288eda7e5..a0595e7be 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm/parser/DirectEncodingParser.cpp @@ -40,26 +40,27 @@ namespace storm { bool sawParameters = false; size_t nrStates = 0; storm::models::ModelType type; - std::vector rewardModelNames; - - std::shared_ptr> modelComponents; + std::shared_ptr> modelComponents; // Parse header - while(std::getline(file, line)) { - if(line.empty() || boost::starts_with(line, "//")) { + while (std::getline(file, line)) { + if (line.empty() || boost::starts_with(line, "//")) { continue; } if (boost::starts_with(line, "@type: ")) { + // Parse type STORM_LOG_THROW(!sawType, storm::exceptions::WrongFormatException, "Type declared twice"); type = storm::models::getModelType(line.substr(7)); STORM_LOG_TRACE("Model type: " << type); STORM_LOG_THROW(type != storm::models::ModelType::MarkovAutomaton, storm::exceptions::NotSupportedException, "Markov Automata in DRN format are not supported (unclear indication of Markovian Choices in DRN format)"); STORM_LOG_THROW(type != storm::models::ModelType::S2pg, storm::exceptions::NotSupportedException, "Stochastic Two Player Games in DRN format are not supported."); sawType = true; - } - if(line == "@parameters") { + + } else if (line == "@parameters") { + // Parse parameters + STORM_LOG_THROW(!sawParameters, storm::exceptions::WrongFormatException, "Parameters declared twice"); std::getline(file, line); if (line != "") { std::vector parameters; @@ -70,26 +71,28 @@ namespace storm { } } sawParameters = true; - } - if(line == "@reward_models") { + + } else if (line == "@reward_models") { + // Parse reward models STORM_LOG_THROW(rewardModelNames.size() == 0, storm::exceptions::WrongFormatException, "Reward model names declared twice"); std::getline(file, line); boost::split(rewardModelNames, line, boost::is_any_of("\t ")); - } - if(line == "@nr_states") { + } else if (line == "@nr_states") { + // Parse no. of states STORM_LOG_THROW(nrStates == 0, storm::exceptions::WrongFormatException, "Number states declared twice"); std::getline(file, line); nrStates = NumberParser::parse(line); - - } - if(line == "@model") { + } else if (line == "@model") { + // Parse rest of the model STORM_LOG_THROW(sawType, storm::exceptions::WrongFormatException, "Type has to be declared before model."); STORM_LOG_THROW(sawParameters, storm::exceptions::WrongFormatException, "Parameters have to be declared before model."); - STORM_LOG_THROW(nrStates != 0, storm::exceptions::WrongFormatException, "Nr States has to be declared before model."); + STORM_LOG_THROW(nrStates != 0, storm::exceptions::WrongFormatException, "No. of states has to be declared before model."); // Construct model components modelComponents = parseStates(file, type, nrStates, valueParser, rewardModelNames); break; + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse line '" << line << "'."); } } // Done parsing @@ -182,8 +185,8 @@ namespace storm { } else { ++row; } - line = line.substr(8); STORM_LOG_TRACE("New action: " << row); + line = line.substr(8); //Remove "\taction " // Check for rewards if (boost::starts_with(line, "[")) { // Rewards found diff --git a/src/storm/utility/DirectEncodingExporter.cpp b/src/storm/utility/DirectEncodingExporter.cpp index e0913a0f2..43c34b3ce 100644 --- a/src/storm/utility/DirectEncodingExporter.cpp +++ b/src/storm/utility/DirectEncodingExporter.cpp @@ -55,7 +55,8 @@ namespace storm { os << "@model" << std::endl; storm::storage::SparseMatrix const& matrix = sparseModel->getTransitionMatrix(); - + + // Iterate over states and export state information and outgoing transitions for (typename storm::storage::SparseMatrix::index_type group = 0; group < matrix.getRowGroupCount(); ++group) { os << "state " << group; @@ -92,22 +93,23 @@ namespace storm { // Iterate over all actions for (typename storm::storage::SparseMatrix::index_type row = start; row < end; ++row) { - // Print the actual row. + // Write choice if (sparseModel->hasChoiceLabeling()) { os << "\taction "; bool lfirst = true; for (auto const& label : sparseModel->getChoiceLabeling().getLabelsOfChoice(row)) { if (!lfirst) { os << "_"; + lfirst = false; } os << label; - lfirst = false; } } else { os << "\taction " << row - start; } + + // Write action rewards bool first = true; - // Write transition rewards for (auto const& rewardModelEntry : sparseModel->getRewardModels()) { if (first) { os << " ["; @@ -116,7 +118,7 @@ namespace storm { os << ", "; } - if(rewardModelEntry.second.hasStateActionRewards()) { + if (rewardModelEntry.second.hasStateActionRewards()) { os << storm::utility::to_string(rewardModelEntry.second.getStateActionRewardVector().at(row)); } else { os << "0"; @@ -126,19 +128,18 @@ namespace storm { if (!first) { os << "]"; } - os << std::endl; - - // Write probabilities - for(auto it = matrix.begin(row); it != matrix.end(row); ++it) { + + // Write transitions + for (auto it = matrix.begin(row); it != matrix.end(row); ++it) { ValueType prob = it->getValue(); os << "\t\t" << it->getColumn() << " : "; os << storm::utility::to_string(prob) << std::endl; } - + } - } // end matrix iteration - + } // end state iteration + } template @@ -146,9 +147,6 @@ namespace storm { return {}; } - template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters); - -#ifdef STORM_HAVE_CARL template<> std::vector getParameters(std::shared_ptr> sparseModel) { std::vector parameters; @@ -167,8 +165,9 @@ namespace storm { return parameters; } + // Template instantiations + template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters); template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters); template void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters); -#endif } } diff --git a/src/storm/utility/DirectEncodingExporter.h b/src/storm/utility/DirectEncodingExporter.h index 9728599a6..5ffe4d10d 100644 --- a/src/storm/utility/DirectEncodingExporter.h +++ b/src/storm/utility/DirectEncodingExporter.h @@ -18,13 +18,13 @@ namespace storm { void explicitExportSparseModel(std::ostream& os, std::shared_ptr> sparseModel, std::vector const& parameters); /*! - * Accumalate parameters in the model. + * Accumulate parameters in the model. * * @param sparseModel Model. * @return List of parameters in the model. */ template std::vector getParameters(std::shared_ptr> sparseModel); - + } } From 692ded94cfbe7612696a470cf7ef536a9b208e6f Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 13:43:26 +0200 Subject: [PATCH 221/647] Typo --- src/storm/parser/MarkovAutomatonParser.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/storm/parser/MarkovAutomatonParser.cpp b/src/storm/parser/MarkovAutomatonParser.cpp index 0921556fd..829c7256f 100644 --- a/src/storm/parser/MarkovAutomatonParser.cpp +++ b/src/storm/parser/MarkovAutomatonParser.cpp @@ -25,36 +25,36 @@ namespace storm { // Parse the state labeling. storm::models::sparse::StateLabeling resultLabeling(storm::parser::SparseItemLabelingParser::parseAtomicPropositionLabeling(transitionMatrix.getColumnCount(), labelingFilename)); - // Cunstruct the result components - storm::storage::sparse::ModelComponents> componets(std::move(transitionMatrix), std::move(resultLabeling)); - componets.rateTransitions = true; - componets.markovianStates = std::move(transitionResult.markovianStates); - componets.exitRates = std::move(transitionResult.exitRates); + // Construct the result components + storm::storage::sparse::ModelComponents> components(std::move(transitionMatrix), std::move(resultLabeling)); + components.rateTransitions = true; + components.markovianStates = std::move(transitionResult.markovianStates); + components.exitRates = std::move(transitionResult.exitRates); // If given, parse the state rewards file. boost::optional> stateRewards; if (!stateRewardFilename.empty()) { - stateRewards.reset(storm::parser::SparseStateRewardParser::parseSparseStateReward(componets.transitionMatrix.getColumnCount(), stateRewardFilename)); + stateRewards.reset(storm::parser::SparseStateRewardParser::parseSparseStateReward(components.transitionMatrix.getColumnCount(), stateRewardFilename)); } // Only parse transition rewards if a file is given. boost::optional> transitionRewards; if (!transitionRewardFilename.empty()) { - transitionRewards = std::move(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(transitionRewardFilename, componets.transitionMatrix)); + transitionRewards = std::move(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(transitionRewardFilename, components.transitionMatrix)); } if (stateRewards || transitionRewards) { - componets.rewardModels.insert(std::make_pair("", storm::models::sparse::StandardRewardModel(std::move(stateRewards), boost::none, std::move(transitionRewards)))); + components.rewardModels.insert(std::make_pair("", storm::models::sparse::StandardRewardModel(std::move(stateRewards), boost::none, std::move(transitionRewards)))); } // Only parse choice labeling if a file is given. boost::optional choiceLabeling; if (!choiceLabelingFilename.empty()) { - componets.choiceLabeling = storm::parser::SparseItemLabelingParser::parseChoiceLabeling(componets.transitionMatrix.getRowCount(), choiceLabelingFilename, componets.transitionMatrix.getRowGroupIndices()); + components.choiceLabeling = storm::parser::SparseItemLabelingParser::parseChoiceLabeling(components.transitionMatrix.getRowCount(), choiceLabelingFilename, components.transitionMatrix.getRowGroupIndices()); } // generate the Markov Automaton. - return storm::models::sparse::MarkovAutomaton> (std::move(componets)); + return storm::models::sparse::MarkovAutomaton> (std::move(components)); } template class MarkovAutomatonParser; From 3e2aba515d2bcc570fda57106996ffe1565e309b Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 13:44:23 +0200 Subject: [PATCH 222/647] Added support for exit rates and Markovian/probabilistic states in DRN Format --- src/storm/parser/DirectEncodingParser.cpp | 109 ++++++++++++------- src/storm/utility/DirectEncodingExporter.cpp | 14 ++- 2 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm/parser/DirectEncodingParser.cpp index a0595e7be..93d8a60f2 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm/parser/DirectEncodingParser.cpp @@ -54,7 +54,6 @@ namespace storm { STORM_LOG_THROW(!sawType, storm::exceptions::WrongFormatException, "Type declared twice"); type = storm::models::getModelType(line.substr(7)); STORM_LOG_TRACE("Model type: " << type); - STORM_LOG_THROW(type != storm::models::ModelType::MarkovAutomaton, storm::exceptions::NotSupportedException, "Markov Automata in DRN format are not supported (unclear indication of Markovian Choices in DRN format)"); STORM_LOG_THROW(type != storm::models::ModelType::S2pg, storm::exceptions::NotSupportedException, "Stochastic Two Player Games in DRN format are not supported."); sawType = true; @@ -107,15 +106,21 @@ namespace storm { // Initialize auto modelComponents = std::make_shared>(); bool nonDeterministic = (type == storm::models::ModelType::Mdp || type == storm::models::ModelType::MarkovAutomaton); + bool continousTime = (type == storm::models::ModelType::Ctmc || type == storm::models::ModelType::MarkovAutomaton); storm::storage::SparseMatrixBuilder builder = storm::storage::SparseMatrixBuilder(0, 0, 0, false, nonDeterministic, 0); modelComponents->stateLabeling = storm::models::sparse::StateLabeling(stateSize); std::vector> stateRewards; - + if (continousTime) { + modelComponents->exitRates = std::vector(stateSize); + if (type == storm::models::ModelType::MarkovAutomaton) { + modelComponents->markovianStates = storm::storage::BitVector(stateSize); + } + } // We parse rates for continuous time models. if (type == storm::models::ModelType::Ctmc) { modelComponents->rateTransitions = true; } - + // Iterate over all lines std::string line; size_t row = 0; @@ -131,34 +136,66 @@ namespace storm { } else { ++state; } - line = line.substr(6); - size_t parsedId; - size_t posId = line.find(" "); - if (posId != std::string::npos) { - parsedId = NumberParser::parse(line.substr(0, posId)); - - // Parse rewards and labels - line = line.substr(posId+1); - // Check for rewards - if (boost::starts_with(line, "[")) { - // Rewards found - size_t posEndReward = line.find(']'); - STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); - std::string rewardsStr = line.substr(1, posEndReward-1); - STORM_LOG_TRACE("State rewards: " << rewardsStr); - std::vector rewards; - boost::split(rewards, rewardsStr, boost::is_any_of(",")); - if (stateRewards.size() < rewards.size()) { - stateRewards.resize(rewards.size(), std::vector(stateSize, storm::utility::zero())); - } - auto stateRewardsIt = stateRewards.begin(); - for (auto const& rew : rewards) { - (*stateRewardsIt)[state] = valueParser.parseValue(rew); - ++stateRewardsIt; - } - line = line.substr(posEndReward+1); + STORM_LOG_TRACE("New state " << state); + + // Parse state id + line = line.substr(6); // Remove "state " + std::string curString = line; + size_t posEnd = line.find(" "); + if (posEnd != std::string::npos) { + curString = line.substr(0, posEnd); + line = line.substr(posEnd+1); + } else { + line = ""; + } + size_t parsedId = NumberParser::parse(curString); + STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); + if (nonDeterministic) { + STORM_LOG_TRACE("new Row Group starts at " << row << "."); + builder.newRowGroup(row); + } + + if (type == storm::models::ModelType::Ctmc || type == storm::models::ModelType::MarkovAutomaton) { + // Parse exit rate for CTMC or MA + STORM_LOG_THROW(boost::starts_with(line, "!"), storm::exceptions::WrongFormatException, "Exit rate missing."); + line = line.substr(1); //Remove "!" + curString = line; + posEnd = line.find(" "); + if (posEnd != std::string::npos) { + curString = line.substr(0, posEnd); + line = line.substr(posEnd+1); + } else { + line = ""; + } + ValueType exitRate = valueParser.parseValue(curString); + if (type == storm::models::ModelType::MarkovAutomaton && !storm::utility::isZero(exitRate)) { + modelComponents->markovianStates.get().set(state); + } + STORM_LOG_TRACE("Exit rate " << exitRate); + modelComponents->exitRates.get()[state] = exitRate; + } + + if (boost::starts_with(line, "[")) { + // Parse rewards + size_t posEndReward = line.find(']'); + STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); + std::string rewardsStr = line.substr(1, posEndReward-1); + STORM_LOG_TRACE("State rewards: " << rewardsStr); + std::vector rewards; + boost::split(rewards, rewardsStr, boost::is_any_of(",")); + if (stateRewards.size() < rewards.size()) { + stateRewards.resize(rewards.size(), std::vector(stateSize, storm::utility::zero())); } - // Check for labels + auto stateRewardsIt = stateRewards.begin(); + for (auto const& rew : rewards) { + (*stateRewardsIt)[state] = valueParser.parseValue(rew); + ++stateRewardsIt; + } + line = line.substr(posEndReward+1); + } + + // Parse labels + if (!line.empty()) { std::vector labels; boost::split(labels, line, boost::is_any_of(" ")); for (std::string label : labels) { @@ -166,18 +203,10 @@ namespace storm { modelComponents->stateLabeling.addLabel(label); } modelComponents->stateLabeling.addLabelToState(label, state); - STORM_LOG_TRACE("New label: " << label); + STORM_LOG_TRACE("New label: '" << label << "'"); } - } else { - // Only state id given - parsedId = NumberParser::parse(line); - } - STORM_LOG_TRACE("New state " << state); - STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); - if (nonDeterministic) { - STORM_LOG_TRACE("new Row Group starts at " << row << "."); - builder.newRowGroup(row); } + } else if (boost::starts_with(line, "\taction ")) { // New action if (firstAction) { diff --git a/src/storm/utility/DirectEncodingExporter.cpp b/src/storm/utility/DirectEncodingExporter.cpp index 43c34b3ce..9953a4108 100644 --- a/src/storm/utility/DirectEncodingExporter.cpp +++ b/src/storm/utility/DirectEncodingExporter.cpp @@ -21,20 +21,17 @@ namespace storm { // Notice that for CTMCs we write the rate matrix instead of probabilities // Initialize - storm::models::ModelType type = sparseModel->getType(); std::vector exitRates; // Only for CTMCs and MAs. - if(sparseModel->getType() == storm::models::ModelType::Ctmc) { + if (sparseModel->getType() == storm::models::ModelType::Ctmc) { exitRates = sparseModel->template as>()->getExitRateVector(); - } else if(sparseModel->getType() == storm::models::ModelType::MarkovAutomaton) { - type = storm::models::ModelType::Mdp; - STORM_LOG_WARN("Markov automaton is exported as MDP (indication of Markovian choices is not supported in DRN format)."); + } else if (sparseModel->getType() == storm::models::ModelType::MarkovAutomaton) { exitRates = sparseModel->template as>()->getExitRates(); } // Write header os << "// Exported by storm" << std::endl; os << "// Original model type: " << sparseModel->getType() << std::endl; - os << "@type: " << type << std::endl; + os << "@type: " << sparseModel->getType() << std::endl; os << "@parameters" << std::endl; if (parameters.empty()) { for (std::string const& parameter : getParameters(sparseModel)) { @@ -60,6 +57,11 @@ namespace storm { for (typename storm::storage::SparseMatrix::index_type group = 0; group < matrix.getRowGroupCount(); ++group) { os << "state " << group; + // Write exit rates for CTMCs and MAs + if (!exitRates.empty()) { + os << " !" << exitRates.at(group); + } + // Write state rewards bool first = true; for (auto const& rewardModelEntry : sparseModel->getRewardModels()) { From db32a91c7c43017a309026ac604c147892c18b32 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 13:45:20 +0200 Subject: [PATCH 223/647] Changed logging level for some output --- src/storm/models/sparse/Model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/models/sparse/Model.cpp b/src/storm/models/sparse/Model.cpp index edeefb825..4bece4dcf 100644 --- a/src/storm/models/sparse/Model.cpp +++ b/src/storm/models/sparse/Model.cpp @@ -74,9 +74,9 @@ namespace storm { STORM_LOG_THROW(!components.exitRates.is_initialized() || components.exitRates->size() == stateCount, storm::exceptions::IllegalArgumentException, "Size of exit rate vector does not match state count."); STORM_LOG_THROW(this->isOfType(ModelType::Ctmc) || components.markovianStates.is_initialized(), storm::exceptions::IllegalArgumentException, "Can not create Markov Automaton: no Markovian states given."); } else { - STORM_LOG_ERROR_COND(!components.rateTransitions && !components.exitRates.is_initialized(), "Rates specified for discrete-time model. The rates will be ignored."); + STORM_LOG_WARN_COND(!components.rateTransitions && !components.exitRates.is_initialized(), "Rates specified for discrete-time model. The rates will be ignored."); } - STORM_LOG_ERROR_COND(this->isOfType(ModelType::MarkovAutomaton) || !components.markovianStates.is_initialized(), "Markovian states given for a model that is not a Markov automaton (will be ignored)."); + STORM_LOG_WARN_COND(this->isOfType(ModelType::MarkovAutomaton) || !components.markovianStates.is_initialized(), "Markovian states given for a model that is not a Markov automaton (will be ignored)."); } template From ef1cbae83c83b824a73d22ff23d3eb591e51433b Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 14:21:05 +0200 Subject: [PATCH 224/647] Tests for DRN parser --- .../examples/testfiles/ctmc/cluster2.drn | 554 +- .../examples/testfiles/dtmc/crowds-5-5.drn | 32337 ++++++++++++++++ .../examples/testfiles/ma/jobscheduler.drn | 71 + resources/examples/testfiles/mdp/two_dice.drn | 2 + .../storm/parser/DirectEncodingParserTest.cpp | 54 +- 5 files changed, 32732 insertions(+), 286 deletions(-) create mode 100644 resources/examples/testfiles/dtmc/crowds-5-5.drn create mode 100644 resources/examples/testfiles/ma/jobscheduler.drn diff --git a/resources/examples/testfiles/ctmc/cluster2.drn b/resources/examples/testfiles/ctmc/cluster2.drn index a58875e50..4d32a5a0c 100644 --- a/resources/examples/testfiles/ctmc/cluster2.drn +++ b/resources/examples/testfiles/ctmc/cluster2.drn @@ -3,17 +3,19 @@ @type: CTMC @parameters +@reward_models +num_repairs @nr_states 276 @model -state 0 [0] init minimum premium +state 0 !0.0087 [0] init minimum premium action 0 [0] 1 : 0.004 2 : 0.004 3 : 0.0002 4 : 0.00025 5 : 0.00025 -state 1 [0] minimum premium +state 1 !10.0067 [0] minimum premium action 0 [0] 6 : 0.002 7 : 0.004 @@ -21,7 +23,7 @@ state 1 [0] minimum premium 9 : 0.00025 10 : 0.00025 11 : 10 -state 2 [0] minimum premium +state 2 !10.0067 [0] minimum premium action 0 [0] 7 : 0.004 12 : 0.002 @@ -29,35 +31,35 @@ state 2 [0] minimum premium 14 : 0.00025 15 : 0.00025 16 : 10 -state 3 [0] minimum premium +state 3 !10.0085 [0] minimum premium action 0 [0] 8 : 0.004 13 : 0.004 17 : 0.00025 18 : 0.00025 19 : 10 -state 4 [0] minimum premium +state 4 !10.0084 [0] minimum premium action 0 [0] 9 : 0.004 14 : 0.004 17 : 0.0002 20 : 0.00025 21 : 10 -state 5 [0] minimum premium +state 5 !10.0084 [0] minimum premium action 0 [0] 10 : 0.004 15 : 0.004 18 : 0.0002 20 : 0.00025 22 : 10 -state 6 [0] minimum premium +state 6 !10.0047 [0] minimum premium action 0 [0] 23 : 0.004 24 : 0.0002 25 : 0.00025 26 : 0.00025 27 : 10 -state 7 [0] minimum premium +state 7 !20.0047 [0] minimum premium action 0 [0] 23 : 0.002 28 : 0.002 @@ -66,7 +68,7 @@ state 7 [0] minimum premium 31 : 0.00025 32 : 10 33 : 10 -state 8 [0] minimum premium +state 8 !20.0065 [0] minimum premium action 0 [0] 24 : 0.002 29 : 0.004 @@ -74,7 +76,7 @@ state 8 [0] minimum premium 35 : 0.00025 36 : 10 37 : 10 -state 9 [0] minimum premium +state 9 !20.0065 [0] minimum premium action 0 [0] 25 : 0.002 30 : 0.004 @@ -82,7 +84,7 @@ state 9 [0] minimum premium 38 : 0.00025 39 : 10 40 : 10 -state 10 [0] minimum +state 10 !20.0065 [0] minimum action 0 [0] 26 : 0.002 31 : 0.004 @@ -90,7 +92,7 @@ state 10 [0] minimum 38 : 0.00025 41 : 10 42 : 10 -state 11 [0] minimum premium +state 11 !2.0067 [0] minimum premium action 0 [0.996661] 0 : 2 27 : 0.002 @@ -98,14 +100,14 @@ state 11 [0] minimum premium 36 : 0.0002 39 : 0.00025 41 : 0.00025 -state 12 [0] minimum premium +state 12 !10.0047 [0] minimum premium action 0 [0] 28 : 0.004 43 : 0.0002 44 : 0.00025 45 : 0.00025 46 : 10 -state 13 [0] minimum premium +state 13 !20.0065 [0] minimum premium action 0 [0] 29 : 0.004 43 : 0.002 @@ -113,7 +115,7 @@ state 13 [0] minimum premium 48 : 0.00025 49 : 10 50 : 10 -state 14 [0] minimum +state 14 !20.0065 [0] minimum action 0 [0] 30 : 0.004 44 : 0.002 @@ -121,7 +123,7 @@ state 14 [0] minimum 51 : 0.00025 52 : 10 53 : 10 -state 15 [0] minimum premium +state 15 !20.0065 [0] minimum premium action 0 [0] 31 : 0.004 45 : 0.002 @@ -129,7 +131,7 @@ state 15 [0] minimum premium 51 : 0.00025 54 : 10 55 : 10 -state 16 [0] minimum premium +state 16 !2.0067 [0] minimum premium action 0 [0.996661] 0 : 2 33 : 0.004 @@ -137,49 +139,49 @@ state 16 [0] minimum premium 49 : 0.0002 52 : 0.00025 54 : 0.00025 -state 17 [0] minimum premium +state 17 !20.0083 [0] minimum premium action 0 [0] 34 : 0.004 47 : 0.004 56 : 0.00025 57 : 10 58 : 10 -state 18 [0] minimum premium +state 18 !20.0083 [0] minimum premium action 0 [0] 35 : 0.004 48 : 0.004 56 : 0.00025 59 : 10 60 : 10 -state 19 [0] minimum premium +state 19 !0.1335 [0] minimum premium action 0 [0.93633] 0 : 0.125 37 : 0.004 50 : 0.004 58 : 0.00025 60 : 0.00025 -state 20 [0] +state 20 !20.0082 [0] action 0 [0] 38 : 0.004 51 : 0.004 56 : 0.0002 61 : 10 62 : 10 -state 21 [0] minimum premium +state 21 !0.25845 [0] minimum premium action 0 [0.967305] 0 : 0.25 40 : 0.004 53 : 0.004 57 : 0.0002 61 : 0.00025 -state 22 [0] minimum premium +state 22 !0.25845 [0] minimum premium action 0 [0.967305] 0 : 0.25 42 : 0.004 55 : 0.004 59 : 0.0002 62 : 0.00025 -state 23 [0] minimum +state 23 !20.0027 [0] minimum action 0 [0] 63 : 0.002 64 : 0.0002 @@ -187,35 +189,35 @@ state 23 [0] minimum 66 : 0.00025 67 : 10 68 : 10 -state 24 [0] minimum premium +state 24 !20.0045 [0] minimum premium action 0 [0] 64 : 0.004 69 : 0.00025 70 : 0.00025 71 : 10 72 : 10 -state 25 [0] minimum premium +state 25 !20.0044 [0] minimum premium action 0 [0] 65 : 0.004 69 : 0.0002 73 : 0.00025 74 : 10 75 : 10 -state 26 [0] +state 26 !20.0044 [0] action 0 [0] 66 : 0.004 70 : 0.0002 73 : 0.00025 76 : 10 77 : 10 -state 27 [0] minimum premium +state 27 !2.0047 [0] minimum premium action 0 [0.997656] 1 : 2 67 : 0.004 71 : 0.0002 74 : 0.00025 76 : 0.00025 -state 28 [0] minimum +state 28 !20.0027 [0] minimum action 0 [0] 63 : 0.002 78 : 0.0002 @@ -223,7 +225,7 @@ state 28 [0] minimum 80 : 0.00025 81 : 10 82 : 10 -state 29 [0] minimum +state 29 !30.0045 [0] minimum action 0 [0] 64 : 0.002 78 : 0.002 @@ -232,7 +234,7 @@ state 29 [0] minimum 85 : 10 86 : 10 87 : 10 -state 30 [0] minimum +state 30 !30.0044 [0] minimum action 0 [0] 65 : 0.002 79 : 0.002 @@ -241,7 +243,7 @@ state 30 [0] minimum 89 : 10 90 : 10 91 : 10 -state 31 [0] minimum +state 31 !30.0044 [0] minimum action 0 [0] 66 : 0.002 80 : 0.002 @@ -250,7 +252,7 @@ state 31 [0] minimum 92 : 10 93 : 10 94 : 10 -state 32 [0] minimum premium +state 32 !2.0047 [0] minimum premium action 0 [0.997656] 2 : 2 67 : 0.002 @@ -258,7 +260,7 @@ state 32 [0] minimum premium 85 : 0.0002 89 : 0.00025 92 : 0.00025 -state 33 [0] minimum premium +state 33 !2.0047 [0] minimum premium action 0 [0.997656] 1 : 2 68 : 0.002 @@ -266,7 +268,7 @@ state 33 [0] minimum premium 86 : 0.0002 90 : 0.00025 93 : 0.00025 -state 34 [0] minimum premium +state 34 !30.0063 [0] minimum premium action 0 [0] 69 : 0.002 83 : 0.004 @@ -274,7 +276,7 @@ state 34 [0] minimum premium 96 : 10 97 : 10 98 : 10 -state 35 [0] minimum +state 35 !30.0063 [0] minimum action 0 [0] 70 : 0.002 84 : 0.004 @@ -282,21 +284,21 @@ state 35 [0] minimum 99 : 10 100 : 10 101 : 10 -state 36 [0] minimum premium +state 36 !2.0065 [0] minimum premium action 0 [0.996761] 3 : 2 71 : 0.002 85 : 0.004 96 : 0.00025 99 : 0.00025 -state 37 [0] minimum premium +state 37 !0.1315 [0] minimum premium action 0 [0.95057] 1 : 0.125 72 : 0.002 87 : 0.004 98 : 0.00025 101 : 0.00025 -state 38 [0] +state 38 !30.0062 [0] action 0 [0] 73 : 0.002 88 : 0.004 @@ -304,63 +306,63 @@ state 38 [0] 102 : 10 103 : 10 104 : 10 -state 39 [0] minimum premium +state 39 !2.00645 [0] minimum premium action 0 [0.996785] 4 : 2 74 : 0.002 89 : 0.004 96 : 0.0002 102 : 0.00025 -state 40 [0] minimum premium +state 40 !0.25645 [0] minimum premium action 0 [0.974849] 1 : 0.25 75 : 0.002 91 : 0.004 97 : 0.0002 103 : 0.00025 -state 41 [0] minimum +state 41 !2.00645 [0] minimum action 0 [0.996785] 5 : 2 76 : 0.002 92 : 0.004 99 : 0.0002 102 : 0.00025 -state 42 [0] minimum +state 42 !0.25645 [0] minimum action 0 [0.974849] 1 : 0.25 77 : 0.002 94 : 0.004 100 : 0.0002 104 : 0.00025 -state 43 [0] minimum premium +state 43 !20.0045 [0] minimum premium action 0 [0] 78 : 0.004 105 : 0.00025 106 : 0.00025 107 : 10 108 : 10 -state 44 [0] +state 44 !20.0044 [0] action 0 [0] 79 : 0.004 105 : 0.0002 109 : 0.00025 110 : 10 111 : 10 -state 45 [0] minimum premium +state 45 !20.0044 [0] minimum premium action 0 [0] 80 : 0.004 106 : 0.0002 109 : 0.00025 112 : 10 113 : 10 -state 46 [0] minimum premium +state 46 !2.0047 [0] minimum premium action 0 [0.997656] 2 : 2 82 : 0.004 107 : 0.0002 110 : 0.00025 112 : 0.00025 -state 47 [0] minimum +state 47 !30.0063 [0] minimum action 0 [0] 83 : 0.004 105 : 0.002 @@ -368,7 +370,7 @@ state 47 [0] minimum 115 : 10 116 : 10 117 : 10 -state 48 [0] minimum premium +state 48 !30.0063 [0] minimum premium action 0 [0] 84 : 0.004 106 : 0.002 @@ -376,21 +378,21 @@ state 48 [0] minimum premium 118 : 10 119 : 10 120 : 10 -state 49 [0] minimum premium +state 49 !2.0065 [0] minimum premium action 0 [0.996761] 3 : 2 86 : 0.004 107 : 0.002 115 : 0.00025 118 : 0.00025 -state 50 [0] minimum premium +state 50 !0.1315 [0] minimum premium action 0 [0.95057] 2 : 0.125 87 : 0.004 108 : 0.002 117 : 0.00025 120 : 0.00025 -state 51 [0] +state 51 !30.0062 [0] action 0 [0] 88 : 0.004 109 : 0.002 @@ -398,85 +400,85 @@ state 51 [0] 121 : 10 122 : 10 123 : 10 -state 52 [0] minimum +state 52 !2.00645 [0] minimum action 0 [0.996785] 4 : 2 90 : 0.004 110 : 0.002 115 : 0.0002 121 : 0.00025 -state 53 [0] minimum +state 53 !0.25645 [0] minimum action 0 [0.974849] 2 : 0.25 91 : 0.004 111 : 0.002 116 : 0.0002 122 : 0.00025 -state 54 [0] minimum premium +state 54 !2.00645 [0] minimum premium action 0 [0.996785] 5 : 2 93 : 0.004 112 : 0.002 118 : 0.0002 121 : 0.00025 -state 55 [0] minimum premium +state 55 !0.25645 [0] minimum premium action 0 [0.974849] 2 : 0.25 94 : 0.004 113 : 0.002 119 : 0.0002 123 : 0.00025 -state 56 [0] +state 56 !30.008 [0] action 0 [0] 95 : 0.004 114 : 0.004 124 : 10 125 : 10 126 : 10 -state 57 [0] minimum premium +state 57 !0.25825 [0] minimum premium action 0 [0.968054] 3 : 0.25 97 : 0.004 116 : 0.004 124 : 0.00025 -state 58 [0] minimum premium +state 58 !0.13325 [0] minimum premium action 0 [0.938086] 4 : 0.125 98 : 0.004 117 : 0.004 126 : 0.00025 -state 59 [0] minimum premium +state 59 !0.25825 [0] minimum premium action 0 [0.968054] 3 : 0.25 100 : 0.004 119 : 0.004 125 : 0.00025 -state 60 [0] minimum premium +state 60 !0.13325 [0] minimum premium action 0 [0.938086] 5 : 0.125 101 : 0.004 120 : 0.004 126 : 0.00025 -state 61 [0] +state 61 !0.2582 [0] action 0 [0.968242] 5 : 0.25 103 : 0.004 122 : 0.004 124 : 0.0002 -state 62 [0] +state 62 !0.2582 [0] action 0 [0.968242] 4 : 0.25 104 : 0.004 123 : 0.004 125 : 0.0002 -state 63 [0] +state 63 !20.0007 [0] action 0 [0] 127 : 0.0002 128 : 0.00025 129 : 0.00025 130 : 10 131 : 10 -state 64 [0] minimum +state 64 !30.0025 [0] minimum action 0 [0] 127 : 0.002 132 : 0.00025 @@ -484,7 +486,7 @@ state 64 [0] minimum 134 : 10 135 : 10 136 : 10 -state 65 [0] minimum +state 65 !30.0024 [0] minimum action 0 [0] 128 : 0.002 132 : 0.0002 @@ -492,7 +494,7 @@ state 65 [0] minimum 138 : 10 139 : 10 140 : 10 -state 66 [0] +state 66 !30.0024 [0] action 0 [0] 129 : 0.002 133 : 0.0002 @@ -500,78 +502,78 @@ state 66 [0] 141 : 10 142 : 10 143 : 10 -state 67 [0] minimum +state 67 !2.0027 [0] minimum action 0 [0.998652] 7 : 2 130 : 0.002 134 : 0.0002 138 : 0.00025 141 : 0.00025 -state 68 [0] minimum +state 68 !2.0027 [0] minimum action 0 [0.998652] 6 : 2 131 : 0.002 135 : 0.0002 139 : 0.00025 142 : 0.00025 -state 69 [0] minimum premium +state 69 !30.0042 [0] minimum premium action 0 [0] 132 : 0.004 144 : 0.00025 145 : 10 146 : 10 147 : 10 -state 70 [0] +state 70 !30.0042 [0] action 0 [0] 133 : 0.004 144 : 0.00025 148 : 10 149 : 10 150 : 10 -state 71 [0] minimum premium +state 71 !2.0045 [0] minimum premium action 0 [0.997755] 8 : 2 134 : 0.004 145 : 0.00025 148 : 0.00025 -state 72 [0] minimum premium +state 72 !0.1295 [0] minimum premium action 0 [0.965251] 6 : 0.125 136 : 0.004 147 : 0.00025 150 : 0.00025 -state 73 [0] +state 73 !30.0042 [0] action 0 [0] 137 : 0.004 144 : 0.0002 151 : 10 152 : 10 153 : 10 -state 74 [0] minimum premium +state 74 !2.00445 [0] minimum premium action 0 [0.99778] 9 : 2 138 : 0.004 145 : 0.0002 151 : 0.00025 -state 75 [0] minimum premium +state 75 !0.25445 [0] minimum premium action 0 [0.982511] 6 : 0.25 140 : 0.004 146 : 0.0002 152 : 0.00025 -state 76 [0] +state 76 !2.00445 [0] action 0 [0.99778] 10 : 2 141 : 0.004 148 : 0.0002 151 : 0.00025 -state 77 [0] +state 77 !0.25445 [0] action 0 [0.982511] 6 : 0.25 143 : 0.004 149 : 0.0002 153 : 0.00025 -state 78 [0] minimum +state 78 !30.0025 [0] minimum action 0 [0] 127 : 0.002 154 : 0.00025 @@ -579,7 +581,7 @@ state 78 [0] minimum 156 : 10 157 : 10 158 : 10 -state 79 [0] +state 79 !30.0024 [0] action 0 [0] 128 : 0.002 154 : 0.0002 @@ -587,7 +589,7 @@ state 79 [0] 160 : 10 161 : 10 162 : 10 -state 80 [0] minimum +state 80 !30.0024 [0] minimum action 0 [0] 129 : 0.002 155 : 0.0002 @@ -595,21 +597,21 @@ state 80 [0] minimum 163 : 10 164 : 10 165 : 10 -state 81 [0] minimum +state 81 !2.0027 [0] minimum action 0 [0.998652] 12 : 2 130 : 0.002 156 : 0.0002 160 : 0.00025 163 : 0.00025 -state 82 [0] minimum +state 82 !2.0027 [0] minimum action 0 [0.998652] 7 : 2 131 : 0.002 157 : 0.0002 161 : 0.00025 164 : 0.00025 -state 83 [0] minimum +state 83 !40.0042 [0] minimum action 0 [0] 132 : 0.002 154 : 0.002 @@ -618,7 +620,7 @@ state 83 [0] minimum 168 : 10 169 : 10 170 : 10 -state 84 [0] minimum +state 84 !40.0042 [0] minimum action 0 [0] 133 : 0.002 155 : 0.002 @@ -627,28 +629,28 @@ state 84 [0] minimum 172 : 10 173 : 10 174 : 10 -state 85 [0] minimum +state 85 !2.0045 [0] minimum action 0 [0.997755] 13 : 2 134 : 0.002 156 : 0.002 167 : 0.00025 171 : 0.00025 -state 86 [0] minimum +state 86 !2.0045 [0] minimum action 0 [0.997755] 8 : 2 135 : 0.002 157 : 0.002 168 : 0.00025 172 : 0.00025 -state 87 [0] minimum +state 87 !0.1295 [0] minimum action 0 [0.965251] 7 : 0.125 136 : 0.002 158 : 0.002 170 : 0.00025 174 : 0.00025 -state 88 [0] +state 88 !40.0042 [0] action 0 [0] 137 : 0.002 159 : 0.002 @@ -657,49 +659,49 @@ state 88 [0] 176 : 10 177 : 10 178 : 10 -state 89 [0] minimum +state 89 !2.00445 [0] minimum action 0 [0.99778] 14 : 2 138 : 0.002 160 : 0.002 167 : 0.0002 175 : 0.00025 -state 90 [0] minimum +state 90 !2.00445 [0] minimum action 0 [0.99778] 9 : 2 139 : 0.002 161 : 0.002 168 : 0.0002 176 : 0.00025 -state 91 [0] minimum +state 91 !0.25445 [0] minimum action 0 [0.982511] 7 : 0.25 140 : 0.002 162 : 0.002 169 : 0.0002 177 : 0.00025 -state 92 [0] minimum +state 92 !2.00445 [0] minimum action 0 [0.99778] 15 : 2 141 : 0.002 163 : 0.002 171 : 0.0002 175 : 0.00025 -state 93 [0] minimum +state 93 !2.00445 [0] minimum action 0 [0.99778] 10 : 2 142 : 0.002 164 : 0.002 172 : 0.0002 176 : 0.00025 -state 94 [0] minimum +state 94 !0.25445 [0] minimum action 0 [0.982511] 7 : 0.25 143 : 0.002 165 : 0.002 173 : 0.0002 178 : 0.00025 -state 95 [0] +state 95 !40.006 [0] action 0 [0] 144 : 0.002 166 : 0.004 @@ -707,118 +709,118 @@ state 95 [0] 180 : 10 181 : 10 182 : 10 -state 96 [0] minimum premium +state 96 !2.00625 [0] minimum premium action 0 [0.996885] 17 : 2 145 : 0.002 167 : 0.004 179 : 0.00025 -state 97 [0] minimum premium +state 97 !0.25625 [0] minimum premium action 0 [0.97561] 8 : 0.25 146 : 0.002 169 : 0.004 180 : 0.00025 -state 98 [0] minimum premium +state 98 !0.13125 [0] minimum premium action 0 [0.952381] 9 : 0.125 147 : 0.002 170 : 0.004 182 : 0.00025 -state 99 [0] minimum +state 99 !2.00625 [0] minimum action 0 [0.996885] 18 : 2 148 : 0.002 171 : 0.004 179 : 0.00025 -state 100 [0] minimum +state 100 !0.25625 [0] minimum action 0 [0.97561] 8 : 0.25 149 : 0.002 173 : 0.004 181 : 0.00025 -state 101 [0] minimum +state 101 !0.13125 [0] minimum action 0 [0.952381] 10 : 0.125 150 : 0.002 174 : 0.004 182 : 0.00025 -state 102 [0] +state 102 !2.0062 [0] action 0 [0.99691] 20 : 2 151 : 0.002 175 : 0.004 179 : 0.0002 -state 103 [0] +state 103 !0.2562 [0] action 0 [0.9758] 10 : 0.25 152 : 0.002 177 : 0.004 180 : 0.0002 -state 104 [0] +state 104 !0.2562 [0] action 0 [0.9758] 9 : 0.25 153 : 0.002 178 : 0.004 181 : 0.0002 -state 105 [0] +state 105 !30.0042 [0] action 0 [0] 154 : 0.004 183 : 0.00025 184 : 10 185 : 10 186 : 10 -state 106 [0] minimum premium +state 106 !30.0042 [0] minimum premium action 0 [0] 155 : 0.004 183 : 0.00025 187 : 10 188 : 10 189 : 10 -state 107 [0] minimum premium +state 107 !2.0045 [0] minimum premium action 0 [0.997755] 13 : 2 157 : 0.004 184 : 0.00025 187 : 0.00025 -state 108 [0] minimum premium +state 108 !0.1295 [0] minimum premium action 0 [0.965251] 12 : 0.125 158 : 0.004 186 : 0.00025 189 : 0.00025 -state 109 [0] +state 109 !30.0042 [0] action 0 [0] 159 : 0.004 183 : 0.0002 190 : 10 191 : 10 192 : 10 -state 110 [0] +state 110 !2.00445 [0] action 0 [0.99778] 14 : 2 161 : 0.004 184 : 0.0002 190 : 0.00025 -state 111 [0] +state 111 !0.25445 [0] action 0 [0.982511] 12 : 0.25 162 : 0.004 185 : 0.0002 191 : 0.00025 -state 112 [0] minimum premium +state 112 !2.00445 [0] minimum premium action 0 [0.99778] 15 : 2 164 : 0.004 187 : 0.0002 190 : 0.00025 -state 113 [0] minimum premium +state 113 !0.25445 [0] minimum premium action 0 [0.982511] 12 : 0.25 165 : 0.004 188 : 0.0002 192 : 0.00025 -state 114 [0] +state 114 !40.006 [0] action 0 [0] 166 : 0.004 183 : 0.002 @@ -826,109 +828,109 @@ state 114 [0] 194 : 10 195 : 10 196 : 10 -state 115 [0] minimum +state 115 !2.00625 [0] minimum action 0 [0.996885] 17 : 2 168 : 0.004 184 : 0.002 193 : 0.00025 -state 116 [0] minimum +state 116 !0.25625 [0] minimum action 0 [0.97561] 13 : 0.25 169 : 0.004 185 : 0.002 194 : 0.00025 -state 117 [0] minimum +state 117 !0.13125 [0] minimum action 0 [0.952381] 14 : 0.125 170 : 0.004 186 : 0.002 196 : 0.00025 -state 118 [0] minimum premium +state 118 !2.00625 [0] minimum premium action 0 [0.996885] 18 : 2 172 : 0.004 187 : 0.002 193 : 0.00025 -state 119 [0] minimum premium +state 119 !0.25625 [0] minimum premium action 0 [0.97561] 13 : 0.25 173 : 0.004 188 : 0.002 195 : 0.00025 -state 120 [0] minimum premium +state 120 !0.13125 [0] minimum premium action 0 [0.952381] 15 : 0.125 174 : 0.004 189 : 0.002 196 : 0.00025 -state 121 [0] +state 121 !2.0062 [0] action 0 [0.99691] 20 : 2 176 : 0.004 190 : 0.002 193 : 0.0002 -state 122 [0] +state 122 !0.2562 [0] action 0 [0.9758] 15 : 0.25 177 : 0.004 191 : 0.002 194 : 0.0002 -state 123 [0] +state 123 !0.2562 [0] action 0 [0.9758] 14 : 0.25 178 : 0.004 192 : 0.002 195 : 0.0002 -state 124 [0] +state 124 !0.258 [0] action 0 [0.968992] 18 : 0.25 180 : 0.004 194 : 0.004 -state 125 [0] +state 125 !0.258 [0] action 0 [0.968992] 17 : 0.25 181 : 0.004 195 : 0.004 -state 126 [0] +state 126 !0.133 [0] action 0 [0.93985] 20 : 0.125 182 : 0.004 196 : 0.004 -state 127 [0] +state 127 !30.0005 [0] action 0 [0] 197 : 0.00025 198 : 0.00025 199 : 10 200 : 10 201 : 10 -state 128 [0] +state 128 !30.0005 [0] action 0 [0] 197 : 0.0002 202 : 0.00025 203 : 10 204 : 10 205 : 10 -state 129 [0] +state 129 !30.0005 [0] action 0 [0] 198 : 0.0002 202 : 0.00025 206 : 10 207 : 10 208 : 10 -state 130 [0] +state 130 !2.0007 [0] action 0 [0.99965] 28 : 2 199 : 0.0002 203 : 0.00025 206 : 0.00025 -state 131 [0] +state 131 !2.0007 [0] action 0 [0.99965] 23 : 2 200 : 0.0002 204 : 0.00025 207 : 0.00025 -state 132 [0] minimum +state 132 !40.0023 [0] minimum action 0 [0] 197 : 0.002 209 : 0.00025 @@ -936,7 +938,7 @@ state 132 [0] minimum 211 : 10 212 : 10 213 : 10 -state 133 [0] +state 133 !40.0023 [0] action 0 [0] 198 : 0.002 209 : 0.00025 @@ -944,25 +946,25 @@ state 133 [0] 215 : 10 216 : 10 217 : 10 -state 134 [0] minimum +state 134 !2.0025 [0] minimum action 0 [0.998752] 29 : 2 199 : 0.002 210 : 0.00025 214 : 0.00025 -state 135 [0] minimum +state 135 !2.0025 [0] minimum action 0 [0.998752] 24 : 2 200 : 0.002 211 : 0.00025 215 : 0.00025 -state 136 [0] minimum +state 136 !0.1275 [0] minimum action 0 [0.980392] 23 : 0.125 201 : 0.002 213 : 0.00025 217 : 0.00025 -state 137 [0] +state 137 !40.0022 [0] action 0 [0] 202 : 0.002 209 : 0.0002 @@ -970,95 +972,95 @@ state 137 [0] 219 : 10 220 : 10 221 : 10 -state 138 [0] minimum +state 138 !2.00245 [0] minimum action 0 [0.998776] 30 : 2 203 : 0.002 210 : 0.0002 218 : 0.00025 -state 139 [0] minimum +state 139 !2.00245 [0] minimum action 0 [0.998776] 25 : 2 204 : 0.002 211 : 0.0002 219 : 0.00025 -state 140 [0] minimum +state 140 !0.25245 [0] minimum action 0 [0.990295] 23 : 0.25 205 : 0.002 212 : 0.0002 220 : 0.00025 -state 141 [0] +state 141 !2.00245 [0] action 0 [0.998776] 31 : 2 206 : 0.002 214 : 0.0002 218 : 0.00025 -state 142 [0] +state 142 !2.00245 [0] action 0 [0.998776] 26 : 2 207 : 0.002 215 : 0.0002 219 : 0.00025 -state 143 [0] +state 143 !0.25245 [0] action 0 [0.990295] 23 : 0.25 208 : 0.002 216 : 0.0002 221 : 0.00025 -state 144 [0] +state 144 !40.004 [0] action 0 [0] 209 : 0.004 222 : 10 223 : 10 224 : 10 225 : 10 -state 145 [0] minimum premium +state 145 !2.00425 [0] minimum premium action 0 [0.99788] 34 : 2 210 : 0.004 222 : 0.00025 -state 146 [0] minimum premium +state 146 !0.25425 [0] minimum premium action 0 [0.983284] 24 : 0.25 212 : 0.004 223 : 0.00025 -state 147 [0] minimum premium +state 147 !0.12925 [0] minimum premium action 0 [0.967118] 25 : 0.125 213 : 0.004 225 : 0.00025 -state 148 [0] +state 148 !2.00425 [0] action 0 [0.99788] 35 : 2 214 : 0.004 222 : 0.00025 -state 149 [0] +state 149 !0.25425 [0] action 0 [0.983284] 24 : 0.25 216 : 0.004 224 : 0.00025 -state 150 [0] +state 150 !0.12925 [0] action 0 [0.967118] 26 : 0.125 217 : 0.004 225 : 0.00025 -state 151 [0] +state 151 !2.0042 [0] action 0 [0.997904] 38 : 2 218 : 0.004 222 : 0.0002 -state 152 [0] +state 152 !0.2542 [0] action 0 [0.983478] 26 : 0.25 220 : 0.004 223 : 0.0002 -state 153 [0] +state 153 !0.2542 [0] action 0 [0.983478] 25 : 0.25 221 : 0.004 224 : 0.0002 -state 154 [0] +state 154 !40.0023 [0] action 0 [0] 197 : 0.002 226 : 0.00025 @@ -1066,7 +1068,7 @@ state 154 [0] 228 : 10 229 : 10 230 : 10 -state 155 [0] minimum +state 155 !40.0023 [0] minimum action 0 [0] 198 : 0.002 226 : 0.00025 @@ -1074,25 +1076,25 @@ state 155 [0] minimum 232 : 10 233 : 10 234 : 10 -state 156 [0] minimum +state 156 !2.0025 [0] minimum action 0 [0.998752] 43 : 2 199 : 0.002 227 : 0.00025 231 : 0.00025 -state 157 [0] minimum +state 157 !2.0025 [0] minimum action 0 [0.998752] 29 : 2 200 : 0.002 228 : 0.00025 232 : 0.00025 -state 158 [0] minimum +state 158 !0.1275 [0] minimum action 0 [0.980392] 28 : 0.125 201 : 0.002 230 : 0.00025 234 : 0.00025 -state 159 [0] +state 159 !40.0022 [0] action 0 [0] 202 : 0.002 226 : 0.0002 @@ -1100,43 +1102,43 @@ state 159 [0] 236 : 10 237 : 10 238 : 10 -state 160 [0] +state 160 !2.00245 [0] action 0 [0.998776] 44 : 2 203 : 0.002 227 : 0.0002 235 : 0.00025 -state 161 [0] +state 161 !2.00245 [0] action 0 [0.998776] 30 : 2 204 : 0.002 228 : 0.0002 236 : 0.00025 -state 162 [0] +state 162 !0.25245 [0] action 0 [0.990295] 28 : 0.25 205 : 0.002 229 : 0.0002 237 : 0.00025 -state 163 [0] minimum +state 163 !2.00245 [0] minimum action 0 [0.998776] 45 : 2 206 : 0.002 231 : 0.0002 235 : 0.00025 -state 164 [0] minimum +state 164 !2.00245 [0] minimum action 0 [0.998776] 31 : 2 207 : 0.002 232 : 0.0002 236 : 0.00025 -state 165 [0] minimum +state 165 !0.25245 [0] minimum action 0 [0.990295] 28 : 0.25 208 : 0.002 233 : 0.0002 238 : 0.00025 -state 166 [0] +state 166 !50.004 [0] action 0 [0] 209 : 0.002 226 : 0.002 @@ -1145,237 +1147,237 @@ state 166 [0] 241 : 10 242 : 10 243 : 10 -state 167 [0] minimum +state 167 !2.00425 [0] minimum action 0 [0.99788] 47 : 2 210 : 0.002 227 : 0.002 239 : 0.00025 -state 168 [0] minimum +state 168 !2.00425 [0] minimum action 0 [0.99788] 34 : 2 211 : 0.002 228 : 0.002 240 : 0.00025 -state 169 [0] minimum +state 169 !0.25425 [0] minimum action 0 [0.983284] 29 : 0.25 212 : 0.002 229 : 0.002 241 : 0.00025 -state 170 [0] minimum +state 170 !0.12925 [0] minimum action 0 [0.967118] 30 : 0.125 213 : 0.002 230 : 0.002 243 : 0.00025 -state 171 [0] minimum +state 171 !2.00425 [0] minimum action 0 [0.99788] 48 : 2 214 : 0.002 231 : 0.002 239 : 0.00025 -state 172 [0] minimum +state 172 !2.00425 [0] minimum action 0 [0.99788] 35 : 2 215 : 0.002 232 : 0.002 240 : 0.00025 -state 173 [0] minimum +state 173 !0.25425 [0] minimum action 0 [0.983284] 29 : 0.25 216 : 0.002 233 : 0.002 242 : 0.00025 -state 174 [0] minimum +state 174 !0.12925 [0] minimum action 0 [0.967118] 31 : 0.125 217 : 0.002 234 : 0.002 243 : 0.00025 -state 175 [0] +state 175 !2.0042 [0] action 0 [0.997904] 51 : 2 218 : 0.002 235 : 0.002 239 : 0.0002 -state 176 [0] +state 176 !2.0042 [0] action 0 [0.997904] 38 : 2 219 : 0.002 236 : 0.002 240 : 0.0002 -state 177 [0] +state 177 !0.2542 [0] action 0 [0.983478] 31 : 0.25 220 : 0.002 237 : 0.002 241 : 0.0002 -state 178 [0] +state 178 !0.2542 [0] action 0 [0.983478] 30 : 0.25 221 : 0.002 238 : 0.002 242 : 0.0002 -state 179 [0] +state 179 !2.006 [0] action 0 [0.997009] 56 : 2 222 : 0.002 239 : 0.004 -state 180 [0] +state 180 !0.256 [0] action 0 [0.976562] 35 : 0.25 223 : 0.002 241 : 0.004 -state 181 [0] +state 181 !0.256 [0] action 0 [0.976562] 34 : 0.25 224 : 0.002 242 : 0.004 -state 182 [0] +state 182 !0.131 [0] action 0 [0.954198] 38 : 0.125 225 : 0.002 243 : 0.004 -state 183 [0] +state 183 !40.004 [0] action 0 [0] 226 : 0.004 244 : 10 245 : 10 246 : 10 247 : 10 -state 184 [0] +state 184 !2.00425 [0] action 0 [0.99788] 47 : 2 228 : 0.004 244 : 0.00025 -state 185 [0] +state 185 !0.25425 [0] action 0 [0.983284] 43 : 0.25 229 : 0.004 245 : 0.00025 -state 186 [0] +state 186 !0.12925 [0] action 0 [0.967118] 44 : 0.125 230 : 0.004 247 : 0.00025 -state 187 [0] minimum premium +state 187 !2.00425 [0] minimum premium action 0 [0.99788] 48 : 2 232 : 0.004 244 : 0.00025 -state 188 [0] minimum premium +state 188 !0.25425 [0] minimum premium action 0 [0.983284] 43 : 0.25 233 : 0.004 246 : 0.00025 -state 189 [0] minimum premium +state 189 !0.12925 [0] minimum premium action 0 [0.967118] 45 : 0.125 234 : 0.004 247 : 0.00025 -state 190 [0] +state 190 !2.0042 [0] action 0 [0.997904] 51 : 2 236 : 0.004 244 : 0.0002 -state 191 [0] +state 191 !0.2542 [0] action 0 [0.983478] 45 : 0.25 237 : 0.004 245 : 0.0002 -state 192 [0] +state 192 !0.2542 [0] action 0 [0.983478] 44 : 0.25 238 : 0.004 246 : 0.0002 -state 193 [0] +state 193 !2.006 [0] action 0 [0.997009] 56 : 2 240 : 0.004 244 : 0.002 -state 194 [0] +state 194 !0.256 [0] action 0 [0.976562] 48 : 0.25 241 : 0.004 245 : 0.002 -state 195 [0] +state 195 !0.256 [0] action 0 [0.976562] 47 : 0.25 242 : 0.004 246 : 0.002 -state 196 [0] +state 196 !0.131 [0] action 0 [0.954198] 51 : 0.125 243 : 0.004 247 : 0.002 -state 197 [0] +state 197 !40.0003 [0] action 0 [0] 248 : 0.00025 249 : 10 250 : 10 251 : 10 252 : 10 -state 198 [0] +state 198 !40.0003 [0] action 0 [0] 248 : 0.00025 253 : 10 254 : 10 255 : 10 256 : 10 -state 199 [0] +state 199 !2.0005 [0] action 0 [0.99975] 78 : 2 249 : 0.00025 253 : 0.00025 -state 200 [0] +state 200 !2.0005 [0] action 0 [0.99975] 64 : 2 250 : 0.00025 254 : 0.00025 -state 201 [0] +state 201 !0.1255 [0] action 0 [0.996016] 63 : 0.125 252 : 0.00025 256 : 0.00025 -state 202 [0] +state 202 !40.0002 [0] action 0 [0] 248 : 0.0002 257 : 10 258 : 10 259 : 10 260 : 10 -state 203 [0] +state 203 !2.00045 [0] action 0 [0.999775] 79 : 2 249 : 0.0002 257 : 0.00025 -state 204 [0] +state 204 !2.00045 [0] action 0 [0.999775] 65 : 2 250 : 0.0002 258 : 0.00025 -state 205 [0] +state 205 !0.25045 [0] action 0 [0.998203] 63 : 0.25 251 : 0.0002 259 : 0.00025 -state 206 [0] +state 206 !2.00045 [0] action 0 [0.999775] 80 : 2 253 : 0.0002 257 : 0.00025 -state 207 [0] +state 207 !2.00045 [0] action 0 [0.999775] 66 : 2 254 : 0.0002 258 : 0.00025 -state 208 [0] +state 208 !0.25045 [0] action 0 [0.998203] 63 : 0.25 255 : 0.0002 260 : 0.00025 -state 209 [0] +state 209 !50.002 [0] action 0 [0] 248 : 0.002 261 : 10 @@ -1383,83 +1385,83 @@ state 209 [0] 263 : 10 264 : 10 265 : 10 -state 210 [0] minimum +state 210 !2.00225 [0] minimum action 0 [0.998876] 83 : 2 249 : 0.002 261 : 0.00025 -state 211 [0] minimum +state 211 !2.00225 [0] minimum action 0 [0.998876] 69 : 2 250 : 0.002 262 : 0.00025 -state 212 [0] minimum +state 212 !0.25225 [0] minimum action 0 [0.99108] 64 : 0.25 251 : 0.002 263 : 0.00025 -state 213 [0] minimum +state 213 !0.12725 [0] minimum action 0 [0.982318] 65 : 0.125 252 : 0.002 265 : 0.00025 -state 214 [0] +state 214 !2.00225 [0] action 0 [0.998876] 84 : 2 253 : 0.002 261 : 0.00025 -state 215 [0] +state 215 !2.00225 [0] action 0 [0.998876] 70 : 2 254 : 0.002 262 : 0.00025 -state 216 [0] +state 216 !0.25225 [0] action 0 [0.99108] 64 : 0.25 255 : 0.002 264 : 0.00025 -state 217 [0] +state 217 !0.12725 [0] action 0 [0.982318] 66 : 0.125 256 : 0.002 265 : 0.00025 -state 218 [0] +state 218 !2.0022 [0] action 0 [0.998901] 88 : 2 257 : 0.002 261 : 0.0002 -state 219 [0] +state 219 !2.0022 [0] action 0 [0.998901] 73 : 2 258 : 0.002 262 : 0.0002 -state 220 [0] +state 220 !0.2522 [0] action 0 [0.991277] 66 : 0.25 259 : 0.002 263 : 0.0002 -state 221 [0] +state 221 !0.2522 [0] action 0 [0.991277] 65 : 0.25 260 : 0.002 264 : 0.0002 -state 222 [0] +state 222 !2.004 [0] action 0 [0.998004] 95 : 2 261 : 0.004 -state 223 [0] +state 223 !0.254 [0] action 0 [0.984252] 70 : 0.25 263 : 0.004 -state 224 [0] +state 224 !0.254 [0] action 0 [0.984252] 69 : 0.25 264 : 0.004 -state 225 [0] +state 225 !0.129 [0] action 0 [0.968992] 73 : 0.125 265 : 0.004 -state 226 [0] +state 226 !50.002 [0] action 0 [0] 248 : 0.002 266 : 10 @@ -1467,214 +1469,214 @@ state 226 [0] 268 : 10 269 : 10 270 : 10 -state 227 [0] +state 227 !2.00225 [0] action 0 [0.998876] 105 : 2 249 : 0.002 266 : 0.00025 -state 228 [0] +state 228 !2.00225 [0] action 0 [0.998876] 83 : 2 250 : 0.002 267 : 0.00025 -state 229 [0] +state 229 !0.25225 [0] action 0 [0.99108] 78 : 0.25 251 : 0.002 268 : 0.00025 -state 230 [0] +state 230 !0.12725 [0] action 0 [0.982318] 79 : 0.125 252 : 0.002 270 : 0.00025 -state 231 [0] minimum +state 231 !2.00225 [0] minimum action 0 [0.998876] 106 : 2 253 : 0.002 266 : 0.00025 -state 232 [0] minimum +state 232 !2.00225 [0] minimum action 0 [0.998876] 84 : 2 254 : 0.002 267 : 0.00025 -state 233 [0] minimum +state 233 !0.25225 [0] minimum action 0 [0.99108] 78 : 0.25 255 : 0.002 269 : 0.00025 -state 234 [0] minimum +state 234 !0.12725 [0] minimum action 0 [0.982318] 80 : 0.125 256 : 0.002 270 : 0.00025 -state 235 [0] +state 235 !2.0022 [0] action 0 [0.998901] 109 : 2 257 : 0.002 266 : 0.0002 -state 236 [0] +state 236 !2.0022 [0] action 0 [0.998901] 88 : 2 258 : 0.002 267 : 0.0002 -state 237 [0] +state 237 !0.2522 [0] action 0 [0.991277] 80 : 0.25 259 : 0.002 268 : 0.0002 -state 238 [0] +state 238 !0.2522 [0] action 0 [0.991277] 79 : 0.25 260 : 0.002 269 : 0.0002 -state 239 [0] +state 239 !2.004 [0] action 0 [0.998004] 114 : 2 261 : 0.002 266 : 0.002 -state 240 [0] +state 240 !2.004 [0] action 0 [0.998004] 95 : 2 262 : 0.002 267 : 0.002 -state 241 [0] +state 241 !0.254 [0] action 0 [0.984252] 84 : 0.25 263 : 0.002 268 : 0.002 -state 242 [0] +state 242 !0.254 [0] action 0 [0.984252] 83 : 0.25 264 : 0.002 269 : 0.002 -state 243 [0] +state 243 !0.129 [0] action 0 [0.968992] 88 : 0.125 265 : 0.002 270 : 0.002 -state 244 [0] +state 244 !2.004 [0] action 0 [0.998004] 114 : 2 267 : 0.004 -state 245 [0] +state 245 !0.254 [0] action 0 [0.984252] 106 : 0.25 268 : 0.004 -state 246 [0] +state 246 !0.254 [0] action 0 [0.984252] 105 : 0.25 269 : 0.004 -state 247 [0] +state 247 !0.129 [0] action 0 [0.968992] 109 : 0.125 270 : 0.004 -state 248 [0] +state 248 !50 [0] action 0 [0] 271 : 10 272 : 10 273 : 10 274 : 10 275 : 10 -state 249 [0] +state 249 !2.00025 [0] action 0 [0.999875] 154 : 2 271 : 0.00025 -state 250 [0] +state 250 !2.00025 [0] action 0 [0.999875] 132 : 2 272 : 0.00025 -state 251 [0] +state 251 !0.25025 [0] action 0 [0.999001] 127 : 0.25 273 : 0.00025 -state 252 [0] +state 252 !0.12525 [0] action 0 [0.998004] 128 : 0.125 275 : 0.00025 -state 253 [0] +state 253 !2.00025 [0] action 0 [0.999875] 155 : 2 271 : 0.00025 -state 254 [0] +state 254 !2.00025 [0] action 0 [0.999875] 133 : 2 272 : 0.00025 -state 255 [0] +state 255 !0.25025 [0] action 0 [0.999001] 127 : 0.25 274 : 0.00025 -state 256 [0] +state 256 !0.12525 [0] action 0 [0.998004] 129 : 0.125 275 : 0.00025 -state 257 [0] +state 257 !2.0002 [0] action 0 [0.9999] 159 : 2 271 : 0.0002 -state 258 [0] +state 258 !2.0002 [0] action 0 [0.9999] 137 : 2 272 : 0.0002 -state 259 [0] +state 259 !0.2502 [0] action 0 [0.999201] 129 : 0.25 273 : 0.0002 -state 260 [0] +state 260 !0.2502 [0] action 0 [0.999201] 128 : 0.25 274 : 0.0002 -state 261 [0] +state 261 !2.002 [0] action 0 [0.999001] 166 : 2 271 : 0.002 -state 262 [0] +state 262 !2.002 [0] action 0 [0.999001] 144 : 2 272 : 0.002 -state 263 [0] +state 263 !0.252 [0] action 0 [0.992063] 133 : 0.25 273 : 0.002 -state 264 [0] +state 264 !0.252 [0] action 0 [0.992063] 132 : 0.25 274 : 0.002 -state 265 [0] +state 265 !0.127 [0] action 0 [0.984252] 137 : 0.125 275 : 0.002 -state 266 [0] +state 266 !2.002 [0] action 0 [0.999001] 183 : 2 271 : 0.002 -state 267 [0] +state 267 !2.002 [0] action 0 [0.999001] 166 : 2 272 : 0.002 -state 268 [0] +state 268 !0.252 [0] action 0 [0.992063] 155 : 0.25 273 : 0.002 -state 269 [0] +state 269 !0.252 [0] action 0 [0.992063] 154 : 0.25 274 : 0.002 -state 270 [0] +state 270 !0.127 [0] action 0 [0.984252] 159 : 0.125 275 : 0.002 -state 271 [0] +state 271 !2 [0] action 0 [1] 226 : 2 -state 272 [0] +state 272 !2 [0] action 0 [1] 209 : 2 -state 273 [0] +state 273 !0.25 [0] action 0 [1] 198 : 0.25 -state 274 [0] +state 274 !0.25 [0] action 0 [1] 197 : 0.25 -state 275 [0] +state 275 !0.125 [0] action 0 [1] 202 : 0.125 diff --git a/resources/examples/testfiles/dtmc/crowds-5-5.drn b/resources/examples/testfiles/dtmc/crowds-5-5.drn new file mode 100644 index 000000000..54dfa7161 --- /dev/null +++ b/resources/examples/testfiles/dtmc/crowds-5-5.drn @@ -0,0 +1,32337 @@ +// Exported by storm +// Original model type: DTMC +@type: DTMC +@parameters + +@reward_models + +@nr_states +8607 +@model +state 0 init + action 0 + 1 : 1 +state 1 + action 0 + 2 : 0.833 + 3 : 0.167 +state 2 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 3 + action 0 + 9 : 1 +state 4 + action 0 + 10 : 0.8 + 11 : 0.2 +state 5 + action 0 + 12 : 0.8 + 13 : 0.2 +state 6 + action 0 + 14 : 0.8 + 15 : 0.2 +state 7 + action 0 + 16 : 0.8 + 17 : 0.2 +state 8 + action 0 + 18 : 0.8 + 19 : 0.2 +state 9 + action 0 + 20 : 1 +state 10 + action 0 + 2 : 0.833 + 3 : 0.167 +state 11 + action 0 + 21 : 1 +state 12 + action 0 + 22 : 0.833 + 23 : 0.167 +state 13 + action 0 + 24 : 1 +state 14 + action 0 + 25 : 0.833 + 26 : 0.167 +state 15 + action 0 + 27 : 1 +state 16 + action 0 + 28 : 0.833 + 29 : 0.167 +state 17 + action 0 + 30 : 1 +state 18 + action 0 + 31 : 0.833 + 32 : 0.167 +state 19 + action 0 + 33 : 1 +state 20 + action 0 + 34 : 1 +state 21 + action 0 + 35 : 1 +state 22 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 23 + action 0 + 36 : 1 +state 24 + action 0 + 35 : 1 +state 25 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 26 + action 0 + 37 : 1 +state 27 + action 0 + 35 : 1 +state 28 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 29 + action 0 + 38 : 1 +state 30 + action 0 + 35 : 1 +state 31 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 32 + action 0 + 39 : 1 +state 33 + action 0 + 35 : 1 +state 34 + action 0 + 40 : 0.833 + 41 : 0.167 +state 35 + action 0 + 42 : 0.833 + 43 : 0.167 +state 36 + action 0 + 44 : 1 +state 37 + action 0 + 45 : 1 +state 38 + action 0 + 46 : 1 +state 39 + action 0 + 47 : 1 +state 40 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 41 + action 0 + 53 : 1 +state 42 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 43 + action 0 + 59 : 1 +state 44 + action 0 + 60 : 1 +state 45 + action 0 + 61 : 1 +state 46 + action 0 + 62 : 1 +state 47 + action 0 + 63 : 1 +state 48 + action 0 + 64 : 0.8 + 65 : 0.2 +state 49 + action 0 + 66 : 0.8 + 67 : 0.2 +state 50 + action 0 + 68 : 0.8 + 69 : 0.2 +state 51 + action 0 + 70 : 0.8 + 71 : 0.2 +state 52 + action 0 + 72 : 0.8 + 73 : 0.2 +state 53 observe0Greater1 observeOnlyTrueSender + action 0 + 74 : 1 +state 54 + action 0 + 35 : 0.8 + 75 : 0.2 +state 55 + action 0 + 76 : 0.8 + 77 : 0.2 +state 56 + action 0 + 78 : 0.8 + 79 : 0.2 +state 57 + action 0 + 80 : 0.8 + 81 : 0.2 +state 58 + action 0 + 82 : 0.8 + 83 : 0.2 +state 59 + action 0 + 84 : 1 +state 60 + action 0 + 85 : 0.833 + 86 : 0.167 +state 61 + action 0 + 87 : 0.833 + 88 : 0.167 +state 62 + action 0 + 89 : 0.833 + 90 : 0.167 +state 63 + action 0 + 91 : 0.833 + 92 : 0.167 +state 64 + action 0 + 40 : 0.833 + 41 : 0.167 +state 65 + action 0 + 93 : 1 +state 66 + action 0 + 94 : 0.833 + 95 : 0.167 +state 67 + action 0 + 96 : 1 +state 68 + action 0 + 97 : 0.833 + 98 : 0.167 +state 69 + action 0 + 99 : 1 +state 70 + action 0 + 100 : 0.833 + 101 : 0.167 +state 71 + action 0 + 102 : 1 +state 72 + action 0 + 103 : 0.833 + 104 : 0.167 +state 73 + action 0 + 105 : 1 +state 74 observe0Greater1 observeOnlyTrueSender + action 0 + 106 : 1 +state 75 + action 0 + 107 : 1 +state 76 + action 0 + 108 : 0.833 + 109 : 0.167 +state 77 + action 0 + 110 : 1 +state 78 + action 0 + 111 : 0.833 + 112 : 0.167 +state 79 + action 0 + 113 : 1 +state 80 + action 0 + 114 : 0.833 + 115 : 0.167 +state 81 + action 0 + 116 : 1 +state 82 + action 0 + 117 : 0.833 + 118 : 0.167 +state 83 + action 0 + 119 : 1 +state 84 + action 0 + 120 : 1 +state 85 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 86 + action 0 + 126 : 1 +state 87 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 88 + action 0 + 132 : 1 +state 89 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 90 + action 0 + 138 : 1 +state 91 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 92 + action 0 + 144 : 1 +state 93 + action 0 + 145 : 1 +state 94 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 95 + action 0 + 146 : 1 +state 96 + action 0 + 145 : 1 +state 97 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 98 + action 0 + 147 : 1 +state 99 + action 0 + 145 : 1 +state 100 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 101 + action 0 + 148 : 1 +state 102 + action 0 + 145 : 1 +state 103 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 104 + action 0 + 149 : 1 +state 105 + action 0 + 145 : 1 +state 106 observe0Greater1 observeOnlyTrueSender + action 0 + 150 : 0.833 + 151 : 0.167 +state 107 + action 0 + 152 : 1 +state 108 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 109 + action 0 + 153 : 1 +state 110 + action 0 + 152 : 1 +state 111 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 112 + action 0 + 154 : 1 +state 113 + action 0 + 152 : 1 +state 114 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 115 + action 0 + 155 : 1 +state 116 + action 0 + 152 : 1 +state 117 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 118 + action 0 + 156 : 1 +state 119 + action 0 + 152 : 1 +state 120 + action 0 + 157 : 0.833 + 158 : 0.167 +state 121 + action 0 + 159 : 0.8 + 160 : 0.2 +state 122 + action 0 + 161 : 0.8 + 162 : 0.2 +state 123 + action 0 + 163 : 0.8 + 164 : 0.2 +state 124 + action 0 + 165 : 0.8 + 166 : 0.2 +state 125 + action 0 + 167 : 0.8 + 168 : 0.2 +state 126 + action 0 + 169 : 1 +state 127 + action 0 + 170 : 0.8 + 171 : 0.2 +state 128 + action 0 + 172 : 0.8 + 173 : 0.2 +state 129 + action 0 + 174 : 0.8 + 175 : 0.2 +state 130 + action 0 + 176 : 0.8 + 177 : 0.2 +state 131 + action 0 + 178 : 0.8 + 179 : 0.2 +state 132 + action 0 + 180 : 1 +state 133 + action 0 + 181 : 0.8 + 182 : 0.2 +state 134 + action 0 + 183 : 0.8 + 184 : 0.2 +state 135 + action 0 + 185 : 0.8 + 186 : 0.2 +state 136 + action 0 + 187 : 0.8 + 188 : 0.2 +state 137 + action 0 + 189 : 0.8 + 190 : 0.2 +state 138 + action 0 + 191 : 1 +state 139 + action 0 + 192 : 0.8 + 193 : 0.2 +state 140 + action 0 + 194 : 0.8 + 195 : 0.2 +state 141 + action 0 + 196 : 0.8 + 197 : 0.2 +state 142 + action 0 + 198 : 0.8 + 199 : 0.2 +state 143 + action 0 + 200 : 0.8 + 201 : 0.2 +state 144 + action 0 + 202 : 1 +state 145 + action 0 + 157 : 0.833 + 158 : 0.167 +state 146 + action 0 + 203 : 1 +state 147 + action 0 + 204 : 1 +state 148 + action 0 + 205 : 1 +state 149 + action 0 + 206 : 1 +state 150 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 151 observe0Greater1 observeOnlyTrueSender + action 0 + 212 : 1 +state 152 + action 0 + 213 : 0.833 + 214 : 0.167 +state 153 + action 0 + 215 : 1 +state 154 + action 0 + 216 : 1 +state 155 + action 0 + 217 : 1 +state 156 + action 0 + 218 : 1 +state 157 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 158 + action 0 + 224 : 1 +state 159 + action 0 + 85 : 0.833 + 86 : 0.167 +state 160 + action 0 + 225 : 1 +state 161 + action 0 + 226 : 0.833 + 227 : 0.167 +state 162 + action 0 + 228 : 1 +state 163 + action 0 + 229 : 0.833 + 230 : 0.167 +state 164 + action 0 + 231 : 1 +state 165 + action 0 + 232 : 0.833 + 233 : 0.167 +state 166 + action 0 + 234 : 1 +state 167 + action 0 + 235 : 0.833 + 236 : 0.167 +state 168 + action 0 + 237 : 1 +state 169 + action 0 + 238 : 1 +state 170 + action 0 + 87 : 0.833 + 88 : 0.167 +state 171 + action 0 + 239 : 1 +state 172 + action 0 + 240 : 0.833 + 241 : 0.167 +state 173 + action 0 + 242 : 1 +state 174 + action 0 + 243 : 0.833 + 244 : 0.167 +state 175 + action 0 + 245 : 1 +state 176 + action 0 + 246 : 0.833 + 247 : 0.167 +state 177 + action 0 + 248 : 1 +state 178 + action 0 + 249 : 0.833 + 250 : 0.167 +state 179 + action 0 + 251 : 1 +state 180 + action 0 + 252 : 1 +state 181 + action 0 + 89 : 0.833 + 90 : 0.167 +state 182 + action 0 + 253 : 1 +state 183 + action 0 + 254 : 0.833 + 255 : 0.167 +state 184 + action 0 + 256 : 1 +state 185 + action 0 + 257 : 0.833 + 258 : 0.167 +state 186 + action 0 + 259 : 1 +state 187 + action 0 + 260 : 0.833 + 261 : 0.167 +state 188 + action 0 + 262 : 1 +state 189 + action 0 + 263 : 0.833 + 264 : 0.167 +state 190 + action 0 + 265 : 1 +state 191 + action 0 + 266 : 1 +state 192 + action 0 + 91 : 0.833 + 92 : 0.167 +state 193 + action 0 + 267 : 1 +state 194 + action 0 + 268 : 0.833 + 269 : 0.167 +state 195 + action 0 + 270 : 1 +state 196 + action 0 + 271 : 0.833 + 272 : 0.167 +state 197 + action 0 + 273 : 1 +state 198 + action 0 + 274 : 0.833 + 275 : 0.167 +state 199 + action 0 + 276 : 1 +state 200 + action 0 + 277 : 0.833 + 278 : 0.167 +state 201 + action 0 + 279 : 1 +state 202 + action 0 + 280 : 1 +state 203 + action 0 + 238 : 1 +state 204 + action 0 + 252 : 1 +state 205 + action 0 + 266 : 1 +state 206 + action 0 + 280 : 1 +state 207 observe0Greater1 observeOnlyTrueSender + action 0 + 281 : 0.8 + 282 : 0.2 +state 208 observe0Greater1 observeOnlyTrueSender + action 0 + 283 : 0.8 + 284 : 0.2 +state 209 observe0Greater1 observeOnlyTrueSender + action 0 + 285 : 0.8 + 286 : 0.2 +state 210 observe0Greater1 observeOnlyTrueSender + action 0 + 287 : 0.8 + 288 : 0.2 +state 211 observe0Greater1 observeOnlyTrueSender + action 0 + 289 : 0.8 + 290 : 0.2 +state 212 observe0Greater1 observeOnlyTrueSender + action 0 + 291 : 1 +state 213 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 214 + action 0 + 297 : 1 +state 215 + action 0 + 298 : 1 +state 216 + action 0 + 299 : 1 +state 217 + action 0 + 300 : 1 +state 218 + action 0 + 301 : 1 +state 219 + action 0 + 145 : 0.8 + 302 : 0.2 +state 220 + action 0 + 303 : 0.8 + 304 : 0.2 +state 221 + action 0 + 305 : 0.8 + 306 : 0.2 +state 222 + action 0 + 307 : 0.8 + 308 : 0.2 +state 223 + action 0 + 309 : 0.8 + 310 : 0.2 +state 224 observe0Greater1 observeOnlyTrueSender + action 0 + 311 : 1 +state 225 + action 0 + 312 : 1 +state 226 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 227 + action 0 + 313 : 1 +state 228 + action 0 + 312 : 1 +state 229 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 230 + action 0 + 314 : 1 +state 231 + action 0 + 312 : 1 +state 232 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 233 + action 0 + 315 : 1 +state 234 + action 0 + 312 : 1 +state 235 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 236 + action 0 + 316 : 1 +state 237 + action 0 + 312 : 1 +state 238 + action 0 + 317 : 0.833 + 318 : 0.167 +state 239 + action 0 + 319 : 1 +state 240 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 241 + action 0 + 320 : 1 +state 242 + action 0 + 319 : 1 +state 243 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 244 + action 0 + 321 : 1 +state 245 + action 0 + 319 : 1 +state 246 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 247 + action 0 + 322 : 1 +state 248 + action 0 + 319 : 1 +state 249 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 250 + action 0 + 323 : 1 +state 251 + action 0 + 319 : 1 +state 252 + action 0 + 324 : 0.833 + 325 : 0.167 +state 253 + action 0 + 326 : 1 +state 254 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 255 + action 0 + 327 : 1 +state 256 + action 0 + 326 : 1 +state 257 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 258 + action 0 + 328 : 1 +state 259 + action 0 + 326 : 1 +state 260 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 261 + action 0 + 329 : 1 +state 262 + action 0 + 326 : 1 +state 263 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 264 + action 0 + 330 : 1 +state 265 + action 0 + 326 : 1 +state 266 + action 0 + 331 : 0.833 + 332 : 0.167 +state 267 + action 0 + 333 : 1 +state 268 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 269 + action 0 + 334 : 1 +state 270 + action 0 + 333 : 1 +state 271 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 272 + action 0 + 335 : 1 +state 273 + action 0 + 333 : 1 +state 274 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 275 + action 0 + 336 : 1 +state 276 + action 0 + 333 : 1 +state 277 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 278 + action 0 + 337 : 1 +state 279 + action 0 + 333 : 1 +state 280 + action 0 + 338 : 0.833 + 339 : 0.167 +state 281 observe0Greater1 observeOnlyTrueSender + action 0 + 150 : 0.833 + 151 : 0.167 +state 282 observe0Greater1 observeOnlyTrueSender + action 0 + 340 : 1 +state 283 observe0Greater1 observeOnlyTrueSender + action 0 + 341 : 0.833 + 342 : 0.167 +state 284 observe0Greater1 observeOnlyTrueSender + action 0 + 343 : 1 +state 285 observe0Greater1 observeOnlyTrueSender + action 0 + 344 : 0.833 + 345 : 0.167 +state 286 observe0Greater1 observeOnlyTrueSender + action 0 + 346 : 1 +state 287 observe0Greater1 observeOnlyTrueSender + action 0 + 347 : 0.833 + 348 : 0.167 +state 288 observe0Greater1 observeOnlyTrueSender + action 0 + 349 : 1 +state 289 observe0Greater1 observeOnlyTrueSender + action 0 + 350 : 0.833 + 351 : 0.167 +state 290 observe0Greater1 observeOnlyTrueSender + action 0 + 352 : 1 +state 291 observe0Greater1 observeOnlyTrueSender + action 0 + 353 : 1 +state 292 + action 0 + 152 : 0.8 + 354 : 0.2 +state 293 + action 0 + 355 : 0.8 + 356 : 0.2 +state 294 + action 0 + 357 : 0.8 + 358 : 0.2 +state 295 + action 0 + 359 : 0.8 + 360 : 0.2 +state 296 + action 0 + 361 : 0.8 + 362 : 0.2 +state 297 + action 0 + 363 : 1 +state 298 + action 0 + 364 : 0.833 + 365 : 0.167 +state 299 + action 0 + 366 : 0.833 + 367 : 0.167 +state 300 + action 0 + 368 : 0.833 + 369 : 0.167 +state 301 + action 0 + 370 : 0.833 + 371 : 0.167 +state 302 + action 0 + 372 : 1 +state 303 + action 0 + 373 : 0.833 + 374 : 0.167 +state 304 + action 0 + 375 : 1 +state 305 + action 0 + 376 : 0.833 + 377 : 0.167 +state 306 + action 0 + 378 : 1 +state 307 + action 0 + 379 : 0.833 + 380 : 0.167 +state 308 + action 0 + 381 : 1 +state 309 + action 0 + 382 : 0.833 + 383 : 0.167 +state 310 + action 0 + 384 : 1 +state 311 observe0Greater1 observeOnlyTrueSender + action 0 + 385 : 1 +state 312 + action 0 + 364 : 0.833 + 365 : 0.167 +state 313 observe1Greater1 observeIGreater1 + action 0 + 386 : 1 +state 314 + action 0 + 387 : 1 +state 315 + action 0 + 388 : 1 +state 316 + action 0 + 389 : 1 +state 317 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 318 + action 0 + 395 : 1 +state 319 + action 0 + 366 : 0.833 + 367 : 0.167 +state 320 + action 0 + 396 : 1 +state 321 observe2Greater1 observeIGreater1 + action 0 + 397 : 1 +state 322 + action 0 + 398 : 1 +state 323 + action 0 + 399 : 1 +state 324 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 325 + action 0 + 405 : 1 +state 326 + action 0 + 368 : 0.833 + 369 : 0.167 +state 327 + action 0 + 406 : 1 +state 328 + action 0 + 407 : 1 +state 329 observe3Greater1 observeIGreater1 + action 0 + 408 : 1 +state 330 + action 0 + 409 : 1 +state 331 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 332 + action 0 + 415 : 1 +state 333 + action 0 + 370 : 0.833 + 371 : 0.167 +state 334 + action 0 + 416 : 1 +state 335 + action 0 + 417 : 1 +state 336 + action 0 + 418 : 1 +state 337 observe4Greater1 observeIGreater1 + action 0 + 419 : 1 +state 338 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 339 + action 0 + 425 : 1 +state 340 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 341 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 342 observe0Greater1 observeOnlyTrueSender + action 0 + 427 : 1 +state 343 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 344 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 345 observe0Greater1 observeOnlyTrueSender + action 0 + 428 : 1 +state 346 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 347 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 348 observe0Greater1 observeOnlyTrueSender + action 0 + 429 : 1 +state 349 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 350 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 351 observe0Greater1 observeOnlyTrueSender + action 0 + 430 : 1 +state 352 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 353 observe0Greater1 observeOnlyTrueSender + action 0 + 431 : 0.833 + 432 : 0.167 +state 354 + action 0 + 433 : 1 +state 355 + action 0 + 434 : 0.833 + 435 : 0.167 +state 356 + action 0 + 436 : 1 +state 357 + action 0 + 437 : 0.833 + 438 : 0.167 +state 358 + action 0 + 439 : 1 +state 359 + action 0 + 440 : 0.833 + 441 : 0.167 +state 360 + action 0 + 442 : 1 +state 361 + action 0 + 443 : 0.833 + 444 : 0.167 +state 362 + action 0 + 445 : 1 +state 363 + action 0 + 446 : 1 +state 364 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 365 + action 0 + 452 : 1 +state 366 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 367 + action 0 + 458 : 1 +state 368 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 369 + action 0 + 464 : 1 +state 370 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 371 + action 0 + 470 : 1 +state 372 + action 0 + 471 : 1 +state 373 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 374 + action 0 + 472 : 1 +state 375 + action 0 + 471 : 1 +state 376 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 377 + action 0 + 473 : 1 +state 378 + action 0 + 471 : 1 +state 379 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 380 + action 0 + 474 : 1 +state 381 + action 0 + 471 : 1 +state 382 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 383 + action 0 + 475 : 1 +state 384 + action 0 + 471 : 1 +state 385 observe0Greater1 observeOnlyTrueSender + action 0 + 476 : 0.833 + 477 : 0.167 +state 386 observe1Greater1 observeIGreater1 + action 0 + 478 : 1 +state 387 + action 0 + 479 : 1 +state 388 + action 0 + 480 : 1 +state 389 + action 0 + 481 : 1 +state 390 + action 0 + 482 : 0.8 + 483 : 0.2 +state 391 + action 0 + 484 : 0.8 + 485 : 0.2 +state 392 + action 0 + 486 : 0.8 + 487 : 0.2 +state 393 + action 0 + 488 : 0.8 + 489 : 0.2 +state 394 + action 0 + 490 : 0.8 + 491 : 0.2 +state 395 observe0Greater1 observeOnlyTrueSender + action 0 + 492 : 1 +state 396 + action 0 + 479 : 1 +state 397 observe2Greater1 observeIGreater1 + action 0 + 493 : 1 +state 398 + action 0 + 494 : 1 +state 399 + action 0 + 495 : 1 +state 400 + action 0 + 496 : 0.8 + 497 : 0.2 +state 401 + action 0 + 498 : 0.8 + 499 : 0.2 +state 402 + action 0 + 500 : 0.8 + 501 : 0.2 +state 403 + action 0 + 502 : 0.8 + 503 : 0.2 +state 404 + action 0 + 504 : 0.8 + 505 : 0.2 +state 405 observe0Greater1 observeOnlyTrueSender + action 0 + 506 : 1 +state 406 + action 0 + 480 : 1 +state 407 + action 0 + 494 : 1 +state 408 observe3Greater1 observeIGreater1 + action 0 + 507 : 1 +state 409 + action 0 + 508 : 1 +state 410 + action 0 + 509 : 0.8 + 510 : 0.2 +state 411 + action 0 + 511 : 0.8 + 512 : 0.2 +state 412 + action 0 + 513 : 0.8 + 514 : 0.2 +state 413 + action 0 + 515 : 0.8 + 516 : 0.2 +state 414 + action 0 + 517 : 0.8 + 518 : 0.2 +state 415 observe0Greater1 observeOnlyTrueSender + action 0 + 519 : 1 +state 416 + action 0 + 481 : 1 +state 417 + action 0 + 495 : 1 +state 418 + action 0 + 508 : 1 +state 419 observe4Greater1 observeIGreater1 + action 0 + 520 : 1 +state 420 + action 0 + 521 : 0.8 + 522 : 0.2 +state 421 + action 0 + 523 : 0.8 + 524 : 0.2 +state 422 + action 0 + 525 : 0.8 + 526 : 0.2 +state 423 + action 0 + 527 : 0.8 + 528 : 0.2 +state 424 + action 0 + 529 : 0.8 + 530 : 0.2 +state 425 observe0Greater1 observeOnlyTrueSender + action 0 + 531 : 1 +state 426 observe0Greater1 observeOnlyTrueSender + action 0 + 476 : 0.833 + 477 : 0.167 +state 427 observe0Greater1 observeOnlyTrueSender + action 0 + 532 : 1 +state 428 observe0Greater1 observeOnlyTrueSender + action 0 + 533 : 1 +state 429 observe0Greater1 observeOnlyTrueSender + action 0 + 534 : 1 +state 430 observe0Greater1 observeOnlyTrueSender + action 0 + 535 : 1 +state 431 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 432 observe0Greater1 observeOnlyTrueSender + action 0 + 541 : 1 +state 433 + action 0 + 542 : 1 +state 434 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 435 + action 0 + 543 : 1 +state 436 + action 0 + 542 : 1 +state 437 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 438 + action 0 + 544 : 1 +state 439 + action 0 + 542 : 1 +state 440 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 441 + action 0 + 545 : 1 +state 442 + action 0 + 542 : 1 +state 443 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 444 + action 0 + 546 : 1 +state 445 + action 0 + 542 : 1 +state 446 + action 0 + 547 : 0.833 + 548 : 0.167 +state 447 + action 0 + 312 : 0.8 + 549 : 0.2 +state 448 + action 0 + 550 : 0.8 + 551 : 0.2 +state 449 + action 0 + 552 : 0.8 + 553 : 0.2 +state 450 + action 0 + 554 : 0.8 + 555 : 0.2 +state 451 + action 0 + 556 : 0.8 + 557 : 0.2 +state 452 + action 0 + 558 : 1 +state 453 + action 0 + 319 : 0.8 + 559 : 0.2 +state 454 + action 0 + 560 : 0.8 + 561 : 0.2 +state 455 + action 0 + 562 : 0.8 + 563 : 0.2 +state 456 + action 0 + 564 : 0.8 + 565 : 0.2 +state 457 + action 0 + 566 : 0.8 + 567 : 0.2 +state 458 + action 0 + 568 : 1 +state 459 + action 0 + 326 : 0.8 + 569 : 0.2 +state 460 + action 0 + 570 : 0.8 + 571 : 0.2 +state 461 + action 0 + 572 : 0.8 + 573 : 0.2 +state 462 + action 0 + 574 : 0.8 + 575 : 0.2 +state 463 + action 0 + 576 : 0.8 + 577 : 0.2 +state 464 + action 0 + 578 : 1 +state 465 + action 0 + 333 : 0.8 + 579 : 0.2 +state 466 + action 0 + 580 : 0.8 + 581 : 0.2 +state 467 + action 0 + 582 : 0.8 + 583 : 0.2 +state 468 + action 0 + 584 : 0.8 + 585 : 0.2 +state 469 + action 0 + 586 : 0.8 + 587 : 0.2 +state 470 + action 0 + 588 : 1 +state 471 + action 0 + 547 : 0.833 + 548 : 0.167 +state 472 + action 0 + 589 : 1 +state 473 + action 0 + 590 : 1 +state 474 + action 0 + 591 : 1 +state 475 + action 0 + 592 : 1 +state 476 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 477 observe0Greater1 observeOnlyTrueSender + action 0 + 598 : 1 +state 478 observe1Greater1 observeIGreater1 + action 0 + 599 : 0.833 + 600 : 0.167 +state 479 + action 0 + 601 : 0.833 + 602 : 0.167 +state 480 + action 0 + 603 : 0.833 + 604 : 0.167 +state 481 + action 0 + 605 : 0.833 + 606 : 0.167 +state 482 + action 0 + 317 : 0.833 + 318 : 0.167 +state 483 + action 0 + 607 : 1 +state 484 + action 0 + 608 : 0.833 + 609 : 0.167 +state 485 + action 0 + 610 : 1 +state 486 + action 0 + 611 : 0.833 + 612 : 0.167 +state 487 + action 0 + 613 : 1 +state 488 + action 0 + 614 : 0.833 + 615 : 0.167 +state 489 + action 0 + 616 : 1 +state 490 + action 0 + 617 : 0.833 + 618 : 0.167 +state 491 + action 0 + 619 : 1 +state 492 observe0Greater1 observeOnlyTrueSender + action 0 + 620 : 1 +state 493 observe2Greater1 observeIGreater1 + action 0 + 621 : 0.833 + 622 : 0.167 +state 494 + action 0 + 623 : 0.833 + 624 : 0.167 +state 495 + action 0 + 625 : 0.833 + 626 : 0.167 +state 496 + action 0 + 324 : 0.833 + 325 : 0.167 +state 497 + action 0 + 627 : 1 +state 498 + action 0 + 628 : 0.833 + 629 : 0.167 +state 499 + action 0 + 630 : 1 +state 500 + action 0 + 631 : 0.833 + 632 : 0.167 +state 501 + action 0 + 633 : 1 +state 502 + action 0 + 634 : 0.833 + 635 : 0.167 +state 503 + action 0 + 636 : 1 +state 504 + action 0 + 637 : 0.833 + 638 : 0.167 +state 505 + action 0 + 639 : 1 +state 506 observe0Greater1 observeOnlyTrueSender + action 0 + 640 : 1 +state 507 observe3Greater1 observeIGreater1 + action 0 + 641 : 0.833 + 642 : 0.167 +state 508 + action 0 + 643 : 0.833 + 644 : 0.167 +state 509 + action 0 + 331 : 0.833 + 332 : 0.167 +state 510 + action 0 + 645 : 1 +state 511 + action 0 + 646 : 0.833 + 647 : 0.167 +state 512 + action 0 + 648 : 1 +state 513 + action 0 + 649 : 0.833 + 650 : 0.167 +state 514 + action 0 + 651 : 1 +state 515 + action 0 + 652 : 0.833 + 653 : 0.167 +state 516 + action 0 + 654 : 1 +state 517 + action 0 + 655 : 0.833 + 656 : 0.167 +state 518 + action 0 + 657 : 1 +state 519 observe0Greater1 observeOnlyTrueSender + action 0 + 658 : 1 +state 520 observe4Greater1 observeIGreater1 + action 0 + 659 : 0.833 + 660 : 0.167 +state 521 + action 0 + 338 : 0.833 + 339 : 0.167 +state 522 + action 0 + 661 : 1 +state 523 + action 0 + 662 : 0.833 + 663 : 0.167 +state 524 + action 0 + 664 : 1 +state 525 + action 0 + 665 : 0.833 + 666 : 0.167 +state 526 + action 0 + 667 : 1 +state 527 + action 0 + 668 : 0.833 + 669 : 0.167 +state 528 + action 0 + 670 : 1 +state 529 + action 0 + 671 : 0.833 + 672 : 0.167 +state 530 + action 0 + 673 : 1 +state 531 observe0Greater1 observeOnlyTrueSender + action 0 + 674 : 1 +state 532 observe0Greater1 observeOnlyTrueSender + action 0 + 620 : 1 +state 533 observe0Greater1 observeOnlyTrueSender + action 0 + 640 : 1 +state 534 observe0Greater1 observeOnlyTrueSender + action 0 + 658 : 1 +state 535 observe0Greater1 observeOnlyTrueSender + action 0 + 674 : 1 +state 536 observe0Greater1 observeOnlyTrueSender + action 0 + 675 : 0.8 + 676 : 0.2 +state 537 observe0Greater1 observeOnlyTrueSender + action 0 + 677 : 0.8 + 678 : 0.2 +state 538 observe0Greater1 observeOnlyTrueSender + action 0 + 679 : 0.8 + 680 : 0.2 +state 539 observe0Greater1 observeOnlyTrueSender + action 0 + 681 : 0.8 + 682 : 0.2 +state 540 observe0Greater1 observeOnlyTrueSender + action 0 + 683 : 0.8 + 684 : 0.2 +state 541 observe0Greater1 observeOnlyTrueSender + action 0 + 685 : 1 +state 542 + action 0 + 686 : 0.833 + 687 : 0.167 +state 543 + action 0 + 688 : 1 +state 544 + action 0 + 689 : 1 +state 545 + action 0 + 690 : 1 +state 546 + action 0 + 691 : 1 +state 547 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 548 + action 0 + 697 : 1 +state 549 + action 0 + 698 : 1 +state 550 + action 0 + 699 : 0.833 + 700 : 0.167 +state 551 + action 0 + 701 : 1 +state 552 + action 0 + 702 : 0.833 + 703 : 0.167 +state 553 + action 0 + 704 : 1 +state 554 + action 0 + 705 : 0.833 + 706 : 0.167 +state 555 + action 0 + 707 : 1 +state 556 + action 0 + 708 : 0.833 + 709 : 0.167 +state 557 + action 0 + 710 : 1 +state 558 + action 0 + 711 : 1 +state 559 + action 0 + 712 : 1 +state 560 + action 0 + 713 : 0.833 + 714 : 0.167 +state 561 + action 0 + 715 : 1 +state 562 + action 0 + 716 : 0.833 + 717 : 0.167 +state 563 + action 0 + 718 : 1 +state 564 + action 0 + 719 : 0.833 + 720 : 0.167 +state 565 + action 0 + 721 : 1 +state 566 + action 0 + 722 : 0.833 + 723 : 0.167 +state 567 + action 0 + 724 : 1 +state 568 + action 0 + 725 : 1 +state 569 + action 0 + 726 : 1 +state 570 + action 0 + 727 : 0.833 + 728 : 0.167 +state 571 + action 0 + 729 : 1 +state 572 + action 0 + 730 : 0.833 + 731 : 0.167 +state 573 + action 0 + 732 : 1 +state 574 + action 0 + 733 : 0.833 + 734 : 0.167 +state 575 + action 0 + 735 : 1 +state 576 + action 0 + 736 : 0.833 + 737 : 0.167 +state 577 + action 0 + 738 : 1 +state 578 + action 0 + 739 : 1 +state 579 + action 0 + 740 : 1 +state 580 + action 0 + 741 : 0.833 + 742 : 0.167 +state 581 + action 0 + 743 : 1 +state 582 + action 0 + 744 : 0.833 + 745 : 0.167 +state 583 + action 0 + 746 : 1 +state 584 + action 0 + 747 : 0.833 + 748 : 0.167 +state 585 + action 0 + 749 : 1 +state 586 + action 0 + 750 : 0.833 + 751 : 0.167 +state 587 + action 0 + 752 : 1 +state 588 + action 0 + 753 : 1 +state 589 + action 0 + 711 : 1 +state 590 + action 0 + 725 : 1 +state 591 + action 0 + 739 : 1 +state 592 + action 0 + 753 : 1 +state 593 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 0.8 + 754 : 0.2 +state 594 observe0Greater1 observeOnlyTrueSender + action 0 + 755 : 0.8 + 756 : 0.2 +state 595 observe0Greater1 observeOnlyTrueSender + action 0 + 757 : 0.8 + 758 : 0.2 +state 596 observe0Greater1 observeOnlyTrueSender + action 0 + 759 : 0.8 + 760 : 0.2 +state 597 observe0Greater1 observeOnlyTrueSender + action 0 + 761 : 0.8 + 762 : 0.2 +state 598 observe0Greater1 observeOnlyTrueSender + action 0 + 763 : 1 +state 599 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 600 observe1Greater1 observeIGreater1 + action 0 + 769 : 1 +state 601 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 602 + action 0 + 775 : 1 +state 603 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 604 + action 0 + 781 : 1 +state 605 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 606 + action 0 + 787 : 1 +state 607 + action 0 + 788 : 1 +state 608 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 609 + action 0 + 789 : 1 +state 610 + action 0 + 788 : 1 +state 611 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 612 + action 0 + 790 : 1 +state 613 + action 0 + 788 : 1 +state 614 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 615 + action 0 + 791 : 1 +state 616 + action 0 + 788 : 1 +state 617 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 618 + action 0 + 792 : 1 +state 619 + action 0 + 788 : 1 +state 620 observe0Greater1 observeOnlyTrueSender + action 0 + 793 : 0.833 + 794 : 0.167 +state 621 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 622 observe2Greater1 observeIGreater1 + action 0 + 800 : 1 +state 623 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 624 + action 0 + 806 : 1 +state 625 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 626 + action 0 + 812 : 1 +state 627 + action 0 + 813 : 1 +state 628 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 629 + action 0 + 814 : 1 +state 630 + action 0 + 813 : 1 +state 631 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 632 + action 0 + 815 : 1 +state 633 + action 0 + 813 : 1 +state 634 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 635 + action 0 + 816 : 1 +state 636 + action 0 + 813 : 1 +state 637 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 638 + action 0 + 817 : 1 +state 639 + action 0 + 813 : 1 +state 640 observe0Greater1 observeOnlyTrueSender + action 0 + 818 : 0.833 + 819 : 0.167 +state 641 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 642 observe3Greater1 observeIGreater1 + action 0 + 825 : 1 +state 643 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 644 + action 0 + 831 : 1 +state 645 + action 0 + 832 : 1 +state 646 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 647 + action 0 + 833 : 1 +state 648 + action 0 + 832 : 1 +state 649 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 650 + action 0 + 834 : 1 +state 651 + action 0 + 832 : 1 +state 652 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 653 + action 0 + 835 : 1 +state 654 + action 0 + 832 : 1 +state 655 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 656 + action 0 + 836 : 1 +state 657 + action 0 + 832 : 1 +state 658 observe0Greater1 observeOnlyTrueSender + action 0 + 837 : 0.833 + 838 : 0.167 +state 659 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 660 observe4Greater1 observeIGreater1 + action 0 + 844 : 1 +state 661 + action 0 + 845 : 1 +state 662 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 663 + action 0 + 846 : 1 +state 664 + action 0 + 845 : 1 +state 665 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 666 + action 0 + 847 : 1 +state 667 + action 0 + 845 : 1 +state 668 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 669 + action 0 + 848 : 1 +state 670 + action 0 + 845 : 1 +state 671 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 672 + action 0 + 849 : 1 +state 673 + action 0 + 845 : 1 +state 674 observe0Greater1 observeOnlyTrueSender + action 0 + 850 : 0.833 + 851 : 0.167 +state 675 observe0Greater1 observeOnlyTrueSender + action 0 + 431 : 0.833 + 432 : 0.167 +state 676 observe0Greater1 observeOnlyTrueSender + action 0 + 852 : 1 +state 677 observe0Greater1 observeOnlyTrueSender + action 0 + 853 : 0.833 + 854 : 0.167 +state 678 observe0Greater1 observeOnlyTrueSender + action 0 + 855 : 1 +state 679 observe0Greater1 observeOnlyTrueSender + action 0 + 856 : 0.833 + 857 : 0.167 +state 680 observe0Greater1 observeOnlyTrueSender + action 0 + 858 : 1 +state 681 observe0Greater1 observeOnlyTrueSender + action 0 + 859 : 0.833 + 860 : 0.167 +state 682 observe0Greater1 observeOnlyTrueSender + action 0 + 861 : 1 +state 683 observe0Greater1 observeOnlyTrueSender + action 0 + 862 : 0.833 + 863 : 0.167 +state 684 observe0Greater1 observeOnlyTrueSender + action 0 + 864 : 1 +state 685 observe0Greater1 observeOnlyTrueSender + action 0 + 865 : 1 +state 686 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 687 + action 0 + 871 : 1 +state 688 + action 0 + 872 : 1 +state 689 + action 0 + 873 : 1 +state 690 + action 0 + 874 : 1 +state 691 + action 0 + 875 : 1 +state 692 + action 0 + 471 : 0.8 + 876 : 0.2 +state 693 + action 0 + 877 : 0.8 + 878 : 0.2 +state 694 + action 0 + 879 : 0.8 + 880 : 0.2 +state 695 + action 0 + 881 : 0.8 + 882 : 0.2 +state 696 + action 0 + 883 : 0.8 + 884 : 0.2 +state 697 observe0Greater1 observeOnlyTrueSender + action 0 + 885 : 1 +state 698 + action 0 + 886 : 1 +state 699 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 700 + action 0 + 887 : 1 +state 701 + action 0 + 886 : 1 +state 702 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 703 + action 0 + 888 : 1 +state 704 + action 0 + 886 : 1 +state 705 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 706 + action 0 + 889 : 1 +state 707 + action 0 + 886 : 1 +state 708 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 709 + action 0 + 890 : 1 +state 710 + action 0 + 886 : 1 +state 711 + action 0 + 891 : 0.833 + 892 : 0.167 +state 712 + action 0 + 893 : 1 +state 713 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 714 + action 0 + 894 : 1 +state 715 + action 0 + 893 : 1 +state 716 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 717 + action 0 + 895 : 1 +state 718 + action 0 + 893 : 1 +state 719 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 720 + action 0 + 896 : 1 +state 721 + action 0 + 893 : 1 +state 722 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 723 + action 0 + 897 : 1 +state 724 + action 0 + 893 : 1 +state 725 + action 0 + 898 : 0.833 + 899 : 0.167 +state 726 + action 0 + 900 : 1 +state 727 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 728 + action 0 + 901 : 1 +state 729 + action 0 + 900 : 1 +state 730 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 731 + action 0 + 902 : 1 +state 732 + action 0 + 900 : 1 +state 733 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 734 + action 0 + 903 : 1 +state 735 + action 0 + 900 : 1 +state 736 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 737 + action 0 + 904 : 1 +state 738 + action 0 + 900 : 1 +state 739 + action 0 + 905 : 0.833 + 906 : 0.167 +state 740 + action 0 + 907 : 1 +state 741 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 742 + action 0 + 908 : 1 +state 743 + action 0 + 907 : 1 +state 744 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 745 + action 0 + 909 : 1 +state 746 + action 0 + 907 : 1 +state 747 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 748 + action 0 + 910 : 1 +state 749 + action 0 + 907 : 1 +state 750 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 751 + action 0 + 911 : 1 +state 752 + action 0 + 907 : 1 +state 753 + action 0 + 912 : 0.833 + 913 : 0.167 +state 754 observe0Greater1 observeOnlyTrueSender + action 0 + 914 : 1 +state 755 observe0Greater1 observeOnlyTrueSender + action 0 + 915 : 0.833 + 916 : 0.167 +state 756 observe0Greater1 observeOnlyTrueSender + action 0 + 917 : 1 +state 757 observe0Greater1 observeOnlyTrueSender + action 0 + 918 : 0.833 + 919 : 0.167 +state 758 observe0Greater1 observeOnlyTrueSender + action 0 + 920 : 1 +state 759 observe0Greater1 observeOnlyTrueSender + action 0 + 921 : 0.833 + 922 : 0.167 +state 760 observe0Greater1 observeOnlyTrueSender + action 0 + 923 : 1 +state 761 observe0Greater1 observeOnlyTrueSender + action 0 + 924 : 0.833 + 925 : 0.167 +state 762 observe0Greater1 observeOnlyTrueSender + action 0 + 926 : 1 +state 763 observe0Greater1 observeOnlyTrueSender + action 0 + 927 : 1 +state 764 observe1Greater1 observeIGreater1 + action 0 + 928 : 0.8 + 929 : 0.2 +state 765 observe1Greater1 observeIGreater1 + action 0 + 930 : 0.8 + 931 : 0.2 +state 766 observe1Greater1 observeIGreater1 + action 0 + 932 : 0.8 + 933 : 0.2 +state 767 observe1Greater1 observeIGreater1 + action 0 + 934 : 0.8 + 935 : 0.2 +state 768 observe1Greater1 observeIGreater1 + action 0 + 936 : 0.8 + 937 : 0.2 +state 769 observe1Greater1 observeIGreater1 + action 0 + 938 : 1 +state 770 + action 0 + 939 : 0.8 + 940 : 0.2 +state 771 + action 0 + 941 : 0.8 + 942 : 0.2 +state 772 + action 0 + 943 : 0.8 + 944 : 0.2 +state 773 + action 0 + 945 : 0.8 + 946 : 0.2 +state 774 + action 0 + 947 : 0.8 + 948 : 0.2 +state 775 + action 0 + 949 : 1 +state 776 + action 0 + 950 : 0.8 + 951 : 0.2 +state 777 + action 0 + 952 : 0.8 + 953 : 0.2 +state 778 + action 0 + 954 : 0.8 + 955 : 0.2 +state 779 + action 0 + 956 : 0.8 + 957 : 0.2 +state 780 + action 0 + 958 : 0.8 + 959 : 0.2 +state 781 + action 0 + 960 : 1 +state 782 + action 0 + 961 : 0.8 + 962 : 0.2 +state 783 + action 0 + 963 : 0.8 + 964 : 0.2 +state 784 + action 0 + 965 : 0.8 + 966 : 0.2 +state 785 + action 0 + 967 : 0.8 + 968 : 0.2 +state 786 + action 0 + 969 : 0.8 + 970 : 0.2 +state 787 + action 0 + 971 : 1 +state 788 + action 0 + 891 : 0.833 + 892 : 0.167 +state 789 observe1Greater1 observeIGreater1 + action 0 + 972 : 1 +state 790 + action 0 + 973 : 1 +state 791 + action 0 + 974 : 1 +state 792 + action 0 + 975 : 1 +state 793 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 794 observe0Greater1 observeOnlyTrueSender + action 0 + 981 : 1 +state 795 observe2Greater1 observeIGreater1 + action 0 + 982 : 0.8 + 983 : 0.2 +state 796 observe2Greater1 observeIGreater1 + action 0 + 984 : 0.8 + 985 : 0.2 +state 797 observe2Greater1 observeIGreater1 + action 0 + 986 : 0.8 + 987 : 0.2 +state 798 observe2Greater1 observeIGreater1 + action 0 + 988 : 0.8 + 989 : 0.2 +state 799 observe2Greater1 observeIGreater1 + action 0 + 990 : 0.8 + 991 : 0.2 +state 800 observe2Greater1 observeIGreater1 + action 0 + 992 : 1 +state 801 + action 0 + 993 : 0.8 + 994 : 0.2 +state 802 + action 0 + 995 : 0.8 + 996 : 0.2 +state 803 + action 0 + 997 : 0.8 + 998 : 0.2 +state 804 + action 0 + 999 : 0.8 + 1000 : 0.2 +state 805 + action 0 + 1001 : 0.8 + 1002 : 0.2 +state 806 + action 0 + 1003 : 1 +state 807 + action 0 + 1004 : 0.8 + 1005 : 0.2 +state 808 + action 0 + 1006 : 0.8 + 1007 : 0.2 +state 809 + action 0 + 1008 : 0.8 + 1009 : 0.2 +state 810 + action 0 + 1010 : 0.8 + 1011 : 0.2 +state 811 + action 0 + 1012 : 0.8 + 1013 : 0.2 +state 812 + action 0 + 1014 : 1 +state 813 + action 0 + 898 : 0.833 + 899 : 0.167 +state 814 + action 0 + 1015 : 1 +state 815 observe2Greater1 observeIGreater1 + action 0 + 1016 : 1 +state 816 + action 0 + 1017 : 1 +state 817 + action 0 + 1018 : 1 +state 818 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 819 observe0Greater1 observeOnlyTrueSender + action 0 + 1024 : 1 +state 820 observe3Greater1 observeIGreater1 + action 0 + 1025 : 0.8 + 1026 : 0.2 +state 821 observe3Greater1 observeIGreater1 + action 0 + 1027 : 0.8 + 1028 : 0.2 +state 822 observe3Greater1 observeIGreater1 + action 0 + 1029 : 0.8 + 1030 : 0.2 +state 823 observe3Greater1 observeIGreater1 + action 0 + 1031 : 0.8 + 1032 : 0.2 +state 824 observe3Greater1 observeIGreater1 + action 0 + 1033 : 0.8 + 1034 : 0.2 +state 825 observe3Greater1 observeIGreater1 + action 0 + 1035 : 1 +state 826 + action 0 + 1036 : 0.8 + 1037 : 0.2 +state 827 + action 0 + 1038 : 0.8 + 1039 : 0.2 +state 828 + action 0 + 1040 : 0.8 + 1041 : 0.2 +state 829 + action 0 + 1042 : 0.8 + 1043 : 0.2 +state 830 + action 0 + 1044 : 0.8 + 1045 : 0.2 +state 831 + action 0 + 1046 : 1 +state 832 + action 0 + 905 : 0.833 + 906 : 0.167 +state 833 + action 0 + 1047 : 1 +state 834 + action 0 + 1048 : 1 +state 835 observe3Greater1 observeIGreater1 + action 0 + 1049 : 1 +state 836 + action 0 + 1050 : 1 +state 837 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 838 observe0Greater1 observeOnlyTrueSender + action 0 + 1056 : 1 +state 839 observe4Greater1 observeIGreater1 + action 0 + 1057 : 0.8 + 1058 : 0.2 +state 840 observe4Greater1 observeIGreater1 + action 0 + 1059 : 0.8 + 1060 : 0.2 +state 841 observe4Greater1 observeIGreater1 + action 0 + 1061 : 0.8 + 1062 : 0.2 +state 842 observe4Greater1 observeIGreater1 + action 0 + 1063 : 0.8 + 1064 : 0.2 +state 843 observe4Greater1 observeIGreater1 + action 0 + 1065 : 0.8 + 1066 : 0.2 +state 844 observe4Greater1 observeIGreater1 + action 0 + 1067 : 1 +state 845 + action 0 + 912 : 0.833 + 913 : 0.167 +state 846 + action 0 + 1068 : 1 +state 847 + action 0 + 1069 : 1 +state 848 + action 0 + 1070 : 1 +state 849 observe4Greater1 observeIGreater1 + action 0 + 1071 : 1 +state 850 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 851 observe0Greater1 observeOnlyTrueSender + action 0 + 1077 : 1 +state 852 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 853 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 854 observe0Greater1 observeOnlyTrueSender + action 0 + 1079 : 1 +state 855 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 856 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 857 observe0Greater1 observeOnlyTrueSender + action 0 + 1080 : 1 +state 858 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 859 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 860 observe0Greater1 observeOnlyTrueSender + action 0 + 1081 : 1 +state 861 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 862 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 863 observe0Greater1 observeOnlyTrueSender + action 0 + 1082 : 1 +state 864 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 865 observe0Greater1 observeOnlyTrueSender + action 0 + 1083 : 0.833 + 1084 : 0.167 +state 866 + action 0 + 542 : 0.8 + 1085 : 0.2 +state 867 + action 0 + 1086 : 0.8 + 1087 : 0.2 +state 868 + action 0 + 1088 : 0.8 + 1089 : 0.2 +state 869 + action 0 + 1090 : 0.8 + 1091 : 0.2 +state 870 + action 0 + 1092 : 0.8 + 1093 : 0.2 +state 871 + action 0 + 1094 : 1 +state 872 + action 0 + 1095 : 0.833 + 1096 : 0.167 +state 873 + action 0 + 1097 : 0.833 + 1098 : 0.167 +state 874 + action 0 + 1099 : 0.833 + 1100 : 0.167 +state 875 + action 0 + 1101 : 0.833 + 1102 : 0.167 +state 876 + action 0 + 1103 : 1 +state 877 + action 0 + 1104 : 0.833 + 1105 : 0.167 +state 878 + action 0 + 1106 : 1 +state 879 + action 0 + 1107 : 0.833 + 1108 : 0.167 +state 880 + action 0 + 1109 : 1 +state 881 + action 0 + 1110 : 0.833 + 1111 : 0.167 +state 882 + action 0 + 1112 : 1 +state 883 + action 0 + 1113 : 0.833 + 1114 : 0.167 +state 884 + action 0 + 1115 : 1 +state 885 observe0Greater1 observeOnlyTrueSender + action 0 + 1116 : 1 +state 886 + action 0 + 1095 : 0.833 + 1096 : 0.167 +state 887 observe1Greater1 observeIGreater1 + action 0 + 1117 : 1 +state 888 + action 0 + 1118 : 1 +state 889 + action 0 + 1119 : 1 +state 890 + action 0 + 1120 : 1 +state 891 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 892 + action 0 + 1126 : 1 +state 893 + action 0 + 1097 : 0.833 + 1098 : 0.167 +state 894 + action 0 + 1127 : 1 +state 895 observe2Greater1 observeIGreater1 + action 0 + 1128 : 1 +state 896 + action 0 + 1129 : 1 +state 897 + action 0 + 1130 : 1 +state 898 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 899 + action 0 + 1136 : 1 +state 900 + action 0 + 1099 : 0.833 + 1100 : 0.167 +state 901 + action 0 + 1137 : 1 +state 902 + action 0 + 1138 : 1 +state 903 observe3Greater1 observeIGreater1 + action 0 + 1139 : 1 +state 904 + action 0 + 1140 : 1 +state 905 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 906 + action 0 + 1146 : 1 +state 907 + action 0 + 1101 : 0.833 + 1102 : 0.167 +state 908 + action 0 + 1147 : 1 +state 909 + action 0 + 1148 : 1 +state 910 + action 0 + 1149 : 1 +state 911 observe4Greater1 observeIGreater1 + action 0 + 1150 : 1 +state 912 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 913 + action 0 + 1156 : 1 +state 914 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 915 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 916 observe0Greater1 observeOnlyTrueSender + action 0 + 1158 : 1 +state 917 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 918 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 919 observe0Greater1 observeOnlyTrueSender + action 0 + 1159 : 1 +state 920 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 921 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 922 observe0Greater1 observeOnlyTrueSender + action 0 + 1160 : 1 +state 923 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 924 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 925 observe0Greater1 observeOnlyTrueSender + action 0 + 1161 : 1 +state 926 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 927 observe0Greater1 observeOnlyTrueSender + action 0 + 1162 : 0.833 + 1163 : 0.167 +state 928 observe1Greater1 observeIGreater1 + action 0 + 599 : 0.833 + 600 : 0.167 +state 929 observe1Greater1 observeIGreater1 + action 0 + 1164 : 1 +state 930 observe1Greater1 observeIGreater1 + action 0 + 1165 : 0.833 + 1166 : 0.167 +state 931 observe1Greater1 observeIGreater1 + action 0 + 1167 : 1 +state 932 observe1Greater1 observeIGreater1 + action 0 + 1168 : 0.833 + 1169 : 0.167 +state 933 observe1Greater1 observeIGreater1 + action 0 + 1170 : 1 +state 934 observe1Greater1 observeIGreater1 + action 0 + 1171 : 0.833 + 1172 : 0.167 +state 935 observe1Greater1 observeIGreater1 + action 0 + 1173 : 1 +state 936 observe1Greater1 observeIGreater1 + action 0 + 1174 : 0.833 + 1175 : 0.167 +state 937 observe1Greater1 observeIGreater1 + action 0 + 1176 : 1 +state 938 observe1Greater1 observeIGreater1 + action 0 + 1177 : 1 +state 939 + action 0 + 601 : 0.833 + 602 : 0.167 +state 940 + action 0 + 1178 : 1 +state 941 + action 0 + 1179 : 0.833 + 1180 : 0.167 +state 942 + action 0 + 1181 : 1 +state 943 + action 0 + 1182 : 0.833 + 1183 : 0.167 +state 944 + action 0 + 1184 : 1 +state 945 + action 0 + 1185 : 0.833 + 1186 : 0.167 +state 946 + action 0 + 1187 : 1 +state 947 + action 0 + 1188 : 0.833 + 1189 : 0.167 +state 948 + action 0 + 1190 : 1 +state 949 + action 0 + 1191 : 1 +state 950 + action 0 + 603 : 0.833 + 604 : 0.167 +state 951 + action 0 + 1192 : 1 +state 952 + action 0 + 1193 : 0.833 + 1194 : 0.167 +state 953 + action 0 + 1195 : 1 +state 954 + action 0 + 1196 : 0.833 + 1197 : 0.167 +state 955 + action 0 + 1198 : 1 +state 956 + action 0 + 1199 : 0.833 + 1200 : 0.167 +state 957 + action 0 + 1201 : 1 +state 958 + action 0 + 1202 : 0.833 + 1203 : 0.167 +state 959 + action 0 + 1204 : 1 +state 960 + action 0 + 1205 : 1 +state 961 + action 0 + 605 : 0.833 + 606 : 0.167 +state 962 + action 0 + 1206 : 1 +state 963 + action 0 + 1207 : 0.833 + 1208 : 0.167 +state 964 + action 0 + 1209 : 1 +state 965 + action 0 + 1210 : 0.833 + 1211 : 0.167 +state 966 + action 0 + 1212 : 1 +state 967 + action 0 + 1213 : 0.833 + 1214 : 0.167 +state 968 + action 0 + 1215 : 1 +state 969 + action 0 + 1216 : 0.833 + 1217 : 0.167 +state 970 + action 0 + 1218 : 1 +state 971 + action 0 + 1219 : 1 +state 972 observe1Greater1 observeIGreater1 + action 0 + 1177 : 1 +state 973 + action 0 + 1191 : 1 +state 974 + action 0 + 1205 : 1 +state 975 + action 0 + 1219 : 1 +state 976 observe0Greater1 observeOnlyTrueSender + action 0 + 1220 : 0.8 + 1221 : 0.2 +state 977 observe0Greater1 observeOnlyTrueSender + action 0 + 1222 : 0.8 + 1223 : 0.2 +state 978 observe0Greater1 observeOnlyTrueSender + action 0 + 1224 : 0.8 + 1225 : 0.2 +state 979 observe0Greater1 observeOnlyTrueSender + action 0 + 1226 : 0.8 + 1227 : 0.2 +state 980 observe0Greater1 observeOnlyTrueSender + action 0 + 1228 : 0.8 + 1229 : 0.2 +state 981 observe0Greater1 observeOnlyTrueSender + action 0 + 1230 : 1 +state 982 observe2Greater1 observeIGreater1 + action 0 + 621 : 0.833 + 622 : 0.167 +state 983 observe2Greater1 observeIGreater1 + action 0 + 1231 : 1 +state 984 observe2Greater1 observeIGreater1 + action 0 + 1232 : 0.833 + 1233 : 0.167 +state 985 observe2Greater1 observeIGreater1 + action 0 + 1234 : 1 +state 986 observe2Greater1 observeIGreater1 + action 0 + 1235 : 0.833 + 1236 : 0.167 +state 987 observe2Greater1 observeIGreater1 + action 0 + 1237 : 1 +state 988 observe2Greater1 observeIGreater1 + action 0 + 1238 : 0.833 + 1239 : 0.167 +state 989 observe2Greater1 observeIGreater1 + action 0 + 1240 : 1 +state 990 observe2Greater1 observeIGreater1 + action 0 + 1241 : 0.833 + 1242 : 0.167 +state 991 observe2Greater1 observeIGreater1 + action 0 + 1243 : 1 +state 992 observe2Greater1 observeIGreater1 + action 0 + 1244 : 1 +state 993 + action 0 + 623 : 0.833 + 624 : 0.167 +state 994 + action 0 + 1245 : 1 +state 995 + action 0 + 1246 : 0.833 + 1247 : 0.167 +state 996 + action 0 + 1248 : 1 +state 997 + action 0 + 1249 : 0.833 + 1250 : 0.167 +state 998 + action 0 + 1251 : 1 +state 999 + action 0 + 1252 : 0.833 + 1253 : 0.167 +state 1000 + action 0 + 1254 : 1 +state 1001 + action 0 + 1255 : 0.833 + 1256 : 0.167 +state 1002 + action 0 + 1257 : 1 +state 1003 + action 0 + 1258 : 1 +state 1004 + action 0 + 625 : 0.833 + 626 : 0.167 +state 1005 + action 0 + 1259 : 1 +state 1006 + action 0 + 1260 : 0.833 + 1261 : 0.167 +state 1007 + action 0 + 1262 : 1 +state 1008 + action 0 + 1263 : 0.833 + 1264 : 0.167 +state 1009 + action 0 + 1265 : 1 +state 1010 + action 0 + 1266 : 0.833 + 1267 : 0.167 +state 1011 + action 0 + 1268 : 1 +state 1012 + action 0 + 1269 : 0.833 + 1270 : 0.167 +state 1013 + action 0 + 1271 : 1 +state 1014 + action 0 + 1272 : 1 +state 1015 + action 0 + 1191 : 1 +state 1016 observe2Greater1 observeIGreater1 + action 0 + 1244 : 1 +state 1017 + action 0 + 1258 : 1 +state 1018 + action 0 + 1272 : 1 +state 1019 observe0Greater1 observeOnlyTrueSender + action 0 + 1273 : 0.8 + 1274 : 0.2 +state 1020 observe0Greater1 observeOnlyTrueSender + action 0 + 1275 : 0.8 + 1276 : 0.2 +state 1021 observe0Greater1 observeOnlyTrueSender + action 0 + 1277 : 0.8 + 1278 : 0.2 +state 1022 observe0Greater1 observeOnlyTrueSender + action 0 + 1279 : 0.8 + 1280 : 0.2 +state 1023 observe0Greater1 observeOnlyTrueSender + action 0 + 1281 : 0.8 + 1282 : 0.2 +state 1024 observe0Greater1 observeOnlyTrueSender + action 0 + 1283 : 1 +state 1025 observe3Greater1 observeIGreater1 + action 0 + 641 : 0.833 + 642 : 0.167 +state 1026 observe3Greater1 observeIGreater1 + action 0 + 1284 : 1 +state 1027 observe3Greater1 observeIGreater1 + action 0 + 1285 : 0.833 + 1286 : 0.167 +state 1028 observe3Greater1 observeIGreater1 + action 0 + 1287 : 1 +state 1029 observe3Greater1 observeIGreater1 + action 0 + 1288 : 0.833 + 1289 : 0.167 +state 1030 observe3Greater1 observeIGreater1 + action 0 + 1290 : 1 +state 1031 observe3Greater1 observeIGreater1 + action 0 + 1291 : 0.833 + 1292 : 0.167 +state 1032 observe3Greater1 observeIGreater1 + action 0 + 1293 : 1 +state 1033 observe3Greater1 observeIGreater1 + action 0 + 1294 : 0.833 + 1295 : 0.167 +state 1034 observe3Greater1 observeIGreater1 + action 0 + 1296 : 1 +state 1035 observe3Greater1 observeIGreater1 + action 0 + 1297 : 1 +state 1036 + action 0 + 643 : 0.833 + 644 : 0.167 +state 1037 + action 0 + 1298 : 1 +state 1038 + action 0 + 1299 : 0.833 + 1300 : 0.167 +state 1039 + action 0 + 1301 : 1 +state 1040 + action 0 + 1302 : 0.833 + 1303 : 0.167 +state 1041 + action 0 + 1304 : 1 +state 1042 + action 0 + 1305 : 0.833 + 1306 : 0.167 +state 1043 + action 0 + 1307 : 1 +state 1044 + action 0 + 1308 : 0.833 + 1309 : 0.167 +state 1045 + action 0 + 1310 : 1 +state 1046 + action 0 + 1311 : 1 +state 1047 + action 0 + 1205 : 1 +state 1048 + action 0 + 1258 : 1 +state 1049 observe3Greater1 observeIGreater1 + action 0 + 1297 : 1 +state 1050 + action 0 + 1311 : 1 +state 1051 observe0Greater1 observeOnlyTrueSender + action 0 + 1312 : 0.8 + 1313 : 0.2 +state 1052 observe0Greater1 observeOnlyTrueSender + action 0 + 1314 : 0.8 + 1315 : 0.2 +state 1053 observe0Greater1 observeOnlyTrueSender + action 0 + 1316 : 0.8 + 1317 : 0.2 +state 1054 observe0Greater1 observeOnlyTrueSender + action 0 + 1318 : 0.8 + 1319 : 0.2 +state 1055 observe0Greater1 observeOnlyTrueSender + action 0 + 1320 : 0.8 + 1321 : 0.2 +state 1056 observe0Greater1 observeOnlyTrueSender + action 0 + 1322 : 1 +state 1057 observe4Greater1 observeIGreater1 + action 0 + 659 : 0.833 + 660 : 0.167 +state 1058 observe4Greater1 observeIGreater1 + action 0 + 1323 : 1 +state 1059 observe4Greater1 observeIGreater1 + action 0 + 1324 : 0.833 + 1325 : 0.167 +state 1060 observe4Greater1 observeIGreater1 + action 0 + 1326 : 1 +state 1061 observe4Greater1 observeIGreater1 + action 0 + 1327 : 0.833 + 1328 : 0.167 +state 1062 observe4Greater1 observeIGreater1 + action 0 + 1329 : 1 +state 1063 observe4Greater1 observeIGreater1 + action 0 + 1330 : 0.833 + 1331 : 0.167 +state 1064 observe4Greater1 observeIGreater1 + action 0 + 1332 : 1 +state 1065 observe4Greater1 observeIGreater1 + action 0 + 1333 : 0.833 + 1334 : 0.167 +state 1066 observe4Greater1 observeIGreater1 + action 0 + 1335 : 1 +state 1067 observe4Greater1 observeIGreater1 + action 0 + 1336 : 1 +state 1068 + action 0 + 1219 : 1 +state 1069 + action 0 + 1272 : 1 +state 1070 + action 0 + 1311 : 1 +state 1071 observe4Greater1 observeIGreater1 + action 0 + 1336 : 1 +state 1072 observe0Greater1 observeOnlyTrueSender + action 0 + 1337 : 0.8 + 1338 : 0.2 +state 1073 observe0Greater1 observeOnlyTrueSender + action 0 + 1339 : 0.8 + 1340 : 0.2 +state 1074 observe0Greater1 observeOnlyTrueSender + action 0 + 1341 : 0.8 + 1342 : 0.2 +state 1075 observe0Greater1 observeOnlyTrueSender + action 0 + 1343 : 0.8 + 1344 : 0.2 +state 1076 observe0Greater1 observeOnlyTrueSender + action 0 + 1345 : 0.8 + 1346 : 0.2 +state 1077 observe0Greater1 observeOnlyTrueSender + action 0 + 1347 : 1 +state 1078 observe0Greater1 observeOnlyTrueSender + action 0 + 1162 : 0.833 + 1163 : 0.167 +state 1079 observe0Greater1 observeOnlyTrueSender + action 0 + 1348 : 1 +state 1080 observe0Greater1 observeOnlyTrueSender + action 0 + 1349 : 1 +state 1081 observe0Greater1 observeOnlyTrueSender + action 0 + 1350 : 1 +state 1082 observe0Greater1 observeOnlyTrueSender + action 0 + 1351 : 1 +state 1083 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1084 observe0Greater1 observeOnlyTrueSender + action 0 + 1357 : 1 +state 1085 + action 0 + 1358 : 1 +state 1086 + action 0 + 1359 : 0.833 + 1360 : 0.167 +state 1087 + action 0 + 1361 : 1 +state 1088 + action 0 + 1362 : 0.833 + 1363 : 0.167 +state 1089 + action 0 + 1364 : 1 +state 1090 + action 0 + 1365 : 0.833 + 1366 : 0.167 +state 1091 + action 0 + 1367 : 1 +state 1092 + action 0 + 1368 : 0.833 + 1369 : 0.167 +state 1093 + action 0 + 1370 : 1 +state 1094 + action 0 + 1371 : 1 +state 1095 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1096 + action 0 + 1377 : 1 +state 1097 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1098 + action 0 + 1383 : 1 +state 1099 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1100 + action 0 + 1389 : 1 +state 1101 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1102 + action 0 + 1395 : 1 +state 1103 + action 0 + 1396 : 1 +state 1104 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1105 + action 0 + 1397 : 1 +state 1106 + action 0 + 1396 : 1 +state 1107 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1108 + action 0 + 1398 : 1 +state 1109 + action 0 + 1396 : 1 +state 1110 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1111 + action 0 + 1399 : 1 +state 1112 + action 0 + 1396 : 1 +state 1113 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1114 + action 0 + 1400 : 1 +state 1115 + action 0 + 1396 : 1 +state 1116 observe0Greater1 observeOnlyTrueSender + action 0 + 1401 : 0.833 + 1402 : 0.167 +state 1117 observe1Greater1 observeIGreater1 + action 0 + 1403 : 1 +state 1118 + action 0 + 1404 : 1 +state 1119 + action 0 + 1405 : 1 +state 1120 + action 0 + 1406 : 1 +state 1121 + action 0 + 788 : 0.8 + 1407 : 0.2 +state 1122 + action 0 + 1408 : 0.8 + 1409 : 0.2 +state 1123 + action 0 + 1410 : 0.8 + 1411 : 0.2 +state 1124 + action 0 + 1412 : 0.8 + 1413 : 0.2 +state 1125 + action 0 + 1414 : 0.8 + 1415 : 0.2 +state 1126 observe0Greater1 observeOnlyTrueSender + action 0 + 1416 : 1 +state 1127 + action 0 + 1404 : 1 +state 1128 observe2Greater1 observeIGreater1 + action 0 + 1417 : 1 +state 1129 + action 0 + 1418 : 1 +state 1130 + action 0 + 1419 : 1 +state 1131 + action 0 + 813 : 0.8 + 1420 : 0.2 +state 1132 + action 0 + 1421 : 0.8 + 1422 : 0.2 +state 1133 + action 0 + 1423 : 0.8 + 1424 : 0.2 +state 1134 + action 0 + 1425 : 0.8 + 1426 : 0.2 +state 1135 + action 0 + 1427 : 0.8 + 1428 : 0.2 +state 1136 observe0Greater1 observeOnlyTrueSender + action 0 + 1429 : 1 +state 1137 + action 0 + 1405 : 1 +state 1138 + action 0 + 1418 : 1 +state 1139 observe3Greater1 observeIGreater1 + action 0 + 1430 : 1 +state 1140 + action 0 + 1431 : 1 +state 1141 + action 0 + 832 : 0.8 + 1432 : 0.2 +state 1142 + action 0 + 1433 : 0.8 + 1434 : 0.2 +state 1143 + action 0 + 1435 : 0.8 + 1436 : 0.2 +state 1144 + action 0 + 1437 : 0.8 + 1438 : 0.2 +state 1145 + action 0 + 1439 : 0.8 + 1440 : 0.2 +state 1146 observe0Greater1 observeOnlyTrueSender + action 0 + 1441 : 1 +state 1147 + action 0 + 1406 : 1 +state 1148 + action 0 + 1419 : 1 +state 1149 + action 0 + 1431 : 1 +state 1150 observe4Greater1 observeIGreater1 + action 0 + 1442 : 1 +state 1151 + action 0 + 845 : 0.8 + 1443 : 0.2 +state 1152 + action 0 + 1444 : 0.8 + 1445 : 0.2 +state 1153 + action 0 + 1446 : 0.8 + 1447 : 0.2 +state 1154 + action 0 + 1448 : 0.8 + 1449 : 0.2 +state 1155 + action 0 + 1450 : 0.8 + 1451 : 0.2 +state 1156 observe0Greater1 observeOnlyTrueSender + action 0 + 1452 : 1 +state 1157 observe0Greater1 observeOnlyTrueSender + action 0 + 1401 : 0.833 + 1402 : 0.167 +state 1158 observe0Greater1 observeOnlyTrueSender + action 0 + 1453 : 1 +state 1159 observe0Greater1 observeOnlyTrueSender + action 0 + 1454 : 1 +state 1160 observe0Greater1 observeOnlyTrueSender + action 0 + 1455 : 1 +state 1161 observe0Greater1 observeOnlyTrueSender + action 0 + 1456 : 1 +state 1162 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 1163 observe0Greater1 observeOnlyTrueSender + action 0 + 1462 : 1 +state 1164 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1165 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1166 observe1Greater1 observeIGreater1 + action 0 + 1464 : 1 +state 1167 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1168 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1169 observe1Greater1 observeIGreater1 + action 0 + 1465 : 1 +state 1170 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1171 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1172 observe1Greater1 observeIGreater1 + action 0 + 1466 : 1 +state 1173 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1174 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1175 observe1Greater1 observeIGreater1 + action 0 + 1467 : 1 +state 1176 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1177 observe1Greater1 observeIGreater1 + action 0 + 1468 : 0.833 + 1469 : 0.167 +state 1178 + action 0 + 1470 : 1 +state 1179 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1180 + action 0 + 1471 : 1 +state 1181 + action 0 + 1470 : 1 +state 1182 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1183 + action 0 + 1472 : 1 +state 1184 + action 0 + 1470 : 1 +state 1185 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1186 + action 0 + 1473 : 1 +state 1187 + action 0 + 1470 : 1 +state 1188 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1189 + action 0 + 1474 : 1 +state 1190 + action 0 + 1470 : 1 +state 1191 + action 0 + 1475 : 0.833 + 1476 : 0.167 +state 1192 + action 0 + 1477 : 1 +state 1193 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1194 + action 0 + 1478 : 1 +state 1195 + action 0 + 1477 : 1 +state 1196 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1197 + action 0 + 1479 : 1 +state 1198 + action 0 + 1477 : 1 +state 1199 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1200 + action 0 + 1480 : 1 +state 1201 + action 0 + 1477 : 1 +state 1202 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1203 + action 0 + 1481 : 1 +state 1204 + action 0 + 1477 : 1 +state 1205 + action 0 + 1482 : 0.833 + 1483 : 0.167 +state 1206 + action 0 + 1484 : 1 +state 1207 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1208 + action 0 + 1485 : 1 +state 1209 + action 0 + 1484 : 1 +state 1210 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1211 + action 0 + 1486 : 1 +state 1212 + action 0 + 1484 : 1 +state 1213 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1214 + action 0 + 1487 : 1 +state 1215 + action 0 + 1484 : 1 +state 1216 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1217 + action 0 + 1488 : 1 +state 1218 + action 0 + 1484 : 1 +state 1219 + action 0 + 1489 : 0.833 + 1490 : 0.167 +state 1220 observe0Greater1 observeOnlyTrueSender + action 0 + 793 : 0.833 + 794 : 0.167 +state 1221 observe0Greater1 observeOnlyTrueSender + action 0 + 1491 : 1 +state 1222 observe0Greater1 observeOnlyTrueSender + action 0 + 1492 : 0.833 + 1493 : 0.167 +state 1223 observe0Greater1 observeOnlyTrueSender + action 0 + 1494 : 1 +state 1224 observe0Greater1 observeOnlyTrueSender + action 0 + 1495 : 0.833 + 1496 : 0.167 +state 1225 observe0Greater1 observeOnlyTrueSender + action 0 + 1497 : 1 +state 1226 observe0Greater1 observeOnlyTrueSender + action 0 + 1498 : 0.833 + 1499 : 0.167 +state 1227 observe0Greater1 observeOnlyTrueSender + action 0 + 1500 : 1 +state 1228 observe0Greater1 observeOnlyTrueSender + action 0 + 1501 : 0.833 + 1502 : 0.167 +state 1229 observe0Greater1 observeOnlyTrueSender + action 0 + 1503 : 1 +state 1230 observe0Greater1 observeOnlyTrueSender + action 0 + 1504 : 1 +state 1231 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1232 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1233 observe2Greater1 observeIGreater1 + action 0 + 1506 : 1 +state 1234 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1235 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1236 observe2Greater1 observeIGreater1 + action 0 + 1507 : 1 +state 1237 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1238 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1239 observe2Greater1 observeIGreater1 + action 0 + 1508 : 1 +state 1240 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1241 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1242 observe2Greater1 observeIGreater1 + action 0 + 1509 : 1 +state 1243 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1244 observe2Greater1 observeIGreater1 + action 0 + 1510 : 0.833 + 1511 : 0.167 +state 1245 + action 0 + 1512 : 1 +state 1246 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1247 + action 0 + 1513 : 1 +state 1248 + action 0 + 1512 : 1 +state 1249 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1250 + action 0 + 1514 : 1 +state 1251 + action 0 + 1512 : 1 +state 1252 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1253 + action 0 + 1515 : 1 +state 1254 + action 0 + 1512 : 1 +state 1255 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1256 + action 0 + 1516 : 1 +state 1257 + action 0 + 1512 : 1 +state 1258 + action 0 + 1517 : 0.833 + 1518 : 0.167 +state 1259 + action 0 + 1519 : 1 +state 1260 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1261 + action 0 + 1520 : 1 +state 1262 + action 0 + 1519 : 1 +state 1263 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1264 + action 0 + 1521 : 1 +state 1265 + action 0 + 1519 : 1 +state 1266 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1267 + action 0 + 1522 : 1 +state 1268 + action 0 + 1519 : 1 +state 1269 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1270 + action 0 + 1523 : 1 +state 1271 + action 0 + 1519 : 1 +state 1272 + action 0 + 1524 : 0.833 + 1525 : 0.167 +state 1273 observe0Greater1 observeOnlyTrueSender + action 0 + 818 : 0.833 + 819 : 0.167 +state 1274 observe0Greater1 observeOnlyTrueSender + action 0 + 1526 : 1 +state 1275 observe0Greater1 observeOnlyTrueSender + action 0 + 1527 : 0.833 + 1528 : 0.167 +state 1276 observe0Greater1 observeOnlyTrueSender + action 0 + 1529 : 1 +state 1277 observe0Greater1 observeOnlyTrueSender + action 0 + 1530 : 0.833 + 1531 : 0.167 +state 1278 observe0Greater1 observeOnlyTrueSender + action 0 + 1532 : 1 +state 1279 observe0Greater1 observeOnlyTrueSender + action 0 + 1533 : 0.833 + 1534 : 0.167 +state 1280 observe0Greater1 observeOnlyTrueSender + action 0 + 1535 : 1 +state 1281 observe0Greater1 observeOnlyTrueSender + action 0 + 1536 : 0.833 + 1537 : 0.167 +state 1282 observe0Greater1 observeOnlyTrueSender + action 0 + 1538 : 1 +state 1283 observe0Greater1 observeOnlyTrueSender + action 0 + 1539 : 1 +state 1284 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1285 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1286 observe3Greater1 observeIGreater1 + action 0 + 1541 : 1 +state 1287 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1288 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1289 observe3Greater1 observeIGreater1 + action 0 + 1542 : 1 +state 1290 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1291 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1292 observe3Greater1 observeIGreater1 + action 0 + 1543 : 1 +state 1293 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1294 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1295 observe3Greater1 observeIGreater1 + action 0 + 1544 : 1 +state 1296 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1297 observe3Greater1 observeIGreater1 + action 0 + 1545 : 0.833 + 1546 : 0.167 +state 1298 + action 0 + 1547 : 1 +state 1299 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1300 + action 0 + 1548 : 1 +state 1301 + action 0 + 1547 : 1 +state 1302 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1303 + action 0 + 1549 : 1 +state 1304 + action 0 + 1547 : 1 +state 1305 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1306 + action 0 + 1550 : 1 +state 1307 + action 0 + 1547 : 1 +state 1308 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1309 + action 0 + 1551 : 1 +state 1310 + action 0 + 1547 : 1 +state 1311 + action 0 + 1552 : 0.833 + 1553 : 0.167 +state 1312 observe0Greater1 observeOnlyTrueSender + action 0 + 837 : 0.833 + 838 : 0.167 +state 1313 observe0Greater1 observeOnlyTrueSender + action 0 + 1554 : 1 +state 1314 observe0Greater1 observeOnlyTrueSender + action 0 + 1555 : 0.833 + 1556 : 0.167 +state 1315 observe0Greater1 observeOnlyTrueSender + action 0 + 1557 : 1 +state 1316 observe0Greater1 observeOnlyTrueSender + action 0 + 1558 : 0.833 + 1559 : 0.167 +state 1317 observe0Greater1 observeOnlyTrueSender + action 0 + 1560 : 1 +state 1318 observe0Greater1 observeOnlyTrueSender + action 0 + 1561 : 0.833 + 1562 : 0.167 +state 1319 observe0Greater1 observeOnlyTrueSender + action 0 + 1563 : 1 +state 1320 observe0Greater1 observeOnlyTrueSender + action 0 + 1564 : 0.833 + 1565 : 0.167 +state 1321 observe0Greater1 observeOnlyTrueSender + action 0 + 1566 : 1 +state 1322 observe0Greater1 observeOnlyTrueSender + action 0 + 1567 : 1 +state 1323 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1324 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1325 observe4Greater1 observeIGreater1 + action 0 + 1569 : 1 +state 1326 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1327 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1328 observe4Greater1 observeIGreater1 + action 0 + 1570 : 1 +state 1329 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1330 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1331 observe4Greater1 observeIGreater1 + action 0 + 1571 : 1 +state 1332 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1333 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1334 observe4Greater1 observeIGreater1 + action 0 + 1572 : 1 +state 1335 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1336 observe4Greater1 observeIGreater1 + action 0 + 1573 : 0.833 + 1574 : 0.167 +state 1337 observe0Greater1 observeOnlyTrueSender + action 0 + 850 : 0.833 + 851 : 0.167 +state 1338 observe0Greater1 observeOnlyTrueSender + action 0 + 1575 : 1 +state 1339 observe0Greater1 observeOnlyTrueSender + action 0 + 1576 : 0.833 + 1577 : 0.167 +state 1340 observe0Greater1 observeOnlyTrueSender + action 0 + 1578 : 1 +state 1341 observe0Greater1 observeOnlyTrueSender + action 0 + 1579 : 0.833 + 1580 : 0.167 +state 1342 observe0Greater1 observeOnlyTrueSender + action 0 + 1581 : 1 +state 1343 observe0Greater1 observeOnlyTrueSender + action 0 + 1582 : 0.833 + 1583 : 0.167 +state 1344 observe0Greater1 observeOnlyTrueSender + action 0 + 1584 : 1 +state 1345 observe0Greater1 observeOnlyTrueSender + action 0 + 1585 : 0.833 + 1586 : 0.167 +state 1346 observe0Greater1 observeOnlyTrueSender + action 0 + 1587 : 1 +state 1347 observe0Greater1 observeOnlyTrueSender + action 0 + 1588 : 1 +state 1348 observe0Greater1 observeOnlyTrueSender + action 0 + 1504 : 1 +state 1349 observe0Greater1 observeOnlyTrueSender + action 0 + 1539 : 1 +state 1350 observe0Greater1 observeOnlyTrueSender + action 0 + 1567 : 1 +state 1351 observe0Greater1 observeOnlyTrueSender + action 0 + 1588 : 1 +state 1352 observe0Greater1 observeOnlyTrueSender + action 0 + 1589 : 0.8 + 1590 : 0.2 +state 1353 observe0Greater1 observeOnlyTrueSender + action 0 + 1591 : 0.8 + 1592 : 0.2 +state 1354 observe0Greater1 observeOnlyTrueSender + action 0 + 1593 : 0.8 + 1594 : 0.2 +state 1355 observe0Greater1 observeOnlyTrueSender + action 0 + 1595 : 0.8 + 1596 : 0.2 +state 1356 observe0Greater1 observeOnlyTrueSender + action 0 + 1597 : 0.8 + 1598 : 0.2 +state 1357 observe0Greater1 observeOnlyTrueSender + action 0 + 1599 : 1 +state 1358 + action 0 + 1600 : 1 +state 1359 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1360 + action 0 + 1601 : 1 +state 1361 + action 0 + 1600 : 1 +state 1362 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1363 + action 0 + 1602 : 1 +state 1364 + action 0 + 1600 : 1 +state 1365 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1366 + action 0 + 1603 : 1 +state 1367 + action 0 + 1600 : 1 +state 1368 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1369 + action 0 + 1604 : 1 +state 1370 + action 0 + 1600 : 1 +state 1371 + action 0 + 1605 : 0.833 + 1606 : 0.167 +state 1372 + action 0 + 886 : 0.8 + 1607 : 0.2 +state 1373 + action 0 + 1608 : 0.8 + 1609 : 0.2 +state 1374 + action 0 + 1610 : 0.8 + 1611 : 0.2 +state 1375 + action 0 + 1612 : 0.8 + 1613 : 0.2 +state 1376 + action 0 + 1614 : 0.8 + 1615 : 0.2 +state 1377 + action 0 + 1616 : 1 +state 1378 + action 0 + 893 : 0.8 + 1617 : 0.2 +state 1379 + action 0 + 1618 : 0.8 + 1619 : 0.2 +state 1380 + action 0 + 1620 : 0.8 + 1621 : 0.2 +state 1381 + action 0 + 1622 : 0.8 + 1623 : 0.2 +state 1382 + action 0 + 1624 : 0.8 + 1625 : 0.2 +state 1383 + action 0 + 1626 : 1 +state 1384 + action 0 + 900 : 0.8 + 1627 : 0.2 +state 1385 + action 0 + 1628 : 0.8 + 1629 : 0.2 +state 1386 + action 0 + 1630 : 0.8 + 1631 : 0.2 +state 1387 + action 0 + 1632 : 0.8 + 1633 : 0.2 +state 1388 + action 0 + 1634 : 0.8 + 1635 : 0.2 +state 1389 + action 0 + 1636 : 1 +state 1390 + action 0 + 907 : 0.8 + 1637 : 0.2 +state 1391 + action 0 + 1638 : 0.8 + 1639 : 0.2 +state 1392 + action 0 + 1640 : 0.8 + 1641 : 0.2 +state 1393 + action 0 + 1642 : 0.8 + 1643 : 0.2 +state 1394 + action 0 + 1644 : 0.8 + 1645 : 0.2 +state 1395 + action 0 + 1646 : 1 +state 1396 + action 0 + 1605 : 0.833 + 1606 : 0.167 +state 1397 + action 0 + 1647 : 1 +state 1398 + action 0 + 1648 : 1 +state 1399 + action 0 + 1649 : 1 +state 1400 + action 0 + 1650 : 1 +state 1401 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 1402 observe0Greater1 observeOnlyTrueSender + action 0 + 1656 : 1 +state 1403 observe1Greater1 observeIGreater1 + action 0 + 1657 : 0.833 + 1658 : 0.167 +state 1404 + action 0 + 1659 : 0.833 + 1660 : 0.167 +state 1405 + action 0 + 1661 : 0.833 + 1662 : 0.167 +state 1406 + action 0 + 1663 : 0.833 + 1664 : 0.167 +state 1407 + action 0 + 1665 : 1 +state 1408 + action 0 + 1666 : 0.833 + 1667 : 0.167 +state 1409 + action 0 + 1668 : 1 +state 1410 + action 0 + 1669 : 0.833 + 1670 : 0.167 +state 1411 + action 0 + 1671 : 1 +state 1412 + action 0 + 1672 : 0.833 + 1673 : 0.167 +state 1413 + action 0 + 1674 : 1 +state 1414 + action 0 + 1675 : 0.833 + 1676 : 0.167 +state 1415 + action 0 + 1677 : 1 +state 1416 observe0Greater1 observeOnlyTrueSender + action 0 + 1678 : 1 +state 1417 observe2Greater1 observeIGreater1 + action 0 + 1679 : 0.833 + 1680 : 0.167 +state 1418 + action 0 + 1681 : 0.833 + 1682 : 0.167 +state 1419 + action 0 + 1683 : 0.833 + 1684 : 0.167 +state 1420 + action 0 + 1685 : 1 +state 1421 + action 0 + 1686 : 0.833 + 1687 : 0.167 +state 1422 + action 0 + 1688 : 1 +state 1423 + action 0 + 1689 : 0.833 + 1690 : 0.167 +state 1424 + action 0 + 1691 : 1 +state 1425 + action 0 + 1692 : 0.833 + 1693 : 0.167 +state 1426 + action 0 + 1694 : 1 +state 1427 + action 0 + 1695 : 0.833 + 1696 : 0.167 +state 1428 + action 0 + 1697 : 1 +state 1429 observe0Greater1 observeOnlyTrueSender + action 0 + 1698 : 1 +state 1430 observe3Greater1 observeIGreater1 + action 0 + 1699 : 0.833 + 1700 : 0.167 +state 1431 + action 0 + 1701 : 0.833 + 1702 : 0.167 +state 1432 + action 0 + 1703 : 1 +state 1433 + action 0 + 1704 : 0.833 + 1705 : 0.167 +state 1434 + action 0 + 1706 : 1 +state 1435 + action 0 + 1707 : 0.833 + 1708 : 0.167 +state 1436 + action 0 + 1709 : 1 +state 1437 + action 0 + 1710 : 0.833 + 1711 : 0.167 +state 1438 + action 0 + 1712 : 1 +state 1439 + action 0 + 1713 : 0.833 + 1714 : 0.167 +state 1440 + action 0 + 1715 : 1 +state 1441 observe0Greater1 observeOnlyTrueSender + action 0 + 1716 : 1 +state 1442 observe4Greater1 observeIGreater1 + action 0 + 1717 : 0.833 + 1718 : 0.167 +state 1443 + action 0 + 1719 : 1 +state 1444 + action 0 + 1720 : 0.833 + 1721 : 0.167 +state 1445 + action 0 + 1722 : 1 +state 1446 + action 0 + 1723 : 0.833 + 1724 : 0.167 +state 1447 + action 0 + 1725 : 1 +state 1448 + action 0 + 1726 : 0.833 + 1727 : 0.167 +state 1449 + action 0 + 1728 : 1 +state 1450 + action 0 + 1729 : 0.833 + 1730 : 0.167 +state 1451 + action 0 + 1731 : 1 +state 1452 observe0Greater1 observeOnlyTrueSender + action 0 + 1732 : 1 +state 1453 observe0Greater1 observeOnlyTrueSender + action 0 + 1678 : 1 +state 1454 observe0Greater1 observeOnlyTrueSender + action 0 + 1698 : 1 +state 1455 observe0Greater1 observeOnlyTrueSender + action 0 + 1716 : 1 +state 1456 observe0Greater1 observeOnlyTrueSender + action 0 + 1732 : 1 +state 1457 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 0.8 + 1733 : 0.2 +state 1458 observe0Greater1 observeOnlyTrueSender + action 0 + 1734 : 0.8 + 1735 : 0.2 +state 1459 observe0Greater1 observeOnlyTrueSender + action 0 + 1736 : 0.8 + 1737 : 0.2 +state 1460 observe0Greater1 observeOnlyTrueSender + action 0 + 1738 : 0.8 + 1739 : 0.2 +state 1461 observe0Greater1 observeOnlyTrueSender + action 0 + 1740 : 0.8 + 1741 : 0.2 +state 1462 observe0Greater1 observeOnlyTrueSender + action 0 + 1742 : 1 +state 1463 observe1Greater1 observeIGreater1 + action 0 + 1657 : 0.833 + 1658 : 0.167 +state 1464 observe1Greater1 observeIGreater1 + action 0 + 1743 : 1 +state 1465 observe1Greater1 observeIGreater1 + action 0 + 1744 : 1 +state 1466 observe1Greater1 observeIGreater1 + action 0 + 1745 : 1 +state 1467 observe1Greater1 observeIGreater1 + action 0 + 1746 : 1 +state 1468 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 1469 observe1Greater1 observeIGreater1 + action 0 + 1752 : 1 +state 1470 + action 0 + 1659 : 0.833 + 1660 : 0.167 +state 1471 observe1Greater1 observeIGreater1 + action 0 + 1753 : 1 +state 1472 observe2Greater1 observeIGreater1 + action 0 + 1754 : 1 +state 1473 + action 0 + 1755 : 1 +state 1474 + action 0 + 1756 : 1 +state 1475 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 1476 + action 0 + 1762 : 1 +state 1477 + action 0 + 1661 : 0.833 + 1662 : 0.167 +state 1478 observe1Greater1 observeIGreater1 + action 0 + 1763 : 1 +state 1479 + action 0 + 1764 : 1 +state 1480 observe3Greater1 observeIGreater1 + action 0 + 1765 : 1 +state 1481 + action 0 + 1766 : 1 +state 1482 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 1483 + action 0 + 1772 : 1 +state 1484 + action 0 + 1663 : 0.833 + 1664 : 0.167 +state 1485 observe1Greater1 observeIGreater1 + action 0 + 1773 : 1 +state 1486 + action 0 + 1774 : 1 +state 1487 + action 0 + 1775 : 1 +state 1488 observe4Greater1 observeIGreater1 + action 0 + 1776 : 1 +state 1489 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 1490 + action 0 + 1782 : 1 +state 1491 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1492 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1493 observe0Greater1 observeOnlyTrueSender + action 0 + 1784 : 1 +state 1494 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1495 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1496 observe0Greater1 observeOnlyTrueSender + action 0 + 1785 : 1 +state 1497 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1498 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1499 observe0Greater1 observeOnlyTrueSender + action 0 + 1786 : 1 +state 1500 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1501 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1502 observe0Greater1 observeOnlyTrueSender + action 0 + 1787 : 1 +state 1503 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1504 observe0Greater1 observeOnlyTrueSender + action 0 + 1788 : 0.833 + 1789 : 0.167 +state 1505 observe2Greater1 observeIGreater1 + action 0 + 1679 : 0.833 + 1680 : 0.167 +state 1506 observe2Greater1 observeIGreater1 + action 0 + 1790 : 1 +state 1507 observe2Greater1 observeIGreater1 + action 0 + 1791 : 1 +state 1508 observe2Greater1 observeIGreater1 + action 0 + 1792 : 1 +state 1509 observe2Greater1 observeIGreater1 + action 0 + 1793 : 1 +state 1510 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 1511 observe2Greater1 observeIGreater1 + action 0 + 1799 : 1 +state 1512 + action 0 + 1681 : 0.833 + 1682 : 0.167 +state 1513 + action 0 + 1800 : 1 +state 1514 observe2Greater1 observeIGreater1 + action 0 + 1801 : 1 +state 1515 observe3Greater1 observeIGreater1 + action 0 + 1802 : 1 +state 1516 + action 0 + 1803 : 1 +state 1517 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 1518 + action 0 + 1809 : 1 +state 1519 + action 0 + 1683 : 0.833 + 1684 : 0.167 +state 1520 + action 0 + 1810 : 1 +state 1521 observe2Greater1 observeIGreater1 + action 0 + 1811 : 1 +state 1522 + action 0 + 1812 : 1 +state 1523 observe4Greater1 observeIGreater1 + action 0 + 1813 : 1 +state 1524 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 1525 + action 0 + 1819 : 1 +state 1526 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1527 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1528 observe0Greater1 observeOnlyTrueSender + action 0 + 1821 : 1 +state 1529 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1530 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1531 observe0Greater1 observeOnlyTrueSender + action 0 + 1822 : 1 +state 1532 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1533 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1534 observe0Greater1 observeOnlyTrueSender + action 0 + 1823 : 1 +state 1535 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1536 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1537 observe0Greater1 observeOnlyTrueSender + action 0 + 1824 : 1 +state 1538 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1539 observe0Greater1 observeOnlyTrueSender + action 0 + 1825 : 0.833 + 1826 : 0.167 +state 1540 observe3Greater1 observeIGreater1 + action 0 + 1699 : 0.833 + 1700 : 0.167 +state 1541 observe3Greater1 observeIGreater1 + action 0 + 1827 : 1 +state 1542 observe3Greater1 observeIGreater1 + action 0 + 1828 : 1 +state 1543 observe3Greater1 observeIGreater1 + action 0 + 1829 : 1 +state 1544 observe3Greater1 observeIGreater1 + action 0 + 1830 : 1 +state 1545 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 1546 observe3Greater1 observeIGreater1 + action 0 + 1836 : 1 +state 1547 + action 0 + 1701 : 0.833 + 1702 : 0.167 +state 1548 + action 0 + 1837 : 1 +state 1549 + action 0 + 1838 : 1 +state 1550 observe3Greater1 observeIGreater1 + action 0 + 1839 : 1 +state 1551 observe4Greater1 observeIGreater1 + action 0 + 1840 : 1 +state 1552 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 1553 + action 0 + 1846 : 1 +state 1554 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1555 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1556 observe0Greater1 observeOnlyTrueSender + action 0 + 1848 : 1 +state 1557 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1558 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1559 observe0Greater1 observeOnlyTrueSender + action 0 + 1849 : 1 +state 1560 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1561 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1562 observe0Greater1 observeOnlyTrueSender + action 0 + 1850 : 1 +state 1563 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1564 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1565 observe0Greater1 observeOnlyTrueSender + action 0 + 1851 : 1 +state 1566 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1567 observe0Greater1 observeOnlyTrueSender + action 0 + 1852 : 0.833 + 1853 : 0.167 +state 1568 observe4Greater1 observeIGreater1 + action 0 + 1717 : 0.833 + 1718 : 0.167 +state 1569 observe4Greater1 observeIGreater1 + action 0 + 1854 : 1 +state 1570 observe4Greater1 observeIGreater1 + action 0 + 1855 : 1 +state 1571 observe4Greater1 observeIGreater1 + action 0 + 1856 : 1 +state 1572 observe4Greater1 observeIGreater1 + action 0 + 1857 : 1 +state 1573 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 1574 observe4Greater1 observeIGreater1 + action 0 + 1863 : 1 +state 1575 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1576 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1577 observe0Greater1 observeOnlyTrueSender + action 0 + 1865 : 1 +state 1578 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1579 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1580 observe0Greater1 observeOnlyTrueSender + action 0 + 1866 : 1 +state 1581 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1582 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1583 observe0Greater1 observeOnlyTrueSender + action 0 + 1867 : 1 +state 1584 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1585 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1586 observe0Greater1 observeOnlyTrueSender + action 0 + 1868 : 1 +state 1587 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1588 observe0Greater1 observeOnlyTrueSender + action 0 + 1869 : 0.833 + 1870 : 0.167 +state 1589 observe0Greater1 observeOnlyTrueSender + action 0 + 1083 : 0.833 + 1084 : 0.167 +state 1590 observe0Greater1 observeOnlyTrueSender + action 0 + 1871 : 1 +state 1591 observe0Greater1 observeOnlyTrueSender + action 0 + 1872 : 0.833 + 1873 : 0.167 +state 1592 observe0Greater1 observeOnlyTrueSender + action 0 + 1874 : 1 +state 1593 observe0Greater1 observeOnlyTrueSender + action 0 + 1875 : 0.833 + 1876 : 0.167 +state 1594 observe0Greater1 observeOnlyTrueSender + action 0 + 1877 : 1 +state 1595 observe0Greater1 observeOnlyTrueSender + action 0 + 1878 : 0.833 + 1879 : 0.167 +state 1596 observe0Greater1 observeOnlyTrueSender + action 0 + 1880 : 1 +state 1597 observe0Greater1 observeOnlyTrueSender + action 0 + 1881 : 0.833 + 1882 : 0.167 +state 1598 observe0Greater1 observeOnlyTrueSender + action 0 + 1883 : 1 +state 1599 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1599 : 1 +state 1600 + action 0 + 1884 : 0.833 + 1885 : 0.167 +state 1601 + action 0 + 1886 : 1 +state 1602 + action 0 + 1887 : 1 +state 1603 + action 0 + 1888 : 1 +state 1604 + action 0 + 1889 : 1 +state 1605 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 1606 + action 0 + 1895 : 1 +state 1607 + action 0 + 1896 : 1 +state 1608 + action 0 + 1897 : 0.833 + 1898 : 0.167 +state 1609 + action 0 + 1899 : 1 +state 1610 + action 0 + 1900 : 0.833 + 1901 : 0.167 +state 1611 + action 0 + 1902 : 1 +state 1612 + action 0 + 1903 : 0.833 + 1904 : 0.167 +state 1613 + action 0 + 1905 : 1 +state 1614 + action 0 + 1906 : 0.833 + 1907 : 0.167 +state 1615 + action 0 + 1908 : 1 +state 1616 + action 0 + 1909 : 1 +state 1617 + action 0 + 1910 : 1 +state 1618 + action 0 + 1911 : 0.833 + 1912 : 0.167 +state 1619 + action 0 + 1913 : 1 +state 1620 + action 0 + 1914 : 0.833 + 1915 : 0.167 +state 1621 + action 0 + 1916 : 1 +state 1622 + action 0 + 1917 : 0.833 + 1918 : 0.167 +state 1623 + action 0 + 1919 : 1 +state 1624 + action 0 + 1920 : 0.833 + 1921 : 0.167 +state 1625 + action 0 + 1922 : 1 +state 1626 + action 0 + 1923 : 1 +state 1627 + action 0 + 1924 : 1 +state 1628 + action 0 + 1925 : 0.833 + 1926 : 0.167 +state 1629 + action 0 + 1927 : 1 +state 1630 + action 0 + 1928 : 0.833 + 1929 : 0.167 +state 1631 + action 0 + 1930 : 1 +state 1632 + action 0 + 1931 : 0.833 + 1932 : 0.167 +state 1633 + action 0 + 1933 : 1 +state 1634 + action 0 + 1934 : 0.833 + 1935 : 0.167 +state 1635 + action 0 + 1936 : 1 +state 1636 + action 0 + 1937 : 1 +state 1637 + action 0 + 1938 : 1 +state 1638 + action 0 + 1939 : 0.833 + 1940 : 0.167 +state 1639 + action 0 + 1941 : 1 +state 1640 + action 0 + 1942 : 0.833 + 1943 : 0.167 +state 1641 + action 0 + 1944 : 1 +state 1642 + action 0 + 1945 : 0.833 + 1946 : 0.167 +state 1643 + action 0 + 1947 : 1 +state 1644 + action 0 + 1948 : 0.833 + 1949 : 0.167 +state 1645 + action 0 + 1950 : 1 +state 1646 + action 0 + 1951 : 1 +state 1647 + action 0 + 1909 : 1 +state 1648 + action 0 + 1923 : 1 +state 1649 + action 0 + 1937 : 1 +state 1650 + action 0 + 1951 : 1 +state 1651 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 0.8 + 1952 : 0.2 +state 1652 observe0Greater1 observeOnlyTrueSender + action 0 + 1953 : 0.8 + 1954 : 0.2 +state 1653 observe0Greater1 observeOnlyTrueSender + action 0 + 1955 : 0.8 + 1956 : 0.2 +state 1654 observe0Greater1 observeOnlyTrueSender + action 0 + 1957 : 0.8 + 1958 : 0.2 +state 1655 observe0Greater1 observeOnlyTrueSender + action 0 + 1959 : 0.8 + 1960 : 0.2 +state 1656 observe0Greater1 observeOnlyTrueSender + action 0 + 1961 : 1 +state 1657 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 1658 observe1Greater1 observeIGreater1 + action 0 + 1967 : 1 +state 1659 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 1660 + action 0 + 1973 : 1 +state 1661 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 1662 + action 0 + 1979 : 1 +state 1663 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 1664 + action 0 + 1985 : 1 +state 1665 + action 0 + 1986 : 1 +state 1666 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1667 + action 0 + 1987 : 1 +state 1668 + action 0 + 1986 : 1 +state 1669 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1670 + action 0 + 1988 : 1 +state 1671 + action 0 + 1986 : 1 +state 1672 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1673 + action 0 + 1989 : 1 +state 1674 + action 0 + 1986 : 1 +state 1675 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1676 + action 0 + 1990 : 1 +state 1677 + action 0 + 1986 : 1 +state 1678 observe0Greater1 observeOnlyTrueSender + action 0 + 1991 : 0.833 + 1992 : 0.167 +state 1679 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 1680 observe2Greater1 observeIGreater1 + action 0 + 1998 : 1 +state 1681 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 1682 + action 0 + 2004 : 1 +state 1683 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 1684 + action 0 + 2010 : 1 +state 1685 + action 0 + 2011 : 1 +state 1686 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1687 + action 0 + 2012 : 1 +state 1688 + action 0 + 2011 : 1 +state 1689 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1690 + action 0 + 2013 : 1 +state 1691 + action 0 + 2011 : 1 +state 1692 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1693 + action 0 + 2014 : 1 +state 1694 + action 0 + 2011 : 1 +state 1695 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1696 + action 0 + 2015 : 1 +state 1697 + action 0 + 2011 : 1 +state 1698 observe0Greater1 observeOnlyTrueSender + action 0 + 2016 : 0.833 + 2017 : 0.167 +state 1699 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 1700 observe3Greater1 observeIGreater1 + action 0 + 2023 : 1 +state 1701 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 1702 + action 0 + 2029 : 1 +state 1703 + action 0 + 2030 : 1 +state 1704 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1705 + action 0 + 2031 : 1 +state 1706 + action 0 + 2030 : 1 +state 1707 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1708 + action 0 + 2032 : 1 +state 1709 + action 0 + 2030 : 1 +state 1710 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1711 + action 0 + 2033 : 1 +state 1712 + action 0 + 2030 : 1 +state 1713 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1714 + action 0 + 2034 : 1 +state 1715 + action 0 + 2030 : 1 +state 1716 observe0Greater1 observeOnlyTrueSender + action 0 + 2035 : 0.833 + 2036 : 0.167 +state 1717 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 1718 observe4Greater1 observeIGreater1 + action 0 + 2042 : 1 +state 1719 + action 0 + 2043 : 1 +state 1720 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1721 + action 0 + 2044 : 1 +state 1722 + action 0 + 2043 : 1 +state 1723 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1724 + action 0 + 2045 : 1 +state 1725 + action 0 + 2043 : 1 +state 1726 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1727 + action 0 + 2046 : 1 +state 1728 + action 0 + 2043 : 1 +state 1729 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1730 + action 0 + 2047 : 1 +state 1731 + action 0 + 2043 : 1 +state 1732 observe0Greater1 observeOnlyTrueSender + action 0 + 2048 : 0.833 + 2049 : 0.167 +state 1733 observe0Greater1 observeOnlyTrueSender + action 0 + 2050 : 1 +state 1734 observe0Greater1 observeOnlyTrueSender + action 0 + 2051 : 0.833 + 2052 : 0.167 +state 1735 observe0Greater1 observeOnlyTrueSender + action 0 + 2053 : 1 +state 1736 observe0Greater1 observeOnlyTrueSender + action 0 + 2054 : 0.833 + 2055 : 0.167 +state 1737 observe0Greater1 observeOnlyTrueSender + action 0 + 2056 : 1 +state 1738 observe0Greater1 observeOnlyTrueSender + action 0 + 2057 : 0.833 + 2058 : 0.167 +state 1739 observe0Greater1 observeOnlyTrueSender + action 0 + 2059 : 1 +state 1740 observe0Greater1 observeOnlyTrueSender + action 0 + 2060 : 0.833 + 2061 : 0.167 +state 1741 observe0Greater1 observeOnlyTrueSender + action 0 + 2062 : 1 +state 1742 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1742 : 1 +state 1743 observe1Greater1 observeIGreater1 + action 0 + 2063 : 1 +state 1744 observe1Greater1 observeIGreater1 + action 0 + 2064 : 1 +state 1745 observe1Greater1 observeIGreater1 + action 0 + 2065 : 1 +state 1746 observe1Greater1 observeIGreater1 + action 0 + 2066 : 1 +state 1747 observe1Greater1 observeIGreater1 + action 0 + 2067 : 0.8 + 2068 : 0.2 +state 1748 observe1Greater1 observeIGreater1 + action 0 + 2069 : 0.8 + 2070 : 0.2 +state 1749 observe1Greater1 observeIGreater1 + action 0 + 2071 : 0.8 + 2072 : 0.2 +state 1750 observe1Greater1 observeIGreater1 + action 0 + 2073 : 0.8 + 2074 : 0.2 +state 1751 observe1Greater1 observeIGreater1 + action 0 + 2075 : 0.8 + 2076 : 0.2 +state 1752 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2077 : 1 +state 1753 observe1Greater1 observeIGreater1 + action 0 + 2064 : 1 +state 1754 observe2Greater1 observeIGreater1 + action 0 + 2078 : 1 +state 1755 + action 0 + 2079 : 1 +state 1756 + action 0 + 2080 : 1 +state 1757 + action 0 + 2081 : 0.8 + 2082 : 0.2 +state 1758 + action 0 + 2083 : 0.8 + 2084 : 0.2 +state 1759 + action 0 + 2085 : 0.8 + 2086 : 0.2 +state 1760 + action 0 + 2087 : 0.8 + 2088 : 0.2 +state 1761 + action 0 + 2089 : 0.8 + 2090 : 0.2 +state 1762 observe0Greater1 observeOnlyTrueSender + action 0 + 2091 : 1 +state 1763 observe1Greater1 observeIGreater1 + action 0 + 2065 : 1 +state 1764 + action 0 + 2079 : 1 +state 1765 observe3Greater1 observeIGreater1 + action 0 + 2092 : 1 +state 1766 + action 0 + 2093 : 1 +state 1767 + action 0 + 2094 : 0.8 + 2095 : 0.2 +state 1768 + action 0 + 2096 : 0.8 + 2097 : 0.2 +state 1769 + action 0 + 2098 : 0.8 + 2099 : 0.2 +state 1770 + action 0 + 2100 : 0.8 + 2101 : 0.2 +state 1771 + action 0 + 2102 : 0.8 + 2103 : 0.2 +state 1772 observe0Greater1 observeOnlyTrueSender + action 0 + 2104 : 1 +state 1773 observe1Greater1 observeIGreater1 + action 0 + 2066 : 1 +state 1774 + action 0 + 2080 : 1 +state 1775 + action 0 + 2093 : 1 +state 1776 observe4Greater1 observeIGreater1 + action 0 + 2105 : 1 +state 1777 + action 0 + 2106 : 0.8 + 2107 : 0.2 +state 1778 + action 0 + 2108 : 0.8 + 2109 : 0.2 +state 1779 + action 0 + 2110 : 0.8 + 2111 : 0.2 +state 1780 + action 0 + 2112 : 0.8 + 2113 : 0.2 +state 1781 + action 0 + 2114 : 0.8 + 2115 : 0.2 +state 1782 observe0Greater1 observeOnlyTrueSender + action 0 + 2116 : 1 +state 1783 observe0Greater1 observeOnlyTrueSender + action 0 + 1991 : 0.833 + 1992 : 0.167 +state 1784 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2117 : 1 +state 1785 observe0Greater1 observeOnlyTrueSender + action 0 + 2118 : 1 +state 1786 observe0Greater1 observeOnlyTrueSender + action 0 + 2119 : 1 +state 1787 observe0Greater1 observeOnlyTrueSender + action 0 + 2120 : 1 +state 1788 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 1789 observe0Greater1 observeOnlyTrueSender + action 0 + 2126 : 1 +state 1790 observe2Greater1 observeIGreater1 + action 0 + 2078 : 1 +state 1791 observe2Greater1 observeIGreater1 + action 0 + 2127 : 1 +state 1792 observe2Greater1 observeIGreater1 + action 0 + 2128 : 1 +state 1793 observe2Greater1 observeIGreater1 + action 0 + 2129 : 1 +state 1794 observe2Greater1 observeIGreater1 + action 0 + 2130 : 0.8 + 2131 : 0.2 +state 1795 observe2Greater1 observeIGreater1 + action 0 + 2132 : 0.8 + 2133 : 0.2 +state 1796 observe2Greater1 observeIGreater1 + action 0 + 2134 : 0.8 + 2135 : 0.2 +state 1797 observe2Greater1 observeIGreater1 + action 0 + 2136 : 0.8 + 2137 : 0.2 +state 1798 observe2Greater1 observeIGreater1 + action 0 + 2138 : 0.8 + 2139 : 0.2 +state 1799 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2140 : 1 +state 1800 + action 0 + 2079 : 1 +state 1801 observe2Greater1 observeIGreater1 + action 0 + 2128 : 1 +state 1802 observe3Greater1 observeIGreater1 + action 0 + 2141 : 1 +state 1803 + action 0 + 2142 : 1 +state 1804 + action 0 + 2143 : 0.8 + 2144 : 0.2 +state 1805 + action 0 + 2145 : 0.8 + 2146 : 0.2 +state 1806 + action 0 + 2147 : 0.8 + 2148 : 0.2 +state 1807 + action 0 + 2149 : 0.8 + 2150 : 0.2 +state 1808 + action 0 + 2151 : 0.8 + 2152 : 0.2 +state 1809 observe0Greater1 observeOnlyTrueSender + action 0 + 2153 : 1 +state 1810 + action 0 + 2080 : 1 +state 1811 observe2Greater1 observeIGreater1 + action 0 + 2129 : 1 +state 1812 + action 0 + 2142 : 1 +state 1813 observe4Greater1 observeIGreater1 + action 0 + 2154 : 1 +state 1814 + action 0 + 2155 : 0.8 + 2156 : 0.2 +state 1815 + action 0 + 2157 : 0.8 + 2158 : 0.2 +state 1816 + action 0 + 2159 : 0.8 + 2160 : 0.2 +state 1817 + action 0 + 2161 : 0.8 + 2162 : 0.2 +state 1818 + action 0 + 2163 : 0.8 + 2164 : 0.2 +state 1819 observe0Greater1 observeOnlyTrueSender + action 0 + 2165 : 1 +state 1820 observe0Greater1 observeOnlyTrueSender + action 0 + 2016 : 0.833 + 2017 : 0.167 +state 1821 observe0Greater1 observeOnlyTrueSender + action 0 + 2166 : 1 +state 1822 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2167 : 1 +state 1823 observe0Greater1 observeOnlyTrueSender + action 0 + 2168 : 1 +state 1824 observe0Greater1 observeOnlyTrueSender + action 0 + 2169 : 1 +state 1825 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 1826 observe0Greater1 observeOnlyTrueSender + action 0 + 2175 : 1 +state 1827 observe3Greater1 observeIGreater1 + action 0 + 2092 : 1 +state 1828 observe3Greater1 observeIGreater1 + action 0 + 2141 : 1 +state 1829 observe3Greater1 observeIGreater1 + action 0 + 2176 : 1 +state 1830 observe3Greater1 observeIGreater1 + action 0 + 2177 : 1 +state 1831 observe3Greater1 observeIGreater1 + action 0 + 2178 : 0.8 + 2179 : 0.2 +state 1832 observe3Greater1 observeIGreater1 + action 0 + 2180 : 0.8 + 2181 : 0.2 +state 1833 observe3Greater1 observeIGreater1 + action 0 + 2182 : 0.8 + 2183 : 0.2 +state 1834 observe3Greater1 observeIGreater1 + action 0 + 2184 : 0.8 + 2185 : 0.2 +state 1835 observe3Greater1 observeIGreater1 + action 0 + 2186 : 0.8 + 2187 : 0.2 +state 1836 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2188 : 1 +state 1837 + action 0 + 2093 : 1 +state 1838 + action 0 + 2142 : 1 +state 1839 observe3Greater1 observeIGreater1 + action 0 + 2177 : 1 +state 1840 observe4Greater1 observeIGreater1 + action 0 + 2189 : 1 +state 1841 + action 0 + 2190 : 0.8 + 2191 : 0.2 +state 1842 + action 0 + 2192 : 0.8 + 2193 : 0.2 +state 1843 + action 0 + 2194 : 0.8 + 2195 : 0.2 +state 1844 + action 0 + 2196 : 0.8 + 2197 : 0.2 +state 1845 + action 0 + 2198 : 0.8 + 2199 : 0.2 +state 1846 observe0Greater1 observeOnlyTrueSender + action 0 + 2200 : 1 +state 1847 observe0Greater1 observeOnlyTrueSender + action 0 + 2035 : 0.833 + 2036 : 0.167 +state 1848 observe0Greater1 observeOnlyTrueSender + action 0 + 2201 : 1 +state 1849 observe0Greater1 observeOnlyTrueSender + action 0 + 2202 : 1 +state 1850 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2203 : 1 +state 1851 observe0Greater1 observeOnlyTrueSender + action 0 + 2204 : 1 +state 1852 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 1853 observe0Greater1 observeOnlyTrueSender + action 0 + 2210 : 1 +state 1854 observe4Greater1 observeIGreater1 + action 0 + 2105 : 1 +state 1855 observe4Greater1 observeIGreater1 + action 0 + 2154 : 1 +state 1856 observe4Greater1 observeIGreater1 + action 0 + 2189 : 1 +state 1857 observe4Greater1 observeIGreater1 + action 0 + 2211 : 1 +state 1858 observe4Greater1 observeIGreater1 + action 0 + 2212 : 0.8 + 2213 : 0.2 +state 1859 observe4Greater1 observeIGreater1 + action 0 + 2214 : 0.8 + 2215 : 0.2 +state 1860 observe4Greater1 observeIGreater1 + action 0 + 2216 : 0.8 + 2217 : 0.2 +state 1861 observe4Greater1 observeIGreater1 + action 0 + 2218 : 0.8 + 2219 : 0.2 +state 1862 observe4Greater1 observeIGreater1 + action 0 + 2220 : 0.8 + 2221 : 0.2 +state 1863 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2222 : 1 +state 1864 observe0Greater1 observeOnlyTrueSender + action 0 + 2048 : 0.833 + 2049 : 0.167 +state 1865 observe0Greater1 observeOnlyTrueSender + action 0 + 2223 : 1 +state 1866 observe0Greater1 observeOnlyTrueSender + action 0 + 2224 : 1 +state 1867 observe0Greater1 observeOnlyTrueSender + action 0 + 2225 : 1 +state 1868 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2226 : 1 +state 1869 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 1870 observe0Greater1 observeOnlyTrueSender + action 0 + 2232 : 1 +state 1871 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1871 : 1 +state 1872 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1873 observe0Greater1 observeOnlyTrueSender + action 0 + 2233 : 1 +state 1874 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1874 : 1 +state 1875 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1876 observe0Greater1 observeOnlyTrueSender + action 0 + 2234 : 1 +state 1877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1877 : 1 +state 1878 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1879 observe0Greater1 observeOnlyTrueSender + action 0 + 2235 : 1 +state 1880 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1880 : 1 +state 1881 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1882 observe0Greater1 observeOnlyTrueSender + action 0 + 2236 : 1 +state 1883 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1883 : 1 +state 1884 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 1885 + action 0 + 2242 : 1 +state 1886 + action 0 + 2243 : 1 +state 1887 + action 0 + 2244 : 1 +state 1888 + action 0 + 2245 : 1 +state 1889 + action 0 + 2246 : 1 +state 1890 + action 0 + 1396 : 0.8 + 2247 : 0.2 +state 1891 + action 0 + 2248 : 0.8 + 2249 : 0.2 +state 1892 + action 0 + 2250 : 0.8 + 2251 : 0.2 +state 1893 + action 0 + 2252 : 0.8 + 2253 : 0.2 +state 1894 + action 0 + 2254 : 0.8 + 2255 : 0.2 +state 1895 observe0Greater1 observeOnlyTrueSender + action 0 + 2256 : 1 +state 1896 + action 0 + 2257 : 1 +state 1897 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1898 + action 0 + 2258 : 1 +state 1899 + action 0 + 2257 : 1 +state 1900 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1901 + action 0 + 2259 : 1 +state 1902 + action 0 + 2257 : 1 +state 1903 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1904 + action 0 + 2260 : 1 +state 1905 + action 0 + 2257 : 1 +state 1906 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1907 + action 0 + 2261 : 1 +state 1908 + action 0 + 2257 : 1 +state 1909 + action 0 + 2262 : 0.833 + 2263 : 0.167 +state 1910 + action 0 + 2264 : 1 +state 1911 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1912 + action 0 + 2265 : 1 +state 1913 + action 0 + 2264 : 1 +state 1914 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1915 + action 0 + 2266 : 1 +state 1916 + action 0 + 2264 : 1 +state 1917 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1918 + action 0 + 2267 : 1 +state 1919 + action 0 + 2264 : 1 +state 1920 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1921 + action 0 + 2268 : 1 +state 1922 + action 0 + 2264 : 1 +state 1923 + action 0 + 2269 : 0.833 + 2270 : 0.167 +state 1924 + action 0 + 2271 : 1 +state 1925 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1926 + action 0 + 2272 : 1 +state 1927 + action 0 + 2271 : 1 +state 1928 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1929 + action 0 + 2273 : 1 +state 1930 + action 0 + 2271 : 1 +state 1931 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1932 + action 0 + 2274 : 1 +state 1933 + action 0 + 2271 : 1 +state 1934 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1935 + action 0 + 2275 : 1 +state 1936 + action 0 + 2271 : 1 +state 1937 + action 0 + 2276 : 0.833 + 2277 : 0.167 +state 1938 + action 0 + 2278 : 1 +state 1939 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1940 + action 0 + 2279 : 1 +state 1941 + action 0 + 2278 : 1 +state 1942 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1943 + action 0 + 2280 : 1 +state 1944 + action 0 + 2278 : 1 +state 1945 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1946 + action 0 + 2281 : 1 +state 1947 + action 0 + 2278 : 1 +state 1948 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1949 + action 0 + 2282 : 1 +state 1950 + action 0 + 2278 : 1 +state 1951 + action 0 + 2283 : 0.833 + 2284 : 0.167 +state 1952 observe0Greater1 observeOnlyTrueSender + action 0 + 2285 : 1 +state 1953 observe0Greater1 observeOnlyTrueSender + action 0 + 2286 : 0.833 + 2287 : 0.167 +state 1954 observe0Greater1 observeOnlyTrueSender + action 0 + 2288 : 1 +state 1955 observe0Greater1 observeOnlyTrueSender + action 0 + 2289 : 0.833 + 2290 : 0.167 +state 1956 observe0Greater1 observeOnlyTrueSender + action 0 + 2291 : 1 +state 1957 observe0Greater1 observeOnlyTrueSender + action 0 + 2292 : 0.833 + 2293 : 0.167 +state 1958 observe0Greater1 observeOnlyTrueSender + action 0 + 2294 : 1 +state 1959 observe0Greater1 observeOnlyTrueSender + action 0 + 2295 : 0.833 + 2296 : 0.167 +state 1960 observe0Greater1 observeOnlyTrueSender + action 0 + 2297 : 1 +state 1961 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1961 : 1 +state 1962 observe1Greater1 observeIGreater1 + action 0 + 1463 : 0.8 + 2298 : 0.2 +state 1963 observe1Greater1 observeIGreater1 + action 0 + 2299 : 0.8 + 2300 : 0.2 +state 1964 observe1Greater1 observeIGreater1 + action 0 + 2301 : 0.8 + 2302 : 0.2 +state 1965 observe1Greater1 observeIGreater1 + action 0 + 2303 : 0.8 + 2304 : 0.2 +state 1966 observe1Greater1 observeIGreater1 + action 0 + 2305 : 0.8 + 2306 : 0.2 +state 1967 observe1Greater1 observeIGreater1 + action 0 + 2307 : 1 +state 1968 + action 0 + 1470 : 0.8 + 2308 : 0.2 +state 1969 + action 0 + 2309 : 0.8 + 2310 : 0.2 +state 1970 + action 0 + 2311 : 0.8 + 2312 : 0.2 +state 1971 + action 0 + 2313 : 0.8 + 2314 : 0.2 +state 1972 + action 0 + 2315 : 0.8 + 2316 : 0.2 +state 1973 + action 0 + 2317 : 1 +state 1974 + action 0 + 1477 : 0.8 + 2318 : 0.2 +state 1975 + action 0 + 2319 : 0.8 + 2320 : 0.2 +state 1976 + action 0 + 2321 : 0.8 + 2322 : 0.2 +state 1977 + action 0 + 2323 : 0.8 + 2324 : 0.2 +state 1978 + action 0 + 2325 : 0.8 + 2326 : 0.2 +state 1979 + action 0 + 2327 : 1 +state 1980 + action 0 + 1484 : 0.8 + 2328 : 0.2 +state 1981 + action 0 + 2329 : 0.8 + 2330 : 0.2 +state 1982 + action 0 + 2331 : 0.8 + 2332 : 0.2 +state 1983 + action 0 + 2333 : 0.8 + 2334 : 0.2 +state 1984 + action 0 + 2335 : 0.8 + 2336 : 0.2 +state 1985 + action 0 + 2337 : 1 +state 1986 + action 0 + 2262 : 0.833 + 2263 : 0.167 +state 1987 observe1Greater1 observeIGreater1 + action 0 + 2338 : 1 +state 1988 + action 0 + 2339 : 1 +state 1989 + action 0 + 2340 : 1 +state 1990 + action 0 + 2341 : 1 +state 1991 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 1992 observe0Greater1 observeOnlyTrueSender + action 0 + 2347 : 1 +state 1993 observe2Greater1 observeIGreater1 + action 0 + 1505 : 0.8 + 2348 : 0.2 +state 1994 observe2Greater1 observeIGreater1 + action 0 + 2349 : 0.8 + 2350 : 0.2 +state 1995 observe2Greater1 observeIGreater1 + action 0 + 2351 : 0.8 + 2352 : 0.2 +state 1996 observe2Greater1 observeIGreater1 + action 0 + 2353 : 0.8 + 2354 : 0.2 +state 1997 observe2Greater1 observeIGreater1 + action 0 + 2355 : 0.8 + 2356 : 0.2 +state 1998 observe2Greater1 observeIGreater1 + action 0 + 2357 : 1 +state 1999 + action 0 + 1512 : 0.8 + 2358 : 0.2 +state 2000 + action 0 + 2359 : 0.8 + 2360 : 0.2 +state 2001 + action 0 + 2361 : 0.8 + 2362 : 0.2 +state 2002 + action 0 + 2363 : 0.8 + 2364 : 0.2 +state 2003 + action 0 + 2365 : 0.8 + 2366 : 0.2 +state 2004 + action 0 + 2367 : 1 +state 2005 + action 0 + 1519 : 0.8 + 2368 : 0.2 +state 2006 + action 0 + 2369 : 0.8 + 2370 : 0.2 +state 2007 + action 0 + 2371 : 0.8 + 2372 : 0.2 +state 2008 + action 0 + 2373 : 0.8 + 2374 : 0.2 +state 2009 + action 0 + 2375 : 0.8 + 2376 : 0.2 +state 2010 + action 0 + 2377 : 1 +state 2011 + action 0 + 2269 : 0.833 + 2270 : 0.167 +state 2012 + action 0 + 2378 : 1 +state 2013 observe2Greater1 observeIGreater1 + action 0 + 2379 : 1 +state 2014 + action 0 + 2380 : 1 +state 2015 + action 0 + 2381 : 1 +state 2016 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 2017 observe0Greater1 observeOnlyTrueSender + action 0 + 2387 : 1 +state 2018 observe3Greater1 observeIGreater1 + action 0 + 1540 : 0.8 + 2388 : 0.2 +state 2019 observe3Greater1 observeIGreater1 + action 0 + 2389 : 0.8 + 2390 : 0.2 +state 2020 observe3Greater1 observeIGreater1 + action 0 + 2391 : 0.8 + 2392 : 0.2 +state 2021 observe3Greater1 observeIGreater1 + action 0 + 2393 : 0.8 + 2394 : 0.2 +state 2022 observe3Greater1 observeIGreater1 + action 0 + 2395 : 0.8 + 2396 : 0.2 +state 2023 observe3Greater1 observeIGreater1 + action 0 + 2397 : 1 +state 2024 + action 0 + 1547 : 0.8 + 2398 : 0.2 +state 2025 + action 0 + 2399 : 0.8 + 2400 : 0.2 +state 2026 + action 0 + 2401 : 0.8 + 2402 : 0.2 +state 2027 + action 0 + 2403 : 0.8 + 2404 : 0.2 +state 2028 + action 0 + 2405 : 0.8 + 2406 : 0.2 +state 2029 + action 0 + 2407 : 1 +state 2030 + action 0 + 2276 : 0.833 + 2277 : 0.167 +state 2031 + action 0 + 2408 : 1 +state 2032 + action 0 + 2409 : 1 +state 2033 observe3Greater1 observeIGreater1 + action 0 + 2410 : 1 +state 2034 + action 0 + 2411 : 1 +state 2035 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 2036 observe0Greater1 observeOnlyTrueSender + action 0 + 2417 : 1 +state 2037 observe4Greater1 observeIGreater1 + action 0 + 1568 : 0.8 + 2418 : 0.2 +state 2038 observe4Greater1 observeIGreater1 + action 0 + 2419 : 0.8 + 2420 : 0.2 +state 2039 observe4Greater1 observeIGreater1 + action 0 + 2421 : 0.8 + 2422 : 0.2 +state 2040 observe4Greater1 observeIGreater1 + action 0 + 2423 : 0.8 + 2424 : 0.2 +state 2041 observe4Greater1 observeIGreater1 + action 0 + 2425 : 0.8 + 2426 : 0.2 +state 2042 observe4Greater1 observeIGreater1 + action 0 + 2427 : 1 +state 2043 + action 0 + 2283 : 0.833 + 2284 : 0.167 +state 2044 + action 0 + 2428 : 1 +state 2045 + action 0 + 2429 : 1 +state 2046 + action 0 + 2430 : 1 +state 2047 observe4Greater1 observeIGreater1 + action 0 + 2431 : 1 +state 2048 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 2049 observe0Greater1 observeOnlyTrueSender + action 0 + 2437 : 1 +state 2050 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2050 : 1 +state 2051 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2052 observe0Greater1 observeOnlyTrueSender + action 0 + 2438 : 1 +state 2053 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2053 : 1 +state 2054 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2055 observe0Greater1 observeOnlyTrueSender + action 0 + 2439 : 1 +state 2056 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2056 : 1 +state 2057 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2058 observe0Greater1 observeOnlyTrueSender + action 0 + 2440 : 1 +state 2059 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2059 : 1 +state 2060 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2061 observe0Greater1 observeOnlyTrueSender + action 0 + 2441 : 1 +state 2062 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2062 : 1 +state 2063 observe1Greater1 observeIGreater1 + action 0 + 2442 : 0.833 + 2443 : 0.167 +state 2064 observe1Greater1 observeIGreater1 + action 0 + 2444 : 0.833 + 2445 : 0.167 +state 2065 observe1Greater1 observeIGreater1 + action 0 + 2446 : 0.833 + 2447 : 0.167 +state 2066 observe1Greater1 observeIGreater1 + action 0 + 2448 : 0.833 + 2449 : 0.167 +state 2067 observe1Greater1 observeIGreater1 + action 0 + 1468 : 0.833 + 1469 : 0.167 +state 2068 observe1Greater1 observeIGreater1 + action 0 + 2450 : 1 +state 2069 observe1Greater1 observeIGreater1 + action 0 + 2451 : 0.833 + 2452 : 0.167 +state 2070 observe1Greater1 observeIGreater1 + action 0 + 2453 : 1 +state 2071 observe1Greater1 observeIGreater1 + action 0 + 2454 : 0.833 + 2455 : 0.167 +state 2072 observe1Greater1 observeIGreater1 + action 0 + 2456 : 1 +state 2073 observe1Greater1 observeIGreater1 + action 0 + 2457 : 0.833 + 2458 : 0.167 +state 2074 observe1Greater1 observeIGreater1 + action 0 + 2459 : 1 +state 2075 observe1Greater1 observeIGreater1 + action 0 + 2460 : 0.833 + 2461 : 0.167 +state 2076 observe1Greater1 observeIGreater1 + action 0 + 2462 : 1 +state 2077 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2463 : 1 +state 2078 observe2Greater1 observeIGreater1 + action 0 + 2464 : 0.833 + 2465 : 0.167 +state 2079 + action 0 + 2466 : 0.833 + 2467 : 0.167 +state 2080 + action 0 + 2468 : 0.833 + 2469 : 0.167 +state 2081 + action 0 + 1475 : 0.833 + 1476 : 0.167 +state 2082 + action 0 + 2470 : 1 +state 2083 + action 0 + 2471 : 0.833 + 2472 : 0.167 +state 2084 + action 0 + 2473 : 1 +state 2085 + action 0 + 2474 : 0.833 + 2475 : 0.167 +state 2086 + action 0 + 2476 : 1 +state 2087 + action 0 + 2477 : 0.833 + 2478 : 0.167 +state 2088 + action 0 + 2479 : 1 +state 2089 + action 0 + 2480 : 0.833 + 2481 : 0.167 +state 2090 + action 0 + 2482 : 1 +state 2091 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2092 observe3Greater1 observeIGreater1 + action 0 + 2484 : 0.833 + 2485 : 0.167 +state 2093 + action 0 + 2486 : 0.833 + 2487 : 0.167 +state 2094 + action 0 + 1482 : 0.833 + 1483 : 0.167 +state 2095 + action 0 + 2488 : 1 +state 2096 + action 0 + 2489 : 0.833 + 2490 : 0.167 +state 2097 + action 0 + 2491 : 1 +state 2098 + action 0 + 2492 : 0.833 + 2493 : 0.167 +state 2099 + action 0 + 2494 : 1 +state 2100 + action 0 + 2495 : 0.833 + 2496 : 0.167 +state 2101 + action 0 + 2497 : 1 +state 2102 + action 0 + 2498 : 0.833 + 2499 : 0.167 +state 2103 + action 0 + 2500 : 1 +state 2104 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2105 observe4Greater1 observeIGreater1 + action 0 + 2502 : 0.833 + 2503 : 0.167 +state 2106 + action 0 + 1489 : 0.833 + 1490 : 0.167 +state 2107 + action 0 + 2504 : 1 +state 2108 + action 0 + 2505 : 0.833 + 2506 : 0.167 +state 2109 + action 0 + 2507 : 1 +state 2110 + action 0 + 2508 : 0.833 + 2509 : 0.167 +state 2111 + action 0 + 2510 : 1 +state 2112 + action 0 + 2511 : 0.833 + 2512 : 0.167 +state 2113 + action 0 + 2513 : 1 +state 2114 + action 0 + 2514 : 0.833 + 2515 : 0.167 +state 2115 + action 0 + 2516 : 1 +state 2116 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2117 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2463 : 1 +state 2118 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2119 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2120 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2121 observe0Greater1 observeOnlyTrueSender + action 0 + 2518 : 0.8 + 2519 : 0.2 +state 2122 observe0Greater1 observeOnlyTrueSender + action 0 + 2520 : 0.8 + 2521 : 0.2 +state 2123 observe0Greater1 observeOnlyTrueSender + action 0 + 2522 : 0.8 + 2523 : 0.2 +state 2124 observe0Greater1 observeOnlyTrueSender + action 0 + 2524 : 0.8 + 2525 : 0.2 +state 2125 observe0Greater1 observeOnlyTrueSender + action 0 + 2526 : 0.8 + 2527 : 0.2 +state 2126 observe0Greater1 observeOnlyTrueSender + action 0 + 2528 : 1 +state 2127 observe2Greater1 observeIGreater1 + action 0 + 2529 : 0.833 + 2530 : 0.167 +state 2128 observe2Greater1 observeIGreater1 + action 0 + 2531 : 0.833 + 2532 : 0.167 +state 2129 observe2Greater1 observeIGreater1 + action 0 + 2533 : 0.833 + 2534 : 0.167 +state 2130 observe2Greater1 observeIGreater1 + action 0 + 1510 : 0.833 + 1511 : 0.167 +state 2131 observe2Greater1 observeIGreater1 + action 0 + 2535 : 1 +state 2132 observe2Greater1 observeIGreater1 + action 0 + 2536 : 0.833 + 2537 : 0.167 +state 2133 observe2Greater1 observeIGreater1 + action 0 + 2538 : 1 +state 2134 observe2Greater1 observeIGreater1 + action 0 + 2539 : 0.833 + 2540 : 0.167 +state 2135 observe2Greater1 observeIGreater1 + action 0 + 2541 : 1 +state 2136 observe2Greater1 observeIGreater1 + action 0 + 2542 : 0.833 + 2543 : 0.167 +state 2137 observe2Greater1 observeIGreater1 + action 0 + 2544 : 1 +state 2138 observe2Greater1 observeIGreater1 + action 0 + 2545 : 0.833 + 2546 : 0.167 +state 2139 observe2Greater1 observeIGreater1 + action 0 + 2547 : 1 +state 2140 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2548 : 1 +state 2141 observe3Greater1 observeIGreater1 + action 0 + 2549 : 0.833 + 2550 : 0.167 +state 2142 + action 0 + 2551 : 0.833 + 2552 : 0.167 +state 2143 + action 0 + 1517 : 0.833 + 1518 : 0.167 +state 2144 + action 0 + 2553 : 1 +state 2145 + action 0 + 2554 : 0.833 + 2555 : 0.167 +state 2146 + action 0 + 2556 : 1 +state 2147 + action 0 + 2557 : 0.833 + 2558 : 0.167 +state 2148 + action 0 + 2559 : 1 +state 2149 + action 0 + 2560 : 0.833 + 2561 : 0.167 +state 2150 + action 0 + 2562 : 1 +state 2151 + action 0 + 2563 : 0.833 + 2564 : 0.167 +state 2152 + action 0 + 2565 : 1 +state 2153 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2154 observe4Greater1 observeIGreater1 + action 0 + 2567 : 0.833 + 2568 : 0.167 +state 2155 + action 0 + 1524 : 0.833 + 1525 : 0.167 +state 2156 + action 0 + 2569 : 1 +state 2157 + action 0 + 2570 : 0.833 + 2571 : 0.167 +state 2158 + action 0 + 2572 : 1 +state 2159 + action 0 + 2573 : 0.833 + 2574 : 0.167 +state 2160 + action 0 + 2575 : 1 +state 2161 + action 0 + 2576 : 0.833 + 2577 : 0.167 +state 2162 + action 0 + 2578 : 1 +state 2163 + action 0 + 2579 : 0.833 + 2580 : 0.167 +state 2164 + action 0 + 2581 : 1 +state 2165 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2166 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2167 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2548 : 1 +state 2168 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2169 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2170 observe0Greater1 observeOnlyTrueSender + action 0 + 2583 : 0.8 + 2584 : 0.2 +state 2171 observe0Greater1 observeOnlyTrueSender + action 0 + 2585 : 0.8 + 2586 : 0.2 +state 2172 observe0Greater1 observeOnlyTrueSender + action 0 + 2587 : 0.8 + 2588 : 0.2 +state 2173 observe0Greater1 observeOnlyTrueSender + action 0 + 2589 : 0.8 + 2590 : 0.2 +state 2174 observe0Greater1 observeOnlyTrueSender + action 0 + 2591 : 0.8 + 2592 : 0.2 +state 2175 observe0Greater1 observeOnlyTrueSender + action 0 + 2593 : 1 +state 2176 observe3Greater1 observeIGreater1 + action 0 + 2594 : 0.833 + 2595 : 0.167 +state 2177 observe3Greater1 observeIGreater1 + action 0 + 2596 : 0.833 + 2597 : 0.167 +state 2178 observe3Greater1 observeIGreater1 + action 0 + 1545 : 0.833 + 1546 : 0.167 +state 2179 observe3Greater1 observeIGreater1 + action 0 + 2598 : 1 +state 2180 observe3Greater1 observeIGreater1 + action 0 + 2599 : 0.833 + 2600 : 0.167 +state 2181 observe3Greater1 observeIGreater1 + action 0 + 2601 : 1 +state 2182 observe3Greater1 observeIGreater1 + action 0 + 2602 : 0.833 + 2603 : 0.167 +state 2183 observe3Greater1 observeIGreater1 + action 0 + 2604 : 1 +state 2184 observe3Greater1 observeIGreater1 + action 0 + 2605 : 0.833 + 2606 : 0.167 +state 2185 observe3Greater1 observeIGreater1 + action 0 + 2607 : 1 +state 2186 observe3Greater1 observeIGreater1 + action 0 + 2608 : 0.833 + 2609 : 0.167 +state 2187 observe3Greater1 observeIGreater1 + action 0 + 2610 : 1 +state 2188 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2611 : 1 +state 2189 observe4Greater1 observeIGreater1 + action 0 + 2612 : 0.833 + 2613 : 0.167 +state 2190 + action 0 + 1552 : 0.833 + 1553 : 0.167 +state 2191 + action 0 + 2614 : 1 +state 2192 + action 0 + 2615 : 0.833 + 2616 : 0.167 +state 2193 + action 0 + 2617 : 1 +state 2194 + action 0 + 2618 : 0.833 + 2619 : 0.167 +state 2195 + action 0 + 2620 : 1 +state 2196 + action 0 + 2621 : 0.833 + 2622 : 0.167 +state 2197 + action 0 + 2623 : 1 +state 2198 + action 0 + 2624 : 0.833 + 2625 : 0.167 +state 2199 + action 0 + 2626 : 1 +state 2200 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2201 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2202 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2203 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2611 : 1 +state 2204 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2205 observe0Greater1 observeOnlyTrueSender + action 0 + 2628 : 0.8 + 2629 : 0.2 +state 2206 observe0Greater1 observeOnlyTrueSender + action 0 + 2630 : 0.8 + 2631 : 0.2 +state 2207 observe0Greater1 observeOnlyTrueSender + action 0 + 2632 : 0.8 + 2633 : 0.2 +state 2208 observe0Greater1 observeOnlyTrueSender + action 0 + 2634 : 0.8 + 2635 : 0.2 +state 2209 observe0Greater1 observeOnlyTrueSender + action 0 + 2636 : 0.8 + 2637 : 0.2 +state 2210 observe0Greater1 observeOnlyTrueSender + action 0 + 2638 : 1 +state 2211 observe4Greater1 observeIGreater1 + action 0 + 2639 : 0.833 + 2640 : 0.167 +state 2212 observe4Greater1 observeIGreater1 + action 0 + 1573 : 0.833 + 1574 : 0.167 +state 2213 observe4Greater1 observeIGreater1 + action 0 + 2641 : 1 +state 2214 observe4Greater1 observeIGreater1 + action 0 + 2642 : 0.833 + 2643 : 0.167 +state 2215 observe4Greater1 observeIGreater1 + action 0 + 2644 : 1 +state 2216 observe4Greater1 observeIGreater1 + action 0 + 2645 : 0.833 + 2646 : 0.167 +state 2217 observe4Greater1 observeIGreater1 + action 0 + 2647 : 1 +state 2218 observe4Greater1 observeIGreater1 + action 0 + 2648 : 0.833 + 2649 : 0.167 +state 2219 observe4Greater1 observeIGreater1 + action 0 + 2650 : 1 +state 2220 observe4Greater1 observeIGreater1 + action 0 + 2651 : 0.833 + 2652 : 0.167 +state 2221 observe4Greater1 observeIGreater1 + action 0 + 2653 : 1 +state 2222 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2654 : 1 +state 2223 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2224 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2225 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2226 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2654 : 1 +state 2227 observe0Greater1 observeOnlyTrueSender + action 0 + 2655 : 0.8 + 2656 : 0.2 +state 2228 observe0Greater1 observeOnlyTrueSender + action 0 + 2657 : 0.8 + 2658 : 0.2 +state 2229 observe0Greater1 observeOnlyTrueSender + action 0 + 2659 : 0.8 + 2660 : 0.2 +state 2230 observe0Greater1 observeOnlyTrueSender + action 0 + 2661 : 0.8 + 2662 : 0.2 +state 2231 observe0Greater1 observeOnlyTrueSender + action 0 + 2663 : 0.8 + 2664 : 0.2 +state 2232 observe0Greater1 observeOnlyTrueSender + action 0 + 2665 : 1 +state 2233 observe0Greater1 observeOnlyTrueSender + action 0 + 2666 : 1 +state 2234 observe0Greater1 observeOnlyTrueSender + action 0 + 2667 : 1 +state 2235 observe0Greater1 observeOnlyTrueSender + action 0 + 2668 : 1 +state 2236 observe0Greater1 observeOnlyTrueSender + action 0 + 2669 : 1 +state 2237 + action 0 + 1600 : 0.8 + 2670 : 0.2 +state 2238 + action 0 + 2671 : 0.8 + 2672 : 0.2 +state 2239 + action 0 + 2673 : 0.8 + 2674 : 0.2 +state 2240 + action 0 + 2675 : 0.8 + 2676 : 0.2 +state 2241 + action 0 + 2677 : 0.8 + 2678 : 0.2 +state 2242 + action 0 + 2679 : 1 +state 2243 + action 0 + 2680 : 0.833 + 2681 : 0.167 +state 2244 + action 0 + 2682 : 0.833 + 2683 : 0.167 +state 2245 + action 0 + 2684 : 0.833 + 2685 : 0.167 +state 2246 + action 0 + 2686 : 0.833 + 2687 : 0.167 +state 2247 + action 0 + 2688 : 1 +state 2248 + action 0 + 2689 : 0.833 + 2690 : 0.167 +state 2249 + action 0 + 2691 : 1 +state 2250 + action 0 + 2692 : 0.833 + 2693 : 0.167 +state 2251 + action 0 + 2694 : 1 +state 2252 + action 0 + 2695 : 0.833 + 2696 : 0.167 +state 2253 + action 0 + 2697 : 1 +state 2254 + action 0 + 2698 : 0.833 + 2699 : 0.167 +state 2255 + action 0 + 2700 : 1 +state 2256 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2256 : 1 +state 2257 + action 0 + 2680 : 0.833 + 2681 : 0.167 +state 2258 observe1Greater1 observeIGreater1 + action 0 + 2701 : 1 +state 2259 + action 0 + 2702 : 1 +state 2260 + action 0 + 2703 : 1 +state 2261 + action 0 + 2704 : 1 +state 2262 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 2263 + action 0 + 2710 : 1 +state 2264 + action 0 + 2682 : 0.833 + 2683 : 0.167 +state 2265 + action 0 + 2711 : 1 +state 2266 observe2Greater1 observeIGreater1 + action 0 + 2712 : 1 +state 2267 + action 0 + 2713 : 1 +state 2268 + action 0 + 2714 : 1 +state 2269 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 2270 + action 0 + 2720 : 1 +state 2271 + action 0 + 2684 : 0.833 + 2685 : 0.167 +state 2272 + action 0 + 2721 : 1 +state 2273 + action 0 + 2722 : 1 +state 2274 observe3Greater1 observeIGreater1 + action 0 + 2723 : 1 +state 2275 + action 0 + 2724 : 1 +state 2276 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 2277 + action 0 + 2730 : 1 +state 2278 + action 0 + 2686 : 0.833 + 2687 : 0.167 +state 2279 + action 0 + 2731 : 1 +state 2280 + action 0 + 2732 : 1 +state 2281 + action 0 + 2733 : 1 +state 2282 observe4Greater1 observeIGreater1 + action 0 + 2734 : 1 +state 2283 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 2284 + action 0 + 2740 : 1 +state 2285 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2285 : 1 +state 2286 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2287 observe0Greater1 observeOnlyTrueSender + action 0 + 2741 : 1 +state 2288 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2288 : 1 +state 2289 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2290 observe0Greater1 observeOnlyTrueSender + action 0 + 2742 : 1 +state 2291 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2291 : 1 +state 2292 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2293 observe0Greater1 observeOnlyTrueSender + action 0 + 2743 : 1 +state 2294 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2294 : 1 +state 2295 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2296 observe0Greater1 observeOnlyTrueSender + action 0 + 2744 : 1 +state 2297 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2297 : 1 +state 2298 observe1Greater1 observeIGreater1 + action 0 + 2745 : 1 +state 2299 observe1Greater1 observeIGreater1 + action 0 + 2746 : 0.833 + 2747 : 0.167 +state 2300 observe1Greater1 observeIGreater1 + action 0 + 2748 : 1 +state 2301 observe1Greater1 observeIGreater1 + action 0 + 2749 : 0.833 + 2750 : 0.167 +state 2302 observe1Greater1 observeIGreater1 + action 0 + 2751 : 1 +state 2303 observe1Greater1 observeIGreater1 + action 0 + 2752 : 0.833 + 2753 : 0.167 +state 2304 observe1Greater1 observeIGreater1 + action 0 + 2754 : 1 +state 2305 observe1Greater1 observeIGreater1 + action 0 + 2755 : 0.833 + 2756 : 0.167 +state 2306 observe1Greater1 observeIGreater1 + action 0 + 2757 : 1 +state 2307 observe1Greater1 observeIGreater1 + action 0 + 2758 : 1 +state 2308 + action 0 + 2759 : 1 +state 2309 + action 0 + 2760 : 0.833 + 2761 : 0.167 +state 2310 + action 0 + 2762 : 1 +state 2311 + action 0 + 2763 : 0.833 + 2764 : 0.167 +state 2312 + action 0 + 2765 : 1 +state 2313 + action 0 + 2766 : 0.833 + 2767 : 0.167 +state 2314 + action 0 + 2768 : 1 +state 2315 + action 0 + 2769 : 0.833 + 2770 : 0.167 +state 2316 + action 0 + 2771 : 1 +state 2317 + action 0 + 2772 : 1 +state 2318 + action 0 + 2773 : 1 +state 2319 + action 0 + 2774 : 0.833 + 2775 : 0.167 +state 2320 + action 0 + 2776 : 1 +state 2321 + action 0 + 2777 : 0.833 + 2778 : 0.167 +state 2322 + action 0 + 2779 : 1 +state 2323 + action 0 + 2780 : 0.833 + 2781 : 0.167 +state 2324 + action 0 + 2782 : 1 +state 2325 + action 0 + 2783 : 0.833 + 2784 : 0.167 +state 2326 + action 0 + 2785 : 1 +state 2327 + action 0 + 2786 : 1 +state 2328 + action 0 + 2787 : 1 +state 2329 + action 0 + 2788 : 0.833 + 2789 : 0.167 +state 2330 + action 0 + 2790 : 1 +state 2331 + action 0 + 2791 : 0.833 + 2792 : 0.167 +state 2332 + action 0 + 2793 : 1 +state 2333 + action 0 + 2794 : 0.833 + 2795 : 0.167 +state 2334 + action 0 + 2796 : 1 +state 2335 + action 0 + 2797 : 0.833 + 2798 : 0.167 +state 2336 + action 0 + 2799 : 1 +state 2337 + action 0 + 2800 : 1 +state 2338 observe1Greater1 observeIGreater1 + action 0 + 2758 : 1 +state 2339 + action 0 + 2772 : 1 +state 2340 + action 0 + 2786 : 1 +state 2341 + action 0 + 2800 : 1 +state 2342 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 0.8 + 2801 : 0.2 +state 2343 observe0Greater1 observeOnlyTrueSender + action 0 + 2802 : 0.8 + 2803 : 0.2 +state 2344 observe0Greater1 observeOnlyTrueSender + action 0 + 2804 : 0.8 + 2805 : 0.2 +state 2345 observe0Greater1 observeOnlyTrueSender + action 0 + 2806 : 0.8 + 2807 : 0.2 +state 2346 observe0Greater1 observeOnlyTrueSender + action 0 + 2808 : 0.8 + 2809 : 0.2 +state 2347 observe0Greater1 observeOnlyTrueSender + action 0 + 2810 : 1 +state 2348 observe2Greater1 observeIGreater1 + action 0 + 2811 : 1 +state 2349 observe2Greater1 observeIGreater1 + action 0 + 2812 : 0.833 + 2813 : 0.167 +state 2350 observe2Greater1 observeIGreater1 + action 0 + 2814 : 1 +state 2351 observe2Greater1 observeIGreater1 + action 0 + 2815 : 0.833 + 2816 : 0.167 +state 2352 observe2Greater1 observeIGreater1 + action 0 + 2817 : 1 +state 2353 observe2Greater1 observeIGreater1 + action 0 + 2818 : 0.833 + 2819 : 0.167 +state 2354 observe2Greater1 observeIGreater1 + action 0 + 2820 : 1 +state 2355 observe2Greater1 observeIGreater1 + action 0 + 2821 : 0.833 + 2822 : 0.167 +state 2356 observe2Greater1 observeIGreater1 + action 0 + 2823 : 1 +state 2357 observe2Greater1 observeIGreater1 + action 0 + 2824 : 1 +state 2358 + action 0 + 2825 : 1 +state 2359 + action 0 + 2826 : 0.833 + 2827 : 0.167 +state 2360 + action 0 + 2828 : 1 +state 2361 + action 0 + 2829 : 0.833 + 2830 : 0.167 +state 2362 + action 0 + 2831 : 1 +state 2363 + action 0 + 2832 : 0.833 + 2833 : 0.167 +state 2364 + action 0 + 2834 : 1 +state 2365 + action 0 + 2835 : 0.833 + 2836 : 0.167 +state 2366 + action 0 + 2837 : 1 +state 2367 + action 0 + 2838 : 1 +state 2368 + action 0 + 2839 : 1 +state 2369 + action 0 + 2840 : 0.833 + 2841 : 0.167 +state 2370 + action 0 + 2842 : 1 +state 2371 + action 0 + 2843 : 0.833 + 2844 : 0.167 +state 2372 + action 0 + 2845 : 1 +state 2373 + action 0 + 2846 : 0.833 + 2847 : 0.167 +state 2374 + action 0 + 2848 : 1 +state 2375 + action 0 + 2849 : 0.833 + 2850 : 0.167 +state 2376 + action 0 + 2851 : 1 +state 2377 + action 0 + 2852 : 1 +state 2378 + action 0 + 2772 : 1 +state 2379 observe2Greater1 observeIGreater1 + action 0 + 2824 : 1 +state 2380 + action 0 + 2838 : 1 +state 2381 + action 0 + 2852 : 1 +state 2382 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 0.8 + 2853 : 0.2 +state 2383 observe0Greater1 observeOnlyTrueSender + action 0 + 2854 : 0.8 + 2855 : 0.2 +state 2384 observe0Greater1 observeOnlyTrueSender + action 0 + 2856 : 0.8 + 2857 : 0.2 +state 2385 observe0Greater1 observeOnlyTrueSender + action 0 + 2858 : 0.8 + 2859 : 0.2 +state 2386 observe0Greater1 observeOnlyTrueSender + action 0 + 2860 : 0.8 + 2861 : 0.2 +state 2387 observe0Greater1 observeOnlyTrueSender + action 0 + 2862 : 1 +state 2388 observe3Greater1 observeIGreater1 + action 0 + 2863 : 1 +state 2389 observe3Greater1 observeIGreater1 + action 0 + 2864 : 0.833 + 2865 : 0.167 +state 2390 observe3Greater1 observeIGreater1 + action 0 + 2866 : 1 +state 2391 observe3Greater1 observeIGreater1 + action 0 + 2867 : 0.833 + 2868 : 0.167 +state 2392 observe3Greater1 observeIGreater1 + action 0 + 2869 : 1 +state 2393 observe3Greater1 observeIGreater1 + action 0 + 2870 : 0.833 + 2871 : 0.167 +state 2394 observe3Greater1 observeIGreater1 + action 0 + 2872 : 1 +state 2395 observe3Greater1 observeIGreater1 + action 0 + 2873 : 0.833 + 2874 : 0.167 +state 2396 observe3Greater1 observeIGreater1 + action 0 + 2875 : 1 +state 2397 observe3Greater1 observeIGreater1 + action 0 + 2876 : 1 +state 2398 + action 0 + 2877 : 1 +state 2399 + action 0 + 2878 : 0.833 + 2879 : 0.167 +state 2400 + action 0 + 2880 : 1 +state 2401 + action 0 + 2881 : 0.833 + 2882 : 0.167 +state 2402 + action 0 + 2883 : 1 +state 2403 + action 0 + 2884 : 0.833 + 2885 : 0.167 +state 2404 + action 0 + 2886 : 1 +state 2405 + action 0 + 2887 : 0.833 + 2888 : 0.167 +state 2406 + action 0 + 2889 : 1 +state 2407 + action 0 + 2890 : 1 +state 2408 + action 0 + 2786 : 1 +state 2409 + action 0 + 2838 : 1 +state 2410 observe3Greater1 observeIGreater1 + action 0 + 2876 : 1 +state 2411 + action 0 + 2890 : 1 +state 2412 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 0.8 + 2891 : 0.2 +state 2413 observe0Greater1 observeOnlyTrueSender + action 0 + 2892 : 0.8 + 2893 : 0.2 +state 2414 observe0Greater1 observeOnlyTrueSender + action 0 + 2894 : 0.8 + 2895 : 0.2 +state 2415 observe0Greater1 observeOnlyTrueSender + action 0 + 2896 : 0.8 + 2897 : 0.2 +state 2416 observe0Greater1 observeOnlyTrueSender + action 0 + 2898 : 0.8 + 2899 : 0.2 +state 2417 observe0Greater1 observeOnlyTrueSender + action 0 + 2900 : 1 +state 2418 observe4Greater1 observeIGreater1 + action 0 + 2901 : 1 +state 2419 observe4Greater1 observeIGreater1 + action 0 + 2902 : 0.833 + 2903 : 0.167 +state 2420 observe4Greater1 observeIGreater1 + action 0 + 2904 : 1 +state 2421 observe4Greater1 observeIGreater1 + action 0 + 2905 : 0.833 + 2906 : 0.167 +state 2422 observe4Greater1 observeIGreater1 + action 0 + 2907 : 1 +state 2423 observe4Greater1 observeIGreater1 + action 0 + 2908 : 0.833 + 2909 : 0.167 +state 2424 observe4Greater1 observeIGreater1 + action 0 + 2910 : 1 +state 2425 observe4Greater1 observeIGreater1 + action 0 + 2911 : 0.833 + 2912 : 0.167 +state 2426 observe4Greater1 observeIGreater1 + action 0 + 2913 : 1 +state 2427 observe4Greater1 observeIGreater1 + action 0 + 2914 : 1 +state 2428 + action 0 + 2800 : 1 +state 2429 + action 0 + 2852 : 1 +state 2430 + action 0 + 2890 : 1 +state 2431 observe4Greater1 observeIGreater1 + action 0 + 2914 : 1 +state 2432 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 0.8 + 2915 : 0.2 +state 2433 observe0Greater1 observeOnlyTrueSender + action 0 + 2916 : 0.8 + 2917 : 0.2 +state 2434 observe0Greater1 observeOnlyTrueSender + action 0 + 2918 : 0.8 + 2919 : 0.2 +state 2435 observe0Greater1 observeOnlyTrueSender + action 0 + 2920 : 0.8 + 2921 : 0.2 +state 2436 observe0Greater1 observeOnlyTrueSender + action 0 + 2922 : 0.8 + 2923 : 0.2 +state 2437 observe0Greater1 observeOnlyTrueSender + action 0 + 2924 : 1 +state 2438 observe0Greater1 observeOnlyTrueSender + action 0 + 2925 : 1 +state 2439 observe0Greater1 observeOnlyTrueSender + action 0 + 2926 : 1 +state 2440 observe0Greater1 observeOnlyTrueSender + action 0 + 2927 : 1 +state 2441 observe0Greater1 observeOnlyTrueSender + action 0 + 2928 : 1 +state 2442 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 2443 observe1Greater1 observeIGreater1 + action 0 + 2934 : 1 +state 2444 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 2445 observe1Greater1 observeIGreater1 + action 0 + 2940 : 1 +state 2446 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 2447 observe1Greater1 observeIGreater1 + action 0 + 2946 : 1 +state 2448 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 2449 observe1Greater1 observeIGreater1 + action 0 + 2952 : 1 +state 2450 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2451 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2452 observe1Greater1 observeIGreater1 + action 0 + 2954 : 1 +state 2453 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2454 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2455 observe1Greater1 observeIGreater1 + action 0 + 2955 : 1 +state 2456 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2457 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2458 observe1Greater1 observeIGreater1 + action 0 + 2956 : 1 +state 2459 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2460 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2461 observe1Greater1 observeIGreater1 + action 0 + 2957 : 1 +state 2462 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2463 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2958 : 0.833 + 2959 : 0.167 +state 2464 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 2465 observe2Greater1 observeIGreater1 + action 0 + 2965 : 1 +state 2466 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 2467 + action 0 + 2971 : 1 +state 2468 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 2469 + action 0 + 2977 : 1 +state 2470 + action 0 + 2978 : 1 +state 2471 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2472 + action 0 + 2979 : 1 +state 2473 + action 0 + 2978 : 1 +state 2474 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2475 + action 0 + 2980 : 1 +state 2476 + action 0 + 2978 : 1 +state 2477 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2478 + action 0 + 2981 : 1 +state 2479 + action 0 + 2978 : 1 +state 2480 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2481 + action 0 + 2982 : 1 +state 2482 + action 0 + 2978 : 1 +state 2483 observe0Greater1 observeOnlyTrueSender + action 0 + 2983 : 0.833 + 2984 : 0.167 +state 2484 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 2485 observe3Greater1 observeIGreater1 + action 0 + 2990 : 1 +state 2486 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 2487 + action 0 + 2996 : 1 +state 2488 + action 0 + 2997 : 1 +state 2489 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2490 + action 0 + 2998 : 1 +state 2491 + action 0 + 2997 : 1 +state 2492 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2493 + action 0 + 2999 : 1 +state 2494 + action 0 + 2997 : 1 +state 2495 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2496 + action 0 + 3000 : 1 +state 2497 + action 0 + 2997 : 1 +state 2498 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2499 + action 0 + 3001 : 1 +state 2500 + action 0 + 2997 : 1 +state 2501 observe0Greater1 observeOnlyTrueSender + action 0 + 3002 : 0.833 + 3003 : 0.167 +state 2502 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 2503 observe4Greater1 observeIGreater1 + action 0 + 3009 : 1 +state 2504 + action 0 + 3010 : 1 +state 2505 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2506 + action 0 + 3011 : 1 +state 2507 + action 0 + 3010 : 1 +state 2508 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2509 + action 0 + 3012 : 1 +state 2510 + action 0 + 3010 : 1 +state 2511 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2512 + action 0 + 3013 : 1 +state 2513 + action 0 + 3010 : 1 +state 2514 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2515 + action 0 + 3014 : 1 +state 2516 + action 0 + 3010 : 1 +state 2517 observe0Greater1 observeOnlyTrueSender + action 0 + 3015 : 0.833 + 3016 : 0.167 +state 2518 observe0Greater1 observeOnlyTrueSender + action 0 + 1788 : 0.833 + 1789 : 0.167 +state 2519 observe0Greater1 observeOnlyTrueSender + action 0 + 3017 : 1 +state 2520 observe0Greater1 observeOnlyTrueSender + action 0 + 3018 : 0.833 + 3019 : 0.167 +state 2521 observe0Greater1 observeOnlyTrueSender + action 0 + 3020 : 1 +state 2522 observe0Greater1 observeOnlyTrueSender + action 0 + 3021 : 0.833 + 3022 : 0.167 +state 2523 observe0Greater1 observeOnlyTrueSender + action 0 + 3023 : 1 +state 2524 observe0Greater1 observeOnlyTrueSender + action 0 + 3024 : 0.833 + 3025 : 0.167 +state 2525 observe0Greater1 observeOnlyTrueSender + action 0 + 3026 : 1 +state 2526 observe0Greater1 observeOnlyTrueSender + action 0 + 3027 : 0.833 + 3028 : 0.167 +state 2527 observe0Greater1 observeOnlyTrueSender + action 0 + 3029 : 1 +state 2528 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2528 : 1 +state 2529 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 2530 observe2Greater1 observeIGreater1 + action 0 + 3035 : 1 +state 2531 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 2532 observe2Greater1 observeIGreater1 + action 0 + 3041 : 1 +state 2533 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 2534 observe2Greater1 observeIGreater1 + action 0 + 3047 : 1 +state 2535 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2536 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2537 observe2Greater1 observeIGreater1 + action 0 + 3049 : 1 +state 2538 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2539 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2540 observe2Greater1 observeIGreater1 + action 0 + 3050 : 1 +state 2541 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2542 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2543 observe2Greater1 observeIGreater1 + action 0 + 3051 : 1 +state 2544 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2545 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2546 observe2Greater1 observeIGreater1 + action 0 + 3052 : 1 +state 2547 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2548 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3053 : 0.833 + 3054 : 0.167 +state 2549 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 2550 observe3Greater1 observeIGreater1 + action 0 + 3060 : 1 +state 2551 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 2552 + action 0 + 3066 : 1 +state 2553 + action 0 + 3067 : 1 +state 2554 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2555 + action 0 + 3068 : 1 +state 2556 + action 0 + 3067 : 1 +state 2557 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2558 + action 0 + 3069 : 1 +state 2559 + action 0 + 3067 : 1 +state 2560 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2561 + action 0 + 3070 : 1 +state 2562 + action 0 + 3067 : 1 +state 2563 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2564 + action 0 + 3071 : 1 +state 2565 + action 0 + 3067 : 1 +state 2566 observe0Greater1 observeOnlyTrueSender + action 0 + 3072 : 0.833 + 3073 : 0.167 +state 2567 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 2568 observe4Greater1 observeIGreater1 + action 0 + 3079 : 1 +state 2569 + action 0 + 3080 : 1 +state 2570 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2571 + action 0 + 3081 : 1 +state 2572 + action 0 + 3080 : 1 +state 2573 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2574 + action 0 + 3082 : 1 +state 2575 + action 0 + 3080 : 1 +state 2576 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2577 + action 0 + 3083 : 1 +state 2578 + action 0 + 3080 : 1 +state 2579 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2580 + action 0 + 3084 : 1 +state 2581 + action 0 + 3080 : 1 +state 2582 observe0Greater1 observeOnlyTrueSender + action 0 + 3085 : 0.833 + 3086 : 0.167 +state 2583 observe0Greater1 observeOnlyTrueSender + action 0 + 1825 : 0.833 + 1826 : 0.167 +state 2584 observe0Greater1 observeOnlyTrueSender + action 0 + 3087 : 1 +state 2585 observe0Greater1 observeOnlyTrueSender + action 0 + 3088 : 0.833 + 3089 : 0.167 +state 2586 observe0Greater1 observeOnlyTrueSender + action 0 + 3090 : 1 +state 2587 observe0Greater1 observeOnlyTrueSender + action 0 + 3091 : 0.833 + 3092 : 0.167 +state 2588 observe0Greater1 observeOnlyTrueSender + action 0 + 3093 : 1 +state 2589 observe0Greater1 observeOnlyTrueSender + action 0 + 3094 : 0.833 + 3095 : 0.167 +state 2590 observe0Greater1 observeOnlyTrueSender + action 0 + 3096 : 1 +state 2591 observe0Greater1 observeOnlyTrueSender + action 0 + 3097 : 0.833 + 3098 : 0.167 +state 2592 observe0Greater1 observeOnlyTrueSender + action 0 + 3099 : 1 +state 2593 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2593 : 1 +state 2594 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 2595 observe3Greater1 observeIGreater1 + action 0 + 3105 : 1 +state 2596 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 2597 observe3Greater1 observeIGreater1 + action 0 + 3111 : 1 +state 2598 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2599 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2600 observe3Greater1 observeIGreater1 + action 0 + 3113 : 1 +state 2601 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2602 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2603 observe3Greater1 observeIGreater1 + action 0 + 3114 : 1 +state 2604 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2605 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2606 observe3Greater1 observeIGreater1 + action 0 + 3115 : 1 +state 2607 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2608 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2609 observe3Greater1 observeIGreater1 + action 0 + 3116 : 1 +state 2610 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2611 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3117 : 0.833 + 3118 : 0.167 +state 2612 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 2613 observe4Greater1 observeIGreater1 + action 0 + 3124 : 1 +state 2614 + action 0 + 3125 : 1 +state 2615 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2616 + action 0 + 3126 : 1 +state 2617 + action 0 + 3125 : 1 +state 2618 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2619 + action 0 + 3127 : 1 +state 2620 + action 0 + 3125 : 1 +state 2621 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2622 + action 0 + 3128 : 1 +state 2623 + action 0 + 3125 : 1 +state 2624 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2625 + action 0 + 3129 : 1 +state 2626 + action 0 + 3125 : 1 +state 2627 observe0Greater1 observeOnlyTrueSender + action 0 + 3130 : 0.833 + 3131 : 0.167 +state 2628 observe0Greater1 observeOnlyTrueSender + action 0 + 1852 : 0.833 + 1853 : 0.167 +state 2629 observe0Greater1 observeOnlyTrueSender + action 0 + 3132 : 1 +state 2630 observe0Greater1 observeOnlyTrueSender + action 0 + 3133 : 0.833 + 3134 : 0.167 +state 2631 observe0Greater1 observeOnlyTrueSender + action 0 + 3135 : 1 +state 2632 observe0Greater1 observeOnlyTrueSender + action 0 + 3136 : 0.833 + 3137 : 0.167 +state 2633 observe0Greater1 observeOnlyTrueSender + action 0 + 3138 : 1 +state 2634 observe0Greater1 observeOnlyTrueSender + action 0 + 3139 : 0.833 + 3140 : 0.167 +state 2635 observe0Greater1 observeOnlyTrueSender + action 0 + 3141 : 1 +state 2636 observe0Greater1 observeOnlyTrueSender + action 0 + 3142 : 0.833 + 3143 : 0.167 +state 2637 observe0Greater1 observeOnlyTrueSender + action 0 + 3144 : 1 +state 2638 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2638 : 1 +state 2639 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 2640 observe4Greater1 observeIGreater1 + action 0 + 3150 : 1 +state 2641 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2642 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2643 observe4Greater1 observeIGreater1 + action 0 + 3152 : 1 +state 2644 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2645 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2646 observe4Greater1 observeIGreater1 + action 0 + 3153 : 1 +state 2647 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2648 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2649 observe4Greater1 observeIGreater1 + action 0 + 3154 : 1 +state 2650 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2651 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2652 observe4Greater1 observeIGreater1 + action 0 + 3155 : 1 +state 2653 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2654 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3156 : 0.833 + 3157 : 0.167 +state 2655 observe0Greater1 observeOnlyTrueSender + action 0 + 1869 : 0.833 + 1870 : 0.167 +state 2656 observe0Greater1 observeOnlyTrueSender + action 0 + 3158 : 1 +state 2657 observe0Greater1 observeOnlyTrueSender + action 0 + 3159 : 0.833 + 3160 : 0.167 +state 2658 observe0Greater1 observeOnlyTrueSender + action 0 + 3161 : 1 +state 2659 observe0Greater1 observeOnlyTrueSender + action 0 + 3162 : 0.833 + 3163 : 0.167 +state 2660 observe0Greater1 observeOnlyTrueSender + action 0 + 3164 : 1 +state 2661 observe0Greater1 observeOnlyTrueSender + action 0 + 3165 : 0.833 + 3166 : 0.167 +state 2662 observe0Greater1 observeOnlyTrueSender + action 0 + 3167 : 1 +state 2663 observe0Greater1 observeOnlyTrueSender + action 0 + 3168 : 0.833 + 3169 : 0.167 +state 2664 observe0Greater1 observeOnlyTrueSender + action 0 + 3170 : 1 +state 2665 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2665 : 1 +state 2666 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2666 : 1 +state 2667 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2667 : 1 +state 2668 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2668 : 1 +state 2669 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2669 : 1 +state 2670 + action 0 + 3171 : 1 +state 2671 + action 0 + 3172 : 0.833 + 3173 : 0.167 +state 2672 + action 0 + 3174 : 1 +state 2673 + action 0 + 3175 : 0.833 + 3176 : 0.167 +state 2674 + action 0 + 3177 : 1 +state 2675 + action 0 + 3178 : 0.833 + 3179 : 0.167 +state 2676 + action 0 + 3180 : 1 +state 2677 + action 0 + 3181 : 0.833 + 3182 : 0.167 +state 2678 + action 0 + 3183 : 1 +state 2679 deadlock + action 0 + 2679 : 1 +state 2680 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 2681 + action 0 + 3189 : 1 +state 2682 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 2683 + action 0 + 3195 : 1 +state 2684 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 2685 + action 0 + 3201 : 1 +state 2686 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 2687 + action 0 + 3207 : 1 +state 2688 deadlock + action 0 + 2688 : 1 +state 2689 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2690 + action 0 + 3208 : 1 +state 2691 deadlock + action 0 + 2691 : 1 +state 2692 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2693 + action 0 + 3209 : 1 +state 2694 deadlock + action 0 + 2694 : 1 +state 2695 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2696 + action 0 + 3210 : 1 +state 2697 deadlock + action 0 + 2697 : 1 +state 2698 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2699 + action 0 + 3211 : 1 +state 2700 deadlock + action 0 + 2700 : 1 +state 2701 observe1Greater1 observeIGreater1 + action 0 + 3212 : 1 +state 2702 + action 0 + 3213 : 1 +state 2703 + action 0 + 3214 : 1 +state 2704 + action 0 + 3215 : 1 +state 2705 + action 0 + 1986 : 0.8 + 3216 : 0.2 +state 2706 + action 0 + 3217 : 0.8 + 3218 : 0.2 +state 2707 + action 0 + 3219 : 0.8 + 3220 : 0.2 +state 2708 + action 0 + 3221 : 0.8 + 3222 : 0.2 +state 2709 + action 0 + 3223 : 0.8 + 3224 : 0.2 +state 2710 observe0Greater1 observeOnlyTrueSender + action 0 + 3225 : 1 +state 2711 + action 0 + 3213 : 1 +state 2712 observe2Greater1 observeIGreater1 + action 0 + 3226 : 1 +state 2713 + action 0 + 3227 : 1 +state 2714 + action 0 + 3228 : 1 +state 2715 + action 0 + 2011 : 0.8 + 3229 : 0.2 +state 2716 + action 0 + 3230 : 0.8 + 3231 : 0.2 +state 2717 + action 0 + 3232 : 0.8 + 3233 : 0.2 +state 2718 + action 0 + 3234 : 0.8 + 3235 : 0.2 +state 2719 + action 0 + 3236 : 0.8 + 3237 : 0.2 +state 2720 observe0Greater1 observeOnlyTrueSender + action 0 + 3238 : 1 +state 2721 + action 0 + 3214 : 1 +state 2722 + action 0 + 3227 : 1 +state 2723 observe3Greater1 observeIGreater1 + action 0 + 3239 : 1 +state 2724 + action 0 + 3240 : 1 +state 2725 + action 0 + 2030 : 0.8 + 3241 : 0.2 +state 2726 + action 0 + 3242 : 0.8 + 3243 : 0.2 +state 2727 + action 0 + 3244 : 0.8 + 3245 : 0.2 +state 2728 + action 0 + 3246 : 0.8 + 3247 : 0.2 +state 2729 + action 0 + 3248 : 0.8 + 3249 : 0.2 +state 2730 observe0Greater1 observeOnlyTrueSender + action 0 + 3250 : 1 +state 2731 + action 0 + 3215 : 1 +state 2732 + action 0 + 3228 : 1 +state 2733 + action 0 + 3240 : 1 +state 2734 observe4Greater1 observeIGreater1 + action 0 + 3251 : 1 +state 2735 + action 0 + 2043 : 0.8 + 3252 : 0.2 +state 2736 + action 0 + 3253 : 0.8 + 3254 : 0.2 +state 2737 + action 0 + 3255 : 0.8 + 3256 : 0.2 +state 2738 + action 0 + 3257 : 0.8 + 3258 : 0.2 +state 2739 + action 0 + 3259 : 0.8 + 3260 : 0.2 +state 2740 observe0Greater1 observeOnlyTrueSender + action 0 + 3261 : 1 +state 2741 observe0Greater1 observeOnlyTrueSender + action 0 + 3262 : 1 +state 2742 observe0Greater1 observeOnlyTrueSender + action 0 + 3263 : 1 +state 2743 observe0Greater1 observeOnlyTrueSender + action 0 + 3264 : 1 +state 2744 observe0Greater1 observeOnlyTrueSender + action 0 + 3265 : 1 +state 2745 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2746 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2747 observe1Greater1 observeIGreater1 + action 0 + 3267 : 1 +state 2748 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2749 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2750 observe1Greater1 observeIGreater1 + action 0 + 3268 : 1 +state 2751 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2752 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2753 observe1Greater1 observeIGreater1 + action 0 + 3269 : 1 +state 2754 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2755 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2756 observe1Greater1 observeIGreater1 + action 0 + 3270 : 1 +state 2757 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2758 observe1Greater1 observeIGreater1 + action 0 + 3271 : 0.833 + 3272 : 0.167 +state 2759 + action 0 + 3273 : 1 +state 2760 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2761 + action 0 + 3274 : 1 +state 2762 + action 0 + 3273 : 1 +state 2763 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2764 + action 0 + 3275 : 1 +state 2765 + action 0 + 3273 : 1 +state 2766 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2767 + action 0 + 3276 : 1 +state 2768 + action 0 + 3273 : 1 +state 2769 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2770 + action 0 + 3277 : 1 +state 2771 + action 0 + 3273 : 1 +state 2772 + action 0 + 3278 : 0.833 + 3279 : 0.167 +state 2773 + action 0 + 3280 : 1 +state 2774 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2775 + action 0 + 3281 : 1 +state 2776 + action 0 + 3280 : 1 +state 2777 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2778 + action 0 + 3282 : 1 +state 2779 + action 0 + 3280 : 1 +state 2780 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2781 + action 0 + 3283 : 1 +state 2782 + action 0 + 3280 : 1 +state 2783 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2784 + action 0 + 3284 : 1 +state 2785 + action 0 + 3280 : 1 +state 2786 + action 0 + 3285 : 0.833 + 3286 : 0.167 +state 2787 + action 0 + 3287 : 1 +state 2788 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2789 + action 0 + 3288 : 1 +state 2790 + action 0 + 3287 : 1 +state 2791 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2792 + action 0 + 3289 : 1 +state 2793 + action 0 + 3287 : 1 +state 2794 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2795 + action 0 + 3290 : 1 +state 2796 + action 0 + 3287 : 1 +state 2797 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2798 + action 0 + 3291 : 1 +state 2799 + action 0 + 3287 : 1 +state 2800 + action 0 + 3292 : 0.833 + 3293 : 0.167 +state 2801 observe0Greater1 observeOnlyTrueSender + action 0 + 3294 : 1 +state 2802 observe0Greater1 observeOnlyTrueSender + action 0 + 3295 : 0.833 + 3296 : 0.167 +state 2803 observe0Greater1 observeOnlyTrueSender + action 0 + 3297 : 1 +state 2804 observe0Greater1 observeOnlyTrueSender + action 0 + 3298 : 0.833 + 3299 : 0.167 +state 2805 observe0Greater1 observeOnlyTrueSender + action 0 + 3300 : 1 +state 2806 observe0Greater1 observeOnlyTrueSender + action 0 + 3301 : 0.833 + 3302 : 0.167 +state 2807 observe0Greater1 observeOnlyTrueSender + action 0 + 3303 : 1 +state 2808 observe0Greater1 observeOnlyTrueSender + action 0 + 3304 : 0.833 + 3305 : 0.167 +state 2809 observe0Greater1 observeOnlyTrueSender + action 0 + 3306 : 1 +state 2810 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2810 : 1 +state 2811 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2812 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2813 observe2Greater1 observeIGreater1 + action 0 + 3308 : 1 +state 2814 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2815 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2816 observe2Greater1 observeIGreater1 + action 0 + 3309 : 1 +state 2817 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2818 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2819 observe2Greater1 observeIGreater1 + action 0 + 3310 : 1 +state 2820 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2821 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2822 observe2Greater1 observeIGreater1 + action 0 + 3311 : 1 +state 2823 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2824 observe2Greater1 observeIGreater1 + action 0 + 3312 : 0.833 + 3313 : 0.167 +state 2825 + action 0 + 3314 : 1 +state 2826 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2827 + action 0 + 3315 : 1 +state 2828 + action 0 + 3314 : 1 +state 2829 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2830 + action 0 + 3316 : 1 +state 2831 + action 0 + 3314 : 1 +state 2832 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2833 + action 0 + 3317 : 1 +state 2834 + action 0 + 3314 : 1 +state 2835 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2836 + action 0 + 3318 : 1 +state 2837 + action 0 + 3314 : 1 +state 2838 + action 0 + 3319 : 0.833 + 3320 : 0.167 +state 2839 + action 0 + 3321 : 1 +state 2840 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2841 + action 0 + 3322 : 1 +state 2842 + action 0 + 3321 : 1 +state 2843 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2844 + action 0 + 3323 : 1 +state 2845 + action 0 + 3321 : 1 +state 2846 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2847 + action 0 + 3324 : 1 +state 2848 + action 0 + 3321 : 1 +state 2849 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2850 + action 0 + 3325 : 1 +state 2851 + action 0 + 3321 : 1 +state 2852 + action 0 + 3326 : 0.833 + 3327 : 0.167 +state 2853 observe0Greater1 observeOnlyTrueSender + action 0 + 3328 : 1 +state 2854 observe0Greater1 observeOnlyTrueSender + action 0 + 3329 : 0.833 + 3330 : 0.167 +state 2855 observe0Greater1 observeOnlyTrueSender + action 0 + 3331 : 1 +state 2856 observe0Greater1 observeOnlyTrueSender + action 0 + 3332 : 0.833 + 3333 : 0.167 +state 2857 observe0Greater1 observeOnlyTrueSender + action 0 + 3334 : 1 +state 2858 observe0Greater1 observeOnlyTrueSender + action 0 + 3335 : 0.833 + 3336 : 0.167 +state 2859 observe0Greater1 observeOnlyTrueSender + action 0 + 3337 : 1 +state 2860 observe0Greater1 observeOnlyTrueSender + action 0 + 3338 : 0.833 + 3339 : 0.167 +state 2861 observe0Greater1 observeOnlyTrueSender + action 0 + 3340 : 1 +state 2862 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2862 : 1 +state 2863 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2864 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2865 observe3Greater1 observeIGreater1 + action 0 + 3342 : 1 +state 2866 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2867 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2868 observe3Greater1 observeIGreater1 + action 0 + 3343 : 1 +state 2869 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2870 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2871 observe3Greater1 observeIGreater1 + action 0 + 3344 : 1 +state 2872 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2873 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2874 observe3Greater1 observeIGreater1 + action 0 + 3345 : 1 +state 2875 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2876 observe3Greater1 observeIGreater1 + action 0 + 3346 : 0.833 + 3347 : 0.167 +state 2877 + action 0 + 3348 : 1 +state 2878 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2879 + action 0 + 3349 : 1 +state 2880 + action 0 + 3348 : 1 +state 2881 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2882 + action 0 + 3350 : 1 +state 2883 + action 0 + 3348 : 1 +state 2884 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2885 + action 0 + 3351 : 1 +state 2886 + action 0 + 3348 : 1 +state 2887 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2888 + action 0 + 3352 : 1 +state 2889 + action 0 + 3348 : 1 +state 2890 + action 0 + 3353 : 0.833 + 3354 : 0.167 +state 2891 observe0Greater1 observeOnlyTrueSender + action 0 + 3355 : 1 +state 2892 observe0Greater1 observeOnlyTrueSender + action 0 + 3356 : 0.833 + 3357 : 0.167 +state 2893 observe0Greater1 observeOnlyTrueSender + action 0 + 3358 : 1 +state 2894 observe0Greater1 observeOnlyTrueSender + action 0 + 3359 : 0.833 + 3360 : 0.167 +state 2895 observe0Greater1 observeOnlyTrueSender + action 0 + 3361 : 1 +state 2896 observe0Greater1 observeOnlyTrueSender + action 0 + 3362 : 0.833 + 3363 : 0.167 +state 2897 observe0Greater1 observeOnlyTrueSender + action 0 + 3364 : 1 +state 2898 observe0Greater1 observeOnlyTrueSender + action 0 + 3365 : 0.833 + 3366 : 0.167 +state 2899 observe0Greater1 observeOnlyTrueSender + action 0 + 3367 : 1 +state 2900 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2900 : 1 +state 2901 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2902 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2903 observe4Greater1 observeIGreater1 + action 0 + 3369 : 1 +state 2904 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2905 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2906 observe4Greater1 observeIGreater1 + action 0 + 3370 : 1 +state 2907 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2908 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2909 observe4Greater1 observeIGreater1 + action 0 + 3371 : 1 +state 2910 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2911 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2912 observe4Greater1 observeIGreater1 + action 0 + 3372 : 1 +state 2913 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2914 observe4Greater1 observeIGreater1 + action 0 + 3373 : 0.833 + 3374 : 0.167 +state 2915 observe0Greater1 observeOnlyTrueSender + action 0 + 3375 : 1 +state 2916 observe0Greater1 observeOnlyTrueSender + action 0 + 3376 : 0.833 + 3377 : 0.167 +state 2917 observe0Greater1 observeOnlyTrueSender + action 0 + 3378 : 1 +state 2918 observe0Greater1 observeOnlyTrueSender + action 0 + 3379 : 0.833 + 3380 : 0.167 +state 2919 observe0Greater1 observeOnlyTrueSender + action 0 + 3381 : 1 +state 2920 observe0Greater1 observeOnlyTrueSender + action 0 + 3382 : 0.833 + 3383 : 0.167 +state 2921 observe0Greater1 observeOnlyTrueSender + action 0 + 3384 : 1 +state 2922 observe0Greater1 observeOnlyTrueSender + action 0 + 3385 : 0.833 + 3386 : 0.167 +state 2923 observe0Greater1 observeOnlyTrueSender + action 0 + 3387 : 1 +state 2924 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2924 : 1 +state 2925 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2925 : 1 +state 2926 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2926 : 1 +state 2927 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2927 : 1 +state 2928 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2928 : 1 +state 2929 observe1Greater1 observeIGreater1 + action 0 + 3388 : 0.8 + 3389 : 0.2 +state 2930 observe1Greater1 observeIGreater1 + action 0 + 3390 : 0.8 + 3391 : 0.2 +state 2931 observe1Greater1 observeIGreater1 + action 0 + 3392 : 0.8 + 3393 : 0.2 +state 2932 observe1Greater1 observeIGreater1 + action 0 + 3394 : 0.8 + 3395 : 0.2 +state 2933 observe1Greater1 observeIGreater1 + action 0 + 3396 : 0.8 + 3397 : 0.2 +state 2934 observe1Greater1 observeIGreater1 + action 0 + 3398 : 1 +state 2935 observe1Greater1 observeIGreater1 + action 0 + 3399 : 0.8 + 3400 : 0.2 +state 2936 observe1Greater1 observeIGreater1 + action 0 + 3401 : 0.8 + 3402 : 0.2 +state 2937 observe1Greater1 observeIGreater1 + action 0 + 3403 : 0.8 + 3404 : 0.2 +state 2938 observe1Greater1 observeIGreater1 + action 0 + 3405 : 0.8 + 3406 : 0.2 +state 2939 observe1Greater1 observeIGreater1 + action 0 + 3407 : 0.8 + 3408 : 0.2 +state 2940 observe1Greater1 observeIGreater1 + action 0 + 3409 : 1 +state 2941 observe1Greater1 observeIGreater1 + action 0 + 3410 : 0.8 + 3411 : 0.2 +state 2942 observe1Greater1 observeIGreater1 + action 0 + 3412 : 0.8 + 3413 : 0.2 +state 2943 observe1Greater1 observeIGreater1 + action 0 + 3414 : 0.8 + 3415 : 0.2 +state 2944 observe1Greater1 observeIGreater1 + action 0 + 3416 : 0.8 + 3417 : 0.2 +state 2945 observe1Greater1 observeIGreater1 + action 0 + 3418 : 0.8 + 3419 : 0.2 +state 2946 observe1Greater1 observeIGreater1 + action 0 + 3420 : 1 +state 2947 observe1Greater1 observeIGreater1 + action 0 + 3421 : 0.8 + 3422 : 0.2 +state 2948 observe1Greater1 observeIGreater1 + action 0 + 3423 : 0.8 + 3424 : 0.2 +state 2949 observe1Greater1 observeIGreater1 + action 0 + 3425 : 0.8 + 3426 : 0.2 +state 2950 observe1Greater1 observeIGreater1 + action 0 + 3427 : 0.8 + 3428 : 0.2 +state 2951 observe1Greater1 observeIGreater1 + action 0 + 3429 : 0.8 + 3430 : 0.2 +state 2952 observe1Greater1 observeIGreater1 + action 0 + 3431 : 1 +state 2953 observe1Greater1 observeIGreater1 + action 0 + 3271 : 0.833 + 3272 : 0.167 +state 2954 observe1Greater1 observeIGreater1 + action 0 + 3432 : 1 +state 2955 observe1Greater1 observeIGreater1 + action 0 + 3433 : 1 +state 2956 observe1Greater1 observeIGreater1 + action 0 + 3434 : 1 +state 2957 observe1Greater1 observeIGreater1 + action 0 + 3435 : 1 +state 2958 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 2959 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3441 : 1 +state 2960 observe2Greater1 observeIGreater1 + action 0 + 3442 : 0.8 + 3443 : 0.2 +state 2961 observe2Greater1 observeIGreater1 + action 0 + 3444 : 0.8 + 3445 : 0.2 +state 2962 observe2Greater1 observeIGreater1 + action 0 + 3446 : 0.8 + 3447 : 0.2 +state 2963 observe2Greater1 observeIGreater1 + action 0 + 3448 : 0.8 + 3449 : 0.2 +state 2964 observe2Greater1 observeIGreater1 + action 0 + 3450 : 0.8 + 3451 : 0.2 +state 2965 observe2Greater1 observeIGreater1 + action 0 + 3452 : 1 +state 2966 + action 0 + 3453 : 0.8 + 3454 : 0.2 +state 2967 + action 0 + 3455 : 0.8 + 3456 : 0.2 +state 2968 + action 0 + 3457 : 0.8 + 3458 : 0.2 +state 2969 + action 0 + 3459 : 0.8 + 3460 : 0.2 +state 2970 + action 0 + 3461 : 0.8 + 3462 : 0.2 +state 2971 + action 0 + 3463 : 1 +state 2972 + action 0 + 3464 : 0.8 + 3465 : 0.2 +state 2973 + action 0 + 3466 : 0.8 + 3467 : 0.2 +state 2974 + action 0 + 3468 : 0.8 + 3469 : 0.2 +state 2975 + action 0 + 3470 : 0.8 + 3471 : 0.2 +state 2976 + action 0 + 3472 : 0.8 + 3473 : 0.2 +state 2977 + action 0 + 3474 : 1 +state 2978 + action 0 + 3278 : 0.833 + 3279 : 0.167 +state 2979 observe1Greater1 observeIGreater1 + action 0 + 3475 : 1 +state 2980 observe2Greater1 observeIGreater1 + action 0 + 3476 : 1 +state 2981 + action 0 + 3477 : 1 +state 2982 + action 0 + 3478 : 1 +state 2983 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 2984 observe0Greater1 observeOnlyTrueSender + action 0 + 3484 : 1 +state 2985 observe3Greater1 observeIGreater1 + action 0 + 3485 : 0.8 + 3486 : 0.2 +state 2986 observe3Greater1 observeIGreater1 + action 0 + 3487 : 0.8 + 3488 : 0.2 +state 2987 observe3Greater1 observeIGreater1 + action 0 + 3489 : 0.8 + 3490 : 0.2 +state 2988 observe3Greater1 observeIGreater1 + action 0 + 3491 : 0.8 + 3492 : 0.2 +state 2989 observe3Greater1 observeIGreater1 + action 0 + 3493 : 0.8 + 3494 : 0.2 +state 2990 observe3Greater1 observeIGreater1 + action 0 + 3495 : 1 +state 2991 + action 0 + 3496 : 0.8 + 3497 : 0.2 +state 2992 + action 0 + 3498 : 0.8 + 3499 : 0.2 +state 2993 + action 0 + 3500 : 0.8 + 3501 : 0.2 +state 2994 + action 0 + 3502 : 0.8 + 3503 : 0.2 +state 2995 + action 0 + 3504 : 0.8 + 3505 : 0.2 +state 2996 + action 0 + 3506 : 1 +state 2997 + action 0 + 3285 : 0.833 + 3286 : 0.167 +state 2998 observe1Greater1 observeIGreater1 + action 0 + 3507 : 1 +state 2999 + action 0 + 3508 : 1 +state 3000 observe3Greater1 observeIGreater1 + action 0 + 3509 : 1 +state 3001 + action 0 + 3510 : 1 +state 3002 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 3003 observe0Greater1 observeOnlyTrueSender + action 0 + 3516 : 1 +state 3004 observe4Greater1 observeIGreater1 + action 0 + 3517 : 0.8 + 3518 : 0.2 +state 3005 observe4Greater1 observeIGreater1 + action 0 + 3519 : 0.8 + 3520 : 0.2 +state 3006 observe4Greater1 observeIGreater1 + action 0 + 3521 : 0.8 + 3522 : 0.2 +state 3007 observe4Greater1 observeIGreater1 + action 0 + 3523 : 0.8 + 3524 : 0.2 +state 3008 observe4Greater1 observeIGreater1 + action 0 + 3525 : 0.8 + 3526 : 0.2 +state 3009 observe4Greater1 observeIGreater1 + action 0 + 3527 : 1 +state 3010 + action 0 + 3292 : 0.833 + 3293 : 0.167 +state 3011 observe1Greater1 observeIGreater1 + action 0 + 3528 : 1 +state 3012 + action 0 + 3529 : 1 +state 3013 + action 0 + 3530 : 1 +state 3014 observe4Greater1 observeIGreater1 + action 0 + 3531 : 1 +state 3015 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 3016 observe0Greater1 observeOnlyTrueSender + action 0 + 3537 : 1 +state 3017 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3017 : 1 +state 3018 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3019 observe0Greater1 observeOnlyTrueSender + action 0 + 3538 : 1 +state 3020 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3020 : 1 +state 3021 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3022 observe0Greater1 observeOnlyTrueSender + action 0 + 3539 : 1 +state 3023 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3023 : 1 +state 3024 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3025 observe0Greater1 observeOnlyTrueSender + action 0 + 3540 : 1 +state 3026 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3026 : 1 +state 3027 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3028 observe0Greater1 observeOnlyTrueSender + action 0 + 3541 : 1 +state 3029 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3029 : 1 +state 3030 observe2Greater1 observeIGreater1 + action 0 + 3542 : 0.8 + 3543 : 0.2 +state 3031 observe2Greater1 observeIGreater1 + action 0 + 3544 : 0.8 + 3545 : 0.2 +state 3032 observe2Greater1 observeIGreater1 + action 0 + 3546 : 0.8 + 3547 : 0.2 +state 3033 observe2Greater1 observeIGreater1 + action 0 + 3548 : 0.8 + 3549 : 0.2 +state 3034 observe2Greater1 observeIGreater1 + action 0 + 3550 : 0.8 + 3551 : 0.2 +state 3035 observe2Greater1 observeIGreater1 + action 0 + 3552 : 1 +state 3036 observe2Greater1 observeIGreater1 + action 0 + 3553 : 0.8 + 3554 : 0.2 +state 3037 observe2Greater1 observeIGreater1 + action 0 + 3555 : 0.8 + 3556 : 0.2 +state 3038 observe2Greater1 observeIGreater1 + action 0 + 3557 : 0.8 + 3558 : 0.2 +state 3039 observe2Greater1 observeIGreater1 + action 0 + 3559 : 0.8 + 3560 : 0.2 +state 3040 observe2Greater1 observeIGreater1 + action 0 + 3561 : 0.8 + 3562 : 0.2 +state 3041 observe2Greater1 observeIGreater1 + action 0 + 3563 : 1 +state 3042 observe2Greater1 observeIGreater1 + action 0 + 3564 : 0.8 + 3565 : 0.2 +state 3043 observe2Greater1 observeIGreater1 + action 0 + 3566 : 0.8 + 3567 : 0.2 +state 3044 observe2Greater1 observeIGreater1 + action 0 + 3568 : 0.8 + 3569 : 0.2 +state 3045 observe2Greater1 observeIGreater1 + action 0 + 3570 : 0.8 + 3571 : 0.2 +state 3046 observe2Greater1 observeIGreater1 + action 0 + 3572 : 0.8 + 3573 : 0.2 +state 3047 observe2Greater1 observeIGreater1 + action 0 + 3574 : 1 +state 3048 observe2Greater1 observeIGreater1 + action 0 + 3312 : 0.833 + 3313 : 0.167 +state 3049 observe2Greater1 observeIGreater1 + action 0 + 3575 : 1 +state 3050 observe2Greater1 observeIGreater1 + action 0 + 3576 : 1 +state 3051 observe2Greater1 observeIGreater1 + action 0 + 3577 : 1 +state 3052 observe2Greater1 observeIGreater1 + action 0 + 3578 : 1 +state 3053 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 3054 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3584 : 1 +state 3055 observe3Greater1 observeIGreater1 + action 0 + 3585 : 0.8 + 3586 : 0.2 +state 3056 observe3Greater1 observeIGreater1 + action 0 + 3587 : 0.8 + 3588 : 0.2 +state 3057 observe3Greater1 observeIGreater1 + action 0 + 3589 : 0.8 + 3590 : 0.2 +state 3058 observe3Greater1 observeIGreater1 + action 0 + 3591 : 0.8 + 3592 : 0.2 +state 3059 observe3Greater1 observeIGreater1 + action 0 + 3593 : 0.8 + 3594 : 0.2 +state 3060 observe3Greater1 observeIGreater1 + action 0 + 3595 : 1 +state 3061 + action 0 + 3596 : 0.8 + 3597 : 0.2 +state 3062 + action 0 + 3598 : 0.8 + 3599 : 0.2 +state 3063 + action 0 + 3600 : 0.8 + 3601 : 0.2 +state 3064 + action 0 + 3602 : 0.8 + 3603 : 0.2 +state 3065 + action 0 + 3604 : 0.8 + 3605 : 0.2 +state 3066 + action 0 + 3606 : 1 +state 3067 + action 0 + 3319 : 0.833 + 3320 : 0.167 +state 3068 + action 0 + 3607 : 1 +state 3069 observe2Greater1 observeIGreater1 + action 0 + 3608 : 1 +state 3070 observe3Greater1 observeIGreater1 + action 0 + 3609 : 1 +state 3071 + action 0 + 3610 : 1 +state 3072 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 3073 observe0Greater1 observeOnlyTrueSender + action 0 + 3616 : 1 +state 3074 observe4Greater1 observeIGreater1 + action 0 + 3617 : 0.8 + 3618 : 0.2 +state 3075 observe4Greater1 observeIGreater1 + action 0 + 3619 : 0.8 + 3620 : 0.2 +state 3076 observe4Greater1 observeIGreater1 + action 0 + 3621 : 0.8 + 3622 : 0.2 +state 3077 observe4Greater1 observeIGreater1 + action 0 + 3623 : 0.8 + 3624 : 0.2 +state 3078 observe4Greater1 observeIGreater1 + action 0 + 3625 : 0.8 + 3626 : 0.2 +state 3079 observe4Greater1 observeIGreater1 + action 0 + 3627 : 1 +state 3080 + action 0 + 3326 : 0.833 + 3327 : 0.167 +state 3081 + action 0 + 3628 : 1 +state 3082 observe2Greater1 observeIGreater1 + action 0 + 3629 : 1 +state 3083 + action 0 + 3630 : 1 +state 3084 observe4Greater1 observeIGreater1 + action 0 + 3631 : 1 +state 3085 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 3086 observe0Greater1 observeOnlyTrueSender + action 0 + 3637 : 1 +state 3087 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3087 : 1 +state 3088 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3089 observe0Greater1 observeOnlyTrueSender + action 0 + 3638 : 1 +state 3090 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3090 : 1 +state 3091 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3092 observe0Greater1 observeOnlyTrueSender + action 0 + 3639 : 1 +state 3093 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3093 : 1 +state 3094 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3095 observe0Greater1 observeOnlyTrueSender + action 0 + 3640 : 1 +state 3096 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3096 : 1 +state 3097 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3098 observe0Greater1 observeOnlyTrueSender + action 0 + 3641 : 1 +state 3099 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3099 : 1 +state 3100 observe3Greater1 observeIGreater1 + action 0 + 3642 : 0.8 + 3643 : 0.2 +state 3101 observe3Greater1 observeIGreater1 + action 0 + 3644 : 0.8 + 3645 : 0.2 +state 3102 observe3Greater1 observeIGreater1 + action 0 + 3646 : 0.8 + 3647 : 0.2 +state 3103 observe3Greater1 observeIGreater1 + action 0 + 3648 : 0.8 + 3649 : 0.2 +state 3104 observe3Greater1 observeIGreater1 + action 0 + 3650 : 0.8 + 3651 : 0.2 +state 3105 observe3Greater1 observeIGreater1 + action 0 + 3652 : 1 +state 3106 observe3Greater1 observeIGreater1 + action 0 + 3653 : 0.8 + 3654 : 0.2 +state 3107 observe3Greater1 observeIGreater1 + action 0 + 3655 : 0.8 + 3656 : 0.2 +state 3108 observe3Greater1 observeIGreater1 + action 0 + 3657 : 0.8 + 3658 : 0.2 +state 3109 observe3Greater1 observeIGreater1 + action 0 + 3659 : 0.8 + 3660 : 0.2 +state 3110 observe3Greater1 observeIGreater1 + action 0 + 3661 : 0.8 + 3662 : 0.2 +state 3111 observe3Greater1 observeIGreater1 + action 0 + 3663 : 1 +state 3112 observe3Greater1 observeIGreater1 + action 0 + 3346 : 0.833 + 3347 : 0.167 +state 3113 observe3Greater1 observeIGreater1 + action 0 + 3664 : 1 +state 3114 observe3Greater1 observeIGreater1 + action 0 + 3665 : 1 +state 3115 observe3Greater1 observeIGreater1 + action 0 + 3666 : 1 +state 3116 observe3Greater1 observeIGreater1 + action 0 + 3667 : 1 +state 3117 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 3118 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3673 : 1 +state 3119 observe4Greater1 observeIGreater1 + action 0 + 3674 : 0.8 + 3675 : 0.2 +state 3120 observe4Greater1 observeIGreater1 + action 0 + 3676 : 0.8 + 3677 : 0.2 +state 3121 observe4Greater1 observeIGreater1 + action 0 + 3678 : 0.8 + 3679 : 0.2 +state 3122 observe4Greater1 observeIGreater1 + action 0 + 3680 : 0.8 + 3681 : 0.2 +state 3123 observe4Greater1 observeIGreater1 + action 0 + 3682 : 0.8 + 3683 : 0.2 +state 3124 observe4Greater1 observeIGreater1 + action 0 + 3684 : 1 +state 3125 + action 0 + 3353 : 0.833 + 3354 : 0.167 +state 3126 + action 0 + 3685 : 1 +state 3127 + action 0 + 3686 : 1 +state 3128 observe3Greater1 observeIGreater1 + action 0 + 3687 : 1 +state 3129 observe4Greater1 observeIGreater1 + action 0 + 3688 : 1 +state 3130 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 3131 observe0Greater1 observeOnlyTrueSender + action 0 + 3694 : 1 +state 3132 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3132 : 1 +state 3133 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3134 observe0Greater1 observeOnlyTrueSender + action 0 + 3695 : 1 +state 3135 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3135 : 1 +state 3136 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3137 observe0Greater1 observeOnlyTrueSender + action 0 + 3696 : 1 +state 3138 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3138 : 1 +state 3139 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3140 observe0Greater1 observeOnlyTrueSender + action 0 + 3697 : 1 +state 3141 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3141 : 1 +state 3142 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3143 observe0Greater1 observeOnlyTrueSender + action 0 + 3698 : 1 +state 3144 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3144 : 1 +state 3145 observe4Greater1 observeIGreater1 + action 0 + 3699 : 0.8 + 3700 : 0.2 +state 3146 observe4Greater1 observeIGreater1 + action 0 + 3701 : 0.8 + 3702 : 0.2 +state 3147 observe4Greater1 observeIGreater1 + action 0 + 3703 : 0.8 + 3704 : 0.2 +state 3148 observe4Greater1 observeIGreater1 + action 0 + 3705 : 0.8 + 3706 : 0.2 +state 3149 observe4Greater1 observeIGreater1 + action 0 + 3707 : 0.8 + 3708 : 0.2 +state 3150 observe4Greater1 observeIGreater1 + action 0 + 3709 : 1 +state 3151 observe4Greater1 observeIGreater1 + action 0 + 3373 : 0.833 + 3374 : 0.167 +state 3152 observe4Greater1 observeIGreater1 + action 0 + 3710 : 1 +state 3153 observe4Greater1 observeIGreater1 + action 0 + 3711 : 1 +state 3154 observe4Greater1 observeIGreater1 + action 0 + 3712 : 1 +state 3155 observe4Greater1 observeIGreater1 + action 0 + 3713 : 1 +state 3156 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 3157 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3719 : 1 +state 3158 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3158 : 1 +state 3159 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3160 observe0Greater1 observeOnlyTrueSender + action 0 + 3720 : 1 +state 3161 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3161 : 1 +state 3162 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3163 observe0Greater1 observeOnlyTrueSender + action 0 + 3721 : 1 +state 3164 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3164 : 1 +state 3165 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3166 observe0Greater1 observeOnlyTrueSender + action 0 + 3722 : 1 +state 3167 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3167 : 1 +state 3168 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3169 observe0Greater1 observeOnlyTrueSender + action 0 + 3723 : 1 +state 3170 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3170 : 1 +state 3171 deadlock + action 0 + 3171 : 1 +state 3172 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3173 + action 0 + 3724 : 1 +state 3174 deadlock + action 0 + 3174 : 1 +state 3175 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3176 + action 0 + 3725 : 1 +state 3177 deadlock + action 0 + 3177 : 1 +state 3178 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3179 + action 0 + 3726 : 1 +state 3180 deadlock + action 0 + 3180 : 1 +state 3181 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3182 + action 0 + 3727 : 1 +state 3183 deadlock + action 0 + 3183 : 1 +state 3184 + action 0 + 2257 : 0.8 + 3728 : 0.2 +state 3185 + action 0 + 3729 : 0.8 + 3730 : 0.2 +state 3186 + action 0 + 3731 : 0.8 + 3732 : 0.2 +state 3187 + action 0 + 3733 : 0.8 + 3734 : 0.2 +state 3188 + action 0 + 3735 : 0.8 + 3736 : 0.2 +state 3189 + action 0 + 3737 : 1 +state 3190 + action 0 + 2264 : 0.8 + 3738 : 0.2 +state 3191 + action 0 + 3739 : 0.8 + 3740 : 0.2 +state 3192 + action 0 + 3741 : 0.8 + 3742 : 0.2 +state 3193 + action 0 + 3743 : 0.8 + 3744 : 0.2 +state 3194 + action 0 + 3745 : 0.8 + 3746 : 0.2 +state 3195 + action 0 + 3747 : 1 +state 3196 + action 0 + 2271 : 0.8 + 3748 : 0.2 +state 3197 + action 0 + 3749 : 0.8 + 3750 : 0.2 +state 3198 + action 0 + 3751 : 0.8 + 3752 : 0.2 +state 3199 + action 0 + 3753 : 0.8 + 3754 : 0.2 +state 3200 + action 0 + 3755 : 0.8 + 3756 : 0.2 +state 3201 + action 0 + 3757 : 1 +state 3202 + action 0 + 2278 : 0.8 + 3758 : 0.2 +state 3203 + action 0 + 3759 : 0.8 + 3760 : 0.2 +state 3204 + action 0 + 3761 : 0.8 + 3762 : 0.2 +state 3205 + action 0 + 3763 : 0.8 + 3764 : 0.2 +state 3206 + action 0 + 3765 : 0.8 + 3766 : 0.2 +state 3207 + action 0 + 3767 : 1 +state 3208 + action 0 + 3768 : 1 +state 3209 + action 0 + 3769 : 1 +state 3210 + action 0 + 3770 : 1 +state 3211 + action 0 + 3771 : 1 +state 3212 observe1Greater1 observeIGreater1 + action 0 + 3772 : 0.833 + 3773 : 0.167 +state 3213 + action 0 + 3774 : 0.833 + 3775 : 0.167 +state 3214 + action 0 + 3776 : 0.833 + 3777 : 0.167 +state 3215 + action 0 + 3778 : 0.833 + 3779 : 0.167 +state 3216 + action 0 + 3780 : 1 +state 3217 + action 0 + 3781 : 0.833 + 3782 : 0.167 +state 3218 + action 0 + 3783 : 1 +state 3219 + action 0 + 3784 : 0.833 + 3785 : 0.167 +state 3220 + action 0 + 3786 : 1 +state 3221 + action 0 + 3787 : 0.833 + 3788 : 0.167 +state 3222 + action 0 + 3789 : 1 +state 3223 + action 0 + 3790 : 0.833 + 3791 : 0.167 +state 3224 + action 0 + 3792 : 1 +state 3225 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3225 : 1 +state 3226 observe2Greater1 observeIGreater1 + action 0 + 3793 : 0.833 + 3794 : 0.167 +state 3227 + action 0 + 3795 : 0.833 + 3796 : 0.167 +state 3228 + action 0 + 3797 : 0.833 + 3798 : 0.167 +state 3229 + action 0 + 3799 : 1 +state 3230 + action 0 + 3800 : 0.833 + 3801 : 0.167 +state 3231 + action 0 + 3802 : 1 +state 3232 + action 0 + 3803 : 0.833 + 3804 : 0.167 +state 3233 + action 0 + 3805 : 1 +state 3234 + action 0 + 3806 : 0.833 + 3807 : 0.167 +state 3235 + action 0 + 3808 : 1 +state 3236 + action 0 + 3809 : 0.833 + 3810 : 0.167 +state 3237 + action 0 + 3811 : 1 +state 3238 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3238 : 1 +state 3239 observe3Greater1 observeIGreater1 + action 0 + 3812 : 0.833 + 3813 : 0.167 +state 3240 + action 0 + 3814 : 0.833 + 3815 : 0.167 +state 3241 + action 0 + 3816 : 1 +state 3242 + action 0 + 3817 : 0.833 + 3818 : 0.167 +state 3243 + action 0 + 3819 : 1 +state 3244 + action 0 + 3820 : 0.833 + 3821 : 0.167 +state 3245 + action 0 + 3822 : 1 +state 3246 + action 0 + 3823 : 0.833 + 3824 : 0.167 +state 3247 + action 0 + 3825 : 1 +state 3248 + action 0 + 3826 : 0.833 + 3827 : 0.167 +state 3249 + action 0 + 3828 : 1 +state 3250 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3250 : 1 +state 3251 observe4Greater1 observeIGreater1 + action 0 + 3829 : 0.833 + 3830 : 0.167 +state 3252 + action 0 + 3831 : 1 +state 3253 + action 0 + 3832 : 0.833 + 3833 : 0.167 +state 3254 + action 0 + 3834 : 1 +state 3255 + action 0 + 3835 : 0.833 + 3836 : 0.167 +state 3256 + action 0 + 3837 : 1 +state 3257 + action 0 + 3838 : 0.833 + 3839 : 0.167 +state 3258 + action 0 + 3840 : 1 +state 3259 + action 0 + 3841 : 0.833 + 3842 : 0.167 +state 3260 + action 0 + 3843 : 1 +state 3261 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3261 : 1 +state 3262 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3262 : 1 +state 3263 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3263 : 1 +state 3264 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3264 : 1 +state 3265 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3265 : 1 +state 3266 observe1Greater1 observeIGreater1 + action 0 + 3772 : 0.833 + 3773 : 0.167 +state 3267 observe1Greater1 observeIGreater1 + action 0 + 3844 : 1 +state 3268 observe1Greater1 observeIGreater1 + action 0 + 3845 : 1 +state 3269 observe1Greater1 observeIGreater1 + action 0 + 3846 : 1 +state 3270 observe1Greater1 observeIGreater1 + action 0 + 3847 : 1 +state 3271 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 3272 observe1Greater1 observeIGreater1 + action 0 + 3853 : 1 +state 3273 + action 0 + 3774 : 0.833 + 3775 : 0.167 +state 3274 observe1Greater1 observeIGreater1 + action 0 + 3854 : 1 +state 3275 observe2Greater1 observeIGreater1 + action 0 + 3855 : 1 +state 3276 + action 0 + 3856 : 1 +state 3277 + action 0 + 3857 : 1 +state 3278 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 3279 + action 0 + 3863 : 1 +state 3280 + action 0 + 3776 : 0.833 + 3777 : 0.167 +state 3281 observe1Greater1 observeIGreater1 + action 0 + 3864 : 1 +state 3282 + action 0 + 3865 : 1 +state 3283 observe3Greater1 observeIGreater1 + action 0 + 3866 : 1 +state 3284 + action 0 + 3867 : 1 +state 3285 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 3286 + action 0 + 3873 : 1 +state 3287 + action 0 + 3778 : 0.833 + 3779 : 0.167 +state 3288 observe1Greater1 observeIGreater1 + action 0 + 3874 : 1 +state 3289 + action 0 + 3875 : 1 +state 3290 + action 0 + 3876 : 1 +state 3291 observe4Greater1 observeIGreater1 + action 0 + 3877 : 1 +state 3292 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 3293 + action 0 + 3883 : 1 +state 3294 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3294 : 1 +state 3295 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3296 observe0Greater1 observeOnlyTrueSender + action 0 + 3884 : 1 +state 3297 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3297 : 1 +state 3298 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3299 observe0Greater1 observeOnlyTrueSender + action 0 + 3885 : 1 +state 3300 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3300 : 1 +state 3301 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3302 observe0Greater1 observeOnlyTrueSender + action 0 + 3886 : 1 +state 3303 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3303 : 1 +state 3304 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3305 observe0Greater1 observeOnlyTrueSender + action 0 + 3887 : 1 +state 3306 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3306 : 1 +state 3307 observe2Greater1 observeIGreater1 + action 0 + 3793 : 0.833 + 3794 : 0.167 +state 3308 observe2Greater1 observeIGreater1 + action 0 + 3888 : 1 +state 3309 observe2Greater1 observeIGreater1 + action 0 + 3889 : 1 +state 3310 observe2Greater1 observeIGreater1 + action 0 + 3890 : 1 +state 3311 observe2Greater1 observeIGreater1 + action 0 + 3891 : 1 +state 3312 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 3313 observe2Greater1 observeIGreater1 + action 0 + 3897 : 1 +state 3314 + action 0 + 3795 : 0.833 + 3796 : 0.167 +state 3315 + action 0 + 3898 : 1 +state 3316 observe2Greater1 observeIGreater1 + action 0 + 3899 : 1 +state 3317 observe3Greater1 observeIGreater1 + action 0 + 3900 : 1 +state 3318 + action 0 + 3901 : 1 +state 3319 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 3320 + action 0 + 3907 : 1 +state 3321 + action 0 + 3797 : 0.833 + 3798 : 0.167 +state 3322 + action 0 + 3908 : 1 +state 3323 observe2Greater1 observeIGreater1 + action 0 + 3909 : 1 +state 3324 + action 0 + 3910 : 1 +state 3325 observe4Greater1 observeIGreater1 + action 0 + 3911 : 1 +state 3326 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 3327 + action 0 + 3917 : 1 +state 3328 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3328 : 1 +state 3329 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3330 observe0Greater1 observeOnlyTrueSender + action 0 + 3918 : 1 +state 3331 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3331 : 1 +state 3332 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3333 observe0Greater1 observeOnlyTrueSender + action 0 + 3919 : 1 +state 3334 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3334 : 1 +state 3335 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3336 observe0Greater1 observeOnlyTrueSender + action 0 + 3920 : 1 +state 3337 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3337 : 1 +state 3338 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3339 observe0Greater1 observeOnlyTrueSender + action 0 + 3921 : 1 +state 3340 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3340 : 1 +state 3341 observe3Greater1 observeIGreater1 + action 0 + 3812 : 0.833 + 3813 : 0.167 +state 3342 observe3Greater1 observeIGreater1 + action 0 + 3922 : 1 +state 3343 observe3Greater1 observeIGreater1 + action 0 + 3923 : 1 +state 3344 observe3Greater1 observeIGreater1 + action 0 + 3924 : 1 +state 3345 observe3Greater1 observeIGreater1 + action 0 + 3925 : 1 +state 3346 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 3347 observe3Greater1 observeIGreater1 + action 0 + 3931 : 1 +state 3348 + action 0 + 3814 : 0.833 + 3815 : 0.167 +state 3349 + action 0 + 3932 : 1 +state 3350 + action 0 + 3933 : 1 +state 3351 observe3Greater1 observeIGreater1 + action 0 + 3934 : 1 +state 3352 observe4Greater1 observeIGreater1 + action 0 + 3935 : 1 +state 3353 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 3354 + action 0 + 3941 : 1 +state 3355 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3355 : 1 +state 3356 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3357 observe0Greater1 observeOnlyTrueSender + action 0 + 3942 : 1 +state 3358 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3358 : 1 +state 3359 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3360 observe0Greater1 observeOnlyTrueSender + action 0 + 3943 : 1 +state 3361 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3361 : 1 +state 3362 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3363 observe0Greater1 observeOnlyTrueSender + action 0 + 3944 : 1 +state 3364 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3364 : 1 +state 3365 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3366 observe0Greater1 observeOnlyTrueSender + action 0 + 3945 : 1 +state 3367 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3367 : 1 +state 3368 observe4Greater1 observeIGreater1 + action 0 + 3829 : 0.833 + 3830 : 0.167 +state 3369 observe4Greater1 observeIGreater1 + action 0 + 3946 : 1 +state 3370 observe4Greater1 observeIGreater1 + action 0 + 3947 : 1 +state 3371 observe4Greater1 observeIGreater1 + action 0 + 3948 : 1 +state 3372 observe4Greater1 observeIGreater1 + action 0 + 3949 : 1 +state 3373 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 3374 observe4Greater1 observeIGreater1 + action 0 + 3955 : 1 +state 3375 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3375 : 1 +state 3376 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3377 observe0Greater1 observeOnlyTrueSender + action 0 + 3956 : 1 +state 3378 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3378 : 1 +state 3379 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3380 observe0Greater1 observeOnlyTrueSender + action 0 + 3957 : 1 +state 3381 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3381 : 1 +state 3382 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3383 observe0Greater1 observeOnlyTrueSender + action 0 + 3958 : 1 +state 3384 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3384 : 1 +state 3385 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3386 observe0Greater1 observeOnlyTrueSender + action 0 + 3959 : 1 +state 3387 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3387 : 1 +state 3388 observe1Greater1 observeIGreater1 + action 0 + 2442 : 0.833 + 2443 : 0.167 +state 3389 observe1Greater1 observeIGreater1 + action 0 + 3960 : 1 +state 3390 observe1Greater1 observeIGreater1 + action 0 + 3961 : 0.833 + 3962 : 0.167 +state 3391 observe1Greater1 observeIGreater1 + action 0 + 3963 : 1 +state 3392 observe1Greater1 observeIGreater1 + action 0 + 3964 : 0.833 + 3965 : 0.167 +state 3393 observe1Greater1 observeIGreater1 + action 0 + 3966 : 1 +state 3394 observe1Greater1 observeIGreater1 + action 0 + 3967 : 0.833 + 3968 : 0.167 +state 3395 observe1Greater1 observeIGreater1 + action 0 + 3969 : 1 +state 3396 observe1Greater1 observeIGreater1 + action 0 + 3970 : 0.833 + 3971 : 0.167 +state 3397 observe1Greater1 observeIGreater1 + action 0 + 3972 : 1 +state 3398 observe1Greater1 observeIGreater1 + action 0 + 3973 : 1 +state 3399 observe1Greater1 observeIGreater1 + action 0 + 2444 : 0.833 + 2445 : 0.167 +state 3400 observe1Greater1 observeIGreater1 + action 0 + 3974 : 1 +state 3401 observe1Greater1 observeIGreater1 + action 0 + 3975 : 0.833 + 3976 : 0.167 +state 3402 observe1Greater1 observeIGreater1 + action 0 + 3977 : 1 +state 3403 observe1Greater1 observeIGreater1 + action 0 + 3978 : 0.833 + 3979 : 0.167 +state 3404 observe1Greater1 observeIGreater1 + action 0 + 3980 : 1 +state 3405 observe1Greater1 observeIGreater1 + action 0 + 3981 : 0.833 + 3982 : 0.167 +state 3406 observe1Greater1 observeIGreater1 + action 0 + 3983 : 1 +state 3407 observe1Greater1 observeIGreater1 + action 0 + 3984 : 0.833 + 3985 : 0.167 +state 3408 observe1Greater1 observeIGreater1 + action 0 + 3986 : 1 +state 3409 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3410 observe1Greater1 observeIGreater1 + action 0 + 2446 : 0.833 + 2447 : 0.167 +state 3411 observe1Greater1 observeIGreater1 + action 0 + 3988 : 1 +state 3412 observe1Greater1 observeIGreater1 + action 0 + 3989 : 0.833 + 3990 : 0.167 +state 3413 observe1Greater1 observeIGreater1 + action 0 + 3991 : 1 +state 3414 observe1Greater1 observeIGreater1 + action 0 + 3992 : 0.833 + 3993 : 0.167 +state 3415 observe1Greater1 observeIGreater1 + action 0 + 3994 : 1 +state 3416 observe1Greater1 observeIGreater1 + action 0 + 3995 : 0.833 + 3996 : 0.167 +state 3417 observe1Greater1 observeIGreater1 + action 0 + 3997 : 1 +state 3418 observe1Greater1 observeIGreater1 + action 0 + 3998 : 0.833 + 3999 : 0.167 +state 3419 observe1Greater1 observeIGreater1 + action 0 + 4000 : 1 +state 3420 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3421 observe1Greater1 observeIGreater1 + action 0 + 2448 : 0.833 + 2449 : 0.167 +state 3422 observe1Greater1 observeIGreater1 + action 0 + 4002 : 1 +state 3423 observe1Greater1 observeIGreater1 + action 0 + 4003 : 0.833 + 4004 : 0.167 +state 3424 observe1Greater1 observeIGreater1 + action 0 + 4005 : 1 +state 3425 observe1Greater1 observeIGreater1 + action 0 + 4006 : 0.833 + 4007 : 0.167 +state 3426 observe1Greater1 observeIGreater1 + action 0 + 4008 : 1 +state 3427 observe1Greater1 observeIGreater1 + action 0 + 4009 : 0.833 + 4010 : 0.167 +state 3428 observe1Greater1 observeIGreater1 + action 0 + 4011 : 1 +state 3429 observe1Greater1 observeIGreater1 + action 0 + 4012 : 0.833 + 4013 : 0.167 +state 3430 observe1Greater1 observeIGreater1 + action 0 + 4014 : 1 +state 3431 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3432 observe1Greater1 observeIGreater1 + action 0 + 3973 : 1 +state 3433 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3434 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3435 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3436 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4016 : 0.8 + 4017 : 0.2 +state 3437 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4018 : 0.8 + 4019 : 0.2 +state 3438 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4020 : 0.8 + 4021 : 0.2 +state 3439 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4022 : 0.8 + 4023 : 0.2 +state 3440 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4024 : 0.8 + 4025 : 0.2 +state 3441 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4026 : 1 +state 3442 observe2Greater1 observeIGreater1 + action 0 + 2464 : 0.833 + 2465 : 0.167 +state 3443 observe2Greater1 observeIGreater1 + action 0 + 4027 : 1 +state 3444 observe2Greater1 observeIGreater1 + action 0 + 4028 : 0.833 + 4029 : 0.167 +state 3445 observe2Greater1 observeIGreater1 + action 0 + 4030 : 1 +state 3446 observe2Greater1 observeIGreater1 + action 0 + 4031 : 0.833 + 4032 : 0.167 +state 3447 observe2Greater1 observeIGreater1 + action 0 + 4033 : 1 +state 3448 observe2Greater1 observeIGreater1 + action 0 + 4034 : 0.833 + 4035 : 0.167 +state 3449 observe2Greater1 observeIGreater1 + action 0 + 4036 : 1 +state 3450 observe2Greater1 observeIGreater1 + action 0 + 4037 : 0.833 + 4038 : 0.167 +state 3451 observe2Greater1 observeIGreater1 + action 0 + 4039 : 1 +state 3452 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3453 + action 0 + 2466 : 0.833 + 2467 : 0.167 +state 3454 + action 0 + 4041 : 1 +state 3455 + action 0 + 4042 : 0.833 + 4043 : 0.167 +state 3456 + action 0 + 4044 : 1 +state 3457 + action 0 + 4045 : 0.833 + 4046 : 0.167 +state 3458 + action 0 + 4047 : 1 +state 3459 + action 0 + 4048 : 0.833 + 4049 : 0.167 +state 3460 + action 0 + 4050 : 1 +state 3461 + action 0 + 4051 : 0.833 + 4052 : 0.167 +state 3462 + action 0 + 4053 : 1 +state 3463 + action 0 + 4054 : 1 +state 3464 + action 0 + 2468 : 0.833 + 2469 : 0.167 +state 3465 + action 0 + 4055 : 1 +state 3466 + action 0 + 4056 : 0.833 + 4057 : 0.167 +state 3467 + action 0 + 4058 : 1 +state 3468 + action 0 + 4059 : 0.833 + 4060 : 0.167 +state 3469 + action 0 + 4061 : 1 +state 3470 + action 0 + 4062 : 0.833 + 4063 : 0.167 +state 3471 + action 0 + 4064 : 1 +state 3472 + action 0 + 4065 : 0.833 + 4066 : 0.167 +state 3473 + action 0 + 4067 : 1 +state 3474 + action 0 + 4068 : 1 +state 3475 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3476 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3477 + action 0 + 4054 : 1 +state 3478 + action 0 + 4068 : 1 +state 3479 observe0Greater1 observeOnlyTrueSender + action 0 + 4069 : 0.8 + 4070 : 0.2 +state 3480 observe0Greater1 observeOnlyTrueSender + action 0 + 4071 : 0.8 + 4072 : 0.2 +state 3481 observe0Greater1 observeOnlyTrueSender + action 0 + 4073 : 0.8 + 4074 : 0.2 +state 3482 observe0Greater1 observeOnlyTrueSender + action 0 + 4075 : 0.8 + 4076 : 0.2 +state 3483 observe0Greater1 observeOnlyTrueSender + action 0 + 4077 : 0.8 + 4078 : 0.2 +state 3484 observe0Greater1 observeOnlyTrueSender + action 0 + 4079 : 1 +state 3485 observe3Greater1 observeIGreater1 + action 0 + 2484 : 0.833 + 2485 : 0.167 +state 3486 observe3Greater1 observeIGreater1 + action 0 + 4080 : 1 +state 3487 observe3Greater1 observeIGreater1 + action 0 + 4081 : 0.833 + 4082 : 0.167 +state 3488 observe3Greater1 observeIGreater1 + action 0 + 4083 : 1 +state 3489 observe3Greater1 observeIGreater1 + action 0 + 4084 : 0.833 + 4085 : 0.167 +state 3490 observe3Greater1 observeIGreater1 + action 0 + 4086 : 1 +state 3491 observe3Greater1 observeIGreater1 + action 0 + 4087 : 0.833 + 4088 : 0.167 +state 3492 observe3Greater1 observeIGreater1 + action 0 + 4089 : 1 +state 3493 observe3Greater1 observeIGreater1 + action 0 + 4090 : 0.833 + 4091 : 0.167 +state 3494 observe3Greater1 observeIGreater1 + action 0 + 4092 : 1 +state 3495 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3496 + action 0 + 2486 : 0.833 + 2487 : 0.167 +state 3497 + action 0 + 4094 : 1 +state 3498 + action 0 + 4095 : 0.833 + 4096 : 0.167 +state 3499 + action 0 + 4097 : 1 +state 3500 + action 0 + 4098 : 0.833 + 4099 : 0.167 +state 3501 + action 0 + 4100 : 1 +state 3502 + action 0 + 4101 : 0.833 + 4102 : 0.167 +state 3503 + action 0 + 4103 : 1 +state 3504 + action 0 + 4104 : 0.833 + 4105 : 0.167 +state 3505 + action 0 + 4106 : 1 +state 3506 + action 0 + 4107 : 1 +state 3507 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3508 + action 0 + 4054 : 1 +state 3509 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3510 + action 0 + 4107 : 1 +state 3511 observe0Greater1 observeOnlyTrueSender + action 0 + 4108 : 0.8 + 4109 : 0.2 +state 3512 observe0Greater1 observeOnlyTrueSender + action 0 + 4110 : 0.8 + 4111 : 0.2 +state 3513 observe0Greater1 observeOnlyTrueSender + action 0 + 4112 : 0.8 + 4113 : 0.2 +state 3514 observe0Greater1 observeOnlyTrueSender + action 0 + 4114 : 0.8 + 4115 : 0.2 +state 3515 observe0Greater1 observeOnlyTrueSender + action 0 + 4116 : 0.8 + 4117 : 0.2 +state 3516 observe0Greater1 observeOnlyTrueSender + action 0 + 4118 : 1 +state 3517 observe4Greater1 observeIGreater1 + action 0 + 2502 : 0.833 + 2503 : 0.167 +state 3518 observe4Greater1 observeIGreater1 + action 0 + 4119 : 1 +state 3519 observe4Greater1 observeIGreater1 + action 0 + 4120 : 0.833 + 4121 : 0.167 +state 3520 observe4Greater1 observeIGreater1 + action 0 + 4122 : 1 +state 3521 observe4Greater1 observeIGreater1 + action 0 + 4123 : 0.833 + 4124 : 0.167 +state 3522 observe4Greater1 observeIGreater1 + action 0 + 4125 : 1 +state 3523 observe4Greater1 observeIGreater1 + action 0 + 4126 : 0.833 + 4127 : 0.167 +state 3524 observe4Greater1 observeIGreater1 + action 0 + 4128 : 1 +state 3525 observe4Greater1 observeIGreater1 + action 0 + 4129 : 0.833 + 4130 : 0.167 +state 3526 observe4Greater1 observeIGreater1 + action 0 + 4131 : 1 +state 3527 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3528 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3529 + action 0 + 4068 : 1 +state 3530 + action 0 + 4107 : 1 +state 3531 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3532 observe0Greater1 observeOnlyTrueSender + action 0 + 4133 : 0.8 + 4134 : 0.2 +state 3533 observe0Greater1 observeOnlyTrueSender + action 0 + 4135 : 0.8 + 4136 : 0.2 +state 3534 observe0Greater1 observeOnlyTrueSender + action 0 + 4137 : 0.8 + 4138 : 0.2 +state 3535 observe0Greater1 observeOnlyTrueSender + action 0 + 4139 : 0.8 + 4140 : 0.2 +state 3536 observe0Greater1 observeOnlyTrueSender + action 0 + 4141 : 0.8 + 4142 : 0.2 +state 3537 observe0Greater1 observeOnlyTrueSender + action 0 + 4143 : 1 +state 3538 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4144 : 1 +state 3539 observe0Greater1 observeOnlyTrueSender + action 0 + 4145 : 1 +state 3540 observe0Greater1 observeOnlyTrueSender + action 0 + 4146 : 1 +state 3541 observe0Greater1 observeOnlyTrueSender + action 0 + 4147 : 1 +state 3542 observe2Greater1 observeIGreater1 + action 0 + 2529 : 0.833 + 2530 : 0.167 +state 3543 observe2Greater1 observeIGreater1 + action 0 + 4148 : 1 +state 3544 observe2Greater1 observeIGreater1 + action 0 + 4149 : 0.833 + 4150 : 0.167 +state 3545 observe2Greater1 observeIGreater1 + action 0 + 4151 : 1 +state 3546 observe2Greater1 observeIGreater1 + action 0 + 4152 : 0.833 + 4153 : 0.167 +state 3547 observe2Greater1 observeIGreater1 + action 0 + 4154 : 1 +state 3548 observe2Greater1 observeIGreater1 + action 0 + 4155 : 0.833 + 4156 : 0.167 +state 3549 observe2Greater1 observeIGreater1 + action 0 + 4157 : 1 +state 3550 observe2Greater1 observeIGreater1 + action 0 + 4158 : 0.833 + 4159 : 0.167 +state 3551 observe2Greater1 observeIGreater1 + action 0 + 4160 : 1 +state 3552 observe2Greater1 observeIGreater1 + action 0 + 4161 : 1 +state 3553 observe2Greater1 observeIGreater1 + action 0 + 2531 : 0.833 + 2532 : 0.167 +state 3554 observe2Greater1 observeIGreater1 + action 0 + 4162 : 1 +state 3555 observe2Greater1 observeIGreater1 + action 0 + 4163 : 0.833 + 4164 : 0.167 +state 3556 observe2Greater1 observeIGreater1 + action 0 + 4165 : 1 +state 3557 observe2Greater1 observeIGreater1 + action 0 + 4166 : 0.833 + 4167 : 0.167 +state 3558 observe2Greater1 observeIGreater1 + action 0 + 4168 : 1 +state 3559 observe2Greater1 observeIGreater1 + action 0 + 4169 : 0.833 + 4170 : 0.167 +state 3560 observe2Greater1 observeIGreater1 + action 0 + 4171 : 1 +state 3561 observe2Greater1 observeIGreater1 + action 0 + 4172 : 0.833 + 4173 : 0.167 +state 3562 observe2Greater1 observeIGreater1 + action 0 + 4174 : 1 +state 3563 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3564 observe2Greater1 observeIGreater1 + action 0 + 2533 : 0.833 + 2534 : 0.167 +state 3565 observe2Greater1 observeIGreater1 + action 0 + 4176 : 1 +state 3566 observe2Greater1 observeIGreater1 + action 0 + 4177 : 0.833 + 4178 : 0.167 +state 3567 observe2Greater1 observeIGreater1 + action 0 + 4179 : 1 +state 3568 observe2Greater1 observeIGreater1 + action 0 + 4180 : 0.833 + 4181 : 0.167 +state 3569 observe2Greater1 observeIGreater1 + action 0 + 4182 : 1 +state 3570 observe2Greater1 observeIGreater1 + action 0 + 4183 : 0.833 + 4184 : 0.167 +state 3571 observe2Greater1 observeIGreater1 + action 0 + 4185 : 1 +state 3572 observe2Greater1 observeIGreater1 + action 0 + 4186 : 0.833 + 4187 : 0.167 +state 3573 observe2Greater1 observeIGreater1 + action 0 + 4188 : 1 +state 3574 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3575 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3576 observe2Greater1 observeIGreater1 + action 0 + 4161 : 1 +state 3577 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3578 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3579 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4190 : 0.8 + 4191 : 0.2 +state 3580 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4192 : 0.8 + 4193 : 0.2 +state 3581 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4194 : 0.8 + 4195 : 0.2 +state 3582 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4196 : 0.8 + 4197 : 0.2 +state 3583 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4198 : 0.8 + 4199 : 0.2 +state 3584 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4200 : 1 +state 3585 observe3Greater1 observeIGreater1 + action 0 + 2549 : 0.833 + 2550 : 0.167 +state 3586 observe3Greater1 observeIGreater1 + action 0 + 4201 : 1 +state 3587 observe3Greater1 observeIGreater1 + action 0 + 4202 : 0.833 + 4203 : 0.167 +state 3588 observe3Greater1 observeIGreater1 + action 0 + 4204 : 1 +state 3589 observe3Greater1 observeIGreater1 + action 0 + 4205 : 0.833 + 4206 : 0.167 +state 3590 observe3Greater1 observeIGreater1 + action 0 + 4207 : 1 +state 3591 observe3Greater1 observeIGreater1 + action 0 + 4208 : 0.833 + 4209 : 0.167 +state 3592 observe3Greater1 observeIGreater1 + action 0 + 4210 : 1 +state 3593 observe3Greater1 observeIGreater1 + action 0 + 4211 : 0.833 + 4212 : 0.167 +state 3594 observe3Greater1 observeIGreater1 + action 0 + 4213 : 1 +state 3595 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3596 + action 0 + 2551 : 0.833 + 2552 : 0.167 +state 3597 + action 0 + 4215 : 1 +state 3598 + action 0 + 4216 : 0.833 + 4217 : 0.167 +state 3599 + action 0 + 4218 : 1 +state 3600 + action 0 + 4219 : 0.833 + 4220 : 0.167 +state 3601 + action 0 + 4221 : 1 +state 3602 + action 0 + 4222 : 0.833 + 4223 : 0.167 +state 3603 + action 0 + 4224 : 1 +state 3604 + action 0 + 4225 : 0.833 + 4226 : 0.167 +state 3605 + action 0 + 4227 : 1 +state 3606 + action 0 + 4228 : 1 +state 3607 + action 0 + 4054 : 1 +state 3608 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3609 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3610 + action 0 + 4228 : 1 +state 3611 observe0Greater1 observeOnlyTrueSender + action 0 + 4229 : 0.8 + 4230 : 0.2 +state 3612 observe0Greater1 observeOnlyTrueSender + action 0 + 4231 : 0.8 + 4232 : 0.2 +state 3613 observe0Greater1 observeOnlyTrueSender + action 0 + 4233 : 0.8 + 4234 : 0.2 +state 3614 observe0Greater1 observeOnlyTrueSender + action 0 + 4235 : 0.8 + 4236 : 0.2 +state 3615 observe0Greater1 observeOnlyTrueSender + action 0 + 4237 : 0.8 + 4238 : 0.2 +state 3616 observe0Greater1 observeOnlyTrueSender + action 0 + 4239 : 1 +state 3617 observe4Greater1 observeIGreater1 + action 0 + 2567 : 0.833 + 2568 : 0.167 +state 3618 observe4Greater1 observeIGreater1 + action 0 + 4240 : 1 +state 3619 observe4Greater1 observeIGreater1 + action 0 + 4241 : 0.833 + 4242 : 0.167 +state 3620 observe4Greater1 observeIGreater1 + action 0 + 4243 : 1 +state 3621 observe4Greater1 observeIGreater1 + action 0 + 4244 : 0.833 + 4245 : 0.167 +state 3622 observe4Greater1 observeIGreater1 + action 0 + 4246 : 1 +state 3623 observe4Greater1 observeIGreater1 + action 0 + 4247 : 0.833 + 4248 : 0.167 +state 3624 observe4Greater1 observeIGreater1 + action 0 + 4249 : 1 +state 3625 observe4Greater1 observeIGreater1 + action 0 + 4250 : 0.833 + 4251 : 0.167 +state 3626 observe4Greater1 observeIGreater1 + action 0 + 4252 : 1 +state 3627 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3628 + action 0 + 4068 : 1 +state 3629 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3630 + action 0 + 4228 : 1 +state 3631 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3632 observe0Greater1 observeOnlyTrueSender + action 0 + 4254 : 0.8 + 4255 : 0.2 +state 3633 observe0Greater1 observeOnlyTrueSender + action 0 + 4256 : 0.8 + 4257 : 0.2 +state 3634 observe0Greater1 observeOnlyTrueSender + action 0 + 4258 : 0.8 + 4259 : 0.2 +state 3635 observe0Greater1 observeOnlyTrueSender + action 0 + 4260 : 0.8 + 4261 : 0.2 +state 3636 observe0Greater1 observeOnlyTrueSender + action 0 + 4262 : 0.8 + 4263 : 0.2 +state 3637 observe0Greater1 observeOnlyTrueSender + action 0 + 4264 : 1 +state 3638 observe0Greater1 observeOnlyTrueSender + action 0 + 4265 : 1 +state 3639 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4266 : 1 +state 3640 observe0Greater1 observeOnlyTrueSender + action 0 + 4267 : 1 +state 3641 observe0Greater1 observeOnlyTrueSender + action 0 + 4268 : 1 +state 3642 observe3Greater1 observeIGreater1 + action 0 + 2594 : 0.833 + 2595 : 0.167 +state 3643 observe3Greater1 observeIGreater1 + action 0 + 4269 : 1 +state 3644 observe3Greater1 observeIGreater1 + action 0 + 4270 : 0.833 + 4271 : 0.167 +state 3645 observe3Greater1 observeIGreater1 + action 0 + 4272 : 1 +state 3646 observe3Greater1 observeIGreater1 + action 0 + 4273 : 0.833 + 4274 : 0.167 +state 3647 observe3Greater1 observeIGreater1 + action 0 + 4275 : 1 +state 3648 observe3Greater1 observeIGreater1 + action 0 + 4276 : 0.833 + 4277 : 0.167 +state 3649 observe3Greater1 observeIGreater1 + action 0 + 4278 : 1 +state 3650 observe3Greater1 observeIGreater1 + action 0 + 4279 : 0.833 + 4280 : 0.167 +state 3651 observe3Greater1 observeIGreater1 + action 0 + 4281 : 1 +state 3652 observe3Greater1 observeIGreater1 + action 0 + 4282 : 1 +state 3653 observe3Greater1 observeIGreater1 + action 0 + 2596 : 0.833 + 2597 : 0.167 +state 3654 observe3Greater1 observeIGreater1 + action 0 + 4283 : 1 +state 3655 observe3Greater1 observeIGreater1 + action 0 + 4284 : 0.833 + 4285 : 0.167 +state 3656 observe3Greater1 observeIGreater1 + action 0 + 4286 : 1 +state 3657 observe3Greater1 observeIGreater1 + action 0 + 4287 : 0.833 + 4288 : 0.167 +state 3658 observe3Greater1 observeIGreater1 + action 0 + 4289 : 1 +state 3659 observe3Greater1 observeIGreater1 + action 0 + 4290 : 0.833 + 4291 : 0.167 +state 3660 observe3Greater1 observeIGreater1 + action 0 + 4292 : 1 +state 3661 observe3Greater1 observeIGreater1 + action 0 + 4293 : 0.833 + 4294 : 0.167 +state 3662 observe3Greater1 observeIGreater1 + action 0 + 4295 : 1 +state 3663 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3664 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3665 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3666 observe3Greater1 observeIGreater1 + action 0 + 4282 : 1 +state 3667 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3668 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4297 : 0.8 + 4298 : 0.2 +state 3669 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4299 : 0.8 + 4300 : 0.2 +state 3670 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4301 : 0.8 + 4302 : 0.2 +state 3671 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4303 : 0.8 + 4304 : 0.2 +state 3672 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4305 : 0.8 + 4306 : 0.2 +state 3673 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4307 : 1 +state 3674 observe4Greater1 observeIGreater1 + action 0 + 2612 : 0.833 + 2613 : 0.167 +state 3675 observe4Greater1 observeIGreater1 + action 0 + 4308 : 1 +state 3676 observe4Greater1 observeIGreater1 + action 0 + 4309 : 0.833 + 4310 : 0.167 +state 3677 observe4Greater1 observeIGreater1 + action 0 + 4311 : 1 +state 3678 observe4Greater1 observeIGreater1 + action 0 + 4312 : 0.833 + 4313 : 0.167 +state 3679 observe4Greater1 observeIGreater1 + action 0 + 4314 : 1 +state 3680 observe4Greater1 observeIGreater1 + action 0 + 4315 : 0.833 + 4316 : 0.167 +state 3681 observe4Greater1 observeIGreater1 + action 0 + 4317 : 1 +state 3682 observe4Greater1 observeIGreater1 + action 0 + 4318 : 0.833 + 4319 : 0.167 +state 3683 observe4Greater1 observeIGreater1 + action 0 + 4320 : 1 +state 3684 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3685 + action 0 + 4107 : 1 +state 3686 + action 0 + 4228 : 1 +state 3687 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3688 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3689 observe0Greater1 observeOnlyTrueSender + action 0 + 4322 : 0.8 + 4323 : 0.2 +state 3690 observe0Greater1 observeOnlyTrueSender + action 0 + 4324 : 0.8 + 4325 : 0.2 +state 3691 observe0Greater1 observeOnlyTrueSender + action 0 + 4326 : 0.8 + 4327 : 0.2 +state 3692 observe0Greater1 observeOnlyTrueSender + action 0 + 4328 : 0.8 + 4329 : 0.2 +state 3693 observe0Greater1 observeOnlyTrueSender + action 0 + 4330 : 0.8 + 4331 : 0.2 +state 3694 observe0Greater1 observeOnlyTrueSender + action 0 + 4332 : 1 +state 3695 observe0Greater1 observeOnlyTrueSender + action 0 + 4333 : 1 +state 3696 observe0Greater1 observeOnlyTrueSender + action 0 + 4334 : 1 +state 3697 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4335 : 1 +state 3698 observe0Greater1 observeOnlyTrueSender + action 0 + 4336 : 1 +state 3699 observe4Greater1 observeIGreater1 + action 0 + 2639 : 0.833 + 2640 : 0.167 +state 3700 observe4Greater1 observeIGreater1 + action 0 + 4337 : 1 +state 3701 observe4Greater1 observeIGreater1 + action 0 + 4338 : 0.833 + 4339 : 0.167 +state 3702 observe4Greater1 observeIGreater1 + action 0 + 4340 : 1 +state 3703 observe4Greater1 observeIGreater1 + action 0 + 4341 : 0.833 + 4342 : 0.167 +state 3704 observe4Greater1 observeIGreater1 + action 0 + 4343 : 1 +state 3705 observe4Greater1 observeIGreater1 + action 0 + 4344 : 0.833 + 4345 : 0.167 +state 3706 observe4Greater1 observeIGreater1 + action 0 + 4346 : 1 +state 3707 observe4Greater1 observeIGreater1 + action 0 + 4347 : 0.833 + 4348 : 0.167 +state 3708 observe4Greater1 observeIGreater1 + action 0 + 4349 : 1 +state 3709 observe4Greater1 observeIGreater1 + action 0 + 4350 : 1 +state 3710 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3711 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3712 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3713 observe4Greater1 observeIGreater1 + action 0 + 4350 : 1 +state 3714 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4351 : 0.8 + 4352 : 0.2 +state 3715 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4353 : 0.8 + 4354 : 0.2 +state 3716 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4355 : 0.8 + 4356 : 0.2 +state 3717 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4357 : 0.8 + 4358 : 0.2 +state 3718 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4359 : 0.8 + 4360 : 0.2 +state 3719 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4361 : 1 +state 3720 observe0Greater1 observeOnlyTrueSender + action 0 + 4362 : 1 +state 3721 observe0Greater1 observeOnlyTrueSender + action 0 + 4363 : 1 +state 3722 observe0Greater1 observeOnlyTrueSender + action 0 + 4364 : 1 +state 3723 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4365 : 1 +state 3724 + action 0 + 4366 : 1 +state 3725 + action 0 + 4367 : 1 +state 3726 + action 0 + 4368 : 1 +state 3727 + action 0 + 4369 : 1 +state 3728 + action 0 + 4370 : 1 +state 3729 + action 0 + 4371 : 0.833 + 4372 : 0.167 +state 3730 + action 0 + 4373 : 1 +state 3731 + action 0 + 4374 : 0.833 + 4375 : 0.167 +state 3732 + action 0 + 4376 : 1 +state 3733 + action 0 + 4377 : 0.833 + 4378 : 0.167 +state 3734 + action 0 + 4379 : 1 +state 3735 + action 0 + 4380 : 0.833 + 4381 : 0.167 +state 3736 + action 0 + 4382 : 1 +state 3737 deadlock + action 0 + 3737 : 1 +state 3738 + action 0 + 4383 : 1 +state 3739 + action 0 + 4384 : 0.833 + 4385 : 0.167 +state 3740 + action 0 + 4386 : 1 +state 3741 + action 0 + 4387 : 0.833 + 4388 : 0.167 +state 3742 + action 0 + 4389 : 1 +state 3743 + action 0 + 4390 : 0.833 + 4391 : 0.167 +state 3744 + action 0 + 4392 : 1 +state 3745 + action 0 + 4393 : 0.833 + 4394 : 0.167 +state 3746 + action 0 + 4395 : 1 +state 3747 deadlock + action 0 + 3747 : 1 +state 3748 + action 0 + 4396 : 1 +state 3749 + action 0 + 4397 : 0.833 + 4398 : 0.167 +state 3750 + action 0 + 4399 : 1 +state 3751 + action 0 + 4400 : 0.833 + 4401 : 0.167 +state 3752 + action 0 + 4402 : 1 +state 3753 + action 0 + 4403 : 0.833 + 4404 : 0.167 +state 3754 + action 0 + 4405 : 1 +state 3755 + action 0 + 4406 : 0.833 + 4407 : 0.167 +state 3756 + action 0 + 4408 : 1 +state 3757 deadlock + action 0 + 3757 : 1 +state 3758 + action 0 + 4409 : 1 +state 3759 + action 0 + 4410 : 0.833 + 4411 : 0.167 +state 3760 + action 0 + 4412 : 1 +state 3761 + action 0 + 4413 : 0.833 + 4414 : 0.167 +state 3762 + action 0 + 4415 : 1 +state 3763 + action 0 + 4416 : 0.833 + 4417 : 0.167 +state 3764 + action 0 + 4418 : 1 +state 3765 + action 0 + 4419 : 0.833 + 4420 : 0.167 +state 3766 + action 0 + 4421 : 1 +state 3767 deadlock + action 0 + 3767 : 1 +state 3768 deadlock + action 0 + 3768 : 1 +state 3769 deadlock + action 0 + 3769 : 1 +state 3770 deadlock + action 0 + 3770 : 1 +state 3771 deadlock + action 0 + 3771 : 1 +state 3772 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 3773 observe1Greater1 observeIGreater1 + action 0 + 4427 : 1 +state 3774 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 3775 + action 0 + 4433 : 1 +state 3776 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 3777 + action 0 + 4439 : 1 +state 3778 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 3779 + action 0 + 4445 : 1 +state 3780 deadlock + action 0 + 3780 : 1 +state 3781 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3782 + action 0 + 4446 : 1 +state 3783 deadlock + action 0 + 3783 : 1 +state 3784 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3785 + action 0 + 4447 : 1 +state 3786 deadlock + action 0 + 3786 : 1 +state 3787 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3788 + action 0 + 4448 : 1 +state 3789 deadlock + action 0 + 3789 : 1 +state 3790 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3791 + action 0 + 4449 : 1 +state 3792 deadlock + action 0 + 3792 : 1 +state 3793 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 3794 observe2Greater1 observeIGreater1 + action 0 + 4455 : 1 +state 3795 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 3796 + action 0 + 4461 : 1 +state 3797 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 3798 + action 0 + 4467 : 1 +state 3799 deadlock + action 0 + 3799 : 1 +state 3800 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3801 + action 0 + 4468 : 1 +state 3802 deadlock + action 0 + 3802 : 1 +state 3803 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3804 + action 0 + 4469 : 1 +state 3805 deadlock + action 0 + 3805 : 1 +state 3806 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3807 + action 0 + 4470 : 1 +state 3808 deadlock + action 0 + 3808 : 1 +state 3809 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3810 + action 0 + 4471 : 1 +state 3811 deadlock + action 0 + 3811 : 1 +state 3812 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 3813 observe3Greater1 observeIGreater1 + action 0 + 4477 : 1 +state 3814 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 3815 + action 0 + 4483 : 1 +state 3816 deadlock + action 0 + 3816 : 1 +state 3817 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3818 + action 0 + 4484 : 1 +state 3819 deadlock + action 0 + 3819 : 1 +state 3820 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3821 + action 0 + 4485 : 1 +state 3822 deadlock + action 0 + 3822 : 1 +state 3823 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3824 + action 0 + 4486 : 1 +state 3825 deadlock + action 0 + 3825 : 1 +state 3826 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3827 + action 0 + 4487 : 1 +state 3828 deadlock + action 0 + 3828 : 1 +state 3829 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 3830 observe4Greater1 observeIGreater1 + action 0 + 4493 : 1 +state 3831 deadlock + action 0 + 3831 : 1 +state 3832 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3833 + action 0 + 4494 : 1 +state 3834 deadlock + action 0 + 3834 : 1 +state 3835 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3836 + action 0 + 4495 : 1 +state 3837 deadlock + action 0 + 3837 : 1 +state 3838 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3839 + action 0 + 4496 : 1 +state 3840 deadlock + action 0 + 3840 : 1 +state 3841 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3842 + action 0 + 4497 : 1 +state 3843 deadlock + action 0 + 3843 : 1 +state 3844 observe1Greater1 observeIGreater1 + action 0 + 4498 : 1 +state 3845 observe1Greater1 observeIGreater1 + action 0 + 4499 : 1 +state 3846 observe1Greater1 observeIGreater1 + action 0 + 4500 : 1 +state 3847 observe1Greater1 observeIGreater1 + action 0 + 4501 : 1 +state 3848 observe1Greater1 observeIGreater1 + action 0 + 2953 : 0.8 + 4502 : 0.2 +state 3849 observe1Greater1 observeIGreater1 + action 0 + 4503 : 0.8 + 4504 : 0.2 +state 3850 observe1Greater1 observeIGreater1 + action 0 + 4505 : 0.8 + 4506 : 0.2 +state 3851 observe1Greater1 observeIGreater1 + action 0 + 4507 : 0.8 + 4508 : 0.2 +state 3852 observe1Greater1 observeIGreater1 + action 0 + 4509 : 0.8 + 4510 : 0.2 +state 3853 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4511 : 1 +state 3854 observe1Greater1 observeIGreater1 + action 0 + 4499 : 1 +state 3855 observe2Greater1 observeIGreater1 + action 0 + 4512 : 1 +state 3856 + action 0 + 4513 : 1 +state 3857 + action 0 + 4514 : 1 +state 3858 + action 0 + 2978 : 0.8 + 4515 : 0.2 +state 3859 + action 0 + 4516 : 0.8 + 4517 : 0.2 +state 3860 + action 0 + 4518 : 0.8 + 4519 : 0.2 +state 3861 + action 0 + 4520 : 0.8 + 4521 : 0.2 +state 3862 + action 0 + 4522 : 0.8 + 4523 : 0.2 +state 3863 observe0Greater1 observeOnlyTrueSender + action 0 + 4524 : 1 +state 3864 observe1Greater1 observeIGreater1 + action 0 + 4500 : 1 +state 3865 + action 0 + 4513 : 1 +state 3866 observe3Greater1 observeIGreater1 + action 0 + 4525 : 1 +state 3867 + action 0 + 4526 : 1 +state 3868 + action 0 + 2997 : 0.8 + 4527 : 0.2 +state 3869 + action 0 + 4528 : 0.8 + 4529 : 0.2 +state 3870 + action 0 + 4530 : 0.8 + 4531 : 0.2 +state 3871 + action 0 + 4532 : 0.8 + 4533 : 0.2 +state 3872 + action 0 + 4534 : 0.8 + 4535 : 0.2 +state 3873 observe0Greater1 observeOnlyTrueSender + action 0 + 4536 : 1 +state 3874 observe1Greater1 observeIGreater1 + action 0 + 4501 : 1 +state 3875 + action 0 + 4514 : 1 +state 3876 + action 0 + 4526 : 1 +state 3877 observe4Greater1 observeIGreater1 + action 0 + 4537 : 1 +state 3878 + action 0 + 3010 : 0.8 + 4538 : 0.2 +state 3879 + action 0 + 4539 : 0.8 + 4540 : 0.2 +state 3880 + action 0 + 4541 : 0.8 + 4542 : 0.2 +state 3881 + action 0 + 4543 : 0.8 + 4544 : 0.2 +state 3882 + action 0 + 4545 : 0.8 + 4546 : 0.2 +state 3883 observe0Greater1 observeOnlyTrueSender + action 0 + 4547 : 1 +state 3884 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4548 : 1 +state 3885 observe0Greater1 observeOnlyTrueSender + action 0 + 4549 : 1 +state 3886 observe0Greater1 observeOnlyTrueSender + action 0 + 4550 : 1 +state 3887 observe0Greater1 observeOnlyTrueSender + action 0 + 4551 : 1 +state 3888 observe2Greater1 observeIGreater1 + action 0 + 4512 : 1 +state 3889 observe2Greater1 observeIGreater1 + action 0 + 4552 : 1 +state 3890 observe2Greater1 observeIGreater1 + action 0 + 4553 : 1 +state 3891 observe2Greater1 observeIGreater1 + action 0 + 4554 : 1 +state 3892 observe2Greater1 observeIGreater1 + action 0 + 3048 : 0.8 + 4555 : 0.2 +state 3893 observe2Greater1 observeIGreater1 + action 0 + 4556 : 0.8 + 4557 : 0.2 +state 3894 observe2Greater1 observeIGreater1 + action 0 + 4558 : 0.8 + 4559 : 0.2 +state 3895 observe2Greater1 observeIGreater1 + action 0 + 4560 : 0.8 + 4561 : 0.2 +state 3896 observe2Greater1 observeIGreater1 + action 0 + 4562 : 0.8 + 4563 : 0.2 +state 3897 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4564 : 1 +state 3898 + action 0 + 4513 : 1 +state 3899 observe2Greater1 observeIGreater1 + action 0 + 4553 : 1 +state 3900 observe3Greater1 observeIGreater1 + action 0 + 4565 : 1 +state 3901 + action 0 + 4566 : 1 +state 3902 + action 0 + 3067 : 0.8 + 4567 : 0.2 +state 3903 + action 0 + 4568 : 0.8 + 4569 : 0.2 +state 3904 + action 0 + 4570 : 0.8 + 4571 : 0.2 +state 3905 + action 0 + 4572 : 0.8 + 4573 : 0.2 +state 3906 + action 0 + 4574 : 0.8 + 4575 : 0.2 +state 3907 observe0Greater1 observeOnlyTrueSender + action 0 + 4576 : 1 +state 3908 + action 0 + 4514 : 1 +state 3909 observe2Greater1 observeIGreater1 + action 0 + 4554 : 1 +state 3910 + action 0 + 4566 : 1 +state 3911 observe4Greater1 observeIGreater1 + action 0 + 4577 : 1 +state 3912 + action 0 + 3080 : 0.8 + 4578 : 0.2 +state 3913 + action 0 + 4579 : 0.8 + 4580 : 0.2 +state 3914 + action 0 + 4581 : 0.8 + 4582 : 0.2 +state 3915 + action 0 + 4583 : 0.8 + 4584 : 0.2 +state 3916 + action 0 + 4585 : 0.8 + 4586 : 0.2 +state 3917 observe0Greater1 observeOnlyTrueSender + action 0 + 4587 : 1 +state 3918 observe0Greater1 observeOnlyTrueSender + action 0 + 4588 : 1 +state 3919 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4589 : 1 +state 3920 observe0Greater1 observeOnlyTrueSender + action 0 + 4590 : 1 +state 3921 observe0Greater1 observeOnlyTrueSender + action 0 + 4591 : 1 +state 3922 observe3Greater1 observeIGreater1 + action 0 + 4525 : 1 +state 3923 observe3Greater1 observeIGreater1 + action 0 + 4565 : 1 +state 3924 observe3Greater1 observeIGreater1 + action 0 + 4592 : 1 +state 3925 observe3Greater1 observeIGreater1 + action 0 + 4593 : 1 +state 3926 observe3Greater1 observeIGreater1 + action 0 + 3112 : 0.8 + 4594 : 0.2 +state 3927 observe3Greater1 observeIGreater1 + action 0 + 4595 : 0.8 + 4596 : 0.2 +state 3928 observe3Greater1 observeIGreater1 + action 0 + 4597 : 0.8 + 4598 : 0.2 +state 3929 observe3Greater1 observeIGreater1 + action 0 + 4599 : 0.8 + 4600 : 0.2 +state 3930 observe3Greater1 observeIGreater1 + action 0 + 4601 : 0.8 + 4602 : 0.2 +state 3931 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4603 : 1 +state 3932 + action 0 + 4526 : 1 +state 3933 + action 0 + 4566 : 1 +state 3934 observe3Greater1 observeIGreater1 + action 0 + 4593 : 1 +state 3935 observe4Greater1 observeIGreater1 + action 0 + 4604 : 1 +state 3936 + action 0 + 3125 : 0.8 + 4605 : 0.2 +state 3937 + action 0 + 4606 : 0.8 + 4607 : 0.2 +state 3938 + action 0 + 4608 : 0.8 + 4609 : 0.2 +state 3939 + action 0 + 4610 : 0.8 + 4611 : 0.2 +state 3940 + action 0 + 4612 : 0.8 + 4613 : 0.2 +state 3941 observe0Greater1 observeOnlyTrueSender + action 0 + 4614 : 1 +state 3942 observe0Greater1 observeOnlyTrueSender + action 0 + 4615 : 1 +state 3943 observe0Greater1 observeOnlyTrueSender + action 0 + 4616 : 1 +state 3944 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4617 : 1 +state 3945 observe0Greater1 observeOnlyTrueSender + action 0 + 4618 : 1 +state 3946 observe4Greater1 observeIGreater1 + action 0 + 4537 : 1 +state 3947 observe4Greater1 observeIGreater1 + action 0 + 4577 : 1 +state 3948 observe4Greater1 observeIGreater1 + action 0 + 4604 : 1 +state 3949 observe4Greater1 observeIGreater1 + action 0 + 4619 : 1 +state 3950 observe4Greater1 observeIGreater1 + action 0 + 3151 : 0.8 + 4620 : 0.2 +state 3951 observe4Greater1 observeIGreater1 + action 0 + 4621 : 0.8 + 4622 : 0.2 +state 3952 observe4Greater1 observeIGreater1 + action 0 + 4623 : 0.8 + 4624 : 0.2 +state 3953 observe4Greater1 observeIGreater1 + action 0 + 4625 : 0.8 + 4626 : 0.2 +state 3954 observe4Greater1 observeIGreater1 + action 0 + 4627 : 0.8 + 4628 : 0.2 +state 3955 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4629 : 1 +state 3956 observe0Greater1 observeOnlyTrueSender + action 0 + 4630 : 1 +state 3957 observe0Greater1 observeOnlyTrueSender + action 0 + 4631 : 1 +state 3958 observe0Greater1 observeOnlyTrueSender + action 0 + 4632 : 1 +state 3959 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4633 : 1 +state 3960 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3961 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3962 observe1Greater1 observeIGreater1 + action 0 + 4635 : 1 +state 3963 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3964 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3965 observe1Greater1 observeIGreater1 + action 0 + 4636 : 1 +state 3966 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3967 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3968 observe1Greater1 observeIGreater1 + action 0 + 4637 : 1 +state 3969 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3970 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3971 observe1Greater1 observeIGreater1 + action 0 + 4638 : 1 +state 3972 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3973 observe1Greater1 observeIGreater1 + action 0 + 4639 : 0.833 + 4640 : 0.167 +state 3974 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3975 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3976 observe1Greater1 observeIGreater1 + action 0 + 4642 : 1 +state 3977 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3978 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3979 observe1Greater1 observeIGreater1 + action 0 + 4643 : 1 +state 3980 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3981 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3982 observe1Greater1 observeIGreater1 + action 0 + 4644 : 1 +state 3983 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3984 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3985 observe1Greater1 observeIGreater1 + action 0 + 4645 : 1 +state 3986 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3987 observe1Greater1 observeIGreater1 + action 0 + 4646 : 0.833 + 4647 : 0.167 +state 3988 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3989 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3990 observe1Greater1 observeIGreater1 + action 0 + 4649 : 1 +state 3991 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3992 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3993 observe1Greater1 observeIGreater1 + action 0 + 4650 : 1 +state 3994 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3995 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3996 observe1Greater1 observeIGreater1 + action 0 + 4651 : 1 +state 3997 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3998 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3999 observe1Greater1 observeIGreater1 + action 0 + 4652 : 1 +state 4000 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 4001 observe1Greater1 observeIGreater1 + action 0 + 4653 : 0.833 + 4654 : 0.167 +state 4002 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4003 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4004 observe1Greater1 observeIGreater1 + action 0 + 4656 : 1 +state 4005 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4006 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4007 observe1Greater1 observeIGreater1 + action 0 + 4657 : 1 +state 4008 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4009 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4010 observe1Greater1 observeIGreater1 + action 0 + 4658 : 1 +state 4011 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4012 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4013 observe1Greater1 observeIGreater1 + action 0 + 4659 : 1 +state 4014 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4015 observe1Greater1 observeIGreater1 + action 0 + 4660 : 0.833 + 4661 : 0.167 +state 4016 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2958 : 0.833 + 2959 : 0.167 +state 4017 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4662 : 1 +state 4018 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4663 : 0.833 + 4664 : 0.167 +state 4019 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4665 : 1 +state 4020 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4666 : 0.833 + 4667 : 0.167 +state 4021 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4668 : 1 +state 4022 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4669 : 0.833 + 4670 : 0.167 +state 4023 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4671 : 1 +state 4024 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4672 : 0.833 + 4673 : 0.167 +state 4025 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4674 : 1 +state 4026 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4026 : 1 +state 4027 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4028 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4029 observe2Greater1 observeIGreater1 + action 0 + 4676 : 1 +state 4030 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4031 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4032 observe2Greater1 observeIGreater1 + action 0 + 4677 : 1 +state 4033 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4034 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4035 observe2Greater1 observeIGreater1 + action 0 + 4678 : 1 +state 4036 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4037 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4038 observe2Greater1 observeIGreater1 + action 0 + 4679 : 1 +state 4039 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4040 observe2Greater1 observeIGreater1 + action 0 + 4680 : 0.833 + 4681 : 0.167 +state 4041 + action 0 + 4682 : 1 +state 4042 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4043 + action 0 + 4683 : 1 +state 4044 + action 0 + 4682 : 1 +state 4045 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4046 + action 0 + 4684 : 1 +state 4047 + action 0 + 4682 : 1 +state 4048 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4049 + action 0 + 4685 : 1 +state 4050 + action 0 + 4682 : 1 +state 4051 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4052 + action 0 + 4686 : 1 +state 4053 + action 0 + 4682 : 1 +state 4054 + action 0 + 4687 : 0.833 + 4688 : 0.167 +state 4055 + action 0 + 4689 : 1 +state 4056 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4057 + action 0 + 4690 : 1 +state 4058 + action 0 + 4689 : 1 +state 4059 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4060 + action 0 + 4691 : 1 +state 4061 + action 0 + 4689 : 1 +state 4062 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4063 + action 0 + 4692 : 1 +state 4064 + action 0 + 4689 : 1 +state 4065 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4066 + action 0 + 4693 : 1 +state 4067 + action 0 + 4689 : 1 +state 4068 + action 0 + 4694 : 0.833 + 4695 : 0.167 +state 4069 observe0Greater1 observeOnlyTrueSender + action 0 + 2983 : 0.833 + 2984 : 0.167 +state 4070 observe0Greater1 observeOnlyTrueSender + action 0 + 4696 : 1 +state 4071 observe0Greater1 observeOnlyTrueSender + action 0 + 4697 : 0.833 + 4698 : 0.167 +state 4072 observe0Greater1 observeOnlyTrueSender + action 0 + 4699 : 1 +state 4073 observe0Greater1 observeOnlyTrueSender + action 0 + 4700 : 0.833 + 4701 : 0.167 +state 4074 observe0Greater1 observeOnlyTrueSender + action 0 + 4702 : 1 +state 4075 observe0Greater1 observeOnlyTrueSender + action 0 + 4703 : 0.833 + 4704 : 0.167 +state 4076 observe0Greater1 observeOnlyTrueSender + action 0 + 4705 : 1 +state 4077 observe0Greater1 observeOnlyTrueSender + action 0 + 4706 : 0.833 + 4707 : 0.167 +state 4078 observe0Greater1 observeOnlyTrueSender + action 0 + 4708 : 1 +state 4079 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4079 : 1 +state 4080 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4081 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4082 observe3Greater1 observeIGreater1 + action 0 + 4710 : 1 +state 4083 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4084 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4085 observe3Greater1 observeIGreater1 + action 0 + 4711 : 1 +state 4086 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4087 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4088 observe3Greater1 observeIGreater1 + action 0 + 4712 : 1 +state 4089 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4090 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4091 observe3Greater1 observeIGreater1 + action 0 + 4713 : 1 +state 4092 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4093 observe3Greater1 observeIGreater1 + action 0 + 4714 : 0.833 + 4715 : 0.167 +state 4094 + action 0 + 4716 : 1 +state 4095 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4096 + action 0 + 4717 : 1 +state 4097 + action 0 + 4716 : 1 +state 4098 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4099 + action 0 + 4718 : 1 +state 4100 + action 0 + 4716 : 1 +state 4101 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4102 + action 0 + 4719 : 1 +state 4103 + action 0 + 4716 : 1 +state 4104 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4105 + action 0 + 4720 : 1 +state 4106 + action 0 + 4716 : 1 +state 4107 + action 0 + 4721 : 0.833 + 4722 : 0.167 +state 4108 observe0Greater1 observeOnlyTrueSender + action 0 + 3002 : 0.833 + 3003 : 0.167 +state 4109 observe0Greater1 observeOnlyTrueSender + action 0 + 4723 : 1 +state 4110 observe0Greater1 observeOnlyTrueSender + action 0 + 4724 : 0.833 + 4725 : 0.167 +state 4111 observe0Greater1 observeOnlyTrueSender + action 0 + 4726 : 1 +state 4112 observe0Greater1 observeOnlyTrueSender + action 0 + 4727 : 0.833 + 4728 : 0.167 +state 4113 observe0Greater1 observeOnlyTrueSender + action 0 + 4729 : 1 +state 4114 observe0Greater1 observeOnlyTrueSender + action 0 + 4730 : 0.833 + 4731 : 0.167 +state 4115 observe0Greater1 observeOnlyTrueSender + action 0 + 4732 : 1 +state 4116 observe0Greater1 observeOnlyTrueSender + action 0 + 4733 : 0.833 + 4734 : 0.167 +state 4117 observe0Greater1 observeOnlyTrueSender + action 0 + 4735 : 1 +state 4118 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4118 : 1 +state 4119 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4120 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4121 observe4Greater1 observeIGreater1 + action 0 + 4737 : 1 +state 4122 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4123 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4124 observe4Greater1 observeIGreater1 + action 0 + 4738 : 1 +state 4125 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4126 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4127 observe4Greater1 observeIGreater1 + action 0 + 4739 : 1 +state 4128 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4129 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4130 observe4Greater1 observeIGreater1 + action 0 + 4740 : 1 +state 4131 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4132 observe4Greater1 observeIGreater1 + action 0 + 4741 : 0.833 + 4742 : 0.167 +state 4133 observe0Greater1 observeOnlyTrueSender + action 0 + 3015 : 0.833 + 3016 : 0.167 +state 4134 observe0Greater1 observeOnlyTrueSender + action 0 + 4743 : 1 +state 4135 observe0Greater1 observeOnlyTrueSender + action 0 + 4744 : 0.833 + 4745 : 0.167 +state 4136 observe0Greater1 observeOnlyTrueSender + action 0 + 4746 : 1 +state 4137 observe0Greater1 observeOnlyTrueSender + action 0 + 4747 : 0.833 + 4748 : 0.167 +state 4138 observe0Greater1 observeOnlyTrueSender + action 0 + 4749 : 1 +state 4139 observe0Greater1 observeOnlyTrueSender + action 0 + 4750 : 0.833 + 4751 : 0.167 +state 4140 observe0Greater1 observeOnlyTrueSender + action 0 + 4752 : 1 +state 4141 observe0Greater1 observeOnlyTrueSender + action 0 + 4753 : 0.833 + 4754 : 0.167 +state 4142 observe0Greater1 observeOnlyTrueSender + action 0 + 4755 : 1 +state 4143 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4143 : 1 +state 4144 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4144 : 1 +state 4145 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4145 : 1 +state 4146 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4146 : 1 +state 4147 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4147 : 1 +state 4148 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4149 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4150 observe2Greater1 observeIGreater1 + action 0 + 4757 : 1 +state 4151 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4152 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4153 observe2Greater1 observeIGreater1 + action 0 + 4758 : 1 +state 4154 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4155 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4156 observe2Greater1 observeIGreater1 + action 0 + 4759 : 1 +state 4157 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4158 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4159 observe2Greater1 observeIGreater1 + action 0 + 4760 : 1 +state 4160 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4161 observe2Greater1 observeIGreater1 + action 0 + 4761 : 0.833 + 4762 : 0.167 +state 4162 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4163 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4164 observe2Greater1 observeIGreater1 + action 0 + 4764 : 1 +state 4165 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4166 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4167 observe2Greater1 observeIGreater1 + action 0 + 4765 : 1 +state 4168 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4169 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4170 observe2Greater1 observeIGreater1 + action 0 + 4766 : 1 +state 4171 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4172 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4173 observe2Greater1 observeIGreater1 + action 0 + 4767 : 1 +state 4174 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4175 observe2Greater1 observeIGreater1 + action 0 + 4768 : 0.833 + 4769 : 0.167 +state 4176 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4177 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4178 observe2Greater1 observeIGreater1 + action 0 + 4771 : 1 +state 4179 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4180 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4181 observe2Greater1 observeIGreater1 + action 0 + 4772 : 1 +state 4182 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4183 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4184 observe2Greater1 observeIGreater1 + action 0 + 4773 : 1 +state 4185 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4186 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4187 observe2Greater1 observeIGreater1 + action 0 + 4774 : 1 +state 4188 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4189 observe2Greater1 observeIGreater1 + action 0 + 4775 : 0.833 + 4776 : 0.167 +state 4190 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3053 : 0.833 + 3054 : 0.167 +state 4191 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4777 : 1 +state 4192 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4778 : 0.833 + 4779 : 0.167 +state 4193 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4780 : 1 +state 4194 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4781 : 0.833 + 4782 : 0.167 +state 4195 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4783 : 1 +state 4196 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4784 : 0.833 + 4785 : 0.167 +state 4197 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4786 : 1 +state 4198 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4787 : 0.833 + 4788 : 0.167 +state 4199 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4789 : 1 +state 4200 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4200 : 1 +state 4201 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4202 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4203 observe3Greater1 observeIGreater1 + action 0 + 4791 : 1 +state 4204 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4205 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4206 observe3Greater1 observeIGreater1 + action 0 + 4792 : 1 +state 4207 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4208 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4209 observe3Greater1 observeIGreater1 + action 0 + 4793 : 1 +state 4210 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4211 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4212 observe3Greater1 observeIGreater1 + action 0 + 4794 : 1 +state 4213 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4214 observe3Greater1 observeIGreater1 + action 0 + 4795 : 0.833 + 4796 : 0.167 +state 4215 + action 0 + 4797 : 1 +state 4216 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4217 + action 0 + 4798 : 1 +state 4218 + action 0 + 4797 : 1 +state 4219 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4220 + action 0 + 4799 : 1 +state 4221 + action 0 + 4797 : 1 +state 4222 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4223 + action 0 + 4800 : 1 +state 4224 + action 0 + 4797 : 1 +state 4225 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4226 + action 0 + 4801 : 1 +state 4227 + action 0 + 4797 : 1 +state 4228 + action 0 + 4802 : 0.833 + 4803 : 0.167 +state 4229 observe0Greater1 observeOnlyTrueSender + action 0 + 3072 : 0.833 + 3073 : 0.167 +state 4230 observe0Greater1 observeOnlyTrueSender + action 0 + 4804 : 1 +state 4231 observe0Greater1 observeOnlyTrueSender + action 0 + 4805 : 0.833 + 4806 : 0.167 +state 4232 observe0Greater1 observeOnlyTrueSender + action 0 + 4807 : 1 +state 4233 observe0Greater1 observeOnlyTrueSender + action 0 + 4808 : 0.833 + 4809 : 0.167 +state 4234 observe0Greater1 observeOnlyTrueSender + action 0 + 4810 : 1 +state 4235 observe0Greater1 observeOnlyTrueSender + action 0 + 4811 : 0.833 + 4812 : 0.167 +state 4236 observe0Greater1 observeOnlyTrueSender + action 0 + 4813 : 1 +state 4237 observe0Greater1 observeOnlyTrueSender + action 0 + 4814 : 0.833 + 4815 : 0.167 +state 4238 observe0Greater1 observeOnlyTrueSender + action 0 + 4816 : 1 +state 4239 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4239 : 1 +state 4240 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4241 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4242 observe4Greater1 observeIGreater1 + action 0 + 4818 : 1 +state 4243 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4244 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4245 observe4Greater1 observeIGreater1 + action 0 + 4819 : 1 +state 4246 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4247 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4248 observe4Greater1 observeIGreater1 + action 0 + 4820 : 1 +state 4249 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4250 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4251 observe4Greater1 observeIGreater1 + action 0 + 4821 : 1 +state 4252 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4253 observe4Greater1 observeIGreater1 + action 0 + 4822 : 0.833 + 4823 : 0.167 +state 4254 observe0Greater1 observeOnlyTrueSender + action 0 + 3085 : 0.833 + 3086 : 0.167 +state 4255 observe0Greater1 observeOnlyTrueSender + action 0 + 4824 : 1 +state 4256 observe0Greater1 observeOnlyTrueSender + action 0 + 4825 : 0.833 + 4826 : 0.167 +state 4257 observe0Greater1 observeOnlyTrueSender + action 0 + 4827 : 1 +state 4258 observe0Greater1 observeOnlyTrueSender + action 0 + 4828 : 0.833 + 4829 : 0.167 +state 4259 observe0Greater1 observeOnlyTrueSender + action 0 + 4830 : 1 +state 4260 observe0Greater1 observeOnlyTrueSender + action 0 + 4831 : 0.833 + 4832 : 0.167 +state 4261 observe0Greater1 observeOnlyTrueSender + action 0 + 4833 : 1 +state 4262 observe0Greater1 observeOnlyTrueSender + action 0 + 4834 : 0.833 + 4835 : 0.167 +state 4263 observe0Greater1 observeOnlyTrueSender + action 0 + 4836 : 1 +state 4264 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4264 : 1 +state 4265 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4265 : 1 +state 4266 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4266 : 1 +state 4267 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4267 : 1 +state 4268 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4268 : 1 +state 4269 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4270 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4271 observe3Greater1 observeIGreater1 + action 0 + 4838 : 1 +state 4272 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4273 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4274 observe3Greater1 observeIGreater1 + action 0 + 4839 : 1 +state 4275 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4276 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4277 observe3Greater1 observeIGreater1 + action 0 + 4840 : 1 +state 4278 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4279 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4280 observe3Greater1 observeIGreater1 + action 0 + 4841 : 1 +state 4281 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4282 observe3Greater1 observeIGreater1 + action 0 + 4842 : 0.833 + 4843 : 0.167 +state 4283 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4284 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4285 observe3Greater1 observeIGreater1 + action 0 + 4845 : 1 +state 4286 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4287 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4288 observe3Greater1 observeIGreater1 + action 0 + 4846 : 1 +state 4289 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4290 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4291 observe3Greater1 observeIGreater1 + action 0 + 4847 : 1 +state 4292 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4293 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4294 observe3Greater1 observeIGreater1 + action 0 + 4848 : 1 +state 4295 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4296 observe3Greater1 observeIGreater1 + action 0 + 4849 : 0.833 + 4850 : 0.167 +state 4297 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3117 : 0.833 + 3118 : 0.167 +state 4298 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4851 : 1 +state 4299 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4852 : 0.833 + 4853 : 0.167 +state 4300 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4854 : 1 +state 4301 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4855 : 0.833 + 4856 : 0.167 +state 4302 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4857 : 1 +state 4303 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4858 : 0.833 + 4859 : 0.167 +state 4304 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4860 : 1 +state 4305 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4861 : 0.833 + 4862 : 0.167 +state 4306 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4863 : 1 +state 4307 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4307 : 1 +state 4308 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4309 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4310 observe4Greater1 observeIGreater1 + action 0 + 4865 : 1 +state 4311 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4312 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4313 observe4Greater1 observeIGreater1 + action 0 + 4866 : 1 +state 4314 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4315 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4316 observe4Greater1 observeIGreater1 + action 0 + 4867 : 1 +state 4317 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4318 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4319 observe4Greater1 observeIGreater1 + action 0 + 4868 : 1 +state 4320 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4321 observe4Greater1 observeIGreater1 + action 0 + 4869 : 0.833 + 4870 : 0.167 +state 4322 observe0Greater1 observeOnlyTrueSender + action 0 + 3130 : 0.833 + 3131 : 0.167 +state 4323 observe0Greater1 observeOnlyTrueSender + action 0 + 4871 : 1 +state 4324 observe0Greater1 observeOnlyTrueSender + action 0 + 4872 : 0.833 + 4873 : 0.167 +state 4325 observe0Greater1 observeOnlyTrueSender + action 0 + 4874 : 1 +state 4326 observe0Greater1 observeOnlyTrueSender + action 0 + 4875 : 0.833 + 4876 : 0.167 +state 4327 observe0Greater1 observeOnlyTrueSender + action 0 + 4877 : 1 +state 4328 observe0Greater1 observeOnlyTrueSender + action 0 + 4878 : 0.833 + 4879 : 0.167 +state 4329 observe0Greater1 observeOnlyTrueSender + action 0 + 4880 : 1 +state 4330 observe0Greater1 observeOnlyTrueSender + action 0 + 4881 : 0.833 + 4882 : 0.167 +state 4331 observe0Greater1 observeOnlyTrueSender + action 0 + 4883 : 1 +state 4332 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4332 : 1 +state 4333 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4333 : 1 +state 4334 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4334 : 1 +state 4335 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4335 : 1 +state 4336 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4336 : 1 +state 4337 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4338 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4339 observe4Greater1 observeIGreater1 + action 0 + 4885 : 1 +state 4340 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4341 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4342 observe4Greater1 observeIGreater1 + action 0 + 4886 : 1 +state 4343 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4344 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4345 observe4Greater1 observeIGreater1 + action 0 + 4887 : 1 +state 4346 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4347 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4348 observe4Greater1 observeIGreater1 + action 0 + 4888 : 1 +state 4349 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4350 observe4Greater1 observeIGreater1 + action 0 + 4889 : 0.833 + 4890 : 0.167 +state 4351 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3156 : 0.833 + 3157 : 0.167 +state 4352 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4891 : 1 +state 4353 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4892 : 0.833 + 4893 : 0.167 +state 4354 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4894 : 1 +state 4355 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4895 : 0.833 + 4896 : 0.167 +state 4356 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4897 : 1 +state 4357 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4898 : 0.833 + 4899 : 0.167 +state 4358 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4900 : 1 +state 4359 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4901 : 0.833 + 4902 : 0.167 +state 4360 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4903 : 1 +state 4361 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4361 : 1 +state 4362 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4362 : 1 +state 4363 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4363 : 1 +state 4364 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4364 : 1 +state 4365 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4365 : 1 +state 4366 deadlock + action 0 + 4366 : 1 +state 4367 deadlock + action 0 + 4367 : 1 +state 4368 deadlock + action 0 + 4368 : 1 +state 4369 deadlock + action 0 + 4369 : 1 +state 4370 deadlock + action 0 + 4370 : 1 +state 4371 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4372 + action 0 + 4904 : 1 +state 4373 deadlock + action 0 + 4373 : 1 +state 4374 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4375 + action 0 + 4905 : 1 +state 4376 deadlock + action 0 + 4376 : 1 +state 4377 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4378 + action 0 + 4906 : 1 +state 4379 deadlock + action 0 + 4379 : 1 +state 4380 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4381 + action 0 + 4907 : 1 +state 4382 deadlock + action 0 + 4382 : 1 +state 4383 deadlock + action 0 + 4383 : 1 +state 4384 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4385 + action 0 + 4908 : 1 +state 4386 deadlock + action 0 + 4386 : 1 +state 4387 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4388 + action 0 + 4909 : 1 +state 4389 deadlock + action 0 + 4389 : 1 +state 4390 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4391 + action 0 + 4910 : 1 +state 4392 deadlock + action 0 + 4392 : 1 +state 4393 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4394 + action 0 + 4911 : 1 +state 4395 deadlock + action 0 + 4395 : 1 +state 4396 deadlock + action 0 + 4396 : 1 +state 4397 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4398 + action 0 + 4912 : 1 +state 4399 deadlock + action 0 + 4399 : 1 +state 4400 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4401 + action 0 + 4913 : 1 +state 4402 deadlock + action 0 + 4402 : 1 +state 4403 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4404 + action 0 + 4914 : 1 +state 4405 deadlock + action 0 + 4405 : 1 +state 4406 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4407 + action 0 + 4915 : 1 +state 4408 deadlock + action 0 + 4408 : 1 +state 4409 deadlock + action 0 + 4409 : 1 +state 4410 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4411 + action 0 + 4916 : 1 +state 4412 deadlock + action 0 + 4412 : 1 +state 4413 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4414 + action 0 + 4917 : 1 +state 4415 deadlock + action 0 + 4415 : 1 +state 4416 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4417 + action 0 + 4918 : 1 +state 4418 deadlock + action 0 + 4418 : 1 +state 4419 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4420 + action 0 + 4919 : 1 +state 4421 deadlock + action 0 + 4421 : 1 +state 4422 observe1Greater1 observeIGreater1 + action 0 + 3266 : 0.8 + 4920 : 0.2 +state 4423 observe1Greater1 observeIGreater1 + action 0 + 4921 : 0.8 + 4922 : 0.2 +state 4424 observe1Greater1 observeIGreater1 + action 0 + 4923 : 0.8 + 4924 : 0.2 +state 4425 observe1Greater1 observeIGreater1 + action 0 + 4925 : 0.8 + 4926 : 0.2 +state 4426 observe1Greater1 observeIGreater1 + action 0 + 4927 : 0.8 + 4928 : 0.2 +state 4427 observe1Greater1 observeIGreater1 + action 0 + 4929 : 1 +state 4428 + action 0 + 3273 : 0.8 + 4930 : 0.2 +state 4429 + action 0 + 4931 : 0.8 + 4932 : 0.2 +state 4430 + action 0 + 4933 : 0.8 + 4934 : 0.2 +state 4431 + action 0 + 4935 : 0.8 + 4936 : 0.2 +state 4432 + action 0 + 4937 : 0.8 + 4938 : 0.2 +state 4433 + action 0 + 4939 : 1 +state 4434 + action 0 + 3280 : 0.8 + 4940 : 0.2 +state 4435 + action 0 + 4941 : 0.8 + 4942 : 0.2 +state 4436 + action 0 + 4943 : 0.8 + 4944 : 0.2 +state 4437 + action 0 + 4945 : 0.8 + 4946 : 0.2 +state 4438 + action 0 + 4947 : 0.8 + 4948 : 0.2 +state 4439 + action 0 + 4949 : 1 +state 4440 + action 0 + 3287 : 0.8 + 4950 : 0.2 +state 4441 + action 0 + 4951 : 0.8 + 4952 : 0.2 +state 4442 + action 0 + 4953 : 0.8 + 4954 : 0.2 +state 4443 + action 0 + 4955 : 0.8 + 4956 : 0.2 +state 4444 + action 0 + 4957 : 0.8 + 4958 : 0.2 +state 4445 + action 0 + 4959 : 1 +state 4446 observe1Greater1 observeIGreater1 + action 0 + 4960 : 1 +state 4447 + action 0 + 4961 : 1 +state 4448 + action 0 + 4962 : 1 +state 4449 + action 0 + 4963 : 1 +state 4450 observe2Greater1 observeIGreater1 + action 0 + 3307 : 0.8 + 4964 : 0.2 +state 4451 observe2Greater1 observeIGreater1 + action 0 + 4965 : 0.8 + 4966 : 0.2 +state 4452 observe2Greater1 observeIGreater1 + action 0 + 4967 : 0.8 + 4968 : 0.2 +state 4453 observe2Greater1 observeIGreater1 + action 0 + 4969 : 0.8 + 4970 : 0.2 +state 4454 observe2Greater1 observeIGreater1 + action 0 + 4971 : 0.8 + 4972 : 0.2 +state 4455 observe2Greater1 observeIGreater1 + action 0 + 4973 : 1 +state 4456 + action 0 + 3314 : 0.8 + 4974 : 0.2 +state 4457 + action 0 + 4975 : 0.8 + 4976 : 0.2 +state 4458 + action 0 + 4977 : 0.8 + 4978 : 0.2 +state 4459 + action 0 + 4979 : 0.8 + 4980 : 0.2 +state 4460 + action 0 + 4981 : 0.8 + 4982 : 0.2 +state 4461 + action 0 + 4983 : 1 +state 4462 + action 0 + 3321 : 0.8 + 4984 : 0.2 +state 4463 + action 0 + 4985 : 0.8 + 4986 : 0.2 +state 4464 + action 0 + 4987 : 0.8 + 4988 : 0.2 +state 4465 + action 0 + 4989 : 0.8 + 4990 : 0.2 +state 4466 + action 0 + 4991 : 0.8 + 4992 : 0.2 +state 4467 + action 0 + 4993 : 1 +state 4468 + action 0 + 4994 : 1 +state 4469 observe2Greater1 observeIGreater1 + action 0 + 4995 : 1 +state 4470 + action 0 + 4996 : 1 +state 4471 + action 0 + 4997 : 1 +state 4472 observe3Greater1 observeIGreater1 + action 0 + 3341 : 0.8 + 4998 : 0.2 +state 4473 observe3Greater1 observeIGreater1 + action 0 + 4999 : 0.8 + 5000 : 0.2 +state 4474 observe3Greater1 observeIGreater1 + action 0 + 5001 : 0.8 + 5002 : 0.2 +state 4475 observe3Greater1 observeIGreater1 + action 0 + 5003 : 0.8 + 5004 : 0.2 +state 4476 observe3Greater1 observeIGreater1 + action 0 + 5005 : 0.8 + 5006 : 0.2 +state 4477 observe3Greater1 observeIGreater1 + action 0 + 5007 : 1 +state 4478 + action 0 + 3348 : 0.8 + 5008 : 0.2 +state 4479 + action 0 + 5009 : 0.8 + 5010 : 0.2 +state 4480 + action 0 + 5011 : 0.8 + 5012 : 0.2 +state 4481 + action 0 + 5013 : 0.8 + 5014 : 0.2 +state 4482 + action 0 + 5015 : 0.8 + 5016 : 0.2 +state 4483 + action 0 + 5017 : 1 +state 4484 + action 0 + 5018 : 1 +state 4485 + action 0 + 5019 : 1 +state 4486 observe3Greater1 observeIGreater1 + action 0 + 5020 : 1 +state 4487 + action 0 + 5021 : 1 +state 4488 observe4Greater1 observeIGreater1 + action 0 + 3368 : 0.8 + 5022 : 0.2 +state 4489 observe4Greater1 observeIGreater1 + action 0 + 5023 : 0.8 + 5024 : 0.2 +state 4490 observe4Greater1 observeIGreater1 + action 0 + 5025 : 0.8 + 5026 : 0.2 +state 4491 observe4Greater1 observeIGreater1 + action 0 + 5027 : 0.8 + 5028 : 0.2 +state 4492 observe4Greater1 observeIGreater1 + action 0 + 5029 : 0.8 + 5030 : 0.2 +state 4493 observe4Greater1 observeIGreater1 + action 0 + 5031 : 1 +state 4494 + action 0 + 5032 : 1 +state 4495 + action 0 + 5033 : 1 +state 4496 + action 0 + 5034 : 1 +state 4497 observe4Greater1 observeIGreater1 + action 0 + 5035 : 1 +state 4498 observe1Greater1 observeIGreater1 + action 0 + 5036 : 0.833 + 5037 : 0.167 +state 4499 observe1Greater1 observeIGreater1 + action 0 + 5038 : 0.833 + 5039 : 0.167 +state 4500 observe1Greater1 observeIGreater1 + action 0 + 5040 : 0.833 + 5041 : 0.167 +state 4501 observe1Greater1 observeIGreater1 + action 0 + 5042 : 0.833 + 5043 : 0.167 +state 4502 observe1Greater1 observeIGreater1 + action 0 + 5044 : 1 +state 4503 observe1Greater1 observeIGreater1 + action 0 + 5045 : 0.833 + 5046 : 0.167 +state 4504 observe1Greater1 observeIGreater1 + action 0 + 5047 : 1 +state 4505 observe1Greater1 observeIGreater1 + action 0 + 5048 : 0.833 + 5049 : 0.167 +state 4506 observe1Greater1 observeIGreater1 + action 0 + 5050 : 1 +state 4507 observe1Greater1 observeIGreater1 + action 0 + 5051 : 0.833 + 5052 : 0.167 +state 4508 observe1Greater1 observeIGreater1 + action 0 + 5053 : 1 +state 4509 observe1Greater1 observeIGreater1 + action 0 + 5054 : 0.833 + 5055 : 0.167 +state 4510 observe1Greater1 observeIGreater1 + action 0 + 5056 : 1 +state 4511 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4511 : 1 +state 4512 observe2Greater1 observeIGreater1 + action 0 + 5057 : 0.833 + 5058 : 0.167 +state 4513 + action 0 + 5059 : 0.833 + 5060 : 0.167 +state 4514 + action 0 + 5061 : 0.833 + 5062 : 0.167 +state 4515 + action 0 + 5063 : 1 +state 4516 + action 0 + 5064 : 0.833 + 5065 : 0.167 +state 4517 + action 0 + 5066 : 1 +state 4518 + action 0 + 5067 : 0.833 + 5068 : 0.167 +state 4519 + action 0 + 5069 : 1 +state 4520 + action 0 + 5070 : 0.833 + 5071 : 0.167 +state 4521 + action 0 + 5072 : 1 +state 4522 + action 0 + 5073 : 0.833 + 5074 : 0.167 +state 4523 + action 0 + 5075 : 1 +state 4524 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4524 : 1 +state 4525 observe3Greater1 observeIGreater1 + action 0 + 5076 : 0.833 + 5077 : 0.167 +state 4526 + action 0 + 5078 : 0.833 + 5079 : 0.167 +state 4527 + action 0 + 5080 : 1 +state 4528 + action 0 + 5081 : 0.833 + 5082 : 0.167 +state 4529 + action 0 + 5083 : 1 +state 4530 + action 0 + 5084 : 0.833 + 5085 : 0.167 +state 4531 + action 0 + 5086 : 1 +state 4532 + action 0 + 5087 : 0.833 + 5088 : 0.167 +state 4533 + action 0 + 5089 : 1 +state 4534 + action 0 + 5090 : 0.833 + 5091 : 0.167 +state 4535 + action 0 + 5092 : 1 +state 4536 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4536 : 1 +state 4537 observe4Greater1 observeIGreater1 + action 0 + 5093 : 0.833 + 5094 : 0.167 +state 4538 + action 0 + 5095 : 1 +state 4539 + action 0 + 5096 : 0.833 + 5097 : 0.167 +state 4540 + action 0 + 5098 : 1 +state 4541 + action 0 + 5099 : 0.833 + 5100 : 0.167 +state 4542 + action 0 + 5101 : 1 +state 4543 + action 0 + 5102 : 0.833 + 5103 : 0.167 +state 4544 + action 0 + 5104 : 1 +state 4545 + action 0 + 5105 : 0.833 + 5106 : 0.167 +state 4546 + action 0 + 5107 : 1 +state 4547 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4547 : 1 +state 4548 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4548 : 1 +state 4549 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4549 : 1 +state 4550 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4550 : 1 +state 4551 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4551 : 1 +state 4552 observe2Greater1 observeIGreater1 + action 0 + 5108 : 0.833 + 5109 : 0.167 +state 4553 observe2Greater1 observeIGreater1 + action 0 + 5110 : 0.833 + 5111 : 0.167 +state 4554 observe2Greater1 observeIGreater1 + action 0 + 5112 : 0.833 + 5113 : 0.167 +state 4555 observe2Greater1 observeIGreater1 + action 0 + 5114 : 1 +state 4556 observe2Greater1 observeIGreater1 + action 0 + 5115 : 0.833 + 5116 : 0.167 +state 4557 observe2Greater1 observeIGreater1 + action 0 + 5117 : 1 +state 4558 observe2Greater1 observeIGreater1 + action 0 + 5118 : 0.833 + 5119 : 0.167 +state 4559 observe2Greater1 observeIGreater1 + action 0 + 5120 : 1 +state 4560 observe2Greater1 observeIGreater1 + action 0 + 5121 : 0.833 + 5122 : 0.167 +state 4561 observe2Greater1 observeIGreater1 + action 0 + 5123 : 1 +state 4562 observe2Greater1 observeIGreater1 + action 0 + 5124 : 0.833 + 5125 : 0.167 +state 4563 observe2Greater1 observeIGreater1 + action 0 + 5126 : 1 +state 4564 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4564 : 1 +state 4565 observe3Greater1 observeIGreater1 + action 0 + 5127 : 0.833 + 5128 : 0.167 +state 4566 + action 0 + 5129 : 0.833 + 5130 : 0.167 +state 4567 + action 0 + 5131 : 1 +state 4568 + action 0 + 5132 : 0.833 + 5133 : 0.167 +state 4569 + action 0 + 5134 : 1 +state 4570 + action 0 + 5135 : 0.833 + 5136 : 0.167 +state 4571 + action 0 + 5137 : 1 +state 4572 + action 0 + 5138 : 0.833 + 5139 : 0.167 +state 4573 + action 0 + 5140 : 1 +state 4574 + action 0 + 5141 : 0.833 + 5142 : 0.167 +state 4575 + action 0 + 5143 : 1 +state 4576 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4576 : 1 +state 4577 observe4Greater1 observeIGreater1 + action 0 + 5144 : 0.833 + 5145 : 0.167 +state 4578 + action 0 + 5146 : 1 +state 4579 + action 0 + 5147 : 0.833 + 5148 : 0.167 +state 4580 + action 0 + 5149 : 1 +state 4581 + action 0 + 5150 : 0.833 + 5151 : 0.167 +state 4582 + action 0 + 5152 : 1 +state 4583 + action 0 + 5153 : 0.833 + 5154 : 0.167 +state 4584 + action 0 + 5155 : 1 +state 4585 + action 0 + 5156 : 0.833 + 5157 : 0.167 +state 4586 + action 0 + 5158 : 1 +state 4587 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4587 : 1 +state 4588 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4588 : 1 +state 4589 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4589 : 1 +state 4590 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4590 : 1 +state 4591 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4591 : 1 +state 4592 observe3Greater1 observeIGreater1 + action 0 + 5159 : 0.833 + 5160 : 0.167 +state 4593 observe3Greater1 observeIGreater1 + action 0 + 5161 : 0.833 + 5162 : 0.167 +state 4594 observe3Greater1 observeIGreater1 + action 0 + 5163 : 1 +state 4595 observe3Greater1 observeIGreater1 + action 0 + 5164 : 0.833 + 5165 : 0.167 +state 4596 observe3Greater1 observeIGreater1 + action 0 + 5166 : 1 +state 4597 observe3Greater1 observeIGreater1 + action 0 + 5167 : 0.833 + 5168 : 0.167 +state 4598 observe3Greater1 observeIGreater1 + action 0 + 5169 : 1 +state 4599 observe3Greater1 observeIGreater1 + action 0 + 5170 : 0.833 + 5171 : 0.167 +state 4600 observe3Greater1 observeIGreater1 + action 0 + 5172 : 1 +state 4601 observe3Greater1 observeIGreater1 + action 0 + 5173 : 0.833 + 5174 : 0.167 +state 4602 observe3Greater1 observeIGreater1 + action 0 + 5175 : 1 +state 4603 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4603 : 1 +state 4604 observe4Greater1 observeIGreater1 + action 0 + 5176 : 0.833 + 5177 : 0.167 +state 4605 + action 0 + 5178 : 1 +state 4606 + action 0 + 5179 : 0.833 + 5180 : 0.167 +state 4607 + action 0 + 5181 : 1 +state 4608 + action 0 + 5182 : 0.833 + 5183 : 0.167 +state 4609 + action 0 + 5184 : 1 +state 4610 + action 0 + 5185 : 0.833 + 5186 : 0.167 +state 4611 + action 0 + 5187 : 1 +state 4612 + action 0 + 5188 : 0.833 + 5189 : 0.167 +state 4613 + action 0 + 5190 : 1 +state 4614 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4614 : 1 +state 4615 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4615 : 1 +state 4616 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4616 : 1 +state 4617 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4617 : 1 +state 4618 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4618 : 1 +state 4619 observe4Greater1 observeIGreater1 + action 0 + 5191 : 0.833 + 5192 : 0.167 +state 4620 observe4Greater1 observeIGreater1 + action 0 + 5193 : 1 +state 4621 observe4Greater1 observeIGreater1 + action 0 + 5194 : 0.833 + 5195 : 0.167 +state 4622 observe4Greater1 observeIGreater1 + action 0 + 5196 : 1 +state 4623 observe4Greater1 observeIGreater1 + action 0 + 5197 : 0.833 + 5198 : 0.167 +state 4624 observe4Greater1 observeIGreater1 + action 0 + 5199 : 1 +state 4625 observe4Greater1 observeIGreater1 + action 0 + 5200 : 0.833 + 5201 : 0.167 +state 4626 observe4Greater1 observeIGreater1 + action 0 + 5202 : 1 +state 4627 observe4Greater1 observeIGreater1 + action 0 + 5203 : 0.833 + 5204 : 0.167 +state 4628 observe4Greater1 observeIGreater1 + action 0 + 5205 : 1 +state 4629 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4629 : 1 +state 4630 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4630 : 1 +state 4631 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4631 : 1 +state 4632 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4632 : 1 +state 4633 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4633 : 1 +state 4634 observe1Greater1 observeIGreater1 + action 0 + 5036 : 0.833 + 5037 : 0.167 +state 4635 observe1Greater1 observeIGreater1 + action 0 + 5206 : 1 +state 4636 observe1Greater1 observeIGreater1 + action 0 + 5207 : 1 +state 4637 observe1Greater1 observeIGreater1 + action 0 + 5208 : 1 +state 4638 observe1Greater1 observeIGreater1 + action 0 + 5209 : 1 +state 4639 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 4640 observe1Greater1 observeIGreater1 + action 0 + 5215 : 1 +state 4641 observe1Greater1 observeIGreater1 + action 0 + 5038 : 0.833 + 5039 : 0.167 +state 4642 observe1Greater1 observeIGreater1 + action 0 + 5216 : 1 +state 4643 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5217 : 1 +state 4644 observe1Greater1 observeIGreater1 + action 0 + 5218 : 1 +state 4645 observe1Greater1 observeIGreater1 + action 0 + 5219 : 1 +state 4646 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 4647 observe1Greater1 observeIGreater1 + action 0 + 5225 : 1 +state 4648 observe1Greater1 observeIGreater1 + action 0 + 5040 : 0.833 + 5041 : 0.167 +state 4649 observe1Greater1 observeIGreater1 + action 0 + 5226 : 1 +state 4650 observe1Greater1 observeIGreater1 + action 0 + 5227 : 1 +state 4651 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5228 : 1 +state 4652 observe1Greater1 observeIGreater1 + action 0 + 5229 : 1 +state 4653 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 4654 observe1Greater1 observeIGreater1 + action 0 + 5235 : 1 +state 4655 observe1Greater1 observeIGreater1 + action 0 + 5042 : 0.833 + 5043 : 0.167 +state 4656 observe1Greater1 observeIGreater1 + action 0 + 5236 : 1 +state 4657 observe1Greater1 observeIGreater1 + action 0 + 5237 : 1 +state 4658 observe1Greater1 observeIGreater1 + action 0 + 5238 : 1 +state 4659 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5239 : 1 +state 4660 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 4661 observe1Greater1 observeIGreater1 + action 0 + 5245 : 1 +state 4662 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4662 : 1 +state 4663 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4664 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5246 : 1 +state 4665 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4665 : 1 +state 4666 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4667 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5247 : 1 +state 4668 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4668 : 1 +state 4669 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4670 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5248 : 1 +state 4671 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4671 : 1 +state 4672 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4673 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5249 : 1 +state 4674 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4674 : 1 +state 4675 observe2Greater1 observeIGreater1 + action 0 + 5057 : 0.833 + 5058 : 0.167 +state 4676 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5250 : 1 +state 4677 observe2Greater1 observeIGreater1 + action 0 + 5251 : 1 +state 4678 observe2Greater1 observeIGreater1 + action 0 + 5252 : 1 +state 4679 observe2Greater1 observeIGreater1 + action 0 + 5253 : 1 +state 4680 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 4681 observe2Greater1 observeIGreater1 + action 0 + 5259 : 1 +state 4682 + action 0 + 5059 : 0.833 + 5060 : 0.167 +state 4683 observe1Greater1 observeIGreater1 + action 0 + 5260 : 1 +state 4684 observe2Greater1 observeIGreater1 + action 0 + 5261 : 1 +state 4685 observe3Greater1 observeIGreater1 + action 0 + 5262 : 1 +state 4686 + action 0 + 5263 : 1 +state 4687 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 4688 + action 0 + 5269 : 1 +state 4689 + action 0 + 5061 : 0.833 + 5062 : 0.167 +state 4690 observe1Greater1 observeIGreater1 + action 0 + 5270 : 1 +state 4691 observe2Greater1 observeIGreater1 + action 0 + 5271 : 1 +state 4692 + action 0 + 5272 : 1 +state 4693 observe4Greater1 observeIGreater1 + action 0 + 5273 : 1 +state 4694 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 4695 + action 0 + 5279 : 1 +state 4696 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4696 : 1 +state 4697 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4698 observe0Greater1 observeOnlyTrueSender + action 0 + 5280 : 1 +state 4699 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4699 : 1 +state 4700 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4701 observe0Greater1 observeOnlyTrueSender + action 0 + 5281 : 1 +state 4702 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4702 : 1 +state 4703 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4704 observe0Greater1 observeOnlyTrueSender + action 0 + 5282 : 1 +state 4705 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4705 : 1 +state 4706 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4707 observe0Greater1 observeOnlyTrueSender + action 0 + 5283 : 1 +state 4708 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4708 : 1 +state 4709 observe3Greater1 observeIGreater1 + action 0 + 5076 : 0.833 + 5077 : 0.167 +state 4710 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5284 : 1 +state 4711 observe3Greater1 observeIGreater1 + action 0 + 5285 : 1 +state 4712 observe3Greater1 observeIGreater1 + action 0 + 5286 : 1 +state 4713 observe3Greater1 observeIGreater1 + action 0 + 5287 : 1 +state 4714 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 4715 observe3Greater1 observeIGreater1 + action 0 + 5293 : 1 +state 4716 + action 0 + 5078 : 0.833 + 5079 : 0.167 +state 4717 observe1Greater1 observeIGreater1 + action 0 + 5294 : 1 +state 4718 + action 0 + 5295 : 1 +state 4719 observe3Greater1 observeIGreater1 + action 0 + 5296 : 1 +state 4720 observe4Greater1 observeIGreater1 + action 0 + 5297 : 1 +state 4721 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 4722 + action 0 + 5303 : 1 +state 4723 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4723 : 1 +state 4724 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4725 observe0Greater1 observeOnlyTrueSender + action 0 + 5304 : 1 +state 4726 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4726 : 1 +state 4727 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4728 observe0Greater1 observeOnlyTrueSender + action 0 + 5305 : 1 +state 4729 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4729 : 1 +state 4730 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4731 observe0Greater1 observeOnlyTrueSender + action 0 + 5306 : 1 +state 4732 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4732 : 1 +state 4733 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4734 observe0Greater1 observeOnlyTrueSender + action 0 + 5307 : 1 +state 4735 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4735 : 1 +state 4736 observe4Greater1 observeIGreater1 + action 0 + 5093 : 0.833 + 5094 : 0.167 +state 4737 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5308 : 1 +state 4738 observe4Greater1 observeIGreater1 + action 0 + 5309 : 1 +state 4739 observe4Greater1 observeIGreater1 + action 0 + 5310 : 1 +state 4740 observe4Greater1 observeIGreater1 + action 0 + 5311 : 1 +state 4741 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 4742 observe4Greater1 observeIGreater1 + action 0 + 5317 : 1 +state 4743 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4743 : 1 +state 4744 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4745 observe0Greater1 observeOnlyTrueSender + action 0 + 5318 : 1 +state 4746 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4746 : 1 +state 4747 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4748 observe0Greater1 observeOnlyTrueSender + action 0 + 5319 : 1 +state 4749 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4749 : 1 +state 4750 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4751 observe0Greater1 observeOnlyTrueSender + action 0 + 5320 : 1 +state 4752 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4752 : 1 +state 4753 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4754 observe0Greater1 observeOnlyTrueSender + action 0 + 5321 : 1 +state 4755 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4755 : 1 +state 4756 observe2Greater1 observeIGreater1 + action 0 + 5108 : 0.833 + 5109 : 0.167 +state 4757 observe2Greater1 observeIGreater1 + action 0 + 5322 : 1 +state 4758 observe2Greater1 observeIGreater1 + action 0 + 5323 : 1 +state 4759 observe2Greater1 observeIGreater1 + action 0 + 5324 : 1 +state 4760 observe2Greater1 observeIGreater1 + action 0 + 5325 : 1 +state 4761 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 4762 observe2Greater1 observeIGreater1 + action 0 + 5331 : 1 +state 4763 observe2Greater1 observeIGreater1 + action 0 + 5110 : 0.833 + 5111 : 0.167 +state 4764 observe2Greater1 observeIGreater1 + action 0 + 5332 : 1 +state 4765 observe2Greater1 observeIGreater1 + action 0 + 5333 : 1 +state 4766 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5334 : 1 +state 4767 observe2Greater1 observeIGreater1 + action 0 + 5335 : 1 +state 4768 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 4769 observe2Greater1 observeIGreater1 + action 0 + 5341 : 1 +state 4770 observe2Greater1 observeIGreater1 + action 0 + 5112 : 0.833 + 5113 : 0.167 +state 4771 observe2Greater1 observeIGreater1 + action 0 + 5342 : 1 +state 4772 observe2Greater1 observeIGreater1 + action 0 + 5343 : 1 +state 4773 observe2Greater1 observeIGreater1 + action 0 + 5344 : 1 +state 4774 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5345 : 1 +state 4775 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 4776 observe2Greater1 observeIGreater1 + action 0 + 5351 : 1 +state 4777 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4777 : 1 +state 4778 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4779 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5352 : 1 +state 4780 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4780 : 1 +state 4781 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4782 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5353 : 1 +state 4783 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4783 : 1 +state 4784 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4785 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5354 : 1 +state 4786 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4786 : 1 +state 4787 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4788 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5355 : 1 +state 4789 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4789 : 1 +state 4790 observe3Greater1 observeIGreater1 + action 0 + 5127 : 0.833 + 5128 : 0.167 +state 4791 observe3Greater1 observeIGreater1 + action 0 + 5356 : 1 +state 4792 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5357 : 1 +state 4793 observe3Greater1 observeIGreater1 + action 0 + 5358 : 1 +state 4794 observe3Greater1 observeIGreater1 + action 0 + 5359 : 1 +state 4795 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 4796 observe3Greater1 observeIGreater1 + action 0 + 5365 : 1 +state 4797 + action 0 + 5129 : 0.833 + 5130 : 0.167 +state 4798 + action 0 + 5366 : 1 +state 4799 observe2Greater1 observeIGreater1 + action 0 + 5367 : 1 +state 4800 observe3Greater1 observeIGreater1 + action 0 + 5368 : 1 +state 4801 observe4Greater1 observeIGreater1 + action 0 + 5369 : 1 +state 4802 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 4803 + action 0 + 5375 : 1 +state 4804 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4804 : 1 +state 4805 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4806 observe0Greater1 observeOnlyTrueSender + action 0 + 5376 : 1 +state 4807 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4807 : 1 +state 4808 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4809 observe0Greater1 observeOnlyTrueSender + action 0 + 5377 : 1 +state 4810 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4810 : 1 +state 4811 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4812 observe0Greater1 observeOnlyTrueSender + action 0 + 5378 : 1 +state 4813 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4813 : 1 +state 4814 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4815 observe0Greater1 observeOnlyTrueSender + action 0 + 5379 : 1 +state 4816 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4816 : 1 +state 4817 observe4Greater1 observeIGreater1 + action 0 + 5144 : 0.833 + 5145 : 0.167 +state 4818 observe4Greater1 observeIGreater1 + action 0 + 5380 : 1 +state 4819 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5381 : 1 +state 4820 observe4Greater1 observeIGreater1 + action 0 + 5382 : 1 +state 4821 observe4Greater1 observeIGreater1 + action 0 + 5383 : 1 +state 4822 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 4823 observe4Greater1 observeIGreater1 + action 0 + 5389 : 1 +state 4824 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4824 : 1 +state 4825 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4826 observe0Greater1 observeOnlyTrueSender + action 0 + 5390 : 1 +state 4827 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4827 : 1 +state 4828 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4829 observe0Greater1 observeOnlyTrueSender + action 0 + 5391 : 1 +state 4830 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4830 : 1 +state 4831 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4832 observe0Greater1 observeOnlyTrueSender + action 0 + 5392 : 1 +state 4833 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4833 : 1 +state 4834 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4835 observe0Greater1 observeOnlyTrueSender + action 0 + 5393 : 1 +state 4836 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4836 : 1 +state 4837 observe3Greater1 observeIGreater1 + action 0 + 5159 : 0.833 + 5160 : 0.167 +state 4838 observe3Greater1 observeIGreater1 + action 0 + 5394 : 1 +state 4839 observe3Greater1 observeIGreater1 + action 0 + 5395 : 1 +state 4840 observe3Greater1 observeIGreater1 + action 0 + 5396 : 1 +state 4841 observe3Greater1 observeIGreater1 + action 0 + 5397 : 1 +state 4842 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 4843 observe3Greater1 observeIGreater1 + action 0 + 5403 : 1 +state 4844 observe3Greater1 observeIGreater1 + action 0 + 5161 : 0.833 + 5162 : 0.167 +state 4845 observe3Greater1 observeIGreater1 + action 0 + 5404 : 1 +state 4846 observe3Greater1 observeIGreater1 + action 0 + 5405 : 1 +state 4847 observe3Greater1 observeIGreater1 + action 0 + 5406 : 1 +state 4848 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5407 : 1 +state 4849 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 4850 observe3Greater1 observeIGreater1 + action 0 + 5413 : 1 +state 4851 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4851 : 1 +state 4852 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4853 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5414 : 1 +state 4854 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4854 : 1 +state 4855 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4856 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5415 : 1 +state 4857 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4857 : 1 +state 4858 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4859 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5416 : 1 +state 4860 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4860 : 1 +state 4861 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4862 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5417 : 1 +state 4863 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4863 : 1 +state 4864 observe4Greater1 observeIGreater1 + action 0 + 5176 : 0.833 + 5177 : 0.167 +state 4865 observe4Greater1 observeIGreater1 + action 0 + 5418 : 1 +state 4866 observe4Greater1 observeIGreater1 + action 0 + 5419 : 1 +state 4867 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5420 : 1 +state 4868 observe4Greater1 observeIGreater1 + action 0 + 5421 : 1 +state 4869 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 4870 observe4Greater1 observeIGreater1 + action 0 + 5427 : 1 +state 4871 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4871 : 1 +state 4872 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4873 observe0Greater1 observeOnlyTrueSender + action 0 + 5428 : 1 +state 4874 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4874 : 1 +state 4875 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4876 observe0Greater1 observeOnlyTrueSender + action 0 + 5429 : 1 +state 4877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4877 : 1 +state 4878 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4879 observe0Greater1 observeOnlyTrueSender + action 0 + 5430 : 1 +state 4880 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4880 : 1 +state 4881 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4882 observe0Greater1 observeOnlyTrueSender + action 0 + 5431 : 1 +state 4883 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4883 : 1 +state 4884 observe4Greater1 observeIGreater1 + action 0 + 5191 : 0.833 + 5192 : 0.167 +state 4885 observe4Greater1 observeIGreater1 + action 0 + 5432 : 1 +state 4886 observe4Greater1 observeIGreater1 + action 0 + 5433 : 1 +state 4887 observe4Greater1 observeIGreater1 + action 0 + 5434 : 1 +state 4888 observe4Greater1 observeIGreater1 + action 0 + 5435 : 1 +state 4889 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 4890 observe4Greater1 observeIGreater1 + action 0 + 5441 : 1 +state 4891 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4891 : 1 +state 4892 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4893 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5442 : 1 +state 4894 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4894 : 1 +state 4895 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4896 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5443 : 1 +state 4897 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4897 : 1 +state 4898 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4899 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5444 : 1 +state 4900 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4900 : 1 +state 4901 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4902 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5445 : 1 +state 4903 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4903 : 1 +state 4904 observe1Greater1 observeIGreater1 + action 0 + 5446 : 1 +state 4905 + action 0 + 5447 : 1 +state 4906 + action 0 + 5448 : 1 +state 4907 + action 0 + 5449 : 1 +state 4908 + action 0 + 5450 : 1 +state 4909 observe2Greater1 observeIGreater1 + action 0 + 5451 : 1 +state 4910 + action 0 + 5452 : 1 +state 4911 + action 0 + 5453 : 1 +state 4912 + action 0 + 5454 : 1 +state 4913 + action 0 + 5455 : 1 +state 4914 observe3Greater1 observeIGreater1 + action 0 + 5456 : 1 +state 4915 + action 0 + 5457 : 1 +state 4916 + action 0 + 5458 : 1 +state 4917 + action 0 + 5459 : 1 +state 4918 + action 0 + 5460 : 1 +state 4919 observe4Greater1 observeIGreater1 + action 0 + 5461 : 1 +state 4920 observe1Greater1 observeIGreater1 + action 0 + 5462 : 1 +state 4921 observe1Greater1 observeIGreater1 + action 0 + 5463 : 0.833 + 5464 : 0.167 +state 4922 observe1Greater1 observeIGreater1 + action 0 + 5465 : 1 +state 4923 observe1Greater1 observeIGreater1 + action 0 + 5466 : 0.833 + 5467 : 0.167 +state 4924 observe1Greater1 observeIGreater1 + action 0 + 5468 : 1 +state 4925 observe1Greater1 observeIGreater1 + action 0 + 5469 : 0.833 + 5470 : 0.167 +state 4926 observe1Greater1 observeIGreater1 + action 0 + 5471 : 1 +state 4927 observe1Greater1 observeIGreater1 + action 0 + 5472 : 0.833 + 5473 : 0.167 +state 4928 observe1Greater1 observeIGreater1 + action 0 + 5474 : 1 +state 4929 deadlock observe1Greater1 observeIGreater1 + action 0 + 4929 : 1 +state 4930 + action 0 + 5475 : 1 +state 4931 + action 0 + 5476 : 0.833 + 5477 : 0.167 +state 4932 + action 0 + 5478 : 1 +state 4933 + action 0 + 5479 : 0.833 + 5480 : 0.167 +state 4934 + action 0 + 5481 : 1 +state 4935 + action 0 + 5482 : 0.833 + 5483 : 0.167 +state 4936 + action 0 + 5484 : 1 +state 4937 + action 0 + 5485 : 0.833 + 5486 : 0.167 +state 4938 + action 0 + 5487 : 1 +state 4939 deadlock + action 0 + 4939 : 1 +state 4940 + action 0 + 5488 : 1 +state 4941 + action 0 + 5489 : 0.833 + 5490 : 0.167 +state 4942 + action 0 + 5491 : 1 +state 4943 + action 0 + 5492 : 0.833 + 5493 : 0.167 +state 4944 + action 0 + 5494 : 1 +state 4945 + action 0 + 5495 : 0.833 + 5496 : 0.167 +state 4946 + action 0 + 5497 : 1 +state 4947 + action 0 + 5498 : 0.833 + 5499 : 0.167 +state 4948 + action 0 + 5500 : 1 +state 4949 deadlock + action 0 + 4949 : 1 +state 4950 + action 0 + 5501 : 1 +state 4951 + action 0 + 5502 : 0.833 + 5503 : 0.167 +state 4952 + action 0 + 5504 : 1 +state 4953 + action 0 + 5505 : 0.833 + 5506 : 0.167 +state 4954 + action 0 + 5507 : 1 +state 4955 + action 0 + 5508 : 0.833 + 5509 : 0.167 +state 4956 + action 0 + 5510 : 1 +state 4957 + action 0 + 5511 : 0.833 + 5512 : 0.167 +state 4958 + action 0 + 5513 : 1 +state 4959 deadlock + action 0 + 4959 : 1 +state 4960 deadlock observe1Greater1 observeIGreater1 + action 0 + 4960 : 1 +state 4961 deadlock + action 0 + 4961 : 1 +state 4962 deadlock + action 0 + 4962 : 1 +state 4963 deadlock + action 0 + 4963 : 1 +state 4964 observe2Greater1 observeIGreater1 + action 0 + 5514 : 1 +state 4965 observe2Greater1 observeIGreater1 + action 0 + 5515 : 0.833 + 5516 : 0.167 +state 4966 observe2Greater1 observeIGreater1 + action 0 + 5517 : 1 +state 4967 observe2Greater1 observeIGreater1 + action 0 + 5518 : 0.833 + 5519 : 0.167 +state 4968 observe2Greater1 observeIGreater1 + action 0 + 5520 : 1 +state 4969 observe2Greater1 observeIGreater1 + action 0 + 5521 : 0.833 + 5522 : 0.167 +state 4970 observe2Greater1 observeIGreater1 + action 0 + 5523 : 1 +state 4971 observe2Greater1 observeIGreater1 + action 0 + 5524 : 0.833 + 5525 : 0.167 +state 4972 observe2Greater1 observeIGreater1 + action 0 + 5526 : 1 +state 4973 deadlock observe2Greater1 observeIGreater1 + action 0 + 4973 : 1 +state 4974 + action 0 + 5527 : 1 +state 4975 + action 0 + 5528 : 0.833 + 5529 : 0.167 +state 4976 + action 0 + 5530 : 1 +state 4977 + action 0 + 5531 : 0.833 + 5532 : 0.167 +state 4978 + action 0 + 5533 : 1 +state 4979 + action 0 + 5534 : 0.833 + 5535 : 0.167 +state 4980 + action 0 + 5536 : 1 +state 4981 + action 0 + 5537 : 0.833 + 5538 : 0.167 +state 4982 + action 0 + 5539 : 1 +state 4983 deadlock + action 0 + 4983 : 1 +state 4984 + action 0 + 5540 : 1 +state 4985 + action 0 + 5541 : 0.833 + 5542 : 0.167 +state 4986 + action 0 + 5543 : 1 +state 4987 + action 0 + 5544 : 0.833 + 5545 : 0.167 +state 4988 + action 0 + 5546 : 1 +state 4989 + action 0 + 5547 : 0.833 + 5548 : 0.167 +state 4990 + action 0 + 5549 : 1 +state 4991 + action 0 + 5550 : 0.833 + 5551 : 0.167 +state 4992 + action 0 + 5552 : 1 +state 4993 deadlock + action 0 + 4993 : 1 +state 4994 deadlock + action 0 + 4994 : 1 +state 4995 deadlock observe2Greater1 observeIGreater1 + action 0 + 4995 : 1 +state 4996 deadlock + action 0 + 4996 : 1 +state 4997 deadlock + action 0 + 4997 : 1 +state 4998 observe3Greater1 observeIGreater1 + action 0 + 5553 : 1 +state 4999 observe3Greater1 observeIGreater1 + action 0 + 5554 : 0.833 + 5555 : 0.167 +state 5000 observe3Greater1 observeIGreater1 + action 0 + 5556 : 1 +state 5001 observe3Greater1 observeIGreater1 + action 0 + 5557 : 0.833 + 5558 : 0.167 +state 5002 observe3Greater1 observeIGreater1 + action 0 + 5559 : 1 +state 5003 observe3Greater1 observeIGreater1 + action 0 + 5560 : 0.833 + 5561 : 0.167 +state 5004 observe3Greater1 observeIGreater1 + action 0 + 5562 : 1 +state 5005 observe3Greater1 observeIGreater1 + action 0 + 5563 : 0.833 + 5564 : 0.167 +state 5006 observe3Greater1 observeIGreater1 + action 0 + 5565 : 1 +state 5007 deadlock observe3Greater1 observeIGreater1 + action 0 + 5007 : 1 +state 5008 + action 0 + 5566 : 1 +state 5009 + action 0 + 5567 : 0.833 + 5568 : 0.167 +state 5010 + action 0 + 5569 : 1 +state 5011 + action 0 + 5570 : 0.833 + 5571 : 0.167 +state 5012 + action 0 + 5572 : 1 +state 5013 + action 0 + 5573 : 0.833 + 5574 : 0.167 +state 5014 + action 0 + 5575 : 1 +state 5015 + action 0 + 5576 : 0.833 + 5577 : 0.167 +state 5016 + action 0 + 5578 : 1 +state 5017 deadlock + action 0 + 5017 : 1 +state 5018 deadlock + action 0 + 5018 : 1 +state 5019 deadlock + action 0 + 5019 : 1 +state 5020 deadlock observe3Greater1 observeIGreater1 + action 0 + 5020 : 1 +state 5021 deadlock + action 0 + 5021 : 1 +state 5022 observe4Greater1 observeIGreater1 + action 0 + 5579 : 1 +state 5023 observe4Greater1 observeIGreater1 + action 0 + 5580 : 0.833 + 5581 : 0.167 +state 5024 observe4Greater1 observeIGreater1 + action 0 + 5582 : 1 +state 5025 observe4Greater1 observeIGreater1 + action 0 + 5583 : 0.833 + 5584 : 0.167 +state 5026 observe4Greater1 observeIGreater1 + action 0 + 5585 : 1 +state 5027 observe4Greater1 observeIGreater1 + action 0 + 5586 : 0.833 + 5587 : 0.167 +state 5028 observe4Greater1 observeIGreater1 + action 0 + 5588 : 1 +state 5029 observe4Greater1 observeIGreater1 + action 0 + 5589 : 0.833 + 5590 : 0.167 +state 5030 observe4Greater1 observeIGreater1 + action 0 + 5591 : 1 +state 5031 deadlock observe4Greater1 observeIGreater1 + action 0 + 5031 : 1 +state 5032 deadlock + action 0 + 5032 : 1 +state 5033 deadlock + action 0 + 5033 : 1 +state 5034 deadlock + action 0 + 5034 : 1 +state 5035 deadlock observe4Greater1 observeIGreater1 + action 0 + 5035 : 1 +state 5036 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 5037 observe1Greater1 observeIGreater1 + action 0 + 5597 : 1 +state 5038 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 5039 observe1Greater1 observeIGreater1 + action 0 + 5603 : 1 +state 5040 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 5041 observe1Greater1 observeIGreater1 + action 0 + 5609 : 1 +state 5042 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 5043 observe1Greater1 observeIGreater1 + action 0 + 5615 : 1 +state 5044 deadlock observe1Greater1 observeIGreater1 + action 0 + 5044 : 1 +state 5045 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5046 observe1Greater1 observeIGreater1 + action 0 + 5616 : 1 +state 5047 deadlock observe1Greater1 observeIGreater1 + action 0 + 5047 : 1 +state 5048 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5049 observe1Greater1 observeIGreater1 + action 0 + 5617 : 1 +state 5050 deadlock observe1Greater1 observeIGreater1 + action 0 + 5050 : 1 +state 5051 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5052 observe1Greater1 observeIGreater1 + action 0 + 5618 : 1 +state 5053 deadlock observe1Greater1 observeIGreater1 + action 0 + 5053 : 1 +state 5054 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5055 observe1Greater1 observeIGreater1 + action 0 + 5619 : 1 +state 5056 deadlock observe1Greater1 observeIGreater1 + action 0 + 5056 : 1 +state 5057 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 5058 observe2Greater1 observeIGreater1 + action 0 + 5625 : 1 +state 5059 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 5060 + action 0 + 5631 : 1 +state 5061 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 5062 + action 0 + 5637 : 1 +state 5063 deadlock + action 0 + 5063 : 1 +state 5064 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5065 + action 0 + 5638 : 1 +state 5066 deadlock + action 0 + 5066 : 1 +state 5067 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5068 + action 0 + 5639 : 1 +state 5069 deadlock + action 0 + 5069 : 1 +state 5070 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5071 + action 0 + 5640 : 1 +state 5072 deadlock + action 0 + 5072 : 1 +state 5073 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5074 + action 0 + 5641 : 1 +state 5075 deadlock + action 0 + 5075 : 1 +state 5076 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 5077 observe3Greater1 observeIGreater1 + action 0 + 5647 : 1 +state 5078 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 5079 + action 0 + 5653 : 1 +state 5080 deadlock + action 0 + 5080 : 1 +state 5081 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5082 + action 0 + 5654 : 1 +state 5083 deadlock + action 0 + 5083 : 1 +state 5084 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5085 + action 0 + 5655 : 1 +state 5086 deadlock + action 0 + 5086 : 1 +state 5087 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5088 + action 0 + 5656 : 1 +state 5089 deadlock + action 0 + 5089 : 1 +state 5090 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5091 + action 0 + 5657 : 1 +state 5092 deadlock + action 0 + 5092 : 1 +state 5093 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 5094 observe4Greater1 observeIGreater1 + action 0 + 5663 : 1 +state 5095 deadlock + action 0 + 5095 : 1 +state 5096 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5097 + action 0 + 5664 : 1 +state 5098 deadlock + action 0 + 5098 : 1 +state 5099 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5100 + action 0 + 5665 : 1 +state 5101 deadlock + action 0 + 5101 : 1 +state 5102 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5103 + action 0 + 5666 : 1 +state 5104 deadlock + action 0 + 5104 : 1 +state 5105 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5106 + action 0 + 5667 : 1 +state 5107 deadlock + action 0 + 5107 : 1 +state 5108 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 5109 observe2Greater1 observeIGreater1 + action 0 + 5673 : 1 +state 5110 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 5111 observe2Greater1 observeIGreater1 + action 0 + 5679 : 1 +state 5112 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 5113 observe2Greater1 observeIGreater1 + action 0 + 5685 : 1 +state 5114 deadlock observe2Greater1 observeIGreater1 + action 0 + 5114 : 1 +state 5115 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5116 observe2Greater1 observeIGreater1 + action 0 + 5686 : 1 +state 5117 deadlock observe2Greater1 observeIGreater1 + action 0 + 5117 : 1 +state 5118 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5119 observe2Greater1 observeIGreater1 + action 0 + 5687 : 1 +state 5120 deadlock observe2Greater1 observeIGreater1 + action 0 + 5120 : 1 +state 5121 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5122 observe2Greater1 observeIGreater1 + action 0 + 5688 : 1 +state 5123 deadlock observe2Greater1 observeIGreater1 + action 0 + 5123 : 1 +state 5124 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5125 observe2Greater1 observeIGreater1 + action 0 + 5689 : 1 +state 5126 deadlock observe2Greater1 observeIGreater1 + action 0 + 5126 : 1 +state 5127 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 5128 observe3Greater1 observeIGreater1 + action 0 + 5695 : 1 +state 5129 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 5130 + action 0 + 5701 : 1 +state 5131 deadlock + action 0 + 5131 : 1 +state 5132 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5133 + action 0 + 5702 : 1 +state 5134 deadlock + action 0 + 5134 : 1 +state 5135 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5136 + action 0 + 5703 : 1 +state 5137 deadlock + action 0 + 5137 : 1 +state 5138 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5139 + action 0 + 5704 : 1 +state 5140 deadlock + action 0 + 5140 : 1 +state 5141 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5142 + action 0 + 5705 : 1 +state 5143 deadlock + action 0 + 5143 : 1 +state 5144 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 5145 observe4Greater1 observeIGreater1 + action 0 + 5711 : 1 +state 5146 deadlock + action 0 + 5146 : 1 +state 5147 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5148 + action 0 + 5712 : 1 +state 5149 deadlock + action 0 + 5149 : 1 +state 5150 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5151 + action 0 + 5713 : 1 +state 5152 deadlock + action 0 + 5152 : 1 +state 5153 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5154 + action 0 + 5714 : 1 +state 5155 deadlock + action 0 + 5155 : 1 +state 5156 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5157 + action 0 + 5715 : 1 +state 5158 deadlock + action 0 + 5158 : 1 +state 5159 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 5160 observe3Greater1 observeIGreater1 + action 0 + 5721 : 1 +state 5161 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 5162 observe3Greater1 observeIGreater1 + action 0 + 5727 : 1 +state 5163 deadlock observe3Greater1 observeIGreater1 + action 0 + 5163 : 1 +state 5164 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5165 observe3Greater1 observeIGreater1 + action 0 + 5728 : 1 +state 5166 deadlock observe3Greater1 observeIGreater1 + action 0 + 5166 : 1 +state 5167 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5168 observe3Greater1 observeIGreater1 + action 0 + 5729 : 1 +state 5169 deadlock observe3Greater1 observeIGreater1 + action 0 + 5169 : 1 +state 5170 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5171 observe3Greater1 observeIGreater1 + action 0 + 5730 : 1 +state 5172 deadlock observe3Greater1 observeIGreater1 + action 0 + 5172 : 1 +state 5173 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5174 observe3Greater1 observeIGreater1 + action 0 + 5731 : 1 +state 5175 deadlock observe3Greater1 observeIGreater1 + action 0 + 5175 : 1 +state 5176 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 5177 observe4Greater1 observeIGreater1 + action 0 + 5737 : 1 +state 5178 deadlock + action 0 + 5178 : 1 +state 5179 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5180 + action 0 + 5738 : 1 +state 5181 deadlock + action 0 + 5181 : 1 +state 5182 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5183 + action 0 + 5739 : 1 +state 5184 deadlock + action 0 + 5184 : 1 +state 5185 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5186 + action 0 + 5740 : 1 +state 5187 deadlock + action 0 + 5187 : 1 +state 5188 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5189 + action 0 + 5741 : 1 +state 5190 deadlock + action 0 + 5190 : 1 +state 5191 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 5192 observe4Greater1 observeIGreater1 + action 0 + 5747 : 1 +state 5193 deadlock observe4Greater1 observeIGreater1 + action 0 + 5193 : 1 +state 5194 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5195 observe4Greater1 observeIGreater1 + action 0 + 5748 : 1 +state 5196 deadlock observe4Greater1 observeIGreater1 + action 0 + 5196 : 1 +state 5197 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5198 observe4Greater1 observeIGreater1 + action 0 + 5749 : 1 +state 5199 deadlock observe4Greater1 observeIGreater1 + action 0 + 5199 : 1 +state 5200 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5201 observe4Greater1 observeIGreater1 + action 0 + 5750 : 1 +state 5202 deadlock observe4Greater1 observeIGreater1 + action 0 + 5202 : 1 +state 5203 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5204 observe4Greater1 observeIGreater1 + action 0 + 5751 : 1 +state 5205 deadlock observe4Greater1 observeIGreater1 + action 0 + 5205 : 1 +state 5206 observe1Greater1 observeIGreater1 + action 0 + 5752 : 1 +state 5207 observe1Greater1 observeIGreater1 + action 0 + 5753 : 1 +state 5208 observe1Greater1 observeIGreater1 + action 0 + 5754 : 1 +state 5209 observe1Greater1 observeIGreater1 + action 0 + 5755 : 1 +state 5210 observe1Greater1 observeIGreater1 + action 0 + 5756 : 0.8 + 5757 : 0.2 +state 5211 observe1Greater1 observeIGreater1 + action 0 + 5758 : 0.8 + 5759 : 0.2 +state 5212 observe1Greater1 observeIGreater1 + action 0 + 5760 : 0.8 + 5761 : 0.2 +state 5213 observe1Greater1 observeIGreater1 + action 0 + 5762 : 0.8 + 5763 : 0.2 +state 5214 observe1Greater1 observeIGreater1 + action 0 + 5764 : 0.8 + 5765 : 0.2 +state 5215 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5766 : 1 +state 5216 observe1Greater1 observeIGreater1 + action 0 + 5753 : 1 +state 5217 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5767 : 1 +state 5218 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5219 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5220 observe1Greater1 observeIGreater1 + action 0 + 5770 : 0.8 + 5771 : 0.2 +state 5221 observe1Greater1 observeIGreater1 + action 0 + 5772 : 0.8 + 5773 : 0.2 +state 5222 observe1Greater1 observeIGreater1 + action 0 + 5774 : 0.8 + 5775 : 0.2 +state 5223 observe1Greater1 observeIGreater1 + action 0 + 5776 : 0.8 + 5777 : 0.2 +state 5224 observe1Greater1 observeIGreater1 + action 0 + 5778 : 0.8 + 5779 : 0.2 +state 5225 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5780 : 1 +state 5226 observe1Greater1 observeIGreater1 + action 0 + 5754 : 1 +state 5227 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5228 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5781 : 1 +state 5229 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5230 observe1Greater1 observeIGreater1 + action 0 + 5783 : 0.8 + 5784 : 0.2 +state 5231 observe1Greater1 observeIGreater1 + action 0 + 5785 : 0.8 + 5786 : 0.2 +state 5232 observe1Greater1 observeIGreater1 + action 0 + 5787 : 0.8 + 5788 : 0.2 +state 5233 observe1Greater1 observeIGreater1 + action 0 + 5789 : 0.8 + 5790 : 0.2 +state 5234 observe1Greater1 observeIGreater1 + action 0 + 5791 : 0.8 + 5792 : 0.2 +state 5235 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5793 : 1 +state 5236 observe1Greater1 observeIGreater1 + action 0 + 5755 : 1 +state 5237 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5238 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5239 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5794 : 1 +state 5240 observe1Greater1 observeIGreater1 + action 0 + 5795 : 0.8 + 5796 : 0.2 +state 5241 observe1Greater1 observeIGreater1 + action 0 + 5797 : 0.8 + 5798 : 0.2 +state 5242 observe1Greater1 observeIGreater1 + action 0 + 5799 : 0.8 + 5800 : 0.2 +state 5243 observe1Greater1 observeIGreater1 + action 0 + 5801 : 0.8 + 5802 : 0.2 +state 5244 observe1Greater1 observeIGreater1 + action 0 + 5803 : 0.8 + 5804 : 0.2 +state 5245 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5805 : 1 +state 5246 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5806 : 1 +state 5247 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5807 : 1 +state 5248 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5808 : 1 +state 5249 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5809 : 1 +state 5250 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5767 : 1 +state 5251 observe2Greater1 observeIGreater1 + action 0 + 5810 : 1 +state 5252 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5253 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5254 observe2Greater1 observeIGreater1 + action 0 + 5813 : 0.8 + 5814 : 0.2 +state 5255 observe2Greater1 observeIGreater1 + action 0 + 5815 : 0.8 + 5816 : 0.2 +state 5256 observe2Greater1 observeIGreater1 + action 0 + 5817 : 0.8 + 5818 : 0.2 +state 5257 observe2Greater1 observeIGreater1 + action 0 + 5819 : 0.8 + 5820 : 0.2 +state 5258 observe2Greater1 observeIGreater1 + action 0 + 5821 : 0.8 + 5822 : 0.2 +state 5259 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5823 : 1 +state 5260 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5261 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5262 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5263 + action 0 + 5825 : 1 +state 5264 + action 0 + 5826 : 0.8 + 5827 : 0.2 +state 5265 + action 0 + 5828 : 0.8 + 5829 : 0.2 +state 5266 + action 0 + 5830 : 0.8 + 5831 : 0.2 +state 5267 + action 0 + 5832 : 0.8 + 5833 : 0.2 +state 5268 + action 0 + 5834 : 0.8 + 5835 : 0.2 +state 5269 observe0Greater1 observeOnlyTrueSender + action 0 + 5836 : 1 +state 5270 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5271 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5272 + action 0 + 5825 : 1 +state 5273 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5274 + action 0 + 5838 : 0.8 + 5839 : 0.2 +state 5275 + action 0 + 5840 : 0.8 + 5841 : 0.2 +state 5276 + action 0 + 5842 : 0.8 + 5843 : 0.2 +state 5277 + action 0 + 5844 : 0.8 + 5845 : 0.2 +state 5278 + action 0 + 5846 : 0.8 + 5847 : 0.2 +state 5279 observe0Greater1 observeOnlyTrueSender + action 0 + 5848 : 1 +state 5280 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5849 : 1 +state 5281 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5850 : 1 +state 5282 observe0Greater1 observeOnlyTrueSender + action 0 + 5851 : 1 +state 5283 observe0Greater1 observeOnlyTrueSender + action 0 + 5852 : 1 +state 5284 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5781 : 1 +state 5285 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5286 observe3Greater1 observeIGreater1 + action 0 + 5853 : 1 +state 5287 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5288 observe3Greater1 observeIGreater1 + action 0 + 5855 : 0.8 + 5856 : 0.2 +state 5289 observe3Greater1 observeIGreater1 + action 0 + 5857 : 0.8 + 5858 : 0.2 +state 5290 observe3Greater1 observeIGreater1 + action 0 + 5859 : 0.8 + 5860 : 0.2 +state 5291 observe3Greater1 observeIGreater1 + action 0 + 5861 : 0.8 + 5862 : 0.2 +state 5292 observe3Greater1 observeIGreater1 + action 0 + 5863 : 0.8 + 5864 : 0.2 +state 5293 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5865 : 1 +state 5294 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5295 + action 0 + 5825 : 1 +state 5296 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5297 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5298 + action 0 + 5867 : 0.8 + 5868 : 0.2 +state 5299 + action 0 + 5869 : 0.8 + 5870 : 0.2 +state 5300 + action 0 + 5871 : 0.8 + 5872 : 0.2 +state 5301 + action 0 + 5873 : 0.8 + 5874 : 0.2 +state 5302 + action 0 + 5875 : 0.8 + 5876 : 0.2 +state 5303 observe0Greater1 observeOnlyTrueSender + action 0 + 5877 : 1 +state 5304 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5878 : 1 +state 5305 observe0Greater1 observeOnlyTrueSender + action 0 + 5879 : 1 +state 5306 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5880 : 1 +state 5307 observe0Greater1 observeOnlyTrueSender + action 0 + 5881 : 1 +state 5308 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5794 : 1 +state 5309 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5310 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5311 observe4Greater1 observeIGreater1 + action 0 + 5882 : 1 +state 5312 observe4Greater1 observeIGreater1 + action 0 + 5883 : 0.8 + 5884 : 0.2 +state 5313 observe4Greater1 observeIGreater1 + action 0 + 5885 : 0.8 + 5886 : 0.2 +state 5314 observe4Greater1 observeIGreater1 + action 0 + 5887 : 0.8 + 5888 : 0.2 +state 5315 observe4Greater1 observeIGreater1 + action 0 + 5889 : 0.8 + 5890 : 0.2 +state 5316 observe4Greater1 observeIGreater1 + action 0 + 5891 : 0.8 + 5892 : 0.2 +state 5317 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5893 : 1 +state 5318 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5894 : 1 +state 5319 observe0Greater1 observeOnlyTrueSender + action 0 + 5895 : 1 +state 5320 observe0Greater1 observeOnlyTrueSender + action 0 + 5896 : 1 +state 5321 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5897 : 1 +state 5322 observe2Greater1 observeIGreater1 + action 0 + 5810 : 1 +state 5323 observe2Greater1 observeIGreater1 + action 0 + 5898 : 1 +state 5324 observe2Greater1 observeIGreater1 + action 0 + 5899 : 1 +state 5325 observe2Greater1 observeIGreater1 + action 0 + 5900 : 1 +state 5326 observe2Greater1 observeIGreater1 + action 0 + 5901 : 0.8 + 5902 : 0.2 +state 5327 observe2Greater1 observeIGreater1 + action 0 + 5903 : 0.8 + 5904 : 0.2 +state 5328 observe2Greater1 observeIGreater1 + action 0 + 5905 : 0.8 + 5906 : 0.2 +state 5329 observe2Greater1 observeIGreater1 + action 0 + 5907 : 0.8 + 5908 : 0.2 +state 5330 observe2Greater1 observeIGreater1 + action 0 + 5909 : 0.8 + 5910 : 0.2 +state 5331 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5911 : 1 +state 5332 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5333 observe2Greater1 observeIGreater1 + action 0 + 5899 : 1 +state 5334 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5912 : 1 +state 5335 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5336 observe2Greater1 observeIGreater1 + action 0 + 5914 : 0.8 + 5915 : 0.2 +state 5337 observe2Greater1 observeIGreater1 + action 0 + 5916 : 0.8 + 5917 : 0.2 +state 5338 observe2Greater1 observeIGreater1 + action 0 + 5918 : 0.8 + 5919 : 0.2 +state 5339 observe2Greater1 observeIGreater1 + action 0 + 5920 : 0.8 + 5921 : 0.2 +state 5340 observe2Greater1 observeIGreater1 + action 0 + 5922 : 0.8 + 5923 : 0.2 +state 5341 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5924 : 1 +state 5342 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5343 observe2Greater1 observeIGreater1 + action 0 + 5900 : 1 +state 5344 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5345 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5925 : 1 +state 5346 observe2Greater1 observeIGreater1 + action 0 + 5926 : 0.8 + 5927 : 0.2 +state 5347 observe2Greater1 observeIGreater1 + action 0 + 5928 : 0.8 + 5929 : 0.2 +state 5348 observe2Greater1 observeIGreater1 + action 0 + 5930 : 0.8 + 5931 : 0.2 +state 5349 observe2Greater1 observeIGreater1 + action 0 + 5932 : 0.8 + 5933 : 0.2 +state 5350 observe2Greater1 observeIGreater1 + action 0 + 5934 : 0.8 + 5935 : 0.2 +state 5351 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5936 : 1 +state 5352 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5937 : 1 +state 5353 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5938 : 1 +state 5354 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5939 : 1 +state 5355 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5940 : 1 +state 5356 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5357 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5912 : 1 +state 5358 observe3Greater1 observeIGreater1 + action 0 + 5941 : 1 +state 5359 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5360 observe3Greater1 observeIGreater1 + action 0 + 5943 : 0.8 + 5944 : 0.2 +state 5361 observe3Greater1 observeIGreater1 + action 0 + 5945 : 0.8 + 5946 : 0.2 +state 5362 observe3Greater1 observeIGreater1 + action 0 + 5947 : 0.8 + 5948 : 0.2 +state 5363 observe3Greater1 observeIGreater1 + action 0 + 5949 : 0.8 + 5950 : 0.2 +state 5364 observe3Greater1 observeIGreater1 + action 0 + 5951 : 0.8 + 5952 : 0.2 +state 5365 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5953 : 1 +state 5366 + action 0 + 5825 : 1 +state 5367 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5368 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5369 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5370 + action 0 + 5955 : 0.8 + 5956 : 0.2 +state 5371 + action 0 + 5957 : 0.8 + 5958 : 0.2 +state 5372 + action 0 + 5959 : 0.8 + 5960 : 0.2 +state 5373 + action 0 + 5961 : 0.8 + 5962 : 0.2 +state 5374 + action 0 + 5963 : 0.8 + 5964 : 0.2 +state 5375 observe0Greater1 observeOnlyTrueSender + action 0 + 5965 : 1 +state 5376 observe0Greater1 observeOnlyTrueSender + action 0 + 5966 : 1 +state 5377 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5967 : 1 +state 5378 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5968 : 1 +state 5379 observe0Greater1 observeOnlyTrueSender + action 0 + 5969 : 1 +state 5380 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5381 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5925 : 1 +state 5382 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5383 observe4Greater1 observeIGreater1 + action 0 + 5970 : 1 +state 5384 observe4Greater1 observeIGreater1 + action 0 + 5971 : 0.8 + 5972 : 0.2 +state 5385 observe4Greater1 observeIGreater1 + action 0 + 5973 : 0.8 + 5974 : 0.2 +state 5386 observe4Greater1 observeIGreater1 + action 0 + 5975 : 0.8 + 5976 : 0.2 +state 5387 observe4Greater1 observeIGreater1 + action 0 + 5977 : 0.8 + 5978 : 0.2 +state 5388 observe4Greater1 observeIGreater1 + action 0 + 5979 : 0.8 + 5980 : 0.2 +state 5389 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5981 : 1 +state 5390 observe0Greater1 observeOnlyTrueSender + action 0 + 5982 : 1 +state 5391 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5983 : 1 +state 5392 observe0Greater1 observeOnlyTrueSender + action 0 + 5984 : 1 +state 5393 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5985 : 1 +state 5394 observe3Greater1 observeIGreater1 + action 0 + 5853 : 1 +state 5395 observe3Greater1 observeIGreater1 + action 0 + 5941 : 1 +state 5396 observe3Greater1 observeIGreater1 + action 0 + 5986 : 1 +state 5397 observe3Greater1 observeIGreater1 + action 0 + 5987 : 1 +state 5398 observe3Greater1 observeIGreater1 + action 0 + 5988 : 0.8 + 5989 : 0.2 +state 5399 observe3Greater1 observeIGreater1 + action 0 + 5990 : 0.8 + 5991 : 0.2 +state 5400 observe3Greater1 observeIGreater1 + action 0 + 5992 : 0.8 + 5993 : 0.2 +state 5401 observe3Greater1 observeIGreater1 + action 0 + 5994 : 0.8 + 5995 : 0.2 +state 5402 observe3Greater1 observeIGreater1 + action 0 + 5996 : 0.8 + 5997 : 0.2 +state 5403 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5998 : 1 +state 5404 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5405 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5406 observe3Greater1 observeIGreater1 + action 0 + 5987 : 1 +state 5407 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5999 : 1 +state 5408 observe3Greater1 observeIGreater1 + action 0 + 6000 : 0.8 + 6001 : 0.2 +state 5409 observe3Greater1 observeIGreater1 + action 0 + 6002 : 0.8 + 6003 : 0.2 +state 5410 observe3Greater1 observeIGreater1 + action 0 + 6004 : 0.8 + 6005 : 0.2 +state 5411 observe3Greater1 observeIGreater1 + action 0 + 6006 : 0.8 + 6007 : 0.2 +state 5412 observe3Greater1 observeIGreater1 + action 0 + 6008 : 0.8 + 6009 : 0.2 +state 5413 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6010 : 1 +state 5414 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6011 : 1 +state 5415 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6012 : 1 +state 5416 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6013 : 1 +state 5417 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6014 : 1 +state 5418 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5419 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5420 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5999 : 1 +state 5421 observe4Greater1 observeIGreater1 + action 0 + 6015 : 1 +state 5422 observe4Greater1 observeIGreater1 + action 0 + 6016 : 0.8 + 6017 : 0.2 +state 5423 observe4Greater1 observeIGreater1 + action 0 + 6018 : 0.8 + 6019 : 0.2 +state 5424 observe4Greater1 observeIGreater1 + action 0 + 6020 : 0.8 + 6021 : 0.2 +state 5425 observe4Greater1 observeIGreater1 + action 0 + 6022 : 0.8 + 6023 : 0.2 +state 5426 observe4Greater1 observeIGreater1 + action 0 + 6024 : 0.8 + 6025 : 0.2 +state 5427 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6026 : 1 +state 5428 observe0Greater1 observeOnlyTrueSender + action 0 + 6027 : 1 +state 5429 observe0Greater1 observeOnlyTrueSender + action 0 + 6028 : 1 +state 5430 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6029 : 1 +state 5431 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6030 : 1 +state 5432 observe4Greater1 observeIGreater1 + action 0 + 5882 : 1 +state 5433 observe4Greater1 observeIGreater1 + action 0 + 5970 : 1 +state 5434 observe4Greater1 observeIGreater1 + action 0 + 6015 : 1 +state 5435 observe4Greater1 observeIGreater1 + action 0 + 6031 : 1 +state 5436 observe4Greater1 observeIGreater1 + action 0 + 6032 : 0.8 + 6033 : 0.2 +state 5437 observe4Greater1 observeIGreater1 + action 0 + 6034 : 0.8 + 6035 : 0.2 +state 5438 observe4Greater1 observeIGreater1 + action 0 + 6036 : 0.8 + 6037 : 0.2 +state 5439 observe4Greater1 observeIGreater1 + action 0 + 6038 : 0.8 + 6039 : 0.2 +state 5440 observe4Greater1 observeIGreater1 + action 0 + 6040 : 0.8 + 6041 : 0.2 +state 5441 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6042 : 1 +state 5442 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6043 : 1 +state 5443 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6044 : 1 +state 5444 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6045 : 1 +state 5445 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6046 : 1 +state 5446 deadlock observe1Greater1 observeIGreater1 + action 0 + 5446 : 1 +state 5447 deadlock + action 0 + 5447 : 1 +state 5448 deadlock + action 0 + 5448 : 1 +state 5449 deadlock + action 0 + 5449 : 1 +state 5450 deadlock + action 0 + 5450 : 1 +state 5451 deadlock observe2Greater1 observeIGreater1 + action 0 + 5451 : 1 +state 5452 deadlock + action 0 + 5452 : 1 +state 5453 deadlock + action 0 + 5453 : 1 +state 5454 deadlock + action 0 + 5454 : 1 +state 5455 deadlock + action 0 + 5455 : 1 +state 5456 deadlock observe3Greater1 observeIGreater1 + action 0 + 5456 : 1 +state 5457 deadlock + action 0 + 5457 : 1 +state 5458 deadlock + action 0 + 5458 : 1 +state 5459 deadlock + action 0 + 5459 : 1 +state 5460 deadlock + action 0 + 5460 : 1 +state 5461 deadlock observe4Greater1 observeIGreater1 + action 0 + 5461 : 1 +state 5462 deadlock observe1Greater1 observeIGreater1 + action 0 + 5462 : 1 +state 5463 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5464 observe1Greater1 observeIGreater1 + action 0 + 6047 : 1 +state 5465 deadlock observe1Greater1 observeIGreater1 + action 0 + 5465 : 1 +state 5466 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5467 observe1Greater1 observeIGreater1 + action 0 + 6048 : 1 +state 5468 deadlock observe1Greater1 observeIGreater1 + action 0 + 5468 : 1 +state 5469 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5470 observe1Greater1 observeIGreater1 + action 0 + 6049 : 1 +state 5471 deadlock observe1Greater1 observeIGreater1 + action 0 + 5471 : 1 +state 5472 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5473 observe1Greater1 observeIGreater1 + action 0 + 6050 : 1 +state 5474 deadlock observe1Greater1 observeIGreater1 + action 0 + 5474 : 1 +state 5475 deadlock + action 0 + 5475 : 1 +state 5476 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5477 + action 0 + 6051 : 1 +state 5478 deadlock + action 0 + 5478 : 1 +state 5479 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5480 + action 0 + 6052 : 1 +state 5481 deadlock + action 0 + 5481 : 1 +state 5482 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5483 + action 0 + 6053 : 1 +state 5484 deadlock + action 0 + 5484 : 1 +state 5485 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5486 + action 0 + 6054 : 1 +state 5487 deadlock + action 0 + 5487 : 1 +state 5488 deadlock + action 0 + 5488 : 1 +state 5489 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5490 + action 0 + 6055 : 1 +state 5491 deadlock + action 0 + 5491 : 1 +state 5492 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5493 + action 0 + 6056 : 1 +state 5494 deadlock + action 0 + 5494 : 1 +state 5495 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5496 + action 0 + 6057 : 1 +state 5497 deadlock + action 0 + 5497 : 1 +state 5498 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5499 + action 0 + 6058 : 1 +state 5500 deadlock + action 0 + 5500 : 1 +state 5501 deadlock + action 0 + 5501 : 1 +state 5502 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5503 + action 0 + 6059 : 1 +state 5504 deadlock + action 0 + 5504 : 1 +state 5505 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5506 + action 0 + 6060 : 1 +state 5507 deadlock + action 0 + 5507 : 1 +state 5508 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5509 + action 0 + 6061 : 1 +state 5510 deadlock + action 0 + 5510 : 1 +state 5511 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5512 + action 0 + 6062 : 1 +state 5513 deadlock + action 0 + 5513 : 1 +state 5514 deadlock observe2Greater1 observeIGreater1 + action 0 + 5514 : 1 +state 5515 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5516 observe2Greater1 observeIGreater1 + action 0 + 6063 : 1 +state 5517 deadlock observe2Greater1 observeIGreater1 + action 0 + 5517 : 1 +state 5518 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5519 observe2Greater1 observeIGreater1 + action 0 + 6064 : 1 +state 5520 deadlock observe2Greater1 observeIGreater1 + action 0 + 5520 : 1 +state 5521 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5522 observe2Greater1 observeIGreater1 + action 0 + 6065 : 1 +state 5523 deadlock observe2Greater1 observeIGreater1 + action 0 + 5523 : 1 +state 5524 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5525 observe2Greater1 observeIGreater1 + action 0 + 6066 : 1 +state 5526 deadlock observe2Greater1 observeIGreater1 + action 0 + 5526 : 1 +state 5527 deadlock + action 0 + 5527 : 1 +state 5528 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5529 + action 0 + 6067 : 1 +state 5530 deadlock + action 0 + 5530 : 1 +state 5531 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5532 + action 0 + 6068 : 1 +state 5533 deadlock + action 0 + 5533 : 1 +state 5534 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5535 + action 0 + 6069 : 1 +state 5536 deadlock + action 0 + 5536 : 1 +state 5537 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5538 + action 0 + 6070 : 1 +state 5539 deadlock + action 0 + 5539 : 1 +state 5540 deadlock + action 0 + 5540 : 1 +state 5541 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5542 + action 0 + 6071 : 1 +state 5543 deadlock + action 0 + 5543 : 1 +state 5544 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5545 + action 0 + 6072 : 1 +state 5546 deadlock + action 0 + 5546 : 1 +state 5547 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5548 + action 0 + 6073 : 1 +state 5549 deadlock + action 0 + 5549 : 1 +state 5550 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5551 + action 0 + 6074 : 1 +state 5552 deadlock + action 0 + 5552 : 1 +state 5553 deadlock observe3Greater1 observeIGreater1 + action 0 + 5553 : 1 +state 5554 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5555 observe3Greater1 observeIGreater1 + action 0 + 6075 : 1 +state 5556 deadlock observe3Greater1 observeIGreater1 + action 0 + 5556 : 1 +state 5557 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5558 observe3Greater1 observeIGreater1 + action 0 + 6076 : 1 +state 5559 deadlock observe3Greater1 observeIGreater1 + action 0 + 5559 : 1 +state 5560 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5561 observe3Greater1 observeIGreater1 + action 0 + 6077 : 1 +state 5562 deadlock observe3Greater1 observeIGreater1 + action 0 + 5562 : 1 +state 5563 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5564 observe3Greater1 observeIGreater1 + action 0 + 6078 : 1 +state 5565 deadlock observe3Greater1 observeIGreater1 + action 0 + 5565 : 1 +state 5566 deadlock + action 0 + 5566 : 1 +state 5567 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5568 + action 0 + 6079 : 1 +state 5569 deadlock + action 0 + 5569 : 1 +state 5570 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5571 + action 0 + 6080 : 1 +state 5572 deadlock + action 0 + 5572 : 1 +state 5573 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5574 + action 0 + 6081 : 1 +state 5575 deadlock + action 0 + 5575 : 1 +state 5576 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5577 + action 0 + 6082 : 1 +state 5578 deadlock + action 0 + 5578 : 1 +state 5579 deadlock observe4Greater1 observeIGreater1 + action 0 + 5579 : 1 +state 5580 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5581 observe4Greater1 observeIGreater1 + action 0 + 6083 : 1 +state 5582 deadlock observe4Greater1 observeIGreater1 + action 0 + 5582 : 1 +state 5583 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5584 observe4Greater1 observeIGreater1 + action 0 + 6084 : 1 +state 5585 deadlock observe4Greater1 observeIGreater1 + action 0 + 5585 : 1 +state 5586 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5587 observe4Greater1 observeIGreater1 + action 0 + 6085 : 1 +state 5588 deadlock observe4Greater1 observeIGreater1 + action 0 + 5588 : 1 +state 5589 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5590 observe4Greater1 observeIGreater1 + action 0 + 6086 : 1 +state 5591 deadlock observe4Greater1 observeIGreater1 + action 0 + 5591 : 1 +state 5592 observe1Greater1 observeIGreater1 + action 0 + 4634 : 0.8 + 6087 : 0.2 +state 5593 observe1Greater1 observeIGreater1 + action 0 + 6088 : 0.8 + 6089 : 0.2 +state 5594 observe1Greater1 observeIGreater1 + action 0 + 6090 : 0.8 + 6091 : 0.2 +state 5595 observe1Greater1 observeIGreater1 + action 0 + 6092 : 0.8 + 6093 : 0.2 +state 5596 observe1Greater1 observeIGreater1 + action 0 + 6094 : 0.8 + 6095 : 0.2 +state 5597 observe1Greater1 observeIGreater1 + action 0 + 6096 : 1 +state 5598 observe1Greater1 observeIGreater1 + action 0 + 4641 : 0.8 + 6097 : 0.2 +state 5599 observe1Greater1 observeIGreater1 + action 0 + 6098 : 0.8 + 6099 : 0.2 +state 5600 observe1Greater1 observeIGreater1 + action 0 + 6100 : 0.8 + 6101 : 0.2 +state 5601 observe1Greater1 observeIGreater1 + action 0 + 6102 : 0.8 + 6103 : 0.2 +state 5602 observe1Greater1 observeIGreater1 + action 0 + 6104 : 0.8 + 6105 : 0.2 +state 5603 observe1Greater1 observeIGreater1 + action 0 + 6106 : 1 +state 5604 observe1Greater1 observeIGreater1 + action 0 + 4648 : 0.8 + 6107 : 0.2 +state 5605 observe1Greater1 observeIGreater1 + action 0 + 6108 : 0.8 + 6109 : 0.2 +state 5606 observe1Greater1 observeIGreater1 + action 0 + 6110 : 0.8 + 6111 : 0.2 +state 5607 observe1Greater1 observeIGreater1 + action 0 + 6112 : 0.8 + 6113 : 0.2 +state 5608 observe1Greater1 observeIGreater1 + action 0 + 6114 : 0.8 + 6115 : 0.2 +state 5609 observe1Greater1 observeIGreater1 + action 0 + 6116 : 1 +state 5610 observe1Greater1 observeIGreater1 + action 0 + 4655 : 0.8 + 6117 : 0.2 +state 5611 observe1Greater1 observeIGreater1 + action 0 + 6118 : 0.8 + 6119 : 0.2 +state 5612 observe1Greater1 observeIGreater1 + action 0 + 6120 : 0.8 + 6121 : 0.2 +state 5613 observe1Greater1 observeIGreater1 + action 0 + 6122 : 0.8 + 6123 : 0.2 +state 5614 observe1Greater1 observeIGreater1 + action 0 + 6124 : 0.8 + 6125 : 0.2 +state 5615 observe1Greater1 observeIGreater1 + action 0 + 6126 : 1 +state 5616 observe1Greater1 observeIGreater1 + action 0 + 6127 : 1 +state 5617 observe1Greater1 observeIGreater1 + action 0 + 6128 : 1 +state 5618 observe1Greater1 observeIGreater1 + action 0 + 6129 : 1 +state 5619 observe1Greater1 observeIGreater1 + action 0 + 6130 : 1 +state 5620 observe2Greater1 observeIGreater1 + action 0 + 4675 : 0.8 + 6131 : 0.2 +state 5621 observe2Greater1 observeIGreater1 + action 0 + 6132 : 0.8 + 6133 : 0.2 +state 5622 observe2Greater1 observeIGreater1 + action 0 + 6134 : 0.8 + 6135 : 0.2 +state 5623 observe2Greater1 observeIGreater1 + action 0 + 6136 : 0.8 + 6137 : 0.2 +state 5624 observe2Greater1 observeIGreater1 + action 0 + 6138 : 0.8 + 6139 : 0.2 +state 5625 observe2Greater1 observeIGreater1 + action 0 + 6140 : 1 +state 5626 + action 0 + 4682 : 0.8 + 6141 : 0.2 +state 5627 + action 0 + 6142 : 0.8 + 6143 : 0.2 +state 5628 + action 0 + 6144 : 0.8 + 6145 : 0.2 +state 5629 + action 0 + 6146 : 0.8 + 6147 : 0.2 +state 5630 + action 0 + 6148 : 0.8 + 6149 : 0.2 +state 5631 + action 0 + 6150 : 1 +state 5632 + action 0 + 4689 : 0.8 + 6151 : 0.2 +state 5633 + action 0 + 6152 : 0.8 + 6153 : 0.2 +state 5634 + action 0 + 6154 : 0.8 + 6155 : 0.2 +state 5635 + action 0 + 6156 : 0.8 + 6157 : 0.2 +state 5636 + action 0 + 6158 : 0.8 + 6159 : 0.2 +state 5637 + action 0 + 6160 : 1 +state 5638 observe1Greater1 observeIGreater1 + action 0 + 6161 : 1 +state 5639 observe2Greater1 observeIGreater1 + action 0 + 6162 : 1 +state 5640 + action 0 + 6163 : 1 +state 5641 + action 0 + 6164 : 1 +state 5642 observe3Greater1 observeIGreater1 + action 0 + 4709 : 0.8 + 6165 : 0.2 +state 5643 observe3Greater1 observeIGreater1 + action 0 + 6166 : 0.8 + 6167 : 0.2 +state 5644 observe3Greater1 observeIGreater1 + action 0 + 6168 : 0.8 + 6169 : 0.2 +state 5645 observe3Greater1 observeIGreater1 + action 0 + 6170 : 0.8 + 6171 : 0.2 +state 5646 observe3Greater1 observeIGreater1 + action 0 + 6172 : 0.8 + 6173 : 0.2 +state 5647 observe3Greater1 observeIGreater1 + action 0 + 6174 : 1 +state 5648 + action 0 + 4716 : 0.8 + 6175 : 0.2 +state 5649 + action 0 + 6176 : 0.8 + 6177 : 0.2 +state 5650 + action 0 + 6178 : 0.8 + 6179 : 0.2 +state 5651 + action 0 + 6180 : 0.8 + 6181 : 0.2 +state 5652 + action 0 + 6182 : 0.8 + 6183 : 0.2 +state 5653 + action 0 + 6184 : 1 +state 5654 observe1Greater1 observeIGreater1 + action 0 + 6185 : 1 +state 5655 + action 0 + 6186 : 1 +state 5656 observe3Greater1 observeIGreater1 + action 0 + 6187 : 1 +state 5657 + action 0 + 6188 : 1 +state 5658 observe4Greater1 observeIGreater1 + action 0 + 4736 : 0.8 + 6189 : 0.2 +state 5659 observe4Greater1 observeIGreater1 + action 0 + 6190 : 0.8 + 6191 : 0.2 +state 5660 observe4Greater1 observeIGreater1 + action 0 + 6192 : 0.8 + 6193 : 0.2 +state 5661 observe4Greater1 observeIGreater1 + action 0 + 6194 : 0.8 + 6195 : 0.2 +state 5662 observe4Greater1 observeIGreater1 + action 0 + 6196 : 0.8 + 6197 : 0.2 +state 5663 observe4Greater1 observeIGreater1 + action 0 + 6198 : 1 +state 5664 observe1Greater1 observeIGreater1 + action 0 + 6199 : 1 +state 5665 + action 0 + 6200 : 1 +state 5666 + action 0 + 6201 : 1 +state 5667 observe4Greater1 observeIGreater1 + action 0 + 6202 : 1 +state 5668 observe2Greater1 observeIGreater1 + action 0 + 4756 : 0.8 + 6203 : 0.2 +state 5669 observe2Greater1 observeIGreater1 + action 0 + 6204 : 0.8 + 6205 : 0.2 +state 5670 observe2Greater1 observeIGreater1 + action 0 + 6206 : 0.8 + 6207 : 0.2 +state 5671 observe2Greater1 observeIGreater1 + action 0 + 6208 : 0.8 + 6209 : 0.2 +state 5672 observe2Greater1 observeIGreater1 + action 0 + 6210 : 0.8 + 6211 : 0.2 +state 5673 observe2Greater1 observeIGreater1 + action 0 + 6212 : 1 +state 5674 observe2Greater1 observeIGreater1 + action 0 + 4763 : 0.8 + 6213 : 0.2 +state 5675 observe2Greater1 observeIGreater1 + action 0 + 6214 : 0.8 + 6215 : 0.2 +state 5676 observe2Greater1 observeIGreater1 + action 0 + 6216 : 0.8 + 6217 : 0.2 +state 5677 observe2Greater1 observeIGreater1 + action 0 + 6218 : 0.8 + 6219 : 0.2 +state 5678 observe2Greater1 observeIGreater1 + action 0 + 6220 : 0.8 + 6221 : 0.2 +state 5679 observe2Greater1 observeIGreater1 + action 0 + 6222 : 1 +state 5680 observe2Greater1 observeIGreater1 + action 0 + 4770 : 0.8 + 6223 : 0.2 +state 5681 observe2Greater1 observeIGreater1 + action 0 + 6224 : 0.8 + 6225 : 0.2 +state 5682 observe2Greater1 observeIGreater1 + action 0 + 6226 : 0.8 + 6227 : 0.2 +state 5683 observe2Greater1 observeIGreater1 + action 0 + 6228 : 0.8 + 6229 : 0.2 +state 5684 observe2Greater1 observeIGreater1 + action 0 + 6230 : 0.8 + 6231 : 0.2 +state 5685 observe2Greater1 observeIGreater1 + action 0 + 6232 : 1 +state 5686 observe2Greater1 observeIGreater1 + action 0 + 6233 : 1 +state 5687 observe2Greater1 observeIGreater1 + action 0 + 6234 : 1 +state 5688 observe2Greater1 observeIGreater1 + action 0 + 6235 : 1 +state 5689 observe2Greater1 observeIGreater1 + action 0 + 6236 : 1 +state 5690 observe3Greater1 observeIGreater1 + action 0 + 4790 : 0.8 + 6237 : 0.2 +state 5691 observe3Greater1 observeIGreater1 + action 0 + 6238 : 0.8 + 6239 : 0.2 +state 5692 observe3Greater1 observeIGreater1 + action 0 + 6240 : 0.8 + 6241 : 0.2 +state 5693 observe3Greater1 observeIGreater1 + action 0 + 6242 : 0.8 + 6243 : 0.2 +state 5694 observe3Greater1 observeIGreater1 + action 0 + 6244 : 0.8 + 6245 : 0.2 +state 5695 observe3Greater1 observeIGreater1 + action 0 + 6246 : 1 +state 5696 + action 0 + 4797 : 0.8 + 6247 : 0.2 +state 5697 + action 0 + 6248 : 0.8 + 6249 : 0.2 +state 5698 + action 0 + 6250 : 0.8 + 6251 : 0.2 +state 5699 + action 0 + 6252 : 0.8 + 6253 : 0.2 +state 5700 + action 0 + 6254 : 0.8 + 6255 : 0.2 +state 5701 + action 0 + 6256 : 1 +state 5702 + action 0 + 6257 : 1 +state 5703 observe2Greater1 observeIGreater1 + action 0 + 6258 : 1 +state 5704 observe3Greater1 observeIGreater1 + action 0 + 6259 : 1 +state 5705 + action 0 + 6260 : 1 +state 5706 observe4Greater1 observeIGreater1 + action 0 + 4817 : 0.8 + 6261 : 0.2 +state 5707 observe4Greater1 observeIGreater1 + action 0 + 6262 : 0.8 + 6263 : 0.2 +state 5708 observe4Greater1 observeIGreater1 + action 0 + 6264 : 0.8 + 6265 : 0.2 +state 5709 observe4Greater1 observeIGreater1 + action 0 + 6266 : 0.8 + 6267 : 0.2 +state 5710 observe4Greater1 observeIGreater1 + action 0 + 6268 : 0.8 + 6269 : 0.2 +state 5711 observe4Greater1 observeIGreater1 + action 0 + 6270 : 1 +state 5712 + action 0 + 6271 : 1 +state 5713 observe2Greater1 observeIGreater1 + action 0 + 6272 : 1 +state 5714 + action 0 + 6273 : 1 +state 5715 observe4Greater1 observeIGreater1 + action 0 + 6274 : 1 +state 5716 observe3Greater1 observeIGreater1 + action 0 + 4837 : 0.8 + 6275 : 0.2 +state 5717 observe3Greater1 observeIGreater1 + action 0 + 6276 : 0.8 + 6277 : 0.2 +state 5718 observe3Greater1 observeIGreater1 + action 0 + 6278 : 0.8 + 6279 : 0.2 +state 5719 observe3Greater1 observeIGreater1 + action 0 + 6280 : 0.8 + 6281 : 0.2 +state 5720 observe3Greater1 observeIGreater1 + action 0 + 6282 : 0.8 + 6283 : 0.2 +state 5721 observe3Greater1 observeIGreater1 + action 0 + 6284 : 1 +state 5722 observe3Greater1 observeIGreater1 + action 0 + 4844 : 0.8 + 6285 : 0.2 +state 5723 observe3Greater1 observeIGreater1 + action 0 + 6286 : 0.8 + 6287 : 0.2 +state 5724 observe3Greater1 observeIGreater1 + action 0 + 6288 : 0.8 + 6289 : 0.2 +state 5725 observe3Greater1 observeIGreater1 + action 0 + 6290 : 0.8 + 6291 : 0.2 +state 5726 observe3Greater1 observeIGreater1 + action 0 + 6292 : 0.8 + 6293 : 0.2 +state 5727 observe3Greater1 observeIGreater1 + action 0 + 6294 : 1 +state 5728 observe3Greater1 observeIGreater1 + action 0 + 6295 : 1 +state 5729 observe3Greater1 observeIGreater1 + action 0 + 6296 : 1 +state 5730 observe3Greater1 observeIGreater1 + action 0 + 6297 : 1 +state 5731 observe3Greater1 observeIGreater1 + action 0 + 6298 : 1 +state 5732 observe4Greater1 observeIGreater1 + action 0 + 4864 : 0.8 + 6299 : 0.2 +state 5733 observe4Greater1 observeIGreater1 + action 0 + 6300 : 0.8 + 6301 : 0.2 +state 5734 observe4Greater1 observeIGreater1 + action 0 + 6302 : 0.8 + 6303 : 0.2 +state 5735 observe4Greater1 observeIGreater1 + action 0 + 6304 : 0.8 + 6305 : 0.2 +state 5736 observe4Greater1 observeIGreater1 + action 0 + 6306 : 0.8 + 6307 : 0.2 +state 5737 observe4Greater1 observeIGreater1 + action 0 + 6308 : 1 +state 5738 + action 0 + 6309 : 1 +state 5739 + action 0 + 6310 : 1 +state 5740 observe3Greater1 observeIGreater1 + action 0 + 6311 : 1 +state 5741 observe4Greater1 observeIGreater1 + action 0 + 6312 : 1 +state 5742 observe4Greater1 observeIGreater1 + action 0 + 4884 : 0.8 + 6313 : 0.2 +state 5743 observe4Greater1 observeIGreater1 + action 0 + 6314 : 0.8 + 6315 : 0.2 +state 5744 observe4Greater1 observeIGreater1 + action 0 + 6316 : 0.8 + 6317 : 0.2 +state 5745 observe4Greater1 observeIGreater1 + action 0 + 6318 : 0.8 + 6319 : 0.2 +state 5746 observe4Greater1 observeIGreater1 + action 0 + 6320 : 0.8 + 6321 : 0.2 +state 5747 observe4Greater1 observeIGreater1 + action 0 + 6322 : 1 +state 5748 observe4Greater1 observeIGreater1 + action 0 + 6323 : 1 +state 5749 observe4Greater1 observeIGreater1 + action 0 + 6324 : 1 +state 5750 observe4Greater1 observeIGreater1 + action 0 + 6325 : 1 +state 5751 observe4Greater1 observeIGreater1 + action 0 + 6326 : 1 +state 5752 observe1Greater1 observeIGreater1 + action 0 + 6327 : 0.833 + 6328 : 0.167 +state 5753 observe1Greater1 observeIGreater1 + action 0 + 6329 : 0.833 + 6330 : 0.167 +state 5754 observe1Greater1 observeIGreater1 + action 0 + 6331 : 0.833 + 6332 : 0.167 +state 5755 observe1Greater1 observeIGreater1 + action 0 + 6333 : 0.833 + 6334 : 0.167 +state 5756 observe1Greater1 observeIGreater1 + action 0 + 4639 : 0.833 + 4640 : 0.167 +state 5757 observe1Greater1 observeIGreater1 + action 0 + 6335 : 1 +state 5758 observe1Greater1 observeIGreater1 + action 0 + 6336 : 0.833 + 6337 : 0.167 +state 5759 observe1Greater1 observeIGreater1 + action 0 + 6338 : 1 +state 5760 observe1Greater1 observeIGreater1 + action 0 + 6339 : 0.833 + 6340 : 0.167 +state 5761 observe1Greater1 observeIGreater1 + action 0 + 6341 : 1 +state 5762 observe1Greater1 observeIGreater1 + action 0 + 6342 : 0.833 + 6343 : 0.167 +state 5763 observe1Greater1 observeIGreater1 + action 0 + 6344 : 1 +state 5764 observe1Greater1 observeIGreater1 + action 0 + 6345 : 0.833 + 6346 : 0.167 +state 5765 observe1Greater1 observeIGreater1 + action 0 + 6347 : 1 +state 5766 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5766 : 1 +state 5767 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6348 : 0.833 + 6349 : 0.167 +state 5768 observe1Greater1 observeIGreater1 + action 0 + 6350 : 0.833 + 6351 : 0.167 +state 5769 observe1Greater1 observeIGreater1 + action 0 + 6352 : 0.833 + 6353 : 0.167 +state 5770 observe1Greater1 observeIGreater1 + action 0 + 4646 : 0.833 + 4647 : 0.167 +state 5771 observe1Greater1 observeIGreater1 + action 0 + 6354 : 1 +state 5772 observe1Greater1 observeIGreater1 + action 0 + 6355 : 0.833 + 6356 : 0.167 +state 5773 observe1Greater1 observeIGreater1 + action 0 + 6357 : 1 +state 5774 observe1Greater1 observeIGreater1 + action 0 + 6358 : 0.833 + 6359 : 0.167 +state 5775 observe1Greater1 observeIGreater1 + action 0 + 6360 : 1 +state 5776 observe1Greater1 observeIGreater1 + action 0 + 6361 : 0.833 + 6362 : 0.167 +state 5777 observe1Greater1 observeIGreater1 + action 0 + 6363 : 1 +state 5778 observe1Greater1 observeIGreater1 + action 0 + 6364 : 0.833 + 6365 : 0.167 +state 5779 observe1Greater1 observeIGreater1 + action 0 + 6366 : 1 +state 5780 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5780 : 1 +state 5781 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 6367 : 0.833 + 6368 : 0.167 +state 5782 observe1Greater1 observeIGreater1 + action 0 + 6369 : 0.833 + 6370 : 0.167 +state 5783 observe1Greater1 observeIGreater1 + action 0 + 4653 : 0.833 + 4654 : 0.167 +state 5784 observe1Greater1 observeIGreater1 + action 0 + 6371 : 1 +state 5785 observe1Greater1 observeIGreater1 + action 0 + 6372 : 0.833 + 6373 : 0.167 +state 5786 observe1Greater1 observeIGreater1 + action 0 + 6374 : 1 +state 5787 observe1Greater1 observeIGreater1 + action 0 + 6375 : 0.833 + 6376 : 0.167 +state 5788 observe1Greater1 observeIGreater1 + action 0 + 6377 : 1 +state 5789 observe1Greater1 observeIGreater1 + action 0 + 6378 : 0.833 + 6379 : 0.167 +state 5790 observe1Greater1 observeIGreater1 + action 0 + 6380 : 1 +state 5791 observe1Greater1 observeIGreater1 + action 0 + 6381 : 0.833 + 6382 : 0.167 +state 5792 observe1Greater1 observeIGreater1 + action 0 + 6383 : 1 +state 5793 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5793 : 1 +state 5794 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 6384 : 0.833 + 6385 : 0.167 +state 5795 observe1Greater1 observeIGreater1 + action 0 + 4660 : 0.833 + 4661 : 0.167 +state 5796 observe1Greater1 observeIGreater1 + action 0 + 6386 : 1 +state 5797 observe1Greater1 observeIGreater1 + action 0 + 6387 : 0.833 + 6388 : 0.167 +state 5798 observe1Greater1 observeIGreater1 + action 0 + 6389 : 1 +state 5799 observe1Greater1 observeIGreater1 + action 0 + 6390 : 0.833 + 6391 : 0.167 +state 5800 observe1Greater1 observeIGreater1 + action 0 + 6392 : 1 +state 5801 observe1Greater1 observeIGreater1 + action 0 + 6393 : 0.833 + 6394 : 0.167 +state 5802 observe1Greater1 observeIGreater1 + action 0 + 6395 : 1 +state 5803 observe1Greater1 observeIGreater1 + action 0 + 6396 : 0.833 + 6397 : 0.167 +state 5804 observe1Greater1 observeIGreater1 + action 0 + 6398 : 1 +state 5805 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5805 : 1 +state 5806 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5806 : 1 +state 5807 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5807 : 1 +state 5808 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5808 : 1 +state 5809 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5809 : 1 +state 5810 observe2Greater1 observeIGreater1 + action 0 + 6399 : 0.833 + 6400 : 0.167 +state 5811 observe2Greater1 observeIGreater1 + action 0 + 6401 : 0.833 + 6402 : 0.167 +state 5812 observe2Greater1 observeIGreater1 + action 0 + 6403 : 0.833 + 6404 : 0.167 +state 5813 observe2Greater1 observeIGreater1 + action 0 + 4680 : 0.833 + 4681 : 0.167 +state 5814 observe2Greater1 observeIGreater1 + action 0 + 6405 : 1 +state 5815 observe2Greater1 observeIGreater1 + action 0 + 6406 : 0.833 + 6407 : 0.167 +state 5816 observe2Greater1 observeIGreater1 + action 0 + 6408 : 1 +state 5817 observe2Greater1 observeIGreater1 + action 0 + 6409 : 0.833 + 6410 : 0.167 +state 5818 observe2Greater1 observeIGreater1 + action 0 + 6411 : 1 +state 5819 observe2Greater1 observeIGreater1 + action 0 + 6412 : 0.833 + 6413 : 0.167 +state 5820 observe2Greater1 observeIGreater1 + action 0 + 6414 : 1 +state 5821 observe2Greater1 observeIGreater1 + action 0 + 6415 : 0.833 + 6416 : 0.167 +state 5822 observe2Greater1 observeIGreater1 + action 0 + 6417 : 1 +state 5823 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5823 : 1 +state 5824 observe3Greater1 observeIGreater1 + action 0 + 6418 : 0.833 + 6419 : 0.167 +state 5825 + action 0 + 6420 : 0.833 + 6421 : 0.167 +state 5826 + action 0 + 4687 : 0.833 + 4688 : 0.167 +state 5827 + action 0 + 6422 : 1 +state 5828 + action 0 + 6423 : 0.833 + 6424 : 0.167 +state 5829 + action 0 + 6425 : 1 +state 5830 + action 0 + 6426 : 0.833 + 6427 : 0.167 +state 5831 + action 0 + 6428 : 1 +state 5832 + action 0 + 6429 : 0.833 + 6430 : 0.167 +state 5833 + action 0 + 6431 : 1 +state 5834 + action 0 + 6432 : 0.833 + 6433 : 0.167 +state 5835 + action 0 + 6434 : 1 +state 5836 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5836 : 1 +state 5837 observe4Greater1 observeIGreater1 + action 0 + 6435 : 0.833 + 6436 : 0.167 +state 5838 + action 0 + 4694 : 0.833 + 4695 : 0.167 +state 5839 + action 0 + 6437 : 1 +state 5840 + action 0 + 6438 : 0.833 + 6439 : 0.167 +state 5841 + action 0 + 6440 : 1 +state 5842 + action 0 + 6441 : 0.833 + 6442 : 0.167 +state 5843 + action 0 + 6443 : 1 +state 5844 + action 0 + 6444 : 0.833 + 6445 : 0.167 +state 5845 + action 0 + 6446 : 1 +state 5846 + action 0 + 6447 : 0.833 + 6448 : 0.167 +state 5847 + action 0 + 6449 : 1 +state 5848 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5848 : 1 +state 5849 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5849 : 1 +state 5850 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5850 : 1 +state 5851 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5851 : 1 +state 5852 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5852 : 1 +state 5853 observe3Greater1 observeIGreater1 + action 0 + 6450 : 0.833 + 6451 : 0.167 +state 5854 observe3Greater1 observeIGreater1 + action 0 + 6452 : 0.833 + 6453 : 0.167 +state 5855 observe3Greater1 observeIGreater1 + action 0 + 4714 : 0.833 + 4715 : 0.167 +state 5856 observe3Greater1 observeIGreater1 + action 0 + 6454 : 1 +state 5857 observe3Greater1 observeIGreater1 + action 0 + 6455 : 0.833 + 6456 : 0.167 +state 5858 observe3Greater1 observeIGreater1 + action 0 + 6457 : 1 +state 5859 observe3Greater1 observeIGreater1 + action 0 + 6458 : 0.833 + 6459 : 0.167 +state 5860 observe3Greater1 observeIGreater1 + action 0 + 6460 : 1 +state 5861 observe3Greater1 observeIGreater1 + action 0 + 6461 : 0.833 + 6462 : 0.167 +state 5862 observe3Greater1 observeIGreater1 + action 0 + 6463 : 1 +state 5863 observe3Greater1 observeIGreater1 + action 0 + 6464 : 0.833 + 6465 : 0.167 +state 5864 observe3Greater1 observeIGreater1 + action 0 + 6466 : 1 +state 5865 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5865 : 1 +state 5866 observe4Greater1 observeIGreater1 + action 0 + 6467 : 0.833 + 6468 : 0.167 +state 5867 + action 0 + 4721 : 0.833 + 4722 : 0.167 +state 5868 + action 0 + 6469 : 1 +state 5869 + action 0 + 6470 : 0.833 + 6471 : 0.167 +state 5870 + action 0 + 6472 : 1 +state 5871 + action 0 + 6473 : 0.833 + 6474 : 0.167 +state 5872 + action 0 + 6475 : 1 +state 5873 + action 0 + 6476 : 0.833 + 6477 : 0.167 +state 5874 + action 0 + 6478 : 1 +state 5875 + action 0 + 6479 : 0.833 + 6480 : 0.167 +state 5876 + action 0 + 6481 : 1 +state 5877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5877 : 1 +state 5878 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5878 : 1 +state 5879 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5879 : 1 +state 5880 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5880 : 1 +state 5881 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5881 : 1 +state 5882 observe4Greater1 observeIGreater1 + action 0 + 6482 : 0.833 + 6483 : 0.167 +state 5883 observe4Greater1 observeIGreater1 + action 0 + 4741 : 0.833 + 4742 : 0.167 +state 5884 observe4Greater1 observeIGreater1 + action 0 + 6484 : 1 +state 5885 observe4Greater1 observeIGreater1 + action 0 + 6485 : 0.833 + 6486 : 0.167 +state 5886 observe4Greater1 observeIGreater1 + action 0 + 6487 : 1 +state 5887 observe4Greater1 observeIGreater1 + action 0 + 6488 : 0.833 + 6489 : 0.167 +state 5888 observe4Greater1 observeIGreater1 + action 0 + 6490 : 1 +state 5889 observe4Greater1 observeIGreater1 + action 0 + 6491 : 0.833 + 6492 : 0.167 +state 5890 observe4Greater1 observeIGreater1 + action 0 + 6493 : 1 +state 5891 observe4Greater1 observeIGreater1 + action 0 + 6494 : 0.833 + 6495 : 0.167 +state 5892 observe4Greater1 observeIGreater1 + action 0 + 6496 : 1 +state 5893 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5893 : 1 +state 5894 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5894 : 1 +state 5895 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5895 : 1 +state 5896 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5896 : 1 +state 5897 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5897 : 1 +state 5898 observe2Greater1 observeIGreater1 + action 0 + 6497 : 0.833 + 6498 : 0.167 +state 5899 observe2Greater1 observeIGreater1 + action 0 + 6499 : 0.833 + 6500 : 0.167 +state 5900 observe2Greater1 observeIGreater1 + action 0 + 6501 : 0.833 + 6502 : 0.167 +state 5901 observe2Greater1 observeIGreater1 + action 0 + 4761 : 0.833 + 4762 : 0.167 +state 5902 observe2Greater1 observeIGreater1 + action 0 + 6503 : 1 +state 5903 observe2Greater1 observeIGreater1 + action 0 + 6504 : 0.833 + 6505 : 0.167 +state 5904 observe2Greater1 observeIGreater1 + action 0 + 6506 : 1 +state 5905 observe2Greater1 observeIGreater1 + action 0 + 6507 : 0.833 + 6508 : 0.167 +state 5906 observe2Greater1 observeIGreater1 + action 0 + 6509 : 1 +state 5907 observe2Greater1 observeIGreater1 + action 0 + 6510 : 0.833 + 6511 : 0.167 +state 5908 observe2Greater1 observeIGreater1 + action 0 + 6512 : 1 +state 5909 observe2Greater1 observeIGreater1 + action 0 + 6513 : 0.833 + 6514 : 0.167 +state 5910 observe2Greater1 observeIGreater1 + action 0 + 6515 : 1 +state 5911 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5911 : 1 +state 5912 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 6516 : 0.833 + 6517 : 0.167 +state 5913 observe2Greater1 observeIGreater1 + action 0 + 6518 : 0.833 + 6519 : 0.167 +state 5914 observe2Greater1 observeIGreater1 + action 0 + 4768 : 0.833 + 4769 : 0.167 +state 5915 observe2Greater1 observeIGreater1 + action 0 + 6520 : 1 +state 5916 observe2Greater1 observeIGreater1 + action 0 + 6521 : 0.833 + 6522 : 0.167 +state 5917 observe2Greater1 observeIGreater1 + action 0 + 6523 : 1 +state 5918 observe2Greater1 observeIGreater1 + action 0 + 6524 : 0.833 + 6525 : 0.167 +state 5919 observe2Greater1 observeIGreater1 + action 0 + 6526 : 1 +state 5920 observe2Greater1 observeIGreater1 + action 0 + 6527 : 0.833 + 6528 : 0.167 +state 5921 observe2Greater1 observeIGreater1 + action 0 + 6529 : 1 +state 5922 observe2Greater1 observeIGreater1 + action 0 + 6530 : 0.833 + 6531 : 0.167 +state 5923 observe2Greater1 observeIGreater1 + action 0 + 6532 : 1 +state 5924 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5924 : 1 +state 5925 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 6533 : 0.833 + 6534 : 0.167 +state 5926 observe2Greater1 observeIGreater1 + action 0 + 4775 : 0.833 + 4776 : 0.167 +state 5927 observe2Greater1 observeIGreater1 + action 0 + 6535 : 1 +state 5928 observe2Greater1 observeIGreater1 + action 0 + 6536 : 0.833 + 6537 : 0.167 +state 5929 observe2Greater1 observeIGreater1 + action 0 + 6538 : 1 +state 5930 observe2Greater1 observeIGreater1 + action 0 + 6539 : 0.833 + 6540 : 0.167 +state 5931 observe2Greater1 observeIGreater1 + action 0 + 6541 : 1 +state 5932 observe2Greater1 observeIGreater1 + action 0 + 6542 : 0.833 + 6543 : 0.167 +state 5933 observe2Greater1 observeIGreater1 + action 0 + 6544 : 1 +state 5934 observe2Greater1 observeIGreater1 + action 0 + 6545 : 0.833 + 6546 : 0.167 +state 5935 observe2Greater1 observeIGreater1 + action 0 + 6547 : 1 +state 5936 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5936 : 1 +state 5937 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5937 : 1 +state 5938 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5938 : 1 +state 5939 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5939 : 1 +state 5940 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5940 : 1 +state 5941 observe3Greater1 observeIGreater1 + action 0 + 6548 : 0.833 + 6549 : 0.167 +state 5942 observe3Greater1 observeIGreater1 + action 0 + 6550 : 0.833 + 6551 : 0.167 +state 5943 observe3Greater1 observeIGreater1 + action 0 + 4795 : 0.833 + 4796 : 0.167 +state 5944 observe3Greater1 observeIGreater1 + action 0 + 6552 : 1 +state 5945 observe3Greater1 observeIGreater1 + action 0 + 6553 : 0.833 + 6554 : 0.167 +state 5946 observe3Greater1 observeIGreater1 + action 0 + 6555 : 1 +state 5947 observe3Greater1 observeIGreater1 + action 0 + 6556 : 0.833 + 6557 : 0.167 +state 5948 observe3Greater1 observeIGreater1 + action 0 + 6558 : 1 +state 5949 observe3Greater1 observeIGreater1 + action 0 + 6559 : 0.833 + 6560 : 0.167 +state 5950 observe3Greater1 observeIGreater1 + action 0 + 6561 : 1 +state 5951 observe3Greater1 observeIGreater1 + action 0 + 6562 : 0.833 + 6563 : 0.167 +state 5952 observe3Greater1 observeIGreater1 + action 0 + 6564 : 1 +state 5953 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5953 : 1 +state 5954 observe4Greater1 observeIGreater1 + action 0 + 6565 : 0.833 + 6566 : 0.167 +state 5955 + action 0 + 4802 : 0.833 + 4803 : 0.167 +state 5956 + action 0 + 6567 : 1 +state 5957 + action 0 + 6568 : 0.833 + 6569 : 0.167 +state 5958 + action 0 + 6570 : 1 +state 5959 + action 0 + 6571 : 0.833 + 6572 : 0.167 +state 5960 + action 0 + 6573 : 1 +state 5961 + action 0 + 6574 : 0.833 + 6575 : 0.167 +state 5962 + action 0 + 6576 : 1 +state 5963 + action 0 + 6577 : 0.833 + 6578 : 0.167 +state 5964 + action 0 + 6579 : 1 +state 5965 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5965 : 1 +state 5966 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5966 : 1 +state 5967 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5967 : 1 +state 5968 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5968 : 1 +state 5969 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5969 : 1 +state 5970 observe4Greater1 observeIGreater1 + action 0 + 6580 : 0.833 + 6581 : 0.167 +state 5971 observe4Greater1 observeIGreater1 + action 0 + 4822 : 0.833 + 4823 : 0.167 +state 5972 observe4Greater1 observeIGreater1 + action 0 + 6582 : 1 +state 5973 observe4Greater1 observeIGreater1 + action 0 + 6583 : 0.833 + 6584 : 0.167 +state 5974 observe4Greater1 observeIGreater1 + action 0 + 6585 : 1 +state 5975 observe4Greater1 observeIGreater1 + action 0 + 6586 : 0.833 + 6587 : 0.167 +state 5976 observe4Greater1 observeIGreater1 + action 0 + 6588 : 1 +state 5977 observe4Greater1 observeIGreater1 + action 0 + 6589 : 0.833 + 6590 : 0.167 +state 5978 observe4Greater1 observeIGreater1 + action 0 + 6591 : 1 +state 5979 observe4Greater1 observeIGreater1 + action 0 + 6592 : 0.833 + 6593 : 0.167 +state 5980 observe4Greater1 observeIGreater1 + action 0 + 6594 : 1 +state 5981 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5981 : 1 +state 5982 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5982 : 1 +state 5983 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5983 : 1 +state 5984 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5984 : 1 +state 5985 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5985 : 1 +state 5986 observe3Greater1 observeIGreater1 + action 0 + 6595 : 0.833 + 6596 : 0.167 +state 5987 observe3Greater1 observeIGreater1 + action 0 + 6597 : 0.833 + 6598 : 0.167 +state 5988 observe3Greater1 observeIGreater1 + action 0 + 4842 : 0.833 + 4843 : 0.167 +state 5989 observe3Greater1 observeIGreater1 + action 0 + 6599 : 1 +state 5990 observe3Greater1 observeIGreater1 + action 0 + 6600 : 0.833 + 6601 : 0.167 +state 5991 observe3Greater1 observeIGreater1 + action 0 + 6602 : 1 +state 5992 observe3Greater1 observeIGreater1 + action 0 + 6603 : 0.833 + 6604 : 0.167 +state 5993 observe3Greater1 observeIGreater1 + action 0 + 6605 : 1 +state 5994 observe3Greater1 observeIGreater1 + action 0 + 6606 : 0.833 + 6607 : 0.167 +state 5995 observe3Greater1 observeIGreater1 + action 0 + 6608 : 1 +state 5996 observe3Greater1 observeIGreater1 + action 0 + 6609 : 0.833 + 6610 : 0.167 +state 5997 observe3Greater1 observeIGreater1 + action 0 + 6611 : 1 +state 5998 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5998 : 1 +state 5999 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 6612 : 0.833 + 6613 : 0.167 +state 6000 observe3Greater1 observeIGreater1 + action 0 + 4849 : 0.833 + 4850 : 0.167 +state 6001 observe3Greater1 observeIGreater1 + action 0 + 6614 : 1 +state 6002 observe3Greater1 observeIGreater1 + action 0 + 6615 : 0.833 + 6616 : 0.167 +state 6003 observe3Greater1 observeIGreater1 + action 0 + 6617 : 1 +state 6004 observe3Greater1 observeIGreater1 + action 0 + 6618 : 0.833 + 6619 : 0.167 +state 6005 observe3Greater1 observeIGreater1 + action 0 + 6620 : 1 +state 6006 observe3Greater1 observeIGreater1 + action 0 + 6621 : 0.833 + 6622 : 0.167 +state 6007 observe3Greater1 observeIGreater1 + action 0 + 6623 : 1 +state 6008 observe3Greater1 observeIGreater1 + action 0 + 6624 : 0.833 + 6625 : 0.167 +state 6009 observe3Greater1 observeIGreater1 + action 0 + 6626 : 1 +state 6010 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6010 : 1 +state 6011 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6011 : 1 +state 6012 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6012 : 1 +state 6013 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6013 : 1 +state 6014 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6014 : 1 +state 6015 observe4Greater1 observeIGreater1 + action 0 + 6627 : 0.833 + 6628 : 0.167 +state 6016 observe4Greater1 observeIGreater1 + action 0 + 4869 : 0.833 + 4870 : 0.167 +state 6017 observe4Greater1 observeIGreater1 + action 0 + 6629 : 1 +state 6018 observe4Greater1 observeIGreater1 + action 0 + 6630 : 0.833 + 6631 : 0.167 +state 6019 observe4Greater1 observeIGreater1 + action 0 + 6632 : 1 +state 6020 observe4Greater1 observeIGreater1 + action 0 + 6633 : 0.833 + 6634 : 0.167 +state 6021 observe4Greater1 observeIGreater1 + action 0 + 6635 : 1 +state 6022 observe4Greater1 observeIGreater1 + action 0 + 6636 : 0.833 + 6637 : 0.167 +state 6023 observe4Greater1 observeIGreater1 + action 0 + 6638 : 1 +state 6024 observe4Greater1 observeIGreater1 + action 0 + 6639 : 0.833 + 6640 : 0.167 +state 6025 observe4Greater1 observeIGreater1 + action 0 + 6641 : 1 +state 6026 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6026 : 1 +state 6027 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 6027 : 1 +state 6028 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 6028 : 1 +state 6029 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6029 : 1 +state 6030 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6030 : 1 +state 6031 observe4Greater1 observeIGreater1 + action 0 + 6642 : 0.833 + 6643 : 0.167 +state 6032 observe4Greater1 observeIGreater1 + action 0 + 4889 : 0.833 + 4890 : 0.167 +state 6033 observe4Greater1 observeIGreater1 + action 0 + 6644 : 1 +state 6034 observe4Greater1 observeIGreater1 + action 0 + 6645 : 0.833 + 6646 : 0.167 +state 6035 observe4Greater1 observeIGreater1 + action 0 + 6647 : 1 +state 6036 observe4Greater1 observeIGreater1 + action 0 + 6648 : 0.833 + 6649 : 0.167 +state 6037 observe4Greater1 observeIGreater1 + action 0 + 6650 : 1 +state 6038 observe4Greater1 observeIGreater1 + action 0 + 6651 : 0.833 + 6652 : 0.167 +state 6039 observe4Greater1 observeIGreater1 + action 0 + 6653 : 1 +state 6040 observe4Greater1 observeIGreater1 + action 0 + 6654 : 0.833 + 6655 : 0.167 +state 6041 observe4Greater1 observeIGreater1 + action 0 + 6656 : 1 +state 6042 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6042 : 1 +state 6043 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6043 : 1 +state 6044 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6044 : 1 +state 6045 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6045 : 1 +state 6046 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6046 : 1 +state 6047 observe1Greater1 observeIGreater1 + action 0 + 6657 : 1 +state 6048 observe1Greater1 observeIGreater1 + action 0 + 6658 : 1 +state 6049 observe1Greater1 observeIGreater1 + action 0 + 6659 : 1 +state 6050 observe1Greater1 observeIGreater1 + action 0 + 6660 : 1 +state 6051 observe1Greater1 observeIGreater1 + action 0 + 6661 : 1 +state 6052 observe2Greater1 observeIGreater1 + action 0 + 6662 : 1 +state 6053 + action 0 + 6663 : 1 +state 6054 + action 0 + 6664 : 1 +state 6055 observe1Greater1 observeIGreater1 + action 0 + 6665 : 1 +state 6056 + action 0 + 6666 : 1 +state 6057 observe3Greater1 observeIGreater1 + action 0 + 6667 : 1 +state 6058 + action 0 + 6668 : 1 +state 6059 observe1Greater1 observeIGreater1 + action 0 + 6669 : 1 +state 6060 + action 0 + 6670 : 1 +state 6061 + action 0 + 6671 : 1 +state 6062 observe4Greater1 observeIGreater1 + action 0 + 6672 : 1 +state 6063 observe2Greater1 observeIGreater1 + action 0 + 6673 : 1 +state 6064 observe2Greater1 observeIGreater1 + action 0 + 6674 : 1 +state 6065 observe2Greater1 observeIGreater1 + action 0 + 6675 : 1 +state 6066 observe2Greater1 observeIGreater1 + action 0 + 6676 : 1 +state 6067 + action 0 + 6677 : 1 +state 6068 observe2Greater1 observeIGreater1 + action 0 + 6678 : 1 +state 6069 observe3Greater1 observeIGreater1 + action 0 + 6679 : 1 +state 6070 + action 0 + 6680 : 1 +state 6071 + action 0 + 6681 : 1 +state 6072 observe2Greater1 observeIGreater1 + action 0 + 6682 : 1 +state 6073 + action 0 + 6683 : 1 +state 6074 observe4Greater1 observeIGreater1 + action 0 + 6684 : 1 +state 6075 observe3Greater1 observeIGreater1 + action 0 + 6685 : 1 +state 6076 observe3Greater1 observeIGreater1 + action 0 + 6686 : 1 +state 6077 observe3Greater1 observeIGreater1 + action 0 + 6687 : 1 +state 6078 observe3Greater1 observeIGreater1 + action 0 + 6688 : 1 +state 6079 + action 0 + 6689 : 1 +state 6080 + action 0 + 6690 : 1 +state 6081 observe3Greater1 observeIGreater1 + action 0 + 6691 : 1 +state 6082 observe4Greater1 observeIGreater1 + action 0 + 6692 : 1 +state 6083 observe4Greater1 observeIGreater1 + action 0 + 6693 : 1 +state 6084 observe4Greater1 observeIGreater1 + action 0 + 6694 : 1 +state 6085 observe4Greater1 observeIGreater1 + action 0 + 6695 : 1 +state 6086 observe4Greater1 observeIGreater1 + action 0 + 6696 : 1 +state 6087 observe1Greater1 observeIGreater1 + action 0 + 6697 : 1 +state 6088 observe1Greater1 observeIGreater1 + action 0 + 6698 : 0.833 + 6699 : 0.167 +state 6089 observe1Greater1 observeIGreater1 + action 0 + 6700 : 1 +state 6090 observe1Greater1 observeIGreater1 + action 0 + 6701 : 0.833 + 6702 : 0.167 +state 6091 observe1Greater1 observeIGreater1 + action 0 + 6703 : 1 +state 6092 observe1Greater1 observeIGreater1 + action 0 + 6704 : 0.833 + 6705 : 0.167 +state 6093 observe1Greater1 observeIGreater1 + action 0 + 6706 : 1 +state 6094 observe1Greater1 observeIGreater1 + action 0 + 6707 : 0.833 + 6708 : 0.167 +state 6095 observe1Greater1 observeIGreater1 + action 0 + 6709 : 1 +state 6096 deadlock observe1Greater1 observeIGreater1 + action 0 + 6096 : 1 +state 6097 observe1Greater1 observeIGreater1 + action 0 + 6710 : 1 +state 6098 observe1Greater1 observeIGreater1 + action 0 + 6711 : 0.833 + 6712 : 0.167 +state 6099 observe1Greater1 observeIGreater1 + action 0 + 6713 : 1 +state 6100 observe1Greater1 observeIGreater1 + action 0 + 6714 : 0.833 + 6715 : 0.167 +state 6101 observe1Greater1 observeIGreater1 + action 0 + 6716 : 1 +state 6102 observe1Greater1 observeIGreater1 + action 0 + 6717 : 0.833 + 6718 : 0.167 +state 6103 observe1Greater1 observeIGreater1 + action 0 + 6719 : 1 +state 6104 observe1Greater1 observeIGreater1 + action 0 + 6720 : 0.833 + 6721 : 0.167 +state 6105 observe1Greater1 observeIGreater1 + action 0 + 6722 : 1 +state 6106 deadlock observe1Greater1 observeIGreater1 + action 0 + 6106 : 1 +state 6107 observe1Greater1 observeIGreater1 + action 0 + 6723 : 1 +state 6108 observe1Greater1 observeIGreater1 + action 0 + 6724 : 0.833 + 6725 : 0.167 +state 6109 observe1Greater1 observeIGreater1 + action 0 + 6726 : 1 +state 6110 observe1Greater1 observeIGreater1 + action 0 + 6727 : 0.833 + 6728 : 0.167 +state 6111 observe1Greater1 observeIGreater1 + action 0 + 6729 : 1 +state 6112 observe1Greater1 observeIGreater1 + action 0 + 6730 : 0.833 + 6731 : 0.167 +state 6113 observe1Greater1 observeIGreater1 + action 0 + 6732 : 1 +state 6114 observe1Greater1 observeIGreater1 + action 0 + 6733 : 0.833 + 6734 : 0.167 +state 6115 observe1Greater1 observeIGreater1 + action 0 + 6735 : 1 +state 6116 deadlock observe1Greater1 observeIGreater1 + action 0 + 6116 : 1 +state 6117 observe1Greater1 observeIGreater1 + action 0 + 6736 : 1 +state 6118 observe1Greater1 observeIGreater1 + action 0 + 6737 : 0.833 + 6738 : 0.167 +state 6119 observe1Greater1 observeIGreater1 + action 0 + 6739 : 1 +state 6120 observe1Greater1 observeIGreater1 + action 0 + 6740 : 0.833 + 6741 : 0.167 +state 6121 observe1Greater1 observeIGreater1 + action 0 + 6742 : 1 +state 6122 observe1Greater1 observeIGreater1 + action 0 + 6743 : 0.833 + 6744 : 0.167 +state 6123 observe1Greater1 observeIGreater1 + action 0 + 6745 : 1 +state 6124 observe1Greater1 observeIGreater1 + action 0 + 6746 : 0.833 + 6747 : 0.167 +state 6125 observe1Greater1 observeIGreater1 + action 0 + 6748 : 1 +state 6126 deadlock observe1Greater1 observeIGreater1 + action 0 + 6126 : 1 +state 6127 deadlock observe1Greater1 observeIGreater1 + action 0 + 6127 : 1 +state 6128 deadlock observe1Greater1 observeIGreater1 + action 0 + 6128 : 1 +state 6129 deadlock observe1Greater1 observeIGreater1 + action 0 + 6129 : 1 +state 6130 deadlock observe1Greater1 observeIGreater1 + action 0 + 6130 : 1 +state 6131 observe2Greater1 observeIGreater1 + action 0 + 6749 : 1 +state 6132 observe2Greater1 observeIGreater1 + action 0 + 6750 : 0.833 + 6751 : 0.167 +state 6133 observe2Greater1 observeIGreater1 + action 0 + 6752 : 1 +state 6134 observe2Greater1 observeIGreater1 + action 0 + 6753 : 0.833 + 6754 : 0.167 +state 6135 observe2Greater1 observeIGreater1 + action 0 + 6755 : 1 +state 6136 observe2Greater1 observeIGreater1 + action 0 + 6756 : 0.833 + 6757 : 0.167 +state 6137 observe2Greater1 observeIGreater1 + action 0 + 6758 : 1 +state 6138 observe2Greater1 observeIGreater1 + action 0 + 6759 : 0.833 + 6760 : 0.167 +state 6139 observe2Greater1 observeIGreater1 + action 0 + 6761 : 1 +state 6140 deadlock observe2Greater1 observeIGreater1 + action 0 + 6140 : 1 +state 6141 + action 0 + 6762 : 1 +state 6142 + action 0 + 6763 : 0.833 + 6764 : 0.167 +state 6143 + action 0 + 6765 : 1 +state 6144 + action 0 + 6766 : 0.833 + 6767 : 0.167 +state 6145 + action 0 + 6768 : 1 +state 6146 + action 0 + 6769 : 0.833 + 6770 : 0.167 +state 6147 + action 0 + 6771 : 1 +state 6148 + action 0 + 6772 : 0.833 + 6773 : 0.167 +state 6149 + action 0 + 6774 : 1 +state 6150 deadlock + action 0 + 6150 : 1 +state 6151 + action 0 + 6775 : 1 +state 6152 + action 0 + 6776 : 0.833 + 6777 : 0.167 +state 6153 + action 0 + 6778 : 1 +state 6154 + action 0 + 6779 : 0.833 + 6780 : 0.167 +state 6155 + action 0 + 6781 : 1 +state 6156 + action 0 + 6782 : 0.833 + 6783 : 0.167 +state 6157 + action 0 + 6784 : 1 +state 6158 + action 0 + 6785 : 0.833 + 6786 : 0.167 +state 6159 + action 0 + 6787 : 1 +state 6160 deadlock + action 0 + 6160 : 1 +state 6161 deadlock observe1Greater1 observeIGreater1 + action 0 + 6161 : 1 +state 6162 deadlock observe2Greater1 observeIGreater1 + action 0 + 6162 : 1 +state 6163 deadlock + action 0 + 6163 : 1 +state 6164 deadlock + action 0 + 6164 : 1 +state 6165 observe3Greater1 observeIGreater1 + action 0 + 6788 : 1 +state 6166 observe3Greater1 observeIGreater1 + action 0 + 6789 : 0.833 + 6790 : 0.167 +state 6167 observe3Greater1 observeIGreater1 + action 0 + 6791 : 1 +state 6168 observe3Greater1 observeIGreater1 + action 0 + 6792 : 0.833 + 6793 : 0.167 +state 6169 observe3Greater1 observeIGreater1 + action 0 + 6794 : 1 +state 6170 observe3Greater1 observeIGreater1 + action 0 + 6795 : 0.833 + 6796 : 0.167 +state 6171 observe3Greater1 observeIGreater1 + action 0 + 6797 : 1 +state 6172 observe3Greater1 observeIGreater1 + action 0 + 6798 : 0.833 + 6799 : 0.167 +state 6173 observe3Greater1 observeIGreater1 + action 0 + 6800 : 1 +state 6174 deadlock observe3Greater1 observeIGreater1 + action 0 + 6174 : 1 +state 6175 + action 0 + 6801 : 1 +state 6176 + action 0 + 6802 : 0.833 + 6803 : 0.167 +state 6177 + action 0 + 6804 : 1 +state 6178 + action 0 + 6805 : 0.833 + 6806 : 0.167 +state 6179 + action 0 + 6807 : 1 +state 6180 + action 0 + 6808 : 0.833 + 6809 : 0.167 +state 6181 + action 0 + 6810 : 1 +state 6182 + action 0 + 6811 : 0.833 + 6812 : 0.167 +state 6183 + action 0 + 6813 : 1 +state 6184 deadlock + action 0 + 6184 : 1 +state 6185 deadlock observe1Greater1 observeIGreater1 + action 0 + 6185 : 1 +state 6186 deadlock + action 0 + 6186 : 1 +state 6187 deadlock observe3Greater1 observeIGreater1 + action 0 + 6187 : 1 +state 6188 deadlock + action 0 + 6188 : 1 +state 6189 observe4Greater1 observeIGreater1 + action 0 + 6814 : 1 +state 6190 observe4Greater1 observeIGreater1 + action 0 + 6815 : 0.833 + 6816 : 0.167 +state 6191 observe4Greater1 observeIGreater1 + action 0 + 6817 : 1 +state 6192 observe4Greater1 observeIGreater1 + action 0 + 6818 : 0.833 + 6819 : 0.167 +state 6193 observe4Greater1 observeIGreater1 + action 0 + 6820 : 1 +state 6194 observe4Greater1 observeIGreater1 + action 0 + 6821 : 0.833 + 6822 : 0.167 +state 6195 observe4Greater1 observeIGreater1 + action 0 + 6823 : 1 +state 6196 observe4Greater1 observeIGreater1 + action 0 + 6824 : 0.833 + 6825 : 0.167 +state 6197 observe4Greater1 observeIGreater1 + action 0 + 6826 : 1 +state 6198 deadlock observe4Greater1 observeIGreater1 + action 0 + 6198 : 1 +state 6199 deadlock observe1Greater1 observeIGreater1 + action 0 + 6199 : 1 +state 6200 deadlock + action 0 + 6200 : 1 +state 6201 deadlock + action 0 + 6201 : 1 +state 6202 deadlock observe4Greater1 observeIGreater1 + action 0 + 6202 : 1 +state 6203 observe2Greater1 observeIGreater1 + action 0 + 6827 : 1 +state 6204 observe2Greater1 observeIGreater1 + action 0 + 6828 : 0.833 + 6829 : 0.167 +state 6205 observe2Greater1 observeIGreater1 + action 0 + 6830 : 1 +state 6206 observe2Greater1 observeIGreater1 + action 0 + 6831 : 0.833 + 6832 : 0.167 +state 6207 observe2Greater1 observeIGreater1 + action 0 + 6833 : 1 +state 6208 observe2Greater1 observeIGreater1 + action 0 + 6834 : 0.833 + 6835 : 0.167 +state 6209 observe2Greater1 observeIGreater1 + action 0 + 6836 : 1 +state 6210 observe2Greater1 observeIGreater1 + action 0 + 6837 : 0.833 + 6838 : 0.167 +state 6211 observe2Greater1 observeIGreater1 + action 0 + 6839 : 1 +state 6212 deadlock observe2Greater1 observeIGreater1 + action 0 + 6212 : 1 +state 6213 observe2Greater1 observeIGreater1 + action 0 + 6840 : 1 +state 6214 observe2Greater1 observeIGreater1 + action 0 + 6841 : 0.833 + 6842 : 0.167 +state 6215 observe2Greater1 observeIGreater1 + action 0 + 6843 : 1 +state 6216 observe2Greater1 observeIGreater1 + action 0 + 6844 : 0.833 + 6845 : 0.167 +state 6217 observe2Greater1 observeIGreater1 + action 0 + 6846 : 1 +state 6218 observe2Greater1 observeIGreater1 + action 0 + 6847 : 0.833 + 6848 : 0.167 +state 6219 observe2Greater1 observeIGreater1 + action 0 + 6849 : 1 +state 6220 observe2Greater1 observeIGreater1 + action 0 + 6850 : 0.833 + 6851 : 0.167 +state 6221 observe2Greater1 observeIGreater1 + action 0 + 6852 : 1 +state 6222 deadlock observe2Greater1 observeIGreater1 + action 0 + 6222 : 1 +state 6223 observe2Greater1 observeIGreater1 + action 0 + 6853 : 1 +state 6224 observe2Greater1 observeIGreater1 + action 0 + 6854 : 0.833 + 6855 : 0.167 +state 6225 observe2Greater1 observeIGreater1 + action 0 + 6856 : 1 +state 6226 observe2Greater1 observeIGreater1 + action 0 + 6857 : 0.833 + 6858 : 0.167 +state 6227 observe2Greater1 observeIGreater1 + action 0 + 6859 : 1 +state 6228 observe2Greater1 observeIGreater1 + action 0 + 6860 : 0.833 + 6861 : 0.167 +state 6229 observe2Greater1 observeIGreater1 + action 0 + 6862 : 1 +state 6230 observe2Greater1 observeIGreater1 + action 0 + 6863 : 0.833 + 6864 : 0.167 +state 6231 observe2Greater1 observeIGreater1 + action 0 + 6865 : 1 +state 6232 deadlock observe2Greater1 observeIGreater1 + action 0 + 6232 : 1 +state 6233 deadlock observe2Greater1 observeIGreater1 + action 0 + 6233 : 1 +state 6234 deadlock observe2Greater1 observeIGreater1 + action 0 + 6234 : 1 +state 6235 deadlock observe2Greater1 observeIGreater1 + action 0 + 6235 : 1 +state 6236 deadlock observe2Greater1 observeIGreater1 + action 0 + 6236 : 1 +state 6237 observe3Greater1 observeIGreater1 + action 0 + 6866 : 1 +state 6238 observe3Greater1 observeIGreater1 + action 0 + 6867 : 0.833 + 6868 : 0.167 +state 6239 observe3Greater1 observeIGreater1 + action 0 + 6869 : 1 +state 6240 observe3Greater1 observeIGreater1 + action 0 + 6870 : 0.833 + 6871 : 0.167 +state 6241 observe3Greater1 observeIGreater1 + action 0 + 6872 : 1 +state 6242 observe3Greater1 observeIGreater1 + action 0 + 6873 : 0.833 + 6874 : 0.167 +state 6243 observe3Greater1 observeIGreater1 + action 0 + 6875 : 1 +state 6244 observe3Greater1 observeIGreater1 + action 0 + 6876 : 0.833 + 6877 : 0.167 +state 6245 observe3Greater1 observeIGreater1 + action 0 + 6878 : 1 +state 6246 deadlock observe3Greater1 observeIGreater1 + action 0 + 6246 : 1 +state 6247 + action 0 + 6879 : 1 +state 6248 + action 0 + 6880 : 0.833 + 6881 : 0.167 +state 6249 + action 0 + 6882 : 1 +state 6250 + action 0 + 6883 : 0.833 + 6884 : 0.167 +state 6251 + action 0 + 6885 : 1 +state 6252 + action 0 + 6886 : 0.833 + 6887 : 0.167 +state 6253 + action 0 + 6888 : 1 +state 6254 + action 0 + 6889 : 0.833 + 6890 : 0.167 +state 6255 + action 0 + 6891 : 1 +state 6256 deadlock + action 0 + 6256 : 1 +state 6257 deadlock + action 0 + 6257 : 1 +state 6258 deadlock observe2Greater1 observeIGreater1 + action 0 + 6258 : 1 +state 6259 deadlock observe3Greater1 observeIGreater1 + action 0 + 6259 : 1 +state 6260 deadlock + action 0 + 6260 : 1 +state 6261 observe4Greater1 observeIGreater1 + action 0 + 6892 : 1 +state 6262 observe4Greater1 observeIGreater1 + action 0 + 6893 : 0.833 + 6894 : 0.167 +state 6263 observe4Greater1 observeIGreater1 + action 0 + 6895 : 1 +state 6264 observe4Greater1 observeIGreater1 + action 0 + 6896 : 0.833 + 6897 : 0.167 +state 6265 observe4Greater1 observeIGreater1 + action 0 + 6898 : 1 +state 6266 observe4Greater1 observeIGreater1 + action 0 + 6899 : 0.833 + 6900 : 0.167 +state 6267 observe4Greater1 observeIGreater1 + action 0 + 6901 : 1 +state 6268 observe4Greater1 observeIGreater1 + action 0 + 6902 : 0.833 + 6903 : 0.167 +state 6269 observe4Greater1 observeIGreater1 + action 0 + 6904 : 1 +state 6270 deadlock observe4Greater1 observeIGreater1 + action 0 + 6270 : 1 +state 6271 deadlock + action 0 + 6271 : 1 +state 6272 deadlock observe2Greater1 observeIGreater1 + action 0 + 6272 : 1 +state 6273 deadlock + action 0 + 6273 : 1 +state 6274 deadlock observe4Greater1 observeIGreater1 + action 0 + 6274 : 1 +state 6275 observe3Greater1 observeIGreater1 + action 0 + 6905 : 1 +state 6276 observe3Greater1 observeIGreater1 + action 0 + 6906 : 0.833 + 6907 : 0.167 +state 6277 observe3Greater1 observeIGreater1 + action 0 + 6908 : 1 +state 6278 observe3Greater1 observeIGreater1 + action 0 + 6909 : 0.833 + 6910 : 0.167 +state 6279 observe3Greater1 observeIGreater1 + action 0 + 6911 : 1 +state 6280 observe3Greater1 observeIGreater1 + action 0 + 6912 : 0.833 + 6913 : 0.167 +state 6281 observe3Greater1 observeIGreater1 + action 0 + 6914 : 1 +state 6282 observe3Greater1 observeIGreater1 + action 0 + 6915 : 0.833 + 6916 : 0.167 +state 6283 observe3Greater1 observeIGreater1 + action 0 + 6917 : 1 +state 6284 deadlock observe3Greater1 observeIGreater1 + action 0 + 6284 : 1 +state 6285 observe3Greater1 observeIGreater1 + action 0 + 6918 : 1 +state 6286 observe3Greater1 observeIGreater1 + action 0 + 6919 : 0.833 + 6920 : 0.167 +state 6287 observe3Greater1 observeIGreater1 + action 0 + 6921 : 1 +state 6288 observe3Greater1 observeIGreater1 + action 0 + 6922 : 0.833 + 6923 : 0.167 +state 6289 observe3Greater1 observeIGreater1 + action 0 + 6924 : 1 +state 6290 observe3Greater1 observeIGreater1 + action 0 + 6925 : 0.833 + 6926 : 0.167 +state 6291 observe3Greater1 observeIGreater1 + action 0 + 6927 : 1 +state 6292 observe3Greater1 observeIGreater1 + action 0 + 6928 : 0.833 + 6929 : 0.167 +state 6293 observe3Greater1 observeIGreater1 + action 0 + 6930 : 1 +state 6294 deadlock observe3Greater1 observeIGreater1 + action 0 + 6294 : 1 +state 6295 deadlock observe3Greater1 observeIGreater1 + action 0 + 6295 : 1 +state 6296 deadlock observe3Greater1 observeIGreater1 + action 0 + 6296 : 1 +state 6297 deadlock observe3Greater1 observeIGreater1 + action 0 + 6297 : 1 +state 6298 deadlock observe3Greater1 observeIGreater1 + action 0 + 6298 : 1 +state 6299 observe4Greater1 observeIGreater1 + action 0 + 6931 : 1 +state 6300 observe4Greater1 observeIGreater1 + action 0 + 6932 : 0.833 + 6933 : 0.167 +state 6301 observe4Greater1 observeIGreater1 + action 0 + 6934 : 1 +state 6302 observe4Greater1 observeIGreater1 + action 0 + 6935 : 0.833 + 6936 : 0.167 +state 6303 observe4Greater1 observeIGreater1 + action 0 + 6937 : 1 +state 6304 observe4Greater1 observeIGreater1 + action 0 + 6938 : 0.833 + 6939 : 0.167 +state 6305 observe4Greater1 observeIGreater1 + action 0 + 6940 : 1 +state 6306 observe4Greater1 observeIGreater1 + action 0 + 6941 : 0.833 + 6942 : 0.167 +state 6307 observe4Greater1 observeIGreater1 + action 0 + 6943 : 1 +state 6308 deadlock observe4Greater1 observeIGreater1 + action 0 + 6308 : 1 +state 6309 deadlock + action 0 + 6309 : 1 +state 6310 deadlock + action 0 + 6310 : 1 +state 6311 deadlock observe3Greater1 observeIGreater1 + action 0 + 6311 : 1 +state 6312 deadlock observe4Greater1 observeIGreater1 + action 0 + 6312 : 1 +state 6313 observe4Greater1 observeIGreater1 + action 0 + 6944 : 1 +state 6314 observe4Greater1 observeIGreater1 + action 0 + 6945 : 0.833 + 6946 : 0.167 +state 6315 observe4Greater1 observeIGreater1 + action 0 + 6947 : 1 +state 6316 observe4Greater1 observeIGreater1 + action 0 + 6948 : 0.833 + 6949 : 0.167 +state 6317 observe4Greater1 observeIGreater1 + action 0 + 6950 : 1 +state 6318 observe4Greater1 observeIGreater1 + action 0 + 6951 : 0.833 + 6952 : 0.167 +state 6319 observe4Greater1 observeIGreater1 + action 0 + 6953 : 1 +state 6320 observe4Greater1 observeIGreater1 + action 0 + 6954 : 0.833 + 6955 : 0.167 +state 6321 observe4Greater1 observeIGreater1 + action 0 + 6956 : 1 +state 6322 deadlock observe4Greater1 observeIGreater1 + action 0 + 6322 : 1 +state 6323 deadlock observe4Greater1 observeIGreater1 + action 0 + 6323 : 1 +state 6324 deadlock observe4Greater1 observeIGreater1 + action 0 + 6324 : 1 +state 6325 deadlock observe4Greater1 observeIGreater1 + action 0 + 6325 : 1 +state 6326 deadlock observe4Greater1 observeIGreater1 + action 0 + 6326 : 1 +state 6327 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 6328 observe1Greater1 observeIGreater1 + action 0 + 6962 : 1 +state 6329 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 6330 observe1Greater1 observeIGreater1 + action 0 + 6968 : 1 +state 6331 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 6332 observe1Greater1 observeIGreater1 + action 0 + 6974 : 1 +state 6333 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 6334 observe1Greater1 observeIGreater1 + action 0 + 6980 : 1 +state 6335 deadlock observe1Greater1 observeIGreater1 + action 0 + 6335 : 1 +state 6336 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6337 observe1Greater1 observeIGreater1 + action 0 + 6981 : 1 +state 6338 deadlock observe1Greater1 observeIGreater1 + action 0 + 6338 : 1 +state 6339 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6340 observe1Greater1 observeIGreater1 + action 0 + 6982 : 1 +state 6341 deadlock observe1Greater1 observeIGreater1 + action 0 + 6341 : 1 +state 6342 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6343 observe1Greater1 observeIGreater1 + action 0 + 6983 : 1 +state 6344 deadlock observe1Greater1 observeIGreater1 + action 0 + 6344 : 1 +state 6345 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6346 observe1Greater1 observeIGreater1 + action 0 + 6984 : 1 +state 6347 deadlock observe1Greater1 observeIGreater1 + action 0 + 6347 : 1 +state 6348 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 6349 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6990 : 1 +state 6350 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 6351 observe1Greater1 observeIGreater1 + action 0 + 6996 : 1 +state 6352 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 6353 observe1Greater1 observeIGreater1 + action 0 + 7002 : 1 +state 6354 deadlock observe1Greater1 observeIGreater1 + action 0 + 6354 : 1 +state 6355 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6356 observe1Greater1 observeIGreater1 + action 0 + 7003 : 1 +state 6357 deadlock observe1Greater1 observeIGreater1 + action 0 + 6357 : 1 +state 6358 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6359 observe1Greater1 observeIGreater1 + action 0 + 7004 : 1 +state 6360 deadlock observe1Greater1 observeIGreater1 + action 0 + 6360 : 1 +state 6361 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6362 observe1Greater1 observeIGreater1 + action 0 + 7005 : 1 +state 6363 deadlock observe1Greater1 observeIGreater1 + action 0 + 6363 : 1 +state 6364 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6365 observe1Greater1 observeIGreater1 + action 0 + 7006 : 1 +state 6366 deadlock observe1Greater1 observeIGreater1 + action 0 + 6366 : 1 +state 6367 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 6368 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7012 : 1 +state 6369 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 6370 observe1Greater1 observeIGreater1 + action 0 + 7018 : 1 +state 6371 deadlock observe1Greater1 observeIGreater1 + action 0 + 6371 : 1 +state 6372 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6373 observe1Greater1 observeIGreater1 + action 0 + 7019 : 1 +state 6374 deadlock observe1Greater1 observeIGreater1 + action 0 + 6374 : 1 +state 6375 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6376 observe1Greater1 observeIGreater1 + action 0 + 7020 : 1 +state 6377 deadlock observe1Greater1 observeIGreater1 + action 0 + 6377 : 1 +state 6378 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6379 observe1Greater1 observeIGreater1 + action 0 + 7021 : 1 +state 6380 deadlock observe1Greater1 observeIGreater1 + action 0 + 6380 : 1 +state 6381 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6382 observe1Greater1 observeIGreater1 + action 0 + 7022 : 1 +state 6383 deadlock observe1Greater1 observeIGreater1 + action 0 + 6383 : 1 +state 6384 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 6385 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7028 : 1 +state 6386 deadlock observe1Greater1 observeIGreater1 + action 0 + 6386 : 1 +state 6387 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6388 observe1Greater1 observeIGreater1 + action 0 + 7029 : 1 +state 6389 deadlock observe1Greater1 observeIGreater1 + action 0 + 6389 : 1 +state 6390 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6391 observe1Greater1 observeIGreater1 + action 0 + 7030 : 1 +state 6392 deadlock observe1Greater1 observeIGreater1 + action 0 + 6392 : 1 +state 6393 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6394 observe1Greater1 observeIGreater1 + action 0 + 7031 : 1 +state 6395 deadlock observe1Greater1 observeIGreater1 + action 0 + 6395 : 1 +state 6396 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6397 observe1Greater1 observeIGreater1 + action 0 + 7032 : 1 +state 6398 deadlock observe1Greater1 observeIGreater1 + action 0 + 6398 : 1 +state 6399 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 6400 observe2Greater1 observeIGreater1 + action 0 + 7038 : 1 +state 6401 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 6402 observe2Greater1 observeIGreater1 + action 0 + 7044 : 1 +state 6403 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 6404 observe2Greater1 observeIGreater1 + action 0 + 7050 : 1 +state 6405 deadlock observe2Greater1 observeIGreater1 + action 0 + 6405 : 1 +state 6406 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6407 observe2Greater1 observeIGreater1 + action 0 + 7051 : 1 +state 6408 deadlock observe2Greater1 observeIGreater1 + action 0 + 6408 : 1 +state 6409 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6410 observe2Greater1 observeIGreater1 + action 0 + 7052 : 1 +state 6411 deadlock observe2Greater1 observeIGreater1 + action 0 + 6411 : 1 +state 6412 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6413 observe2Greater1 observeIGreater1 + action 0 + 7053 : 1 +state 6414 deadlock observe2Greater1 observeIGreater1 + action 0 + 6414 : 1 +state 6415 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6416 observe2Greater1 observeIGreater1 + action 0 + 7054 : 1 +state 6417 deadlock observe2Greater1 observeIGreater1 + action 0 + 6417 : 1 +state 6418 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 6419 observe3Greater1 observeIGreater1 + action 0 + 7060 : 1 +state 6420 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 6421 + action 0 + 7066 : 1 +state 6422 deadlock + action 0 + 6422 : 1 +state 6423 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6424 + action 0 + 7067 : 1 +state 6425 deadlock + action 0 + 6425 : 1 +state 6426 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6427 + action 0 + 7068 : 1 +state 6428 deadlock + action 0 + 6428 : 1 +state 6429 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6430 + action 0 + 7069 : 1 +state 6431 deadlock + action 0 + 6431 : 1 +state 6432 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6433 + action 0 + 7070 : 1 +state 6434 deadlock + action 0 + 6434 : 1 +state 6435 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 6436 observe4Greater1 observeIGreater1 + action 0 + 7076 : 1 +state 6437 deadlock + action 0 + 6437 : 1 +state 6438 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6439 + action 0 + 7077 : 1 +state 6440 deadlock + action 0 + 6440 : 1 +state 6441 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6442 + action 0 + 7078 : 1 +state 6443 deadlock + action 0 + 6443 : 1 +state 6444 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6445 + action 0 + 7079 : 1 +state 6446 deadlock + action 0 + 6446 : 1 +state 6447 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6448 + action 0 + 7080 : 1 +state 6449 deadlock + action 0 + 6449 : 1 +state 6450 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 6451 observe3Greater1 observeIGreater1 + action 0 + 7086 : 1 +state 6452 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 6453 observe3Greater1 observeIGreater1 + action 0 + 7092 : 1 +state 6454 deadlock observe3Greater1 observeIGreater1 + action 0 + 6454 : 1 +state 6455 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6456 observe3Greater1 observeIGreater1 + action 0 + 7093 : 1 +state 6457 deadlock observe3Greater1 observeIGreater1 + action 0 + 6457 : 1 +state 6458 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6459 observe3Greater1 observeIGreater1 + action 0 + 7094 : 1 +state 6460 deadlock observe3Greater1 observeIGreater1 + action 0 + 6460 : 1 +state 6461 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6462 observe3Greater1 observeIGreater1 + action 0 + 7095 : 1 +state 6463 deadlock observe3Greater1 observeIGreater1 + action 0 + 6463 : 1 +state 6464 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6465 observe3Greater1 observeIGreater1 + action 0 + 7096 : 1 +state 6466 deadlock observe3Greater1 observeIGreater1 + action 0 + 6466 : 1 +state 6467 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 6468 observe4Greater1 observeIGreater1 + action 0 + 7102 : 1 +state 6469 deadlock + action 0 + 6469 : 1 +state 6470 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6471 + action 0 + 7103 : 1 +state 6472 deadlock + action 0 + 6472 : 1 +state 6473 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6474 + action 0 + 7104 : 1 +state 6475 deadlock + action 0 + 6475 : 1 +state 6476 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6477 + action 0 + 7105 : 1 +state 6478 deadlock + action 0 + 6478 : 1 +state 6479 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6480 + action 0 + 7106 : 1 +state 6481 deadlock + action 0 + 6481 : 1 +state 6482 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 6483 observe4Greater1 observeIGreater1 + action 0 + 7112 : 1 +state 6484 deadlock observe4Greater1 observeIGreater1 + action 0 + 6484 : 1 +state 6485 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6486 observe4Greater1 observeIGreater1 + action 0 + 7113 : 1 +state 6487 deadlock observe4Greater1 observeIGreater1 + action 0 + 6487 : 1 +state 6488 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6489 observe4Greater1 observeIGreater1 + action 0 + 7114 : 1 +state 6490 deadlock observe4Greater1 observeIGreater1 + action 0 + 6490 : 1 +state 6491 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6492 observe4Greater1 observeIGreater1 + action 0 + 7115 : 1 +state 6493 deadlock observe4Greater1 observeIGreater1 + action 0 + 6493 : 1 +state 6494 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6495 observe4Greater1 observeIGreater1 + action 0 + 7116 : 1 +state 6496 deadlock observe4Greater1 observeIGreater1 + action 0 + 6496 : 1 +state 6497 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 6498 observe2Greater1 observeIGreater1 + action 0 + 7122 : 1 +state 6499 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 6500 observe2Greater1 observeIGreater1 + action 0 + 7128 : 1 +state 6501 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 6502 observe2Greater1 observeIGreater1 + action 0 + 7134 : 1 +state 6503 deadlock observe2Greater1 observeIGreater1 + action 0 + 6503 : 1 +state 6504 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6505 observe2Greater1 observeIGreater1 + action 0 + 7135 : 1 +state 6506 deadlock observe2Greater1 observeIGreater1 + action 0 + 6506 : 1 +state 6507 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6508 observe2Greater1 observeIGreater1 + action 0 + 7136 : 1 +state 6509 deadlock observe2Greater1 observeIGreater1 + action 0 + 6509 : 1 +state 6510 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6511 observe2Greater1 observeIGreater1 + action 0 + 7137 : 1 +state 6512 deadlock observe2Greater1 observeIGreater1 + action 0 + 6512 : 1 +state 6513 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6514 observe2Greater1 observeIGreater1 + action 0 + 7138 : 1 +state 6515 deadlock observe2Greater1 observeIGreater1 + action 0 + 6515 : 1 +state 6516 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 6517 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7144 : 1 +state 6518 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 6519 observe2Greater1 observeIGreater1 + action 0 + 7150 : 1 +state 6520 deadlock observe2Greater1 observeIGreater1 + action 0 + 6520 : 1 +state 6521 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6522 observe2Greater1 observeIGreater1 + action 0 + 7151 : 1 +state 6523 deadlock observe2Greater1 observeIGreater1 + action 0 + 6523 : 1 +state 6524 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6525 observe2Greater1 observeIGreater1 + action 0 + 7152 : 1 +state 6526 deadlock observe2Greater1 observeIGreater1 + action 0 + 6526 : 1 +state 6527 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6528 observe2Greater1 observeIGreater1 + action 0 + 7153 : 1 +state 6529 deadlock observe2Greater1 observeIGreater1 + action 0 + 6529 : 1 +state 6530 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6531 observe2Greater1 observeIGreater1 + action 0 + 7154 : 1 +state 6532 deadlock observe2Greater1 observeIGreater1 + action 0 + 6532 : 1 +state 6533 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 6534 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7160 : 1 +state 6535 deadlock observe2Greater1 observeIGreater1 + action 0 + 6535 : 1 +state 6536 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6537 observe2Greater1 observeIGreater1 + action 0 + 7161 : 1 +state 6538 deadlock observe2Greater1 observeIGreater1 + action 0 + 6538 : 1 +state 6539 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6540 observe2Greater1 observeIGreater1 + action 0 + 7162 : 1 +state 6541 deadlock observe2Greater1 observeIGreater1 + action 0 + 6541 : 1 +state 6542 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6543 observe2Greater1 observeIGreater1 + action 0 + 7163 : 1 +state 6544 deadlock observe2Greater1 observeIGreater1 + action 0 + 6544 : 1 +state 6545 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6546 observe2Greater1 observeIGreater1 + action 0 + 7164 : 1 +state 6547 deadlock observe2Greater1 observeIGreater1 + action 0 + 6547 : 1 +state 6548 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 6549 observe3Greater1 observeIGreater1 + action 0 + 7170 : 1 +state 6550 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 6551 observe3Greater1 observeIGreater1 + action 0 + 7176 : 1 +state 6552 deadlock observe3Greater1 observeIGreater1 + action 0 + 6552 : 1 +state 6553 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6554 observe3Greater1 observeIGreater1 + action 0 + 7177 : 1 +state 6555 deadlock observe3Greater1 observeIGreater1 + action 0 + 6555 : 1 +state 6556 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6557 observe3Greater1 observeIGreater1 + action 0 + 7178 : 1 +state 6558 deadlock observe3Greater1 observeIGreater1 + action 0 + 6558 : 1 +state 6559 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6560 observe3Greater1 observeIGreater1 + action 0 + 7179 : 1 +state 6561 deadlock observe3Greater1 observeIGreater1 + action 0 + 6561 : 1 +state 6562 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6563 observe3Greater1 observeIGreater1 + action 0 + 7180 : 1 +state 6564 deadlock observe3Greater1 observeIGreater1 + action 0 + 6564 : 1 +state 6565 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 6566 observe4Greater1 observeIGreater1 + action 0 + 7186 : 1 +state 6567 deadlock + action 0 + 6567 : 1 +state 6568 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6569 + action 0 + 7187 : 1 +state 6570 deadlock + action 0 + 6570 : 1 +state 6571 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6572 + action 0 + 7188 : 1 +state 6573 deadlock + action 0 + 6573 : 1 +state 6574 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6575 + action 0 + 7189 : 1 +state 6576 deadlock + action 0 + 6576 : 1 +state 6577 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6578 + action 0 + 7190 : 1 +state 6579 deadlock + action 0 + 6579 : 1 +state 6580 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 6581 observe4Greater1 observeIGreater1 + action 0 + 7196 : 1 +state 6582 deadlock observe4Greater1 observeIGreater1 + action 0 + 6582 : 1 +state 6583 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6584 observe4Greater1 observeIGreater1 + action 0 + 7197 : 1 +state 6585 deadlock observe4Greater1 observeIGreater1 + action 0 + 6585 : 1 +state 6586 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6587 observe4Greater1 observeIGreater1 + action 0 + 7198 : 1 +state 6588 deadlock observe4Greater1 observeIGreater1 + action 0 + 6588 : 1 +state 6589 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6590 observe4Greater1 observeIGreater1 + action 0 + 7199 : 1 +state 6591 deadlock observe4Greater1 observeIGreater1 + action 0 + 6591 : 1 +state 6592 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6593 observe4Greater1 observeIGreater1 + action 0 + 7200 : 1 +state 6594 deadlock observe4Greater1 observeIGreater1 + action 0 + 6594 : 1 +state 6595 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 6596 observe3Greater1 observeIGreater1 + action 0 + 7206 : 1 +state 6597 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 6598 observe3Greater1 observeIGreater1 + action 0 + 7212 : 1 +state 6599 deadlock observe3Greater1 observeIGreater1 + action 0 + 6599 : 1 +state 6600 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6601 observe3Greater1 observeIGreater1 + action 0 + 7213 : 1 +state 6602 deadlock observe3Greater1 observeIGreater1 + action 0 + 6602 : 1 +state 6603 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6604 observe3Greater1 observeIGreater1 + action 0 + 7214 : 1 +state 6605 deadlock observe3Greater1 observeIGreater1 + action 0 + 6605 : 1 +state 6606 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6607 observe3Greater1 observeIGreater1 + action 0 + 7215 : 1 +state 6608 deadlock observe3Greater1 observeIGreater1 + action 0 + 6608 : 1 +state 6609 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6610 observe3Greater1 observeIGreater1 + action 0 + 7216 : 1 +state 6611 deadlock observe3Greater1 observeIGreater1 + action 0 + 6611 : 1 +state 6612 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 6613 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7222 : 1 +state 6614 deadlock observe3Greater1 observeIGreater1 + action 0 + 6614 : 1 +state 6615 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6616 observe3Greater1 observeIGreater1 + action 0 + 7223 : 1 +state 6617 deadlock observe3Greater1 observeIGreater1 + action 0 + 6617 : 1 +state 6618 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6619 observe3Greater1 observeIGreater1 + action 0 + 7224 : 1 +state 6620 deadlock observe3Greater1 observeIGreater1 + action 0 + 6620 : 1 +state 6621 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6622 observe3Greater1 observeIGreater1 + action 0 + 7225 : 1 +state 6623 deadlock observe3Greater1 observeIGreater1 + action 0 + 6623 : 1 +state 6624 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6625 observe3Greater1 observeIGreater1 + action 0 + 7226 : 1 +state 6626 deadlock observe3Greater1 observeIGreater1 + action 0 + 6626 : 1 +state 6627 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 6628 observe4Greater1 observeIGreater1 + action 0 + 7232 : 1 +state 6629 deadlock observe4Greater1 observeIGreater1 + action 0 + 6629 : 1 +state 6630 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6631 observe4Greater1 observeIGreater1 + action 0 + 7233 : 1 +state 6632 deadlock observe4Greater1 observeIGreater1 + action 0 + 6632 : 1 +state 6633 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6634 observe4Greater1 observeIGreater1 + action 0 + 7234 : 1 +state 6635 deadlock observe4Greater1 observeIGreater1 + action 0 + 6635 : 1 +state 6636 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6637 observe4Greater1 observeIGreater1 + action 0 + 7235 : 1 +state 6638 deadlock observe4Greater1 observeIGreater1 + action 0 + 6638 : 1 +state 6639 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6640 observe4Greater1 observeIGreater1 + action 0 + 7236 : 1 +state 6641 deadlock observe4Greater1 observeIGreater1 + action 0 + 6641 : 1 +state 6642 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 6643 observe4Greater1 observeIGreater1 + action 0 + 7242 : 1 +state 6644 deadlock observe4Greater1 observeIGreater1 + action 0 + 6644 : 1 +state 6645 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6646 observe4Greater1 observeIGreater1 + action 0 + 7243 : 1 +state 6647 deadlock observe4Greater1 observeIGreater1 + action 0 + 6647 : 1 +state 6648 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6649 observe4Greater1 observeIGreater1 + action 0 + 7244 : 1 +state 6650 deadlock observe4Greater1 observeIGreater1 + action 0 + 6650 : 1 +state 6651 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6652 observe4Greater1 observeIGreater1 + action 0 + 7245 : 1 +state 6653 deadlock observe4Greater1 observeIGreater1 + action 0 + 6653 : 1 +state 6654 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6655 observe4Greater1 observeIGreater1 + action 0 + 7246 : 1 +state 6656 deadlock observe4Greater1 observeIGreater1 + action 0 + 6656 : 1 +state 6657 deadlock observe1Greater1 observeIGreater1 + action 0 + 6657 : 1 +state 6658 deadlock observe1Greater1 observeIGreater1 + action 0 + 6658 : 1 +state 6659 deadlock observe1Greater1 observeIGreater1 + action 0 + 6659 : 1 +state 6660 deadlock observe1Greater1 observeIGreater1 + action 0 + 6660 : 1 +state 6661 deadlock observe1Greater1 observeIGreater1 + action 0 + 6661 : 1 +state 6662 deadlock observe2Greater1 observeIGreater1 + action 0 + 6662 : 1 +state 6663 deadlock + action 0 + 6663 : 1 +state 6664 deadlock + action 0 + 6664 : 1 +state 6665 deadlock observe1Greater1 observeIGreater1 + action 0 + 6665 : 1 +state 6666 deadlock + action 0 + 6666 : 1 +state 6667 deadlock observe3Greater1 observeIGreater1 + action 0 + 6667 : 1 +state 6668 deadlock + action 0 + 6668 : 1 +state 6669 deadlock observe1Greater1 observeIGreater1 + action 0 + 6669 : 1 +state 6670 deadlock + action 0 + 6670 : 1 +state 6671 deadlock + action 0 + 6671 : 1 +state 6672 deadlock observe4Greater1 observeIGreater1 + action 0 + 6672 : 1 +state 6673 deadlock observe2Greater1 observeIGreater1 + action 0 + 6673 : 1 +state 6674 deadlock observe2Greater1 observeIGreater1 + action 0 + 6674 : 1 +state 6675 deadlock observe2Greater1 observeIGreater1 + action 0 + 6675 : 1 +state 6676 deadlock observe2Greater1 observeIGreater1 + action 0 + 6676 : 1 +state 6677 deadlock + action 0 + 6677 : 1 +state 6678 deadlock observe2Greater1 observeIGreater1 + action 0 + 6678 : 1 +state 6679 deadlock observe3Greater1 observeIGreater1 + action 0 + 6679 : 1 +state 6680 deadlock + action 0 + 6680 : 1 +state 6681 deadlock + action 0 + 6681 : 1 +state 6682 deadlock observe2Greater1 observeIGreater1 + action 0 + 6682 : 1 +state 6683 deadlock + action 0 + 6683 : 1 +state 6684 deadlock observe4Greater1 observeIGreater1 + action 0 + 6684 : 1 +state 6685 deadlock observe3Greater1 observeIGreater1 + action 0 + 6685 : 1 +state 6686 deadlock observe3Greater1 observeIGreater1 + action 0 + 6686 : 1 +state 6687 deadlock observe3Greater1 observeIGreater1 + action 0 + 6687 : 1 +state 6688 deadlock observe3Greater1 observeIGreater1 + action 0 + 6688 : 1 +state 6689 deadlock + action 0 + 6689 : 1 +state 6690 deadlock + action 0 + 6690 : 1 +state 6691 deadlock observe3Greater1 observeIGreater1 + action 0 + 6691 : 1 +state 6692 deadlock observe4Greater1 observeIGreater1 + action 0 + 6692 : 1 +state 6693 deadlock observe4Greater1 observeIGreater1 + action 0 + 6693 : 1 +state 6694 deadlock observe4Greater1 observeIGreater1 + action 0 + 6694 : 1 +state 6695 deadlock observe4Greater1 observeIGreater1 + action 0 + 6695 : 1 +state 6696 deadlock observe4Greater1 observeIGreater1 + action 0 + 6696 : 1 +state 6697 deadlock observe1Greater1 observeIGreater1 + action 0 + 6697 : 1 +state 6698 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6699 observe1Greater1 observeIGreater1 + action 0 + 7247 : 1 +state 6700 deadlock observe1Greater1 observeIGreater1 + action 0 + 6700 : 1 +state 6701 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6702 observe1Greater1 observeIGreater1 + action 0 + 7248 : 1 +state 6703 deadlock observe1Greater1 observeIGreater1 + action 0 + 6703 : 1 +state 6704 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6705 observe1Greater1 observeIGreater1 + action 0 + 7249 : 1 +state 6706 deadlock observe1Greater1 observeIGreater1 + action 0 + 6706 : 1 +state 6707 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6708 observe1Greater1 observeIGreater1 + action 0 + 7250 : 1 +state 6709 deadlock observe1Greater1 observeIGreater1 + action 0 + 6709 : 1 +state 6710 deadlock observe1Greater1 observeIGreater1 + action 0 + 6710 : 1 +state 6711 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6712 observe1Greater1 observeIGreater1 + action 0 + 7251 : 1 +state 6713 deadlock observe1Greater1 observeIGreater1 + action 0 + 6713 : 1 +state 6714 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6715 observe1Greater1 observeIGreater1 + action 0 + 7252 : 1 +state 6716 deadlock observe1Greater1 observeIGreater1 + action 0 + 6716 : 1 +state 6717 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6718 observe1Greater1 observeIGreater1 + action 0 + 7253 : 1 +state 6719 deadlock observe1Greater1 observeIGreater1 + action 0 + 6719 : 1 +state 6720 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6721 observe1Greater1 observeIGreater1 + action 0 + 7254 : 1 +state 6722 deadlock observe1Greater1 observeIGreater1 + action 0 + 6722 : 1 +state 6723 deadlock observe1Greater1 observeIGreater1 + action 0 + 6723 : 1 +state 6724 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6725 observe1Greater1 observeIGreater1 + action 0 + 7255 : 1 +state 6726 deadlock observe1Greater1 observeIGreater1 + action 0 + 6726 : 1 +state 6727 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6728 observe1Greater1 observeIGreater1 + action 0 + 7256 : 1 +state 6729 deadlock observe1Greater1 observeIGreater1 + action 0 + 6729 : 1 +state 6730 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6731 observe1Greater1 observeIGreater1 + action 0 + 7257 : 1 +state 6732 deadlock observe1Greater1 observeIGreater1 + action 0 + 6732 : 1 +state 6733 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6734 observe1Greater1 observeIGreater1 + action 0 + 7258 : 1 +state 6735 deadlock observe1Greater1 observeIGreater1 + action 0 + 6735 : 1 +state 6736 deadlock observe1Greater1 observeIGreater1 + action 0 + 6736 : 1 +state 6737 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6738 observe1Greater1 observeIGreater1 + action 0 + 7259 : 1 +state 6739 deadlock observe1Greater1 observeIGreater1 + action 0 + 6739 : 1 +state 6740 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6741 observe1Greater1 observeIGreater1 + action 0 + 7260 : 1 +state 6742 deadlock observe1Greater1 observeIGreater1 + action 0 + 6742 : 1 +state 6743 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6744 observe1Greater1 observeIGreater1 + action 0 + 7261 : 1 +state 6745 deadlock observe1Greater1 observeIGreater1 + action 0 + 6745 : 1 +state 6746 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6747 observe1Greater1 observeIGreater1 + action 0 + 7262 : 1 +state 6748 deadlock observe1Greater1 observeIGreater1 + action 0 + 6748 : 1 +state 6749 deadlock observe2Greater1 observeIGreater1 + action 0 + 6749 : 1 +state 6750 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6751 observe2Greater1 observeIGreater1 + action 0 + 7263 : 1 +state 6752 deadlock observe2Greater1 observeIGreater1 + action 0 + 6752 : 1 +state 6753 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6754 observe2Greater1 observeIGreater1 + action 0 + 7264 : 1 +state 6755 deadlock observe2Greater1 observeIGreater1 + action 0 + 6755 : 1 +state 6756 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6757 observe2Greater1 observeIGreater1 + action 0 + 7265 : 1 +state 6758 deadlock observe2Greater1 observeIGreater1 + action 0 + 6758 : 1 +state 6759 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6760 observe2Greater1 observeIGreater1 + action 0 + 7266 : 1 +state 6761 deadlock observe2Greater1 observeIGreater1 + action 0 + 6761 : 1 +state 6762 deadlock + action 0 + 6762 : 1 +state 6763 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6764 + action 0 + 7267 : 1 +state 6765 deadlock + action 0 + 6765 : 1 +state 6766 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6767 + action 0 + 7268 : 1 +state 6768 deadlock + action 0 + 6768 : 1 +state 6769 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6770 + action 0 + 7269 : 1 +state 6771 deadlock + action 0 + 6771 : 1 +state 6772 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6773 + action 0 + 7270 : 1 +state 6774 deadlock + action 0 + 6774 : 1 +state 6775 deadlock + action 0 + 6775 : 1 +state 6776 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6777 + action 0 + 7271 : 1 +state 6778 deadlock + action 0 + 6778 : 1 +state 6779 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6780 + action 0 + 7272 : 1 +state 6781 deadlock + action 0 + 6781 : 1 +state 6782 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6783 + action 0 + 7273 : 1 +state 6784 deadlock + action 0 + 6784 : 1 +state 6785 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6786 + action 0 + 7274 : 1 +state 6787 deadlock + action 0 + 6787 : 1 +state 6788 deadlock observe3Greater1 observeIGreater1 + action 0 + 6788 : 1 +state 6789 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6790 observe3Greater1 observeIGreater1 + action 0 + 7275 : 1 +state 6791 deadlock observe3Greater1 observeIGreater1 + action 0 + 6791 : 1 +state 6792 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6793 observe3Greater1 observeIGreater1 + action 0 + 7276 : 1 +state 6794 deadlock observe3Greater1 observeIGreater1 + action 0 + 6794 : 1 +state 6795 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6796 observe3Greater1 observeIGreater1 + action 0 + 7277 : 1 +state 6797 deadlock observe3Greater1 observeIGreater1 + action 0 + 6797 : 1 +state 6798 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6799 observe3Greater1 observeIGreater1 + action 0 + 7278 : 1 +state 6800 deadlock observe3Greater1 observeIGreater1 + action 0 + 6800 : 1 +state 6801 deadlock + action 0 + 6801 : 1 +state 6802 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6803 + action 0 + 7279 : 1 +state 6804 deadlock + action 0 + 6804 : 1 +state 6805 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6806 + action 0 + 7280 : 1 +state 6807 deadlock + action 0 + 6807 : 1 +state 6808 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6809 + action 0 + 7281 : 1 +state 6810 deadlock + action 0 + 6810 : 1 +state 6811 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6812 + action 0 + 7282 : 1 +state 6813 deadlock + action 0 + 6813 : 1 +state 6814 deadlock observe4Greater1 observeIGreater1 + action 0 + 6814 : 1 +state 6815 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6816 observe4Greater1 observeIGreater1 + action 0 + 7283 : 1 +state 6817 deadlock observe4Greater1 observeIGreater1 + action 0 + 6817 : 1 +state 6818 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6819 observe4Greater1 observeIGreater1 + action 0 + 7284 : 1 +state 6820 deadlock observe4Greater1 observeIGreater1 + action 0 + 6820 : 1 +state 6821 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6822 observe4Greater1 observeIGreater1 + action 0 + 7285 : 1 +state 6823 deadlock observe4Greater1 observeIGreater1 + action 0 + 6823 : 1 +state 6824 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6825 observe4Greater1 observeIGreater1 + action 0 + 7286 : 1 +state 6826 deadlock observe4Greater1 observeIGreater1 + action 0 + 6826 : 1 +state 6827 deadlock observe2Greater1 observeIGreater1 + action 0 + 6827 : 1 +state 6828 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6829 observe2Greater1 observeIGreater1 + action 0 + 7287 : 1 +state 6830 deadlock observe2Greater1 observeIGreater1 + action 0 + 6830 : 1 +state 6831 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6832 observe2Greater1 observeIGreater1 + action 0 + 7288 : 1 +state 6833 deadlock observe2Greater1 observeIGreater1 + action 0 + 6833 : 1 +state 6834 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6835 observe2Greater1 observeIGreater1 + action 0 + 7289 : 1 +state 6836 deadlock observe2Greater1 observeIGreater1 + action 0 + 6836 : 1 +state 6837 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6838 observe2Greater1 observeIGreater1 + action 0 + 7290 : 1 +state 6839 deadlock observe2Greater1 observeIGreater1 + action 0 + 6839 : 1 +state 6840 deadlock observe2Greater1 observeIGreater1 + action 0 + 6840 : 1 +state 6841 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6842 observe2Greater1 observeIGreater1 + action 0 + 7291 : 1 +state 6843 deadlock observe2Greater1 observeIGreater1 + action 0 + 6843 : 1 +state 6844 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6845 observe2Greater1 observeIGreater1 + action 0 + 7292 : 1 +state 6846 deadlock observe2Greater1 observeIGreater1 + action 0 + 6846 : 1 +state 6847 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6848 observe2Greater1 observeIGreater1 + action 0 + 7293 : 1 +state 6849 deadlock observe2Greater1 observeIGreater1 + action 0 + 6849 : 1 +state 6850 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6851 observe2Greater1 observeIGreater1 + action 0 + 7294 : 1 +state 6852 deadlock observe2Greater1 observeIGreater1 + action 0 + 6852 : 1 +state 6853 deadlock observe2Greater1 observeIGreater1 + action 0 + 6853 : 1 +state 6854 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6855 observe2Greater1 observeIGreater1 + action 0 + 7295 : 1 +state 6856 deadlock observe2Greater1 observeIGreater1 + action 0 + 6856 : 1 +state 6857 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6858 observe2Greater1 observeIGreater1 + action 0 + 7296 : 1 +state 6859 deadlock observe2Greater1 observeIGreater1 + action 0 + 6859 : 1 +state 6860 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6861 observe2Greater1 observeIGreater1 + action 0 + 7297 : 1 +state 6862 deadlock observe2Greater1 observeIGreater1 + action 0 + 6862 : 1 +state 6863 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6864 observe2Greater1 observeIGreater1 + action 0 + 7298 : 1 +state 6865 deadlock observe2Greater1 observeIGreater1 + action 0 + 6865 : 1 +state 6866 deadlock observe3Greater1 observeIGreater1 + action 0 + 6866 : 1 +state 6867 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6868 observe3Greater1 observeIGreater1 + action 0 + 7299 : 1 +state 6869 deadlock observe3Greater1 observeIGreater1 + action 0 + 6869 : 1 +state 6870 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6871 observe3Greater1 observeIGreater1 + action 0 + 7300 : 1 +state 6872 deadlock observe3Greater1 observeIGreater1 + action 0 + 6872 : 1 +state 6873 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6874 observe3Greater1 observeIGreater1 + action 0 + 7301 : 1 +state 6875 deadlock observe3Greater1 observeIGreater1 + action 0 + 6875 : 1 +state 6876 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6877 observe3Greater1 observeIGreater1 + action 0 + 7302 : 1 +state 6878 deadlock observe3Greater1 observeIGreater1 + action 0 + 6878 : 1 +state 6879 deadlock + action 0 + 6879 : 1 +state 6880 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6881 + action 0 + 7303 : 1 +state 6882 deadlock + action 0 + 6882 : 1 +state 6883 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6884 + action 0 + 7304 : 1 +state 6885 deadlock + action 0 + 6885 : 1 +state 6886 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6887 + action 0 + 7305 : 1 +state 6888 deadlock + action 0 + 6888 : 1 +state 6889 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6890 + action 0 + 7306 : 1 +state 6891 deadlock + action 0 + 6891 : 1 +state 6892 deadlock observe4Greater1 observeIGreater1 + action 0 + 6892 : 1 +state 6893 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6894 observe4Greater1 observeIGreater1 + action 0 + 7307 : 1 +state 6895 deadlock observe4Greater1 observeIGreater1 + action 0 + 6895 : 1 +state 6896 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6897 observe4Greater1 observeIGreater1 + action 0 + 7308 : 1 +state 6898 deadlock observe4Greater1 observeIGreater1 + action 0 + 6898 : 1 +state 6899 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6900 observe4Greater1 observeIGreater1 + action 0 + 7309 : 1 +state 6901 deadlock observe4Greater1 observeIGreater1 + action 0 + 6901 : 1 +state 6902 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6903 observe4Greater1 observeIGreater1 + action 0 + 7310 : 1 +state 6904 deadlock observe4Greater1 observeIGreater1 + action 0 + 6904 : 1 +state 6905 deadlock observe3Greater1 observeIGreater1 + action 0 + 6905 : 1 +state 6906 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6907 observe3Greater1 observeIGreater1 + action 0 + 7311 : 1 +state 6908 deadlock observe3Greater1 observeIGreater1 + action 0 + 6908 : 1 +state 6909 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6910 observe3Greater1 observeIGreater1 + action 0 + 7312 : 1 +state 6911 deadlock observe3Greater1 observeIGreater1 + action 0 + 6911 : 1 +state 6912 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6913 observe3Greater1 observeIGreater1 + action 0 + 7313 : 1 +state 6914 deadlock observe3Greater1 observeIGreater1 + action 0 + 6914 : 1 +state 6915 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6916 observe3Greater1 observeIGreater1 + action 0 + 7314 : 1 +state 6917 deadlock observe3Greater1 observeIGreater1 + action 0 + 6917 : 1 +state 6918 deadlock observe3Greater1 observeIGreater1 + action 0 + 6918 : 1 +state 6919 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6920 observe3Greater1 observeIGreater1 + action 0 + 7315 : 1 +state 6921 deadlock observe3Greater1 observeIGreater1 + action 0 + 6921 : 1 +state 6922 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6923 observe3Greater1 observeIGreater1 + action 0 + 7316 : 1 +state 6924 deadlock observe3Greater1 observeIGreater1 + action 0 + 6924 : 1 +state 6925 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6926 observe3Greater1 observeIGreater1 + action 0 + 7317 : 1 +state 6927 deadlock observe3Greater1 observeIGreater1 + action 0 + 6927 : 1 +state 6928 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6929 observe3Greater1 observeIGreater1 + action 0 + 7318 : 1 +state 6930 deadlock observe3Greater1 observeIGreater1 + action 0 + 6930 : 1 +state 6931 deadlock observe4Greater1 observeIGreater1 + action 0 + 6931 : 1 +state 6932 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6933 observe4Greater1 observeIGreater1 + action 0 + 7319 : 1 +state 6934 deadlock observe4Greater1 observeIGreater1 + action 0 + 6934 : 1 +state 6935 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6936 observe4Greater1 observeIGreater1 + action 0 + 7320 : 1 +state 6937 deadlock observe4Greater1 observeIGreater1 + action 0 + 6937 : 1 +state 6938 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6939 observe4Greater1 observeIGreater1 + action 0 + 7321 : 1 +state 6940 deadlock observe4Greater1 observeIGreater1 + action 0 + 6940 : 1 +state 6941 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6942 observe4Greater1 observeIGreater1 + action 0 + 7322 : 1 +state 6943 deadlock observe4Greater1 observeIGreater1 + action 0 + 6943 : 1 +state 6944 deadlock observe4Greater1 observeIGreater1 + action 0 + 6944 : 1 +state 6945 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6946 observe4Greater1 observeIGreater1 + action 0 + 7323 : 1 +state 6947 deadlock observe4Greater1 observeIGreater1 + action 0 + 6947 : 1 +state 6948 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6949 observe4Greater1 observeIGreater1 + action 0 + 7324 : 1 +state 6950 deadlock observe4Greater1 observeIGreater1 + action 0 + 6950 : 1 +state 6951 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6952 observe4Greater1 observeIGreater1 + action 0 + 7325 : 1 +state 6953 deadlock observe4Greater1 observeIGreater1 + action 0 + 6953 : 1 +state 6954 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6955 observe4Greater1 observeIGreater1 + action 0 + 7326 : 1 +state 6956 deadlock observe4Greater1 observeIGreater1 + action 0 + 6956 : 1 +state 6957 observe1Greater1 observeIGreater1 + action 0 + 7327 : 0.8 + 7328 : 0.2 +state 6958 observe1Greater1 observeIGreater1 + action 0 + 7329 : 0.8 + 7330 : 0.2 +state 6959 observe1Greater1 observeIGreater1 + action 0 + 7331 : 0.8 + 7332 : 0.2 +state 6960 observe1Greater1 observeIGreater1 + action 0 + 7333 : 0.8 + 7334 : 0.2 +state 6961 observe1Greater1 observeIGreater1 + action 0 + 7335 : 0.8 + 7336 : 0.2 +state 6962 observe1Greater1 observeIGreater1 + action 0 + 7337 : 1 +state 6963 observe1Greater1 observeIGreater1 + action 0 + 7338 : 0.8 + 7339 : 0.2 +state 6964 observe1Greater1 observeIGreater1 + action 0 + 7340 : 0.8 + 7341 : 0.2 +state 6965 observe1Greater1 observeIGreater1 + action 0 + 7342 : 0.8 + 7343 : 0.2 +state 6966 observe1Greater1 observeIGreater1 + action 0 + 7344 : 0.8 + 7345 : 0.2 +state 6967 observe1Greater1 observeIGreater1 + action 0 + 7346 : 0.8 + 7347 : 0.2 +state 6968 observe1Greater1 observeIGreater1 + action 0 + 7348 : 1 +state 6969 observe1Greater1 observeIGreater1 + action 0 + 7349 : 0.8 + 7350 : 0.2 +state 6970 observe1Greater1 observeIGreater1 + action 0 + 7351 : 0.8 + 7352 : 0.2 +state 6971 observe1Greater1 observeIGreater1 + action 0 + 7353 : 0.8 + 7354 : 0.2 +state 6972 observe1Greater1 observeIGreater1 + action 0 + 7355 : 0.8 + 7356 : 0.2 +state 6973 observe1Greater1 observeIGreater1 + action 0 + 7357 : 0.8 + 7358 : 0.2 +state 6974 observe1Greater1 observeIGreater1 + action 0 + 7359 : 1 +state 6975 observe1Greater1 observeIGreater1 + action 0 + 7360 : 0.8 + 7361 : 0.2 +state 6976 observe1Greater1 observeIGreater1 + action 0 + 7362 : 0.8 + 7363 : 0.2 +state 6977 observe1Greater1 observeIGreater1 + action 0 + 7364 : 0.8 + 7365 : 0.2 +state 6978 observe1Greater1 observeIGreater1 + action 0 + 7366 : 0.8 + 7367 : 0.2 +state 6979 observe1Greater1 observeIGreater1 + action 0 + 7368 : 0.8 + 7369 : 0.2 +state 6980 observe1Greater1 observeIGreater1 + action 0 + 7370 : 1 +state 6981 observe1Greater1 observeIGreater1 + action 0 + 7371 : 1 +state 6982 observe1Greater1 observeIGreater1 + action 0 + 7372 : 1 +state 6983 observe1Greater1 observeIGreater1 + action 0 + 7373 : 1 +state 6984 observe1Greater1 observeIGreater1 + action 0 + 7374 : 1 +state 6985 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7375 : 0.8 + 7376 : 0.2 +state 6986 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7377 : 0.8 + 7378 : 0.2 +state 6987 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7379 : 0.8 + 7380 : 0.2 +state 6988 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7381 : 0.8 + 7382 : 0.2 +state 6989 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7383 : 0.8 + 7384 : 0.2 +state 6990 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7385 : 1 +state 6991 observe1Greater1 observeIGreater1 + action 0 + 7386 : 0.8 + 7387 : 0.2 +state 6992 observe1Greater1 observeIGreater1 + action 0 + 7388 : 0.8 + 7389 : 0.2 +state 6993 observe1Greater1 observeIGreater1 + action 0 + 7390 : 0.8 + 7391 : 0.2 +state 6994 observe1Greater1 observeIGreater1 + action 0 + 7392 : 0.8 + 7393 : 0.2 +state 6995 observe1Greater1 observeIGreater1 + action 0 + 7394 : 0.8 + 7395 : 0.2 +state 6996 observe1Greater1 observeIGreater1 + action 0 + 7396 : 1 +state 6997 observe1Greater1 observeIGreater1 + action 0 + 7397 : 0.8 + 7398 : 0.2 +state 6998 observe1Greater1 observeIGreater1 + action 0 + 7399 : 0.8 + 7400 : 0.2 +state 6999 observe1Greater1 observeIGreater1 + action 0 + 7401 : 0.8 + 7402 : 0.2 +state 7000 observe1Greater1 observeIGreater1 + action 0 + 7403 : 0.8 + 7404 : 0.2 +state 7001 observe1Greater1 observeIGreater1 + action 0 + 7405 : 0.8 + 7406 : 0.2 +state 7002 observe1Greater1 observeIGreater1 + action 0 + 7407 : 1 +state 7003 observe1Greater1 observeIGreater1 + action 0 + 7408 : 1 +state 7004 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7409 : 1 +state 7005 observe1Greater1 observeIGreater1 + action 0 + 7410 : 1 +state 7006 observe1Greater1 observeIGreater1 + action 0 + 7411 : 1 +state 7007 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7412 : 0.8 + 7413 : 0.2 +state 7008 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7414 : 0.8 + 7415 : 0.2 +state 7009 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7416 : 0.8 + 7417 : 0.2 +state 7010 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7418 : 0.8 + 7419 : 0.2 +state 7011 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7420 : 0.8 + 7421 : 0.2 +state 7012 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7422 : 1 +state 7013 observe1Greater1 observeIGreater1 + action 0 + 7423 : 0.8 + 7424 : 0.2 +state 7014 observe1Greater1 observeIGreater1 + action 0 + 7425 : 0.8 + 7426 : 0.2 +state 7015 observe1Greater1 observeIGreater1 + action 0 + 7427 : 0.8 + 7428 : 0.2 +state 7016 observe1Greater1 observeIGreater1 + action 0 + 7429 : 0.8 + 7430 : 0.2 +state 7017 observe1Greater1 observeIGreater1 + action 0 + 7431 : 0.8 + 7432 : 0.2 +state 7018 observe1Greater1 observeIGreater1 + action 0 + 7433 : 1 +state 7019 observe1Greater1 observeIGreater1 + action 0 + 7434 : 1 +state 7020 observe1Greater1 observeIGreater1 + action 0 + 7435 : 1 +state 7021 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7436 : 1 +state 7022 observe1Greater1 observeIGreater1 + action 0 + 7437 : 1 +state 7023 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7438 : 0.8 + 7439 : 0.2 +state 7024 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7440 : 0.8 + 7441 : 0.2 +state 7025 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7442 : 0.8 + 7443 : 0.2 +state 7026 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7444 : 0.8 + 7445 : 0.2 +state 7027 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7446 : 0.8 + 7447 : 0.2 +state 7028 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7448 : 1 +state 7029 observe1Greater1 observeIGreater1 + action 0 + 7449 : 1 +state 7030 observe1Greater1 observeIGreater1 + action 0 + 7450 : 1 +state 7031 observe1Greater1 observeIGreater1 + action 0 + 7451 : 1 +state 7032 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7452 : 1 +state 7033 observe2Greater1 observeIGreater1 + action 0 + 7453 : 0.8 + 7454 : 0.2 +state 7034 observe2Greater1 observeIGreater1 + action 0 + 7455 : 0.8 + 7456 : 0.2 +state 7035 observe2Greater1 observeIGreater1 + action 0 + 7457 : 0.8 + 7458 : 0.2 +state 7036 observe2Greater1 observeIGreater1 + action 0 + 7459 : 0.8 + 7460 : 0.2 +state 7037 observe2Greater1 observeIGreater1 + action 0 + 7461 : 0.8 + 7462 : 0.2 +state 7038 observe2Greater1 observeIGreater1 + action 0 + 7463 : 1 +state 7039 observe2Greater1 observeIGreater1 + action 0 + 7464 : 0.8 + 7465 : 0.2 +state 7040 observe2Greater1 observeIGreater1 + action 0 + 7466 : 0.8 + 7467 : 0.2 +state 7041 observe2Greater1 observeIGreater1 + action 0 + 7468 : 0.8 + 7469 : 0.2 +state 7042 observe2Greater1 observeIGreater1 + action 0 + 7470 : 0.8 + 7471 : 0.2 +state 7043 observe2Greater1 observeIGreater1 + action 0 + 7472 : 0.8 + 7473 : 0.2 +state 7044 observe2Greater1 observeIGreater1 + action 0 + 7474 : 1 +state 7045 observe2Greater1 observeIGreater1 + action 0 + 7475 : 0.8 + 7476 : 0.2 +state 7046 observe2Greater1 observeIGreater1 + action 0 + 7477 : 0.8 + 7478 : 0.2 +state 7047 observe2Greater1 observeIGreater1 + action 0 + 7479 : 0.8 + 7480 : 0.2 +state 7048 observe2Greater1 observeIGreater1 + action 0 + 7481 : 0.8 + 7482 : 0.2 +state 7049 observe2Greater1 observeIGreater1 + action 0 + 7483 : 0.8 + 7484 : 0.2 +state 7050 observe2Greater1 observeIGreater1 + action 0 + 7485 : 1 +state 7051 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7486 : 1 +state 7052 observe2Greater1 observeIGreater1 + action 0 + 7487 : 1 +state 7053 observe2Greater1 observeIGreater1 + action 0 + 7488 : 1 +state 7054 observe2Greater1 observeIGreater1 + action 0 + 7489 : 1 +state 7055 observe3Greater1 observeIGreater1 + action 0 + 7490 : 0.8 + 7491 : 0.2 +state 7056 observe3Greater1 observeIGreater1 + action 0 + 7492 : 0.8 + 7493 : 0.2 +state 7057 observe3Greater1 observeIGreater1 + action 0 + 7494 : 0.8 + 7495 : 0.2 +state 7058 observe3Greater1 observeIGreater1 + action 0 + 7496 : 0.8 + 7497 : 0.2 +state 7059 observe3Greater1 observeIGreater1 + action 0 + 7498 : 0.8 + 7499 : 0.2 +state 7060 observe3Greater1 observeIGreater1 + action 0 + 7500 : 1 +state 7061 + action 0 + 7501 : 0.8 + 7502 : 0.2 +state 7062 + action 0 + 7503 : 0.8 + 7504 : 0.2 +state 7063 + action 0 + 7505 : 0.8 + 7506 : 0.2 +state 7064 + action 0 + 7507 : 0.8 + 7508 : 0.2 +state 7065 + action 0 + 7509 : 0.8 + 7510 : 0.2 +state 7066 + action 0 + 7511 : 1 +state 7067 observe1Greater1 observeIGreater1 + action 0 + 7512 : 1 +state 7068 observe2Greater1 observeIGreater1 + action 0 + 7513 : 1 +state 7069 observe3Greater1 observeIGreater1 + action 0 + 7514 : 1 +state 7070 + action 0 + 7515 : 1 +state 7071 observe4Greater1 observeIGreater1 + action 0 + 7516 : 0.8 + 7517 : 0.2 +state 7072 observe4Greater1 observeIGreater1 + action 0 + 7518 : 0.8 + 7519 : 0.2 +state 7073 observe4Greater1 observeIGreater1 + action 0 + 7520 : 0.8 + 7521 : 0.2 +state 7074 observe4Greater1 observeIGreater1 + action 0 + 7522 : 0.8 + 7523 : 0.2 +state 7075 observe4Greater1 observeIGreater1 + action 0 + 7524 : 0.8 + 7525 : 0.2 +state 7076 observe4Greater1 observeIGreater1 + action 0 + 7526 : 1 +state 7077 observe1Greater1 observeIGreater1 + action 0 + 7527 : 1 +state 7078 observe2Greater1 observeIGreater1 + action 0 + 7528 : 1 +state 7079 + action 0 + 7529 : 1 +state 7080 observe4Greater1 observeIGreater1 + action 0 + 7530 : 1 +state 7081 observe3Greater1 observeIGreater1 + action 0 + 7531 : 0.8 + 7532 : 0.2 +state 7082 observe3Greater1 observeIGreater1 + action 0 + 7533 : 0.8 + 7534 : 0.2 +state 7083 observe3Greater1 observeIGreater1 + action 0 + 7535 : 0.8 + 7536 : 0.2 +state 7084 observe3Greater1 observeIGreater1 + action 0 + 7537 : 0.8 + 7538 : 0.2 +state 7085 observe3Greater1 observeIGreater1 + action 0 + 7539 : 0.8 + 7540 : 0.2 +state 7086 observe3Greater1 observeIGreater1 + action 0 + 7541 : 1 +state 7087 observe3Greater1 observeIGreater1 + action 0 + 7542 : 0.8 + 7543 : 0.2 +state 7088 observe3Greater1 observeIGreater1 + action 0 + 7544 : 0.8 + 7545 : 0.2 +state 7089 observe3Greater1 observeIGreater1 + action 0 + 7546 : 0.8 + 7547 : 0.2 +state 7090 observe3Greater1 observeIGreater1 + action 0 + 7548 : 0.8 + 7549 : 0.2 +state 7091 observe3Greater1 observeIGreater1 + action 0 + 7550 : 0.8 + 7551 : 0.2 +state 7092 observe3Greater1 observeIGreater1 + action 0 + 7552 : 1 +state 7093 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7553 : 1 +state 7094 observe3Greater1 observeIGreater1 + action 0 + 7554 : 1 +state 7095 observe3Greater1 observeIGreater1 + action 0 + 7555 : 1 +state 7096 observe3Greater1 observeIGreater1 + action 0 + 7556 : 1 +state 7097 observe4Greater1 observeIGreater1 + action 0 + 7557 : 0.8 + 7558 : 0.2 +state 7098 observe4Greater1 observeIGreater1 + action 0 + 7559 : 0.8 + 7560 : 0.2 +state 7099 observe4Greater1 observeIGreater1 + action 0 + 7561 : 0.8 + 7562 : 0.2 +state 7100 observe4Greater1 observeIGreater1 + action 0 + 7563 : 0.8 + 7564 : 0.2 +state 7101 observe4Greater1 observeIGreater1 + action 0 + 7565 : 0.8 + 7566 : 0.2 +state 7102 observe4Greater1 observeIGreater1 + action 0 + 7567 : 1 +state 7103 observe1Greater1 observeIGreater1 + action 0 + 7568 : 1 +state 7104 + action 0 + 7569 : 1 +state 7105 observe3Greater1 observeIGreater1 + action 0 + 7570 : 1 +state 7106 observe4Greater1 observeIGreater1 + action 0 + 7571 : 1 +state 7107 observe4Greater1 observeIGreater1 + action 0 + 7572 : 0.8 + 7573 : 0.2 +state 7108 observe4Greater1 observeIGreater1 + action 0 + 7574 : 0.8 + 7575 : 0.2 +state 7109 observe4Greater1 observeIGreater1 + action 0 + 7576 : 0.8 + 7577 : 0.2 +state 7110 observe4Greater1 observeIGreater1 + action 0 + 7578 : 0.8 + 7579 : 0.2 +state 7111 observe4Greater1 observeIGreater1 + action 0 + 7580 : 0.8 + 7581 : 0.2 +state 7112 observe4Greater1 observeIGreater1 + action 0 + 7582 : 1 +state 7113 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7583 : 1 +state 7114 observe4Greater1 observeIGreater1 + action 0 + 7584 : 1 +state 7115 observe4Greater1 observeIGreater1 + action 0 + 7585 : 1 +state 7116 observe4Greater1 observeIGreater1 + action 0 + 7586 : 1 +state 7117 observe2Greater1 observeIGreater1 + action 0 + 7587 : 0.8 + 7588 : 0.2 +state 7118 observe2Greater1 observeIGreater1 + action 0 + 7589 : 0.8 + 7590 : 0.2 +state 7119 observe2Greater1 observeIGreater1 + action 0 + 7591 : 0.8 + 7592 : 0.2 +state 7120 observe2Greater1 observeIGreater1 + action 0 + 7593 : 0.8 + 7594 : 0.2 +state 7121 observe2Greater1 observeIGreater1 + action 0 + 7595 : 0.8 + 7596 : 0.2 +state 7122 observe2Greater1 observeIGreater1 + action 0 + 7597 : 1 +state 7123 observe2Greater1 observeIGreater1 + action 0 + 7598 : 0.8 + 7599 : 0.2 +state 7124 observe2Greater1 observeIGreater1 + action 0 + 7600 : 0.8 + 7601 : 0.2 +state 7125 observe2Greater1 observeIGreater1 + action 0 + 7602 : 0.8 + 7603 : 0.2 +state 7126 observe2Greater1 observeIGreater1 + action 0 + 7604 : 0.8 + 7605 : 0.2 +state 7127 observe2Greater1 observeIGreater1 + action 0 + 7606 : 0.8 + 7607 : 0.2 +state 7128 observe2Greater1 observeIGreater1 + action 0 + 7608 : 1 +state 7129 observe2Greater1 observeIGreater1 + action 0 + 7609 : 0.8 + 7610 : 0.2 +state 7130 observe2Greater1 observeIGreater1 + action 0 + 7611 : 0.8 + 7612 : 0.2 +state 7131 observe2Greater1 observeIGreater1 + action 0 + 7613 : 0.8 + 7614 : 0.2 +state 7132 observe2Greater1 observeIGreater1 + action 0 + 7615 : 0.8 + 7616 : 0.2 +state 7133 observe2Greater1 observeIGreater1 + action 0 + 7617 : 0.8 + 7618 : 0.2 +state 7134 observe2Greater1 observeIGreater1 + action 0 + 7619 : 1 +state 7135 observe2Greater1 observeIGreater1 + action 0 + 7620 : 1 +state 7136 observe2Greater1 observeIGreater1 + action 0 + 7621 : 1 +state 7137 observe2Greater1 observeIGreater1 + action 0 + 7622 : 1 +state 7138 observe2Greater1 observeIGreater1 + action 0 + 7623 : 1 +state 7139 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7624 : 0.8 + 7625 : 0.2 +state 7140 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7626 : 0.8 + 7627 : 0.2 +state 7141 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7628 : 0.8 + 7629 : 0.2 +state 7142 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7630 : 0.8 + 7631 : 0.2 +state 7143 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7632 : 0.8 + 7633 : 0.2 +state 7144 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7634 : 1 +state 7145 observe2Greater1 observeIGreater1 + action 0 + 7635 : 0.8 + 7636 : 0.2 +state 7146 observe2Greater1 observeIGreater1 + action 0 + 7637 : 0.8 + 7638 : 0.2 +state 7147 observe2Greater1 observeIGreater1 + action 0 + 7639 : 0.8 + 7640 : 0.2 +state 7148 observe2Greater1 observeIGreater1 + action 0 + 7641 : 0.8 + 7642 : 0.2 +state 7149 observe2Greater1 observeIGreater1 + action 0 + 7643 : 0.8 + 7644 : 0.2 +state 7150 observe2Greater1 observeIGreater1 + action 0 + 7645 : 1 +state 7151 observe2Greater1 observeIGreater1 + action 0 + 7646 : 1 +state 7152 observe2Greater1 observeIGreater1 + action 0 + 7647 : 1 +state 7153 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7648 : 1 +state 7154 observe2Greater1 observeIGreater1 + action 0 + 7649 : 1 +state 7155 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7650 : 0.8 + 7651 : 0.2 +state 7156 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7652 : 0.8 + 7653 : 0.2 +state 7157 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7654 : 0.8 + 7655 : 0.2 +state 7158 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7656 : 0.8 + 7657 : 0.2 +state 7159 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7658 : 0.8 + 7659 : 0.2 +state 7160 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7660 : 1 +state 7161 observe2Greater1 observeIGreater1 + action 0 + 7661 : 1 +state 7162 observe2Greater1 observeIGreater1 + action 0 + 7662 : 1 +state 7163 observe2Greater1 observeIGreater1 + action 0 + 7663 : 1 +state 7164 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7664 : 1 +state 7165 observe3Greater1 observeIGreater1 + action 0 + 7665 : 0.8 + 7666 : 0.2 +state 7166 observe3Greater1 observeIGreater1 + action 0 + 7667 : 0.8 + 7668 : 0.2 +state 7167 observe3Greater1 observeIGreater1 + action 0 + 7669 : 0.8 + 7670 : 0.2 +state 7168 observe3Greater1 observeIGreater1 + action 0 + 7671 : 0.8 + 7672 : 0.2 +state 7169 observe3Greater1 observeIGreater1 + action 0 + 7673 : 0.8 + 7674 : 0.2 +state 7170 observe3Greater1 observeIGreater1 + action 0 + 7675 : 1 +state 7171 observe3Greater1 observeIGreater1 + action 0 + 7676 : 0.8 + 7677 : 0.2 +state 7172 observe3Greater1 observeIGreater1 + action 0 + 7678 : 0.8 + 7679 : 0.2 +state 7173 observe3Greater1 observeIGreater1 + action 0 + 7680 : 0.8 + 7681 : 0.2 +state 7174 observe3Greater1 observeIGreater1 + action 0 + 7682 : 0.8 + 7683 : 0.2 +state 7175 observe3Greater1 observeIGreater1 + action 0 + 7684 : 0.8 + 7685 : 0.2 +state 7176 observe3Greater1 observeIGreater1 + action 0 + 7686 : 1 +state 7177 observe3Greater1 observeIGreater1 + action 0 + 7687 : 1 +state 7178 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7688 : 1 +state 7179 observe3Greater1 observeIGreater1 + action 0 + 7689 : 1 +state 7180 observe3Greater1 observeIGreater1 + action 0 + 7690 : 1 +state 7181 observe4Greater1 observeIGreater1 + action 0 + 7691 : 0.8 + 7692 : 0.2 +state 7182 observe4Greater1 observeIGreater1 + action 0 + 7693 : 0.8 + 7694 : 0.2 +state 7183 observe4Greater1 observeIGreater1 + action 0 + 7695 : 0.8 + 7696 : 0.2 +state 7184 observe4Greater1 observeIGreater1 + action 0 + 7697 : 0.8 + 7698 : 0.2 +state 7185 observe4Greater1 observeIGreater1 + action 0 + 7699 : 0.8 + 7700 : 0.2 +state 7186 observe4Greater1 observeIGreater1 + action 0 + 7701 : 1 +state 7187 + action 0 + 7702 : 1 +state 7188 observe2Greater1 observeIGreater1 + action 0 + 7703 : 1 +state 7189 observe3Greater1 observeIGreater1 + action 0 + 7704 : 1 +state 7190 observe4Greater1 observeIGreater1 + action 0 + 7705 : 1 +state 7191 observe4Greater1 observeIGreater1 + action 0 + 7706 : 0.8 + 7707 : 0.2 +state 7192 observe4Greater1 observeIGreater1 + action 0 + 7708 : 0.8 + 7709 : 0.2 +state 7193 observe4Greater1 observeIGreater1 + action 0 + 7710 : 0.8 + 7711 : 0.2 +state 7194 observe4Greater1 observeIGreater1 + action 0 + 7712 : 0.8 + 7713 : 0.2 +state 7195 observe4Greater1 observeIGreater1 + action 0 + 7714 : 0.8 + 7715 : 0.2 +state 7196 observe4Greater1 observeIGreater1 + action 0 + 7716 : 1 +state 7197 observe4Greater1 observeIGreater1 + action 0 + 7717 : 1 +state 7198 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7718 : 1 +state 7199 observe4Greater1 observeIGreater1 + action 0 + 7719 : 1 +state 7200 observe4Greater1 observeIGreater1 + action 0 + 7720 : 1 +state 7201 observe3Greater1 observeIGreater1 + action 0 + 7721 : 0.8 + 7722 : 0.2 +state 7202 observe3Greater1 observeIGreater1 + action 0 + 7723 : 0.8 + 7724 : 0.2 +state 7203 observe3Greater1 observeIGreater1 + action 0 + 7725 : 0.8 + 7726 : 0.2 +state 7204 observe3Greater1 observeIGreater1 + action 0 + 7727 : 0.8 + 7728 : 0.2 +state 7205 observe3Greater1 observeIGreater1 + action 0 + 7729 : 0.8 + 7730 : 0.2 +state 7206 observe3Greater1 observeIGreater1 + action 0 + 7731 : 1 +state 7207 observe3Greater1 observeIGreater1 + action 0 + 7732 : 0.8 + 7733 : 0.2 +state 7208 observe3Greater1 observeIGreater1 + action 0 + 7734 : 0.8 + 7735 : 0.2 +state 7209 observe3Greater1 observeIGreater1 + action 0 + 7736 : 0.8 + 7737 : 0.2 +state 7210 observe3Greater1 observeIGreater1 + action 0 + 7738 : 0.8 + 7739 : 0.2 +state 7211 observe3Greater1 observeIGreater1 + action 0 + 7740 : 0.8 + 7741 : 0.2 +state 7212 observe3Greater1 observeIGreater1 + action 0 + 7742 : 1 +state 7213 observe3Greater1 observeIGreater1 + action 0 + 7743 : 1 +state 7214 observe3Greater1 observeIGreater1 + action 0 + 7744 : 1 +state 7215 observe3Greater1 observeIGreater1 + action 0 + 7745 : 1 +state 7216 observe3Greater1 observeIGreater1 + action 0 + 7746 : 1 +state 7217 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7747 : 0.8 + 7748 : 0.2 +state 7218 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7749 : 0.8 + 7750 : 0.2 +state 7219 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7751 : 0.8 + 7752 : 0.2 +state 7220 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7753 : 0.8 + 7754 : 0.2 +state 7221 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7755 : 0.8 + 7756 : 0.2 +state 7222 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7757 : 1 +state 7223 observe3Greater1 observeIGreater1 + action 0 + 7758 : 1 +state 7224 observe3Greater1 observeIGreater1 + action 0 + 7759 : 1 +state 7225 observe3Greater1 observeIGreater1 + action 0 + 7760 : 1 +state 7226 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7761 : 1 +state 7227 observe4Greater1 observeIGreater1 + action 0 + 7762 : 0.8 + 7763 : 0.2 +state 7228 observe4Greater1 observeIGreater1 + action 0 + 7764 : 0.8 + 7765 : 0.2 +state 7229 observe4Greater1 observeIGreater1 + action 0 + 7766 : 0.8 + 7767 : 0.2 +state 7230 observe4Greater1 observeIGreater1 + action 0 + 7768 : 0.8 + 7769 : 0.2 +state 7231 observe4Greater1 observeIGreater1 + action 0 + 7770 : 0.8 + 7771 : 0.2 +state 7232 observe4Greater1 observeIGreater1 + action 0 + 7772 : 1 +state 7233 observe4Greater1 observeIGreater1 + action 0 + 7773 : 1 +state 7234 observe4Greater1 observeIGreater1 + action 0 + 7774 : 1 +state 7235 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7775 : 1 +state 7236 observe4Greater1 observeIGreater1 + action 0 + 7776 : 1 +state 7237 observe4Greater1 observeIGreater1 + action 0 + 7777 : 0.8 + 7778 : 0.2 +state 7238 observe4Greater1 observeIGreater1 + action 0 + 7779 : 0.8 + 7780 : 0.2 +state 7239 observe4Greater1 observeIGreater1 + action 0 + 7781 : 0.8 + 7782 : 0.2 +state 7240 observe4Greater1 observeIGreater1 + action 0 + 7783 : 0.8 + 7784 : 0.2 +state 7241 observe4Greater1 observeIGreater1 + action 0 + 7785 : 0.8 + 7786 : 0.2 +state 7242 observe4Greater1 observeIGreater1 + action 0 + 7787 : 1 +state 7243 observe4Greater1 observeIGreater1 + action 0 + 7788 : 1 +state 7244 observe4Greater1 observeIGreater1 + action 0 + 7789 : 1 +state 7245 observe4Greater1 observeIGreater1 + action 0 + 7790 : 1 +state 7246 observe4Greater1 observeIGreater1 + action 0 + 7791 : 1 +state 7247 observe1Greater1 observeIGreater1 + action 0 + 7792 : 1 +state 7248 observe1Greater1 observeIGreater1 + action 0 + 7793 : 1 +state 7249 observe1Greater1 observeIGreater1 + action 0 + 7794 : 1 +state 7250 observe1Greater1 observeIGreater1 + action 0 + 7795 : 1 +state 7251 observe1Greater1 observeIGreater1 + action 0 + 7796 : 1 +state 7252 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7797 : 1 +state 7253 observe1Greater1 observeIGreater1 + action 0 + 7798 : 1 +state 7254 observe1Greater1 observeIGreater1 + action 0 + 7799 : 1 +state 7255 observe1Greater1 observeIGreater1 + action 0 + 7800 : 1 +state 7256 observe1Greater1 observeIGreater1 + action 0 + 7801 : 1 +state 7257 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7802 : 1 +state 7258 observe1Greater1 observeIGreater1 + action 0 + 7803 : 1 +state 7259 observe1Greater1 observeIGreater1 + action 0 + 7804 : 1 +state 7260 observe1Greater1 observeIGreater1 + action 0 + 7805 : 1 +state 7261 observe1Greater1 observeIGreater1 + action 0 + 7806 : 1 +state 7262 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7807 : 1 +state 7263 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7808 : 1 +state 7264 observe2Greater1 observeIGreater1 + action 0 + 7809 : 1 +state 7265 observe2Greater1 observeIGreater1 + action 0 + 7810 : 1 +state 7266 observe2Greater1 observeIGreater1 + action 0 + 7811 : 1 +state 7267 observe1Greater1 observeIGreater1 + action 0 + 7812 : 1 +state 7268 observe2Greater1 observeIGreater1 + action 0 + 7813 : 1 +state 7269 observe3Greater1 observeIGreater1 + action 0 + 7814 : 1 +state 7270 + action 0 + 7815 : 1 +state 7271 observe1Greater1 observeIGreater1 + action 0 + 7816 : 1 +state 7272 observe2Greater1 observeIGreater1 + action 0 + 7817 : 1 +state 7273 + action 0 + 7818 : 1 +state 7274 observe4Greater1 observeIGreater1 + action 0 + 7819 : 1 +state 7275 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7820 : 1 +state 7276 observe3Greater1 observeIGreater1 + action 0 + 7821 : 1 +state 7277 observe3Greater1 observeIGreater1 + action 0 + 7822 : 1 +state 7278 observe3Greater1 observeIGreater1 + action 0 + 7823 : 1 +state 7279 observe1Greater1 observeIGreater1 + action 0 + 7824 : 1 +state 7280 + action 0 + 7825 : 1 +state 7281 observe3Greater1 observeIGreater1 + action 0 + 7826 : 1 +state 7282 observe4Greater1 observeIGreater1 + action 0 + 7827 : 1 +state 7283 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7828 : 1 +state 7284 observe4Greater1 observeIGreater1 + action 0 + 7829 : 1 +state 7285 observe4Greater1 observeIGreater1 + action 0 + 7830 : 1 +state 7286 observe4Greater1 observeIGreater1 + action 0 + 7831 : 1 +state 7287 observe2Greater1 observeIGreater1 + action 0 + 7832 : 1 +state 7288 observe2Greater1 observeIGreater1 + action 0 + 7833 : 1 +state 7289 observe2Greater1 observeIGreater1 + action 0 + 7834 : 1 +state 7290 observe2Greater1 observeIGreater1 + action 0 + 7835 : 1 +state 7291 observe2Greater1 observeIGreater1 + action 0 + 7836 : 1 +state 7292 observe2Greater1 observeIGreater1 + action 0 + 7837 : 1 +state 7293 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7838 : 1 +state 7294 observe2Greater1 observeIGreater1 + action 0 + 7839 : 1 +state 7295 observe2Greater1 observeIGreater1 + action 0 + 7840 : 1 +state 7296 observe2Greater1 observeIGreater1 + action 0 + 7841 : 1 +state 7297 observe2Greater1 observeIGreater1 + action 0 + 7842 : 1 +state 7298 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7843 : 1 +state 7299 observe3Greater1 observeIGreater1 + action 0 + 7844 : 1 +state 7300 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7845 : 1 +state 7301 observe3Greater1 observeIGreater1 + action 0 + 7846 : 1 +state 7302 observe3Greater1 observeIGreater1 + action 0 + 7847 : 1 +state 7303 + action 0 + 7848 : 1 +state 7304 observe2Greater1 observeIGreater1 + action 0 + 7849 : 1 +state 7305 observe3Greater1 observeIGreater1 + action 0 + 7850 : 1 +state 7306 observe4Greater1 observeIGreater1 + action 0 + 7851 : 1 +state 7307 observe4Greater1 observeIGreater1 + action 0 + 7852 : 1 +state 7308 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7853 : 1 +state 7309 observe4Greater1 observeIGreater1 + action 0 + 7854 : 1 +state 7310 observe4Greater1 observeIGreater1 + action 0 + 7855 : 1 +state 7311 observe3Greater1 observeIGreater1 + action 0 + 7856 : 1 +state 7312 observe3Greater1 observeIGreater1 + action 0 + 7857 : 1 +state 7313 observe3Greater1 observeIGreater1 + action 0 + 7858 : 1 +state 7314 observe3Greater1 observeIGreater1 + action 0 + 7859 : 1 +state 7315 observe3Greater1 observeIGreater1 + action 0 + 7860 : 1 +state 7316 observe3Greater1 observeIGreater1 + action 0 + 7861 : 1 +state 7317 observe3Greater1 observeIGreater1 + action 0 + 7862 : 1 +state 7318 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7863 : 1 +state 7319 observe4Greater1 observeIGreater1 + action 0 + 7864 : 1 +state 7320 observe4Greater1 observeIGreater1 + action 0 + 7865 : 1 +state 7321 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7866 : 1 +state 7322 observe4Greater1 observeIGreater1 + action 0 + 7867 : 1 +state 7323 observe4Greater1 observeIGreater1 + action 0 + 7868 : 1 +state 7324 observe4Greater1 observeIGreater1 + action 0 + 7869 : 1 +state 7325 observe4Greater1 observeIGreater1 + action 0 + 7870 : 1 +state 7326 observe4Greater1 observeIGreater1 + action 0 + 7871 : 1 +state 7327 observe1Greater1 observeIGreater1 + action 0 + 6327 : 0.833 + 6328 : 0.167 +state 7328 observe1Greater1 observeIGreater1 + action 0 + 7872 : 1 +state 7329 observe1Greater1 observeIGreater1 + action 0 + 7873 : 0.833 + 7874 : 0.167 +state 7330 observe1Greater1 observeIGreater1 + action 0 + 7875 : 1 +state 7331 observe1Greater1 observeIGreater1 + action 0 + 7876 : 0.833 + 7877 : 0.167 +state 7332 observe1Greater1 observeIGreater1 + action 0 + 7878 : 1 +state 7333 observe1Greater1 observeIGreater1 + action 0 + 7879 : 0.833 + 7880 : 0.167 +state 7334 observe1Greater1 observeIGreater1 + action 0 + 7881 : 1 +state 7335 observe1Greater1 observeIGreater1 + action 0 + 7882 : 0.833 + 7883 : 0.167 +state 7336 observe1Greater1 observeIGreater1 + action 0 + 7884 : 1 +state 7337 deadlock observe1Greater1 observeIGreater1 + action 0 + 7337 : 1 +state 7338 observe1Greater1 observeIGreater1 + action 0 + 6329 : 0.833 + 6330 : 0.167 +state 7339 observe1Greater1 observeIGreater1 + action 0 + 7885 : 1 +state 7340 observe1Greater1 observeIGreater1 + action 0 + 7886 : 0.833 + 7887 : 0.167 +state 7341 observe1Greater1 observeIGreater1 + action 0 + 7888 : 1 +state 7342 observe1Greater1 observeIGreater1 + action 0 + 7889 : 0.833 + 7890 : 0.167 +state 7343 observe1Greater1 observeIGreater1 + action 0 + 7891 : 1 +state 7344 observe1Greater1 observeIGreater1 + action 0 + 7892 : 0.833 + 7893 : 0.167 +state 7345 observe1Greater1 observeIGreater1 + action 0 + 7894 : 1 +state 7346 observe1Greater1 observeIGreater1 + action 0 + 7895 : 0.833 + 7896 : 0.167 +state 7347 observe1Greater1 observeIGreater1 + action 0 + 7897 : 1 +state 7348 deadlock observe1Greater1 observeIGreater1 + action 0 + 7348 : 1 +state 7349 observe1Greater1 observeIGreater1 + action 0 + 6331 : 0.833 + 6332 : 0.167 +state 7350 observe1Greater1 observeIGreater1 + action 0 + 7898 : 1 +state 7351 observe1Greater1 observeIGreater1 + action 0 + 7899 : 0.833 + 7900 : 0.167 +state 7352 observe1Greater1 observeIGreater1 + action 0 + 7901 : 1 +state 7353 observe1Greater1 observeIGreater1 + action 0 + 7902 : 0.833 + 7903 : 0.167 +state 7354 observe1Greater1 observeIGreater1 + action 0 + 7904 : 1 +state 7355 observe1Greater1 observeIGreater1 + action 0 + 7905 : 0.833 + 7906 : 0.167 +state 7356 observe1Greater1 observeIGreater1 + action 0 + 7907 : 1 +state 7357 observe1Greater1 observeIGreater1 + action 0 + 7908 : 0.833 + 7909 : 0.167 +state 7358 observe1Greater1 observeIGreater1 + action 0 + 7910 : 1 +state 7359 deadlock observe1Greater1 observeIGreater1 + action 0 + 7359 : 1 +state 7360 observe1Greater1 observeIGreater1 + action 0 + 6333 : 0.833 + 6334 : 0.167 +state 7361 observe1Greater1 observeIGreater1 + action 0 + 7911 : 1 +state 7362 observe1Greater1 observeIGreater1 + action 0 + 7912 : 0.833 + 7913 : 0.167 +state 7363 observe1Greater1 observeIGreater1 + action 0 + 7914 : 1 +state 7364 observe1Greater1 observeIGreater1 + action 0 + 7915 : 0.833 + 7916 : 0.167 +state 7365 observe1Greater1 observeIGreater1 + action 0 + 7917 : 1 +state 7366 observe1Greater1 observeIGreater1 + action 0 + 7918 : 0.833 + 7919 : 0.167 +state 7367 observe1Greater1 observeIGreater1 + action 0 + 7920 : 1 +state 7368 observe1Greater1 observeIGreater1 + action 0 + 7921 : 0.833 + 7922 : 0.167 +state 7369 observe1Greater1 observeIGreater1 + action 0 + 7923 : 1 +state 7370 deadlock observe1Greater1 observeIGreater1 + action 0 + 7370 : 1 +state 7371 deadlock observe1Greater1 observeIGreater1 + action 0 + 7371 : 1 +state 7372 deadlock observe1Greater1 observeIGreater1 + action 0 + 7372 : 1 +state 7373 deadlock observe1Greater1 observeIGreater1 + action 0 + 7373 : 1 +state 7374 deadlock observe1Greater1 observeIGreater1 + action 0 + 7374 : 1 +state 7375 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6348 : 0.833 + 6349 : 0.167 +state 7376 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7924 : 1 +state 7377 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7925 : 0.833 + 7926 : 0.167 +state 7378 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7927 : 1 +state 7379 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7928 : 0.833 + 7929 : 0.167 +state 7380 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7930 : 1 +state 7381 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7931 : 0.833 + 7932 : 0.167 +state 7382 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7933 : 1 +state 7383 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7934 : 0.833 + 7935 : 0.167 +state 7384 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7936 : 1 +state 7385 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7385 : 1 +state 7386 observe1Greater1 observeIGreater1 + action 0 + 6350 : 0.833 + 6351 : 0.167 +state 7387 observe1Greater1 observeIGreater1 + action 0 + 7937 : 1 +state 7388 observe1Greater1 observeIGreater1 + action 0 + 7938 : 0.833 + 7939 : 0.167 +state 7389 observe1Greater1 observeIGreater1 + action 0 + 7940 : 1 +state 7390 observe1Greater1 observeIGreater1 + action 0 + 7941 : 0.833 + 7942 : 0.167 +state 7391 observe1Greater1 observeIGreater1 + action 0 + 7943 : 1 +state 7392 observe1Greater1 observeIGreater1 + action 0 + 7944 : 0.833 + 7945 : 0.167 +state 7393 observe1Greater1 observeIGreater1 + action 0 + 7946 : 1 +state 7394 observe1Greater1 observeIGreater1 + action 0 + 7947 : 0.833 + 7948 : 0.167 +state 7395 observe1Greater1 observeIGreater1 + action 0 + 7949 : 1 +state 7396 deadlock observe1Greater1 observeIGreater1 + action 0 + 7396 : 1 +state 7397 observe1Greater1 observeIGreater1 + action 0 + 6352 : 0.833 + 6353 : 0.167 +state 7398 observe1Greater1 observeIGreater1 + action 0 + 7950 : 1 +state 7399 observe1Greater1 observeIGreater1 + action 0 + 7951 : 0.833 + 7952 : 0.167 +state 7400 observe1Greater1 observeIGreater1 + action 0 + 7953 : 1 +state 7401 observe1Greater1 observeIGreater1 + action 0 + 7954 : 0.833 + 7955 : 0.167 +state 7402 observe1Greater1 observeIGreater1 + action 0 + 7956 : 1 +state 7403 observe1Greater1 observeIGreater1 + action 0 + 7957 : 0.833 + 7958 : 0.167 +state 7404 observe1Greater1 observeIGreater1 + action 0 + 7959 : 1 +state 7405 observe1Greater1 observeIGreater1 + action 0 + 7960 : 0.833 + 7961 : 0.167 +state 7406 observe1Greater1 observeIGreater1 + action 0 + 7962 : 1 +state 7407 deadlock observe1Greater1 observeIGreater1 + action 0 + 7407 : 1 +state 7408 deadlock observe1Greater1 observeIGreater1 + action 0 + 7408 : 1 +state 7409 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7409 : 1 +state 7410 deadlock observe1Greater1 observeIGreater1 + action 0 + 7410 : 1 +state 7411 deadlock observe1Greater1 observeIGreater1 + action 0 + 7411 : 1 +state 7412 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 6367 : 0.833 + 6368 : 0.167 +state 7413 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7963 : 1 +state 7414 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7964 : 0.833 + 7965 : 0.167 +state 7415 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7966 : 1 +state 7416 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7967 : 0.833 + 7968 : 0.167 +state 7417 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7969 : 1 +state 7418 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7970 : 0.833 + 7971 : 0.167 +state 7419 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7972 : 1 +state 7420 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7973 : 0.833 + 7974 : 0.167 +state 7421 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7975 : 1 +state 7422 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7422 : 1 +state 7423 observe1Greater1 observeIGreater1 + action 0 + 6369 : 0.833 + 6370 : 0.167 +state 7424 observe1Greater1 observeIGreater1 + action 0 + 7976 : 1 +state 7425 observe1Greater1 observeIGreater1 + action 0 + 7977 : 0.833 + 7978 : 0.167 +state 7426 observe1Greater1 observeIGreater1 + action 0 + 7979 : 1 +state 7427 observe1Greater1 observeIGreater1 + action 0 + 7980 : 0.833 + 7981 : 0.167 +state 7428 observe1Greater1 observeIGreater1 + action 0 + 7982 : 1 +state 7429 observe1Greater1 observeIGreater1 + action 0 + 7983 : 0.833 + 7984 : 0.167 +state 7430 observe1Greater1 observeIGreater1 + action 0 + 7985 : 1 +state 7431 observe1Greater1 observeIGreater1 + action 0 + 7986 : 0.833 + 7987 : 0.167 +state 7432 observe1Greater1 observeIGreater1 + action 0 + 7988 : 1 +state 7433 deadlock observe1Greater1 observeIGreater1 + action 0 + 7433 : 1 +state 7434 deadlock observe1Greater1 observeIGreater1 + action 0 + 7434 : 1 +state 7435 deadlock observe1Greater1 observeIGreater1 + action 0 + 7435 : 1 +state 7436 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7436 : 1 +state 7437 deadlock observe1Greater1 observeIGreater1 + action 0 + 7437 : 1 +state 7438 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 6384 : 0.833 + 6385 : 0.167 +state 7439 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7989 : 1 +state 7440 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7990 : 0.833 + 7991 : 0.167 +state 7441 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7992 : 1 +state 7442 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7993 : 0.833 + 7994 : 0.167 +state 7443 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7995 : 1 +state 7444 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7996 : 0.833 + 7997 : 0.167 +state 7445 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7998 : 1 +state 7446 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7999 : 0.833 + 8000 : 0.167 +state 7447 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8001 : 1 +state 7448 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7448 : 1 +state 7449 deadlock observe1Greater1 observeIGreater1 + action 0 + 7449 : 1 +state 7450 deadlock observe1Greater1 observeIGreater1 + action 0 + 7450 : 1 +state 7451 deadlock observe1Greater1 observeIGreater1 + action 0 + 7451 : 1 +state 7452 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7452 : 1 +state 7453 observe2Greater1 observeIGreater1 + action 0 + 6399 : 0.833 + 6400 : 0.167 +state 7454 observe2Greater1 observeIGreater1 + action 0 + 8002 : 1 +state 7455 observe2Greater1 observeIGreater1 + action 0 + 8003 : 0.833 + 8004 : 0.167 +state 7456 observe2Greater1 observeIGreater1 + action 0 + 8005 : 1 +state 7457 observe2Greater1 observeIGreater1 + action 0 + 8006 : 0.833 + 8007 : 0.167 +state 7458 observe2Greater1 observeIGreater1 + action 0 + 8008 : 1 +state 7459 observe2Greater1 observeIGreater1 + action 0 + 8009 : 0.833 + 8010 : 0.167 +state 7460 observe2Greater1 observeIGreater1 + action 0 + 8011 : 1 +state 7461 observe2Greater1 observeIGreater1 + action 0 + 8012 : 0.833 + 8013 : 0.167 +state 7462 observe2Greater1 observeIGreater1 + action 0 + 8014 : 1 +state 7463 deadlock observe2Greater1 observeIGreater1 + action 0 + 7463 : 1 +state 7464 observe2Greater1 observeIGreater1 + action 0 + 6401 : 0.833 + 6402 : 0.167 +state 7465 observe2Greater1 observeIGreater1 + action 0 + 8015 : 1 +state 7466 observe2Greater1 observeIGreater1 + action 0 + 8016 : 0.833 + 8017 : 0.167 +state 7467 observe2Greater1 observeIGreater1 + action 0 + 8018 : 1 +state 7468 observe2Greater1 observeIGreater1 + action 0 + 8019 : 0.833 + 8020 : 0.167 +state 7469 observe2Greater1 observeIGreater1 + action 0 + 8021 : 1 +state 7470 observe2Greater1 observeIGreater1 + action 0 + 8022 : 0.833 + 8023 : 0.167 +state 7471 observe2Greater1 observeIGreater1 + action 0 + 8024 : 1 +state 7472 observe2Greater1 observeIGreater1 + action 0 + 8025 : 0.833 + 8026 : 0.167 +state 7473 observe2Greater1 observeIGreater1 + action 0 + 8027 : 1 +state 7474 deadlock observe2Greater1 observeIGreater1 + action 0 + 7474 : 1 +state 7475 observe2Greater1 observeIGreater1 + action 0 + 6403 : 0.833 + 6404 : 0.167 +state 7476 observe2Greater1 observeIGreater1 + action 0 + 8028 : 1 +state 7477 observe2Greater1 observeIGreater1 + action 0 + 8029 : 0.833 + 8030 : 0.167 +state 7478 observe2Greater1 observeIGreater1 + action 0 + 8031 : 1 +state 7479 observe2Greater1 observeIGreater1 + action 0 + 8032 : 0.833 + 8033 : 0.167 +state 7480 observe2Greater1 observeIGreater1 + action 0 + 8034 : 1 +state 7481 observe2Greater1 observeIGreater1 + action 0 + 8035 : 0.833 + 8036 : 0.167 +state 7482 observe2Greater1 observeIGreater1 + action 0 + 8037 : 1 +state 7483 observe2Greater1 observeIGreater1 + action 0 + 8038 : 0.833 + 8039 : 0.167 +state 7484 observe2Greater1 observeIGreater1 + action 0 + 8040 : 1 +state 7485 deadlock observe2Greater1 observeIGreater1 + action 0 + 7485 : 1 +state 7486 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7486 : 1 +state 7487 deadlock observe2Greater1 observeIGreater1 + action 0 + 7487 : 1 +state 7488 deadlock observe2Greater1 observeIGreater1 + action 0 + 7488 : 1 +state 7489 deadlock observe2Greater1 observeIGreater1 + action 0 + 7489 : 1 +state 7490 observe3Greater1 observeIGreater1 + action 0 + 6418 : 0.833 + 6419 : 0.167 +state 7491 observe3Greater1 observeIGreater1 + action 0 + 8041 : 1 +state 7492 observe3Greater1 observeIGreater1 + action 0 + 8042 : 0.833 + 8043 : 0.167 +state 7493 observe3Greater1 observeIGreater1 + action 0 + 8044 : 1 +state 7494 observe3Greater1 observeIGreater1 + action 0 + 8045 : 0.833 + 8046 : 0.167 +state 7495 observe3Greater1 observeIGreater1 + action 0 + 8047 : 1 +state 7496 observe3Greater1 observeIGreater1 + action 0 + 8048 : 0.833 + 8049 : 0.167 +state 7497 observe3Greater1 observeIGreater1 + action 0 + 8050 : 1 +state 7498 observe3Greater1 observeIGreater1 + action 0 + 8051 : 0.833 + 8052 : 0.167 +state 7499 observe3Greater1 observeIGreater1 + action 0 + 8053 : 1 +state 7500 deadlock observe3Greater1 observeIGreater1 + action 0 + 7500 : 1 +state 7501 + action 0 + 6420 : 0.833 + 6421 : 0.167 +state 7502 + action 0 + 8054 : 1 +state 7503 + action 0 + 8055 : 0.833 + 8056 : 0.167 +state 7504 + action 0 + 8057 : 1 +state 7505 + action 0 + 8058 : 0.833 + 8059 : 0.167 +state 7506 + action 0 + 8060 : 1 +state 7507 + action 0 + 8061 : 0.833 + 8062 : 0.167 +state 7508 + action 0 + 8063 : 1 +state 7509 + action 0 + 8064 : 0.833 + 8065 : 0.167 +state 7510 + action 0 + 8066 : 1 +state 7511 deadlock + action 0 + 7511 : 1 +state 7512 deadlock observe1Greater1 observeIGreater1 + action 0 + 7512 : 1 +state 7513 deadlock observe2Greater1 observeIGreater1 + action 0 + 7513 : 1 +state 7514 deadlock observe3Greater1 observeIGreater1 + action 0 + 7514 : 1 +state 7515 deadlock + action 0 + 7515 : 1 +state 7516 observe4Greater1 observeIGreater1 + action 0 + 6435 : 0.833 + 6436 : 0.167 +state 7517 observe4Greater1 observeIGreater1 + action 0 + 8067 : 1 +state 7518 observe4Greater1 observeIGreater1 + action 0 + 8068 : 0.833 + 8069 : 0.167 +state 7519 observe4Greater1 observeIGreater1 + action 0 + 8070 : 1 +state 7520 observe4Greater1 observeIGreater1 + action 0 + 8071 : 0.833 + 8072 : 0.167 +state 7521 observe4Greater1 observeIGreater1 + action 0 + 8073 : 1 +state 7522 observe4Greater1 observeIGreater1 + action 0 + 8074 : 0.833 + 8075 : 0.167 +state 7523 observe4Greater1 observeIGreater1 + action 0 + 8076 : 1 +state 7524 observe4Greater1 observeIGreater1 + action 0 + 8077 : 0.833 + 8078 : 0.167 +state 7525 observe4Greater1 observeIGreater1 + action 0 + 8079 : 1 +state 7526 deadlock observe4Greater1 observeIGreater1 + action 0 + 7526 : 1 +state 7527 deadlock observe1Greater1 observeIGreater1 + action 0 + 7527 : 1 +state 7528 deadlock observe2Greater1 observeIGreater1 + action 0 + 7528 : 1 +state 7529 deadlock + action 0 + 7529 : 1 +state 7530 deadlock observe4Greater1 observeIGreater1 + action 0 + 7530 : 1 +state 7531 observe3Greater1 observeIGreater1 + action 0 + 6450 : 0.833 + 6451 : 0.167 +state 7532 observe3Greater1 observeIGreater1 + action 0 + 8080 : 1 +state 7533 observe3Greater1 observeIGreater1 + action 0 + 8081 : 0.833 + 8082 : 0.167 +state 7534 observe3Greater1 observeIGreater1 + action 0 + 8083 : 1 +state 7535 observe3Greater1 observeIGreater1 + action 0 + 8084 : 0.833 + 8085 : 0.167 +state 7536 observe3Greater1 observeIGreater1 + action 0 + 8086 : 1 +state 7537 observe3Greater1 observeIGreater1 + action 0 + 8087 : 0.833 + 8088 : 0.167 +state 7538 observe3Greater1 observeIGreater1 + action 0 + 8089 : 1 +state 7539 observe3Greater1 observeIGreater1 + action 0 + 8090 : 0.833 + 8091 : 0.167 +state 7540 observe3Greater1 observeIGreater1 + action 0 + 8092 : 1 +state 7541 deadlock observe3Greater1 observeIGreater1 + action 0 + 7541 : 1 +state 7542 observe3Greater1 observeIGreater1 + action 0 + 6452 : 0.833 + 6453 : 0.167 +state 7543 observe3Greater1 observeIGreater1 + action 0 + 8093 : 1 +state 7544 observe3Greater1 observeIGreater1 + action 0 + 8094 : 0.833 + 8095 : 0.167 +state 7545 observe3Greater1 observeIGreater1 + action 0 + 8096 : 1 +state 7546 observe3Greater1 observeIGreater1 + action 0 + 8097 : 0.833 + 8098 : 0.167 +state 7547 observe3Greater1 observeIGreater1 + action 0 + 8099 : 1 +state 7548 observe3Greater1 observeIGreater1 + action 0 + 8100 : 0.833 + 8101 : 0.167 +state 7549 observe3Greater1 observeIGreater1 + action 0 + 8102 : 1 +state 7550 observe3Greater1 observeIGreater1 + action 0 + 8103 : 0.833 + 8104 : 0.167 +state 7551 observe3Greater1 observeIGreater1 + action 0 + 8105 : 1 +state 7552 deadlock observe3Greater1 observeIGreater1 + action 0 + 7552 : 1 +state 7553 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7553 : 1 +state 7554 deadlock observe3Greater1 observeIGreater1 + action 0 + 7554 : 1 +state 7555 deadlock observe3Greater1 observeIGreater1 + action 0 + 7555 : 1 +state 7556 deadlock observe3Greater1 observeIGreater1 + action 0 + 7556 : 1 +state 7557 observe4Greater1 observeIGreater1 + action 0 + 6467 : 0.833 + 6468 : 0.167 +state 7558 observe4Greater1 observeIGreater1 + action 0 + 8106 : 1 +state 7559 observe4Greater1 observeIGreater1 + action 0 + 8107 : 0.833 + 8108 : 0.167 +state 7560 observe4Greater1 observeIGreater1 + action 0 + 8109 : 1 +state 7561 observe4Greater1 observeIGreater1 + action 0 + 8110 : 0.833 + 8111 : 0.167 +state 7562 observe4Greater1 observeIGreater1 + action 0 + 8112 : 1 +state 7563 observe4Greater1 observeIGreater1 + action 0 + 8113 : 0.833 + 8114 : 0.167 +state 7564 observe4Greater1 observeIGreater1 + action 0 + 8115 : 1 +state 7565 observe4Greater1 observeIGreater1 + action 0 + 8116 : 0.833 + 8117 : 0.167 +state 7566 observe4Greater1 observeIGreater1 + action 0 + 8118 : 1 +state 7567 deadlock observe4Greater1 observeIGreater1 + action 0 + 7567 : 1 +state 7568 deadlock observe1Greater1 observeIGreater1 + action 0 + 7568 : 1 +state 7569 deadlock + action 0 + 7569 : 1 +state 7570 deadlock observe3Greater1 observeIGreater1 + action 0 + 7570 : 1 +state 7571 deadlock observe4Greater1 observeIGreater1 + action 0 + 7571 : 1 +state 7572 observe4Greater1 observeIGreater1 + action 0 + 6482 : 0.833 + 6483 : 0.167 +state 7573 observe4Greater1 observeIGreater1 + action 0 + 8119 : 1 +state 7574 observe4Greater1 observeIGreater1 + action 0 + 8120 : 0.833 + 8121 : 0.167 +state 7575 observe4Greater1 observeIGreater1 + action 0 + 8122 : 1 +state 7576 observe4Greater1 observeIGreater1 + action 0 + 8123 : 0.833 + 8124 : 0.167 +state 7577 observe4Greater1 observeIGreater1 + action 0 + 8125 : 1 +state 7578 observe4Greater1 observeIGreater1 + action 0 + 8126 : 0.833 + 8127 : 0.167 +state 7579 observe4Greater1 observeIGreater1 + action 0 + 8128 : 1 +state 7580 observe4Greater1 observeIGreater1 + action 0 + 8129 : 0.833 + 8130 : 0.167 +state 7581 observe4Greater1 observeIGreater1 + action 0 + 8131 : 1 +state 7582 deadlock observe4Greater1 observeIGreater1 + action 0 + 7582 : 1 +state 7583 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7583 : 1 +state 7584 deadlock observe4Greater1 observeIGreater1 + action 0 + 7584 : 1 +state 7585 deadlock observe4Greater1 observeIGreater1 + action 0 + 7585 : 1 +state 7586 deadlock observe4Greater1 observeIGreater1 + action 0 + 7586 : 1 +state 7587 observe2Greater1 observeIGreater1 + action 0 + 6497 : 0.833 + 6498 : 0.167 +state 7588 observe2Greater1 observeIGreater1 + action 0 + 8132 : 1 +state 7589 observe2Greater1 observeIGreater1 + action 0 + 8133 : 0.833 + 8134 : 0.167 +state 7590 observe2Greater1 observeIGreater1 + action 0 + 8135 : 1 +state 7591 observe2Greater1 observeIGreater1 + action 0 + 8136 : 0.833 + 8137 : 0.167 +state 7592 observe2Greater1 observeIGreater1 + action 0 + 8138 : 1 +state 7593 observe2Greater1 observeIGreater1 + action 0 + 8139 : 0.833 + 8140 : 0.167 +state 7594 observe2Greater1 observeIGreater1 + action 0 + 8141 : 1 +state 7595 observe2Greater1 observeIGreater1 + action 0 + 8142 : 0.833 + 8143 : 0.167 +state 7596 observe2Greater1 observeIGreater1 + action 0 + 8144 : 1 +state 7597 deadlock observe2Greater1 observeIGreater1 + action 0 + 7597 : 1 +state 7598 observe2Greater1 observeIGreater1 + action 0 + 6499 : 0.833 + 6500 : 0.167 +state 7599 observe2Greater1 observeIGreater1 + action 0 + 8145 : 1 +state 7600 observe2Greater1 observeIGreater1 + action 0 + 8146 : 0.833 + 8147 : 0.167 +state 7601 observe2Greater1 observeIGreater1 + action 0 + 8148 : 1 +state 7602 observe2Greater1 observeIGreater1 + action 0 + 8149 : 0.833 + 8150 : 0.167 +state 7603 observe2Greater1 observeIGreater1 + action 0 + 8151 : 1 +state 7604 observe2Greater1 observeIGreater1 + action 0 + 8152 : 0.833 + 8153 : 0.167 +state 7605 observe2Greater1 observeIGreater1 + action 0 + 8154 : 1 +state 7606 observe2Greater1 observeIGreater1 + action 0 + 8155 : 0.833 + 8156 : 0.167 +state 7607 observe2Greater1 observeIGreater1 + action 0 + 8157 : 1 +state 7608 deadlock observe2Greater1 observeIGreater1 + action 0 + 7608 : 1 +state 7609 observe2Greater1 observeIGreater1 + action 0 + 6501 : 0.833 + 6502 : 0.167 +state 7610 observe2Greater1 observeIGreater1 + action 0 + 8158 : 1 +state 7611 observe2Greater1 observeIGreater1 + action 0 + 8159 : 0.833 + 8160 : 0.167 +state 7612 observe2Greater1 observeIGreater1 + action 0 + 8161 : 1 +state 7613 observe2Greater1 observeIGreater1 + action 0 + 8162 : 0.833 + 8163 : 0.167 +state 7614 observe2Greater1 observeIGreater1 + action 0 + 8164 : 1 +state 7615 observe2Greater1 observeIGreater1 + action 0 + 8165 : 0.833 + 8166 : 0.167 +state 7616 observe2Greater1 observeIGreater1 + action 0 + 8167 : 1 +state 7617 observe2Greater1 observeIGreater1 + action 0 + 8168 : 0.833 + 8169 : 0.167 +state 7618 observe2Greater1 observeIGreater1 + action 0 + 8170 : 1 +state 7619 deadlock observe2Greater1 observeIGreater1 + action 0 + 7619 : 1 +state 7620 deadlock observe2Greater1 observeIGreater1 + action 0 + 7620 : 1 +state 7621 deadlock observe2Greater1 observeIGreater1 + action 0 + 7621 : 1 +state 7622 deadlock observe2Greater1 observeIGreater1 + action 0 + 7622 : 1 +state 7623 deadlock observe2Greater1 observeIGreater1 + action 0 + 7623 : 1 +state 7624 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 6516 : 0.833 + 6517 : 0.167 +state 7625 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8171 : 1 +state 7626 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8172 : 0.833 + 8173 : 0.167 +state 7627 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8174 : 1 +state 7628 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8175 : 0.833 + 8176 : 0.167 +state 7629 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8177 : 1 +state 7630 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8178 : 0.833 + 8179 : 0.167 +state 7631 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8180 : 1 +state 7632 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8181 : 0.833 + 8182 : 0.167 +state 7633 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8183 : 1 +state 7634 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7634 : 1 +state 7635 observe2Greater1 observeIGreater1 + action 0 + 6518 : 0.833 + 6519 : 0.167 +state 7636 observe2Greater1 observeIGreater1 + action 0 + 8184 : 1 +state 7637 observe2Greater1 observeIGreater1 + action 0 + 8185 : 0.833 + 8186 : 0.167 +state 7638 observe2Greater1 observeIGreater1 + action 0 + 8187 : 1 +state 7639 observe2Greater1 observeIGreater1 + action 0 + 8188 : 0.833 + 8189 : 0.167 +state 7640 observe2Greater1 observeIGreater1 + action 0 + 8190 : 1 +state 7641 observe2Greater1 observeIGreater1 + action 0 + 8191 : 0.833 + 8192 : 0.167 +state 7642 observe2Greater1 observeIGreater1 + action 0 + 8193 : 1 +state 7643 observe2Greater1 observeIGreater1 + action 0 + 8194 : 0.833 + 8195 : 0.167 +state 7644 observe2Greater1 observeIGreater1 + action 0 + 8196 : 1 +state 7645 deadlock observe2Greater1 observeIGreater1 + action 0 + 7645 : 1 +state 7646 deadlock observe2Greater1 observeIGreater1 + action 0 + 7646 : 1 +state 7647 deadlock observe2Greater1 observeIGreater1 + action 0 + 7647 : 1 +state 7648 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7648 : 1 +state 7649 deadlock observe2Greater1 observeIGreater1 + action 0 + 7649 : 1 +state 7650 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 6533 : 0.833 + 6534 : 0.167 +state 7651 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8197 : 1 +state 7652 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8198 : 0.833 + 8199 : 0.167 +state 7653 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8200 : 1 +state 7654 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8201 : 0.833 + 8202 : 0.167 +state 7655 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8203 : 1 +state 7656 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8204 : 0.833 + 8205 : 0.167 +state 7657 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8206 : 1 +state 7658 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8207 : 0.833 + 8208 : 0.167 +state 7659 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8209 : 1 +state 7660 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7660 : 1 +state 7661 deadlock observe2Greater1 observeIGreater1 + action 0 + 7661 : 1 +state 7662 deadlock observe2Greater1 observeIGreater1 + action 0 + 7662 : 1 +state 7663 deadlock observe2Greater1 observeIGreater1 + action 0 + 7663 : 1 +state 7664 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7664 : 1 +state 7665 observe3Greater1 observeIGreater1 + action 0 + 6548 : 0.833 + 6549 : 0.167 +state 7666 observe3Greater1 observeIGreater1 + action 0 + 8210 : 1 +state 7667 observe3Greater1 observeIGreater1 + action 0 + 8211 : 0.833 + 8212 : 0.167 +state 7668 observe3Greater1 observeIGreater1 + action 0 + 8213 : 1 +state 7669 observe3Greater1 observeIGreater1 + action 0 + 8214 : 0.833 + 8215 : 0.167 +state 7670 observe3Greater1 observeIGreater1 + action 0 + 8216 : 1 +state 7671 observe3Greater1 observeIGreater1 + action 0 + 8217 : 0.833 + 8218 : 0.167 +state 7672 observe3Greater1 observeIGreater1 + action 0 + 8219 : 1 +state 7673 observe3Greater1 observeIGreater1 + action 0 + 8220 : 0.833 + 8221 : 0.167 +state 7674 observe3Greater1 observeIGreater1 + action 0 + 8222 : 1 +state 7675 deadlock observe3Greater1 observeIGreater1 + action 0 + 7675 : 1 +state 7676 observe3Greater1 observeIGreater1 + action 0 + 6550 : 0.833 + 6551 : 0.167 +state 7677 observe3Greater1 observeIGreater1 + action 0 + 8223 : 1 +state 7678 observe3Greater1 observeIGreater1 + action 0 + 8224 : 0.833 + 8225 : 0.167 +state 7679 observe3Greater1 observeIGreater1 + action 0 + 8226 : 1 +state 7680 observe3Greater1 observeIGreater1 + action 0 + 8227 : 0.833 + 8228 : 0.167 +state 7681 observe3Greater1 observeIGreater1 + action 0 + 8229 : 1 +state 7682 observe3Greater1 observeIGreater1 + action 0 + 8230 : 0.833 + 8231 : 0.167 +state 7683 observe3Greater1 observeIGreater1 + action 0 + 8232 : 1 +state 7684 observe3Greater1 observeIGreater1 + action 0 + 8233 : 0.833 + 8234 : 0.167 +state 7685 observe3Greater1 observeIGreater1 + action 0 + 8235 : 1 +state 7686 deadlock observe3Greater1 observeIGreater1 + action 0 + 7686 : 1 +state 7687 deadlock observe3Greater1 observeIGreater1 + action 0 + 7687 : 1 +state 7688 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7688 : 1 +state 7689 deadlock observe3Greater1 observeIGreater1 + action 0 + 7689 : 1 +state 7690 deadlock observe3Greater1 observeIGreater1 + action 0 + 7690 : 1 +state 7691 observe4Greater1 observeIGreater1 + action 0 + 6565 : 0.833 + 6566 : 0.167 +state 7692 observe4Greater1 observeIGreater1 + action 0 + 8236 : 1 +state 7693 observe4Greater1 observeIGreater1 + action 0 + 8237 : 0.833 + 8238 : 0.167 +state 7694 observe4Greater1 observeIGreater1 + action 0 + 8239 : 1 +state 7695 observe4Greater1 observeIGreater1 + action 0 + 8240 : 0.833 + 8241 : 0.167 +state 7696 observe4Greater1 observeIGreater1 + action 0 + 8242 : 1 +state 7697 observe4Greater1 observeIGreater1 + action 0 + 8243 : 0.833 + 8244 : 0.167 +state 7698 observe4Greater1 observeIGreater1 + action 0 + 8245 : 1 +state 7699 observe4Greater1 observeIGreater1 + action 0 + 8246 : 0.833 + 8247 : 0.167 +state 7700 observe4Greater1 observeIGreater1 + action 0 + 8248 : 1 +state 7701 deadlock observe4Greater1 observeIGreater1 + action 0 + 7701 : 1 +state 7702 deadlock + action 0 + 7702 : 1 +state 7703 deadlock observe2Greater1 observeIGreater1 + action 0 + 7703 : 1 +state 7704 deadlock observe3Greater1 observeIGreater1 + action 0 + 7704 : 1 +state 7705 deadlock observe4Greater1 observeIGreater1 + action 0 + 7705 : 1 +state 7706 observe4Greater1 observeIGreater1 + action 0 + 6580 : 0.833 + 6581 : 0.167 +state 7707 observe4Greater1 observeIGreater1 + action 0 + 8249 : 1 +state 7708 observe4Greater1 observeIGreater1 + action 0 + 8250 : 0.833 + 8251 : 0.167 +state 7709 observe4Greater1 observeIGreater1 + action 0 + 8252 : 1 +state 7710 observe4Greater1 observeIGreater1 + action 0 + 8253 : 0.833 + 8254 : 0.167 +state 7711 observe4Greater1 observeIGreater1 + action 0 + 8255 : 1 +state 7712 observe4Greater1 observeIGreater1 + action 0 + 8256 : 0.833 + 8257 : 0.167 +state 7713 observe4Greater1 observeIGreater1 + action 0 + 8258 : 1 +state 7714 observe4Greater1 observeIGreater1 + action 0 + 8259 : 0.833 + 8260 : 0.167 +state 7715 observe4Greater1 observeIGreater1 + action 0 + 8261 : 1 +state 7716 deadlock observe4Greater1 observeIGreater1 + action 0 + 7716 : 1 +state 7717 deadlock observe4Greater1 observeIGreater1 + action 0 + 7717 : 1 +state 7718 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7718 : 1 +state 7719 deadlock observe4Greater1 observeIGreater1 + action 0 + 7719 : 1 +state 7720 deadlock observe4Greater1 observeIGreater1 + action 0 + 7720 : 1 +state 7721 observe3Greater1 observeIGreater1 + action 0 + 6595 : 0.833 + 6596 : 0.167 +state 7722 observe3Greater1 observeIGreater1 + action 0 + 8262 : 1 +state 7723 observe3Greater1 observeIGreater1 + action 0 + 8263 : 0.833 + 8264 : 0.167 +state 7724 observe3Greater1 observeIGreater1 + action 0 + 8265 : 1 +state 7725 observe3Greater1 observeIGreater1 + action 0 + 8266 : 0.833 + 8267 : 0.167 +state 7726 observe3Greater1 observeIGreater1 + action 0 + 8268 : 1 +state 7727 observe3Greater1 observeIGreater1 + action 0 + 8269 : 0.833 + 8270 : 0.167 +state 7728 observe3Greater1 observeIGreater1 + action 0 + 8271 : 1 +state 7729 observe3Greater1 observeIGreater1 + action 0 + 8272 : 0.833 + 8273 : 0.167 +state 7730 observe3Greater1 observeIGreater1 + action 0 + 8274 : 1 +state 7731 deadlock observe3Greater1 observeIGreater1 + action 0 + 7731 : 1 +state 7732 observe3Greater1 observeIGreater1 + action 0 + 6597 : 0.833 + 6598 : 0.167 +state 7733 observe3Greater1 observeIGreater1 + action 0 + 8275 : 1 +state 7734 observe3Greater1 observeIGreater1 + action 0 + 8276 : 0.833 + 8277 : 0.167 +state 7735 observe3Greater1 observeIGreater1 + action 0 + 8278 : 1 +state 7736 observe3Greater1 observeIGreater1 + action 0 + 8279 : 0.833 + 8280 : 0.167 +state 7737 observe3Greater1 observeIGreater1 + action 0 + 8281 : 1 +state 7738 observe3Greater1 observeIGreater1 + action 0 + 8282 : 0.833 + 8283 : 0.167 +state 7739 observe3Greater1 observeIGreater1 + action 0 + 8284 : 1 +state 7740 observe3Greater1 observeIGreater1 + action 0 + 8285 : 0.833 + 8286 : 0.167 +state 7741 observe3Greater1 observeIGreater1 + action 0 + 8287 : 1 +state 7742 deadlock observe3Greater1 observeIGreater1 + action 0 + 7742 : 1 +state 7743 deadlock observe3Greater1 observeIGreater1 + action 0 + 7743 : 1 +state 7744 deadlock observe3Greater1 observeIGreater1 + action 0 + 7744 : 1 +state 7745 deadlock observe3Greater1 observeIGreater1 + action 0 + 7745 : 1 +state 7746 deadlock observe3Greater1 observeIGreater1 + action 0 + 7746 : 1 +state 7747 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 6612 : 0.833 + 6613 : 0.167 +state 7748 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8288 : 1 +state 7749 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8289 : 0.833 + 8290 : 0.167 +state 7750 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8291 : 1 +state 7751 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8292 : 0.833 + 8293 : 0.167 +state 7752 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8294 : 1 +state 7753 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8295 : 0.833 + 8296 : 0.167 +state 7754 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8297 : 1 +state 7755 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8298 : 0.833 + 8299 : 0.167 +state 7756 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8300 : 1 +state 7757 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7757 : 1 +state 7758 deadlock observe3Greater1 observeIGreater1 + action 0 + 7758 : 1 +state 7759 deadlock observe3Greater1 observeIGreater1 + action 0 + 7759 : 1 +state 7760 deadlock observe3Greater1 observeIGreater1 + action 0 + 7760 : 1 +state 7761 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7761 : 1 +state 7762 observe4Greater1 observeIGreater1 + action 0 + 6627 : 0.833 + 6628 : 0.167 +state 7763 observe4Greater1 observeIGreater1 + action 0 + 8301 : 1 +state 7764 observe4Greater1 observeIGreater1 + action 0 + 8302 : 0.833 + 8303 : 0.167 +state 7765 observe4Greater1 observeIGreater1 + action 0 + 8304 : 1 +state 7766 observe4Greater1 observeIGreater1 + action 0 + 8305 : 0.833 + 8306 : 0.167 +state 7767 observe4Greater1 observeIGreater1 + action 0 + 8307 : 1 +state 7768 observe4Greater1 observeIGreater1 + action 0 + 8308 : 0.833 + 8309 : 0.167 +state 7769 observe4Greater1 observeIGreater1 + action 0 + 8310 : 1 +state 7770 observe4Greater1 observeIGreater1 + action 0 + 8311 : 0.833 + 8312 : 0.167 +state 7771 observe4Greater1 observeIGreater1 + action 0 + 8313 : 1 +state 7772 deadlock observe4Greater1 observeIGreater1 + action 0 + 7772 : 1 +state 7773 deadlock observe4Greater1 observeIGreater1 + action 0 + 7773 : 1 +state 7774 deadlock observe4Greater1 observeIGreater1 + action 0 + 7774 : 1 +state 7775 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7775 : 1 +state 7776 deadlock observe4Greater1 observeIGreater1 + action 0 + 7776 : 1 +state 7777 observe4Greater1 observeIGreater1 + action 0 + 6642 : 0.833 + 6643 : 0.167 +state 7778 observe4Greater1 observeIGreater1 + action 0 + 8314 : 1 +state 7779 observe4Greater1 observeIGreater1 + action 0 + 8315 : 0.833 + 8316 : 0.167 +state 7780 observe4Greater1 observeIGreater1 + action 0 + 8317 : 1 +state 7781 observe4Greater1 observeIGreater1 + action 0 + 8318 : 0.833 + 8319 : 0.167 +state 7782 observe4Greater1 observeIGreater1 + action 0 + 8320 : 1 +state 7783 observe4Greater1 observeIGreater1 + action 0 + 8321 : 0.833 + 8322 : 0.167 +state 7784 observe4Greater1 observeIGreater1 + action 0 + 8323 : 1 +state 7785 observe4Greater1 observeIGreater1 + action 0 + 8324 : 0.833 + 8325 : 0.167 +state 7786 observe4Greater1 observeIGreater1 + action 0 + 8326 : 1 +state 7787 deadlock observe4Greater1 observeIGreater1 + action 0 + 7787 : 1 +state 7788 deadlock observe4Greater1 observeIGreater1 + action 0 + 7788 : 1 +state 7789 deadlock observe4Greater1 observeIGreater1 + action 0 + 7789 : 1 +state 7790 deadlock observe4Greater1 observeIGreater1 + action 0 + 7790 : 1 +state 7791 deadlock observe4Greater1 observeIGreater1 + action 0 + 7791 : 1 +state 7792 deadlock observe1Greater1 observeIGreater1 + action 0 + 7792 : 1 +state 7793 deadlock observe1Greater1 observeIGreater1 + action 0 + 7793 : 1 +state 7794 deadlock observe1Greater1 observeIGreater1 + action 0 + 7794 : 1 +state 7795 deadlock observe1Greater1 observeIGreater1 + action 0 + 7795 : 1 +state 7796 deadlock observe1Greater1 observeIGreater1 + action 0 + 7796 : 1 +state 7797 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7797 : 1 +state 7798 deadlock observe1Greater1 observeIGreater1 + action 0 + 7798 : 1 +state 7799 deadlock observe1Greater1 observeIGreater1 + action 0 + 7799 : 1 +state 7800 deadlock observe1Greater1 observeIGreater1 + action 0 + 7800 : 1 +state 7801 deadlock observe1Greater1 observeIGreater1 + action 0 + 7801 : 1 +state 7802 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7802 : 1 +state 7803 deadlock observe1Greater1 observeIGreater1 + action 0 + 7803 : 1 +state 7804 deadlock observe1Greater1 observeIGreater1 + action 0 + 7804 : 1 +state 7805 deadlock observe1Greater1 observeIGreater1 + action 0 + 7805 : 1 +state 7806 deadlock observe1Greater1 observeIGreater1 + action 0 + 7806 : 1 +state 7807 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7807 : 1 +state 7808 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7808 : 1 +state 7809 deadlock observe2Greater1 observeIGreater1 + action 0 + 7809 : 1 +state 7810 deadlock observe2Greater1 observeIGreater1 + action 0 + 7810 : 1 +state 7811 deadlock observe2Greater1 observeIGreater1 + action 0 + 7811 : 1 +state 7812 deadlock observe1Greater1 observeIGreater1 + action 0 + 7812 : 1 +state 7813 deadlock observe2Greater1 observeIGreater1 + action 0 + 7813 : 1 +state 7814 deadlock observe3Greater1 observeIGreater1 + action 0 + 7814 : 1 +state 7815 deadlock + action 0 + 7815 : 1 +state 7816 deadlock observe1Greater1 observeIGreater1 + action 0 + 7816 : 1 +state 7817 deadlock observe2Greater1 observeIGreater1 + action 0 + 7817 : 1 +state 7818 deadlock + action 0 + 7818 : 1 +state 7819 deadlock observe4Greater1 observeIGreater1 + action 0 + 7819 : 1 +state 7820 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7820 : 1 +state 7821 deadlock observe3Greater1 observeIGreater1 + action 0 + 7821 : 1 +state 7822 deadlock observe3Greater1 observeIGreater1 + action 0 + 7822 : 1 +state 7823 deadlock observe3Greater1 observeIGreater1 + action 0 + 7823 : 1 +state 7824 deadlock observe1Greater1 observeIGreater1 + action 0 + 7824 : 1 +state 7825 deadlock + action 0 + 7825 : 1 +state 7826 deadlock observe3Greater1 observeIGreater1 + action 0 + 7826 : 1 +state 7827 deadlock observe4Greater1 observeIGreater1 + action 0 + 7827 : 1 +state 7828 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7828 : 1 +state 7829 deadlock observe4Greater1 observeIGreater1 + action 0 + 7829 : 1 +state 7830 deadlock observe4Greater1 observeIGreater1 + action 0 + 7830 : 1 +state 7831 deadlock observe4Greater1 observeIGreater1 + action 0 + 7831 : 1 +state 7832 deadlock observe2Greater1 observeIGreater1 + action 0 + 7832 : 1 +state 7833 deadlock observe2Greater1 observeIGreater1 + action 0 + 7833 : 1 +state 7834 deadlock observe2Greater1 observeIGreater1 + action 0 + 7834 : 1 +state 7835 deadlock observe2Greater1 observeIGreater1 + action 0 + 7835 : 1 +state 7836 deadlock observe2Greater1 observeIGreater1 + action 0 + 7836 : 1 +state 7837 deadlock observe2Greater1 observeIGreater1 + action 0 + 7837 : 1 +state 7838 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7838 : 1 +state 7839 deadlock observe2Greater1 observeIGreater1 + action 0 + 7839 : 1 +state 7840 deadlock observe2Greater1 observeIGreater1 + action 0 + 7840 : 1 +state 7841 deadlock observe2Greater1 observeIGreater1 + action 0 + 7841 : 1 +state 7842 deadlock observe2Greater1 observeIGreater1 + action 0 + 7842 : 1 +state 7843 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7843 : 1 +state 7844 deadlock observe3Greater1 observeIGreater1 + action 0 + 7844 : 1 +state 7845 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7845 : 1 +state 7846 deadlock observe3Greater1 observeIGreater1 + action 0 + 7846 : 1 +state 7847 deadlock observe3Greater1 observeIGreater1 + action 0 + 7847 : 1 +state 7848 deadlock + action 0 + 7848 : 1 +state 7849 deadlock observe2Greater1 observeIGreater1 + action 0 + 7849 : 1 +state 7850 deadlock observe3Greater1 observeIGreater1 + action 0 + 7850 : 1 +state 7851 deadlock observe4Greater1 observeIGreater1 + action 0 + 7851 : 1 +state 7852 deadlock observe4Greater1 observeIGreater1 + action 0 + 7852 : 1 +state 7853 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7853 : 1 +state 7854 deadlock observe4Greater1 observeIGreater1 + action 0 + 7854 : 1 +state 7855 deadlock observe4Greater1 observeIGreater1 + action 0 + 7855 : 1 +state 7856 deadlock observe3Greater1 observeIGreater1 + action 0 + 7856 : 1 +state 7857 deadlock observe3Greater1 observeIGreater1 + action 0 + 7857 : 1 +state 7858 deadlock observe3Greater1 observeIGreater1 + action 0 + 7858 : 1 +state 7859 deadlock observe3Greater1 observeIGreater1 + action 0 + 7859 : 1 +state 7860 deadlock observe3Greater1 observeIGreater1 + action 0 + 7860 : 1 +state 7861 deadlock observe3Greater1 observeIGreater1 + action 0 + 7861 : 1 +state 7862 deadlock observe3Greater1 observeIGreater1 + action 0 + 7862 : 1 +state 7863 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7863 : 1 +state 7864 deadlock observe4Greater1 observeIGreater1 + action 0 + 7864 : 1 +state 7865 deadlock observe4Greater1 observeIGreater1 + action 0 + 7865 : 1 +state 7866 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7866 : 1 +state 7867 deadlock observe4Greater1 observeIGreater1 + action 0 + 7867 : 1 +state 7868 deadlock observe4Greater1 observeIGreater1 + action 0 + 7868 : 1 +state 7869 deadlock observe4Greater1 observeIGreater1 + action 0 + 7869 : 1 +state 7870 deadlock observe4Greater1 observeIGreater1 + action 0 + 7870 : 1 +state 7871 deadlock observe4Greater1 observeIGreater1 + action 0 + 7871 : 1 +state 7872 deadlock observe1Greater1 observeIGreater1 + action 0 + 7872 : 1 +state 7873 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7874 observe1Greater1 observeIGreater1 + action 0 + 8327 : 1 +state 7875 deadlock observe1Greater1 observeIGreater1 + action 0 + 7875 : 1 +state 7876 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7877 observe1Greater1 observeIGreater1 + action 0 + 8328 : 1 +state 7878 deadlock observe1Greater1 observeIGreater1 + action 0 + 7878 : 1 +state 7879 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7880 observe1Greater1 observeIGreater1 + action 0 + 8329 : 1 +state 7881 deadlock observe1Greater1 observeIGreater1 + action 0 + 7881 : 1 +state 7882 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7883 observe1Greater1 observeIGreater1 + action 0 + 8330 : 1 +state 7884 deadlock observe1Greater1 observeIGreater1 + action 0 + 7884 : 1 +state 7885 deadlock observe1Greater1 observeIGreater1 + action 0 + 7885 : 1 +state 7886 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7887 observe1Greater1 observeIGreater1 + action 0 + 8331 : 1 +state 7888 deadlock observe1Greater1 observeIGreater1 + action 0 + 7888 : 1 +state 7889 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7890 observe1Greater1 observeIGreater1 + action 0 + 8332 : 1 +state 7891 deadlock observe1Greater1 observeIGreater1 + action 0 + 7891 : 1 +state 7892 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7893 observe1Greater1 observeIGreater1 + action 0 + 8333 : 1 +state 7894 deadlock observe1Greater1 observeIGreater1 + action 0 + 7894 : 1 +state 7895 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7896 observe1Greater1 observeIGreater1 + action 0 + 8334 : 1 +state 7897 deadlock observe1Greater1 observeIGreater1 + action 0 + 7897 : 1 +state 7898 deadlock observe1Greater1 observeIGreater1 + action 0 + 7898 : 1 +state 7899 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7900 observe1Greater1 observeIGreater1 + action 0 + 8335 : 1 +state 7901 deadlock observe1Greater1 observeIGreater1 + action 0 + 7901 : 1 +state 7902 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7903 observe1Greater1 observeIGreater1 + action 0 + 8336 : 1 +state 7904 deadlock observe1Greater1 observeIGreater1 + action 0 + 7904 : 1 +state 7905 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7906 observe1Greater1 observeIGreater1 + action 0 + 8337 : 1 +state 7907 deadlock observe1Greater1 observeIGreater1 + action 0 + 7907 : 1 +state 7908 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7909 observe1Greater1 observeIGreater1 + action 0 + 8338 : 1 +state 7910 deadlock observe1Greater1 observeIGreater1 + action 0 + 7910 : 1 +state 7911 deadlock observe1Greater1 observeIGreater1 + action 0 + 7911 : 1 +state 7912 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7913 observe1Greater1 observeIGreater1 + action 0 + 8339 : 1 +state 7914 deadlock observe1Greater1 observeIGreater1 + action 0 + 7914 : 1 +state 7915 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7916 observe1Greater1 observeIGreater1 + action 0 + 8340 : 1 +state 7917 deadlock observe1Greater1 observeIGreater1 + action 0 + 7917 : 1 +state 7918 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7919 observe1Greater1 observeIGreater1 + action 0 + 8341 : 1 +state 7920 deadlock observe1Greater1 observeIGreater1 + action 0 + 7920 : 1 +state 7921 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7922 observe1Greater1 observeIGreater1 + action 0 + 8342 : 1 +state 7923 deadlock observe1Greater1 observeIGreater1 + action 0 + 7923 : 1 +state 7924 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7924 : 1 +state 7925 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7926 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8343 : 1 +state 7927 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7927 : 1 +state 7928 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7929 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8344 : 1 +state 7930 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7930 : 1 +state 7931 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7932 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8345 : 1 +state 7933 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7933 : 1 +state 7934 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7935 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8346 : 1 +state 7936 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7936 : 1 +state 7937 deadlock observe1Greater1 observeIGreater1 + action 0 + 7937 : 1 +state 7938 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7939 observe1Greater1 observeIGreater1 + action 0 + 8347 : 1 +state 7940 deadlock observe1Greater1 observeIGreater1 + action 0 + 7940 : 1 +state 7941 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7942 observe1Greater1 observeIGreater1 + action 0 + 8348 : 1 +state 7943 deadlock observe1Greater1 observeIGreater1 + action 0 + 7943 : 1 +state 7944 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7945 observe1Greater1 observeIGreater1 + action 0 + 8349 : 1 +state 7946 deadlock observe1Greater1 observeIGreater1 + action 0 + 7946 : 1 +state 7947 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7948 observe1Greater1 observeIGreater1 + action 0 + 8350 : 1 +state 7949 deadlock observe1Greater1 observeIGreater1 + action 0 + 7949 : 1 +state 7950 deadlock observe1Greater1 observeIGreater1 + action 0 + 7950 : 1 +state 7951 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7952 observe1Greater1 observeIGreater1 + action 0 + 8351 : 1 +state 7953 deadlock observe1Greater1 observeIGreater1 + action 0 + 7953 : 1 +state 7954 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7955 observe1Greater1 observeIGreater1 + action 0 + 8352 : 1 +state 7956 deadlock observe1Greater1 observeIGreater1 + action 0 + 7956 : 1 +state 7957 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7958 observe1Greater1 observeIGreater1 + action 0 + 8353 : 1 +state 7959 deadlock observe1Greater1 observeIGreater1 + action 0 + 7959 : 1 +state 7960 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7961 observe1Greater1 observeIGreater1 + action 0 + 8354 : 1 +state 7962 deadlock observe1Greater1 observeIGreater1 + action 0 + 7962 : 1 +state 7963 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7963 : 1 +state 7964 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7965 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8355 : 1 +state 7966 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7966 : 1 +state 7967 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7968 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8356 : 1 +state 7969 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7969 : 1 +state 7970 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7971 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8357 : 1 +state 7972 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7972 : 1 +state 7973 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7974 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8358 : 1 +state 7975 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7975 : 1 +state 7976 deadlock observe1Greater1 observeIGreater1 + action 0 + 7976 : 1 +state 7977 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7978 observe1Greater1 observeIGreater1 + action 0 + 8359 : 1 +state 7979 deadlock observe1Greater1 observeIGreater1 + action 0 + 7979 : 1 +state 7980 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7981 observe1Greater1 observeIGreater1 + action 0 + 8360 : 1 +state 7982 deadlock observe1Greater1 observeIGreater1 + action 0 + 7982 : 1 +state 7983 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7984 observe1Greater1 observeIGreater1 + action 0 + 8361 : 1 +state 7985 deadlock observe1Greater1 observeIGreater1 + action 0 + 7985 : 1 +state 7986 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7987 observe1Greater1 observeIGreater1 + action 0 + 8362 : 1 +state 7988 deadlock observe1Greater1 observeIGreater1 + action 0 + 7988 : 1 +state 7989 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7989 : 1 +state 7990 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7991 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8363 : 1 +state 7992 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7992 : 1 +state 7993 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7994 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8364 : 1 +state 7995 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7995 : 1 +state 7996 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7997 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8365 : 1 +state 7998 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7998 : 1 +state 7999 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 8000 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8366 : 1 +state 8001 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8001 : 1 +state 8002 deadlock observe2Greater1 observeIGreater1 + action 0 + 8002 : 1 +state 8003 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8004 observe2Greater1 observeIGreater1 + action 0 + 8367 : 1 +state 8005 deadlock observe2Greater1 observeIGreater1 + action 0 + 8005 : 1 +state 8006 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8007 observe2Greater1 observeIGreater1 + action 0 + 8368 : 1 +state 8008 deadlock observe2Greater1 observeIGreater1 + action 0 + 8008 : 1 +state 8009 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8010 observe2Greater1 observeIGreater1 + action 0 + 8369 : 1 +state 8011 deadlock observe2Greater1 observeIGreater1 + action 0 + 8011 : 1 +state 8012 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8013 observe2Greater1 observeIGreater1 + action 0 + 8370 : 1 +state 8014 deadlock observe2Greater1 observeIGreater1 + action 0 + 8014 : 1 +state 8015 deadlock observe2Greater1 observeIGreater1 + action 0 + 8015 : 1 +state 8016 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8017 observe2Greater1 observeIGreater1 + action 0 + 8371 : 1 +state 8018 deadlock observe2Greater1 observeIGreater1 + action 0 + 8018 : 1 +state 8019 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8020 observe2Greater1 observeIGreater1 + action 0 + 8372 : 1 +state 8021 deadlock observe2Greater1 observeIGreater1 + action 0 + 8021 : 1 +state 8022 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8023 observe2Greater1 observeIGreater1 + action 0 + 8373 : 1 +state 8024 deadlock observe2Greater1 observeIGreater1 + action 0 + 8024 : 1 +state 8025 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8026 observe2Greater1 observeIGreater1 + action 0 + 8374 : 1 +state 8027 deadlock observe2Greater1 observeIGreater1 + action 0 + 8027 : 1 +state 8028 deadlock observe2Greater1 observeIGreater1 + action 0 + 8028 : 1 +state 8029 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8030 observe2Greater1 observeIGreater1 + action 0 + 8375 : 1 +state 8031 deadlock observe2Greater1 observeIGreater1 + action 0 + 8031 : 1 +state 8032 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8033 observe2Greater1 observeIGreater1 + action 0 + 8376 : 1 +state 8034 deadlock observe2Greater1 observeIGreater1 + action 0 + 8034 : 1 +state 8035 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8036 observe2Greater1 observeIGreater1 + action 0 + 8377 : 1 +state 8037 deadlock observe2Greater1 observeIGreater1 + action 0 + 8037 : 1 +state 8038 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8039 observe2Greater1 observeIGreater1 + action 0 + 8378 : 1 +state 8040 deadlock observe2Greater1 observeIGreater1 + action 0 + 8040 : 1 +state 8041 deadlock observe3Greater1 observeIGreater1 + action 0 + 8041 : 1 +state 8042 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8043 observe3Greater1 observeIGreater1 + action 0 + 8379 : 1 +state 8044 deadlock observe3Greater1 observeIGreater1 + action 0 + 8044 : 1 +state 8045 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8046 observe3Greater1 observeIGreater1 + action 0 + 8380 : 1 +state 8047 deadlock observe3Greater1 observeIGreater1 + action 0 + 8047 : 1 +state 8048 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8049 observe3Greater1 observeIGreater1 + action 0 + 8381 : 1 +state 8050 deadlock observe3Greater1 observeIGreater1 + action 0 + 8050 : 1 +state 8051 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8052 observe3Greater1 observeIGreater1 + action 0 + 8382 : 1 +state 8053 deadlock observe3Greater1 observeIGreater1 + action 0 + 8053 : 1 +state 8054 deadlock + action 0 + 8054 : 1 +state 8055 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8056 + action 0 + 8383 : 1 +state 8057 deadlock + action 0 + 8057 : 1 +state 8058 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8059 + action 0 + 8384 : 1 +state 8060 deadlock + action 0 + 8060 : 1 +state 8061 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8062 + action 0 + 8385 : 1 +state 8063 deadlock + action 0 + 8063 : 1 +state 8064 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8065 + action 0 + 8386 : 1 +state 8066 deadlock + action 0 + 8066 : 1 +state 8067 deadlock observe4Greater1 observeIGreater1 + action 0 + 8067 : 1 +state 8068 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8069 observe4Greater1 observeIGreater1 + action 0 + 8387 : 1 +state 8070 deadlock observe4Greater1 observeIGreater1 + action 0 + 8070 : 1 +state 8071 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8072 observe4Greater1 observeIGreater1 + action 0 + 8388 : 1 +state 8073 deadlock observe4Greater1 observeIGreater1 + action 0 + 8073 : 1 +state 8074 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8075 observe4Greater1 observeIGreater1 + action 0 + 8389 : 1 +state 8076 deadlock observe4Greater1 observeIGreater1 + action 0 + 8076 : 1 +state 8077 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8078 observe4Greater1 observeIGreater1 + action 0 + 8390 : 1 +state 8079 deadlock observe4Greater1 observeIGreater1 + action 0 + 8079 : 1 +state 8080 deadlock observe3Greater1 observeIGreater1 + action 0 + 8080 : 1 +state 8081 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8082 observe3Greater1 observeIGreater1 + action 0 + 8391 : 1 +state 8083 deadlock observe3Greater1 observeIGreater1 + action 0 + 8083 : 1 +state 8084 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8085 observe3Greater1 observeIGreater1 + action 0 + 8392 : 1 +state 8086 deadlock observe3Greater1 observeIGreater1 + action 0 + 8086 : 1 +state 8087 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8088 observe3Greater1 observeIGreater1 + action 0 + 8393 : 1 +state 8089 deadlock observe3Greater1 observeIGreater1 + action 0 + 8089 : 1 +state 8090 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8091 observe3Greater1 observeIGreater1 + action 0 + 8394 : 1 +state 8092 deadlock observe3Greater1 observeIGreater1 + action 0 + 8092 : 1 +state 8093 deadlock observe3Greater1 observeIGreater1 + action 0 + 8093 : 1 +state 8094 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8095 observe3Greater1 observeIGreater1 + action 0 + 8395 : 1 +state 8096 deadlock observe3Greater1 observeIGreater1 + action 0 + 8096 : 1 +state 8097 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8098 observe3Greater1 observeIGreater1 + action 0 + 8396 : 1 +state 8099 deadlock observe3Greater1 observeIGreater1 + action 0 + 8099 : 1 +state 8100 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8101 observe3Greater1 observeIGreater1 + action 0 + 8397 : 1 +state 8102 deadlock observe3Greater1 observeIGreater1 + action 0 + 8102 : 1 +state 8103 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8104 observe3Greater1 observeIGreater1 + action 0 + 8398 : 1 +state 8105 deadlock observe3Greater1 observeIGreater1 + action 0 + 8105 : 1 +state 8106 deadlock observe4Greater1 observeIGreater1 + action 0 + 8106 : 1 +state 8107 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8108 observe4Greater1 observeIGreater1 + action 0 + 8399 : 1 +state 8109 deadlock observe4Greater1 observeIGreater1 + action 0 + 8109 : 1 +state 8110 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8111 observe4Greater1 observeIGreater1 + action 0 + 8400 : 1 +state 8112 deadlock observe4Greater1 observeIGreater1 + action 0 + 8112 : 1 +state 8113 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8114 observe4Greater1 observeIGreater1 + action 0 + 8401 : 1 +state 8115 deadlock observe4Greater1 observeIGreater1 + action 0 + 8115 : 1 +state 8116 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8117 observe4Greater1 observeIGreater1 + action 0 + 8402 : 1 +state 8118 deadlock observe4Greater1 observeIGreater1 + action 0 + 8118 : 1 +state 8119 deadlock observe4Greater1 observeIGreater1 + action 0 + 8119 : 1 +state 8120 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8121 observe4Greater1 observeIGreater1 + action 0 + 8403 : 1 +state 8122 deadlock observe4Greater1 observeIGreater1 + action 0 + 8122 : 1 +state 8123 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8124 observe4Greater1 observeIGreater1 + action 0 + 8404 : 1 +state 8125 deadlock observe4Greater1 observeIGreater1 + action 0 + 8125 : 1 +state 8126 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8127 observe4Greater1 observeIGreater1 + action 0 + 8405 : 1 +state 8128 deadlock observe4Greater1 observeIGreater1 + action 0 + 8128 : 1 +state 8129 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8130 observe4Greater1 observeIGreater1 + action 0 + 8406 : 1 +state 8131 deadlock observe4Greater1 observeIGreater1 + action 0 + 8131 : 1 +state 8132 deadlock observe2Greater1 observeIGreater1 + action 0 + 8132 : 1 +state 8133 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8134 observe2Greater1 observeIGreater1 + action 0 + 8407 : 1 +state 8135 deadlock observe2Greater1 observeIGreater1 + action 0 + 8135 : 1 +state 8136 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8137 observe2Greater1 observeIGreater1 + action 0 + 8408 : 1 +state 8138 deadlock observe2Greater1 observeIGreater1 + action 0 + 8138 : 1 +state 8139 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8140 observe2Greater1 observeIGreater1 + action 0 + 8409 : 1 +state 8141 deadlock observe2Greater1 observeIGreater1 + action 0 + 8141 : 1 +state 8142 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8143 observe2Greater1 observeIGreater1 + action 0 + 8410 : 1 +state 8144 deadlock observe2Greater1 observeIGreater1 + action 0 + 8144 : 1 +state 8145 deadlock observe2Greater1 observeIGreater1 + action 0 + 8145 : 1 +state 8146 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8147 observe2Greater1 observeIGreater1 + action 0 + 8411 : 1 +state 8148 deadlock observe2Greater1 observeIGreater1 + action 0 + 8148 : 1 +state 8149 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8150 observe2Greater1 observeIGreater1 + action 0 + 8412 : 1 +state 8151 deadlock observe2Greater1 observeIGreater1 + action 0 + 8151 : 1 +state 8152 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8153 observe2Greater1 observeIGreater1 + action 0 + 8413 : 1 +state 8154 deadlock observe2Greater1 observeIGreater1 + action 0 + 8154 : 1 +state 8155 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8156 observe2Greater1 observeIGreater1 + action 0 + 8414 : 1 +state 8157 deadlock observe2Greater1 observeIGreater1 + action 0 + 8157 : 1 +state 8158 deadlock observe2Greater1 observeIGreater1 + action 0 + 8158 : 1 +state 8159 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8160 observe2Greater1 observeIGreater1 + action 0 + 8415 : 1 +state 8161 deadlock observe2Greater1 observeIGreater1 + action 0 + 8161 : 1 +state 8162 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8163 observe2Greater1 observeIGreater1 + action 0 + 8416 : 1 +state 8164 deadlock observe2Greater1 observeIGreater1 + action 0 + 8164 : 1 +state 8165 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8166 observe2Greater1 observeIGreater1 + action 0 + 8417 : 1 +state 8167 deadlock observe2Greater1 observeIGreater1 + action 0 + 8167 : 1 +state 8168 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8169 observe2Greater1 observeIGreater1 + action 0 + 8418 : 1 +state 8170 deadlock observe2Greater1 observeIGreater1 + action 0 + 8170 : 1 +state 8171 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8171 : 1 +state 8172 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8173 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8419 : 1 +state 8174 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8174 : 1 +state 8175 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8176 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8420 : 1 +state 8177 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8177 : 1 +state 8178 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8179 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8421 : 1 +state 8180 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8180 : 1 +state 8181 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8182 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8422 : 1 +state 8183 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8183 : 1 +state 8184 deadlock observe2Greater1 observeIGreater1 + action 0 + 8184 : 1 +state 8185 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8186 observe2Greater1 observeIGreater1 + action 0 + 8423 : 1 +state 8187 deadlock observe2Greater1 observeIGreater1 + action 0 + 8187 : 1 +state 8188 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8189 observe2Greater1 observeIGreater1 + action 0 + 8424 : 1 +state 8190 deadlock observe2Greater1 observeIGreater1 + action 0 + 8190 : 1 +state 8191 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8192 observe2Greater1 observeIGreater1 + action 0 + 8425 : 1 +state 8193 deadlock observe2Greater1 observeIGreater1 + action 0 + 8193 : 1 +state 8194 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8195 observe2Greater1 observeIGreater1 + action 0 + 8426 : 1 +state 8196 deadlock observe2Greater1 observeIGreater1 + action 0 + 8196 : 1 +state 8197 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8197 : 1 +state 8198 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8199 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8427 : 1 +state 8200 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8200 : 1 +state 8201 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8202 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8428 : 1 +state 8203 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8203 : 1 +state 8204 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8205 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8429 : 1 +state 8206 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8206 : 1 +state 8207 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8208 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8430 : 1 +state 8209 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8209 : 1 +state 8210 deadlock observe3Greater1 observeIGreater1 + action 0 + 8210 : 1 +state 8211 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8212 observe3Greater1 observeIGreater1 + action 0 + 8431 : 1 +state 8213 deadlock observe3Greater1 observeIGreater1 + action 0 + 8213 : 1 +state 8214 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8215 observe3Greater1 observeIGreater1 + action 0 + 8432 : 1 +state 8216 deadlock observe3Greater1 observeIGreater1 + action 0 + 8216 : 1 +state 8217 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8218 observe3Greater1 observeIGreater1 + action 0 + 8433 : 1 +state 8219 deadlock observe3Greater1 observeIGreater1 + action 0 + 8219 : 1 +state 8220 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8221 observe3Greater1 observeIGreater1 + action 0 + 8434 : 1 +state 8222 deadlock observe3Greater1 observeIGreater1 + action 0 + 8222 : 1 +state 8223 deadlock observe3Greater1 observeIGreater1 + action 0 + 8223 : 1 +state 8224 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8225 observe3Greater1 observeIGreater1 + action 0 + 8435 : 1 +state 8226 deadlock observe3Greater1 observeIGreater1 + action 0 + 8226 : 1 +state 8227 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8228 observe3Greater1 observeIGreater1 + action 0 + 8436 : 1 +state 8229 deadlock observe3Greater1 observeIGreater1 + action 0 + 8229 : 1 +state 8230 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8231 observe3Greater1 observeIGreater1 + action 0 + 8437 : 1 +state 8232 deadlock observe3Greater1 observeIGreater1 + action 0 + 8232 : 1 +state 8233 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8234 observe3Greater1 observeIGreater1 + action 0 + 8438 : 1 +state 8235 deadlock observe3Greater1 observeIGreater1 + action 0 + 8235 : 1 +state 8236 deadlock observe4Greater1 observeIGreater1 + action 0 + 8236 : 1 +state 8237 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8238 observe4Greater1 observeIGreater1 + action 0 + 8439 : 1 +state 8239 deadlock observe4Greater1 observeIGreater1 + action 0 + 8239 : 1 +state 8240 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8241 observe4Greater1 observeIGreater1 + action 0 + 8440 : 1 +state 8242 deadlock observe4Greater1 observeIGreater1 + action 0 + 8242 : 1 +state 8243 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8244 observe4Greater1 observeIGreater1 + action 0 + 8441 : 1 +state 8245 deadlock observe4Greater1 observeIGreater1 + action 0 + 8245 : 1 +state 8246 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8247 observe4Greater1 observeIGreater1 + action 0 + 8442 : 1 +state 8248 deadlock observe4Greater1 observeIGreater1 + action 0 + 8248 : 1 +state 8249 deadlock observe4Greater1 observeIGreater1 + action 0 + 8249 : 1 +state 8250 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8251 observe4Greater1 observeIGreater1 + action 0 + 8443 : 1 +state 8252 deadlock observe4Greater1 observeIGreater1 + action 0 + 8252 : 1 +state 8253 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8254 observe4Greater1 observeIGreater1 + action 0 + 8444 : 1 +state 8255 deadlock observe4Greater1 observeIGreater1 + action 0 + 8255 : 1 +state 8256 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8257 observe4Greater1 observeIGreater1 + action 0 + 8445 : 1 +state 8258 deadlock observe4Greater1 observeIGreater1 + action 0 + 8258 : 1 +state 8259 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8260 observe4Greater1 observeIGreater1 + action 0 + 8446 : 1 +state 8261 deadlock observe4Greater1 observeIGreater1 + action 0 + 8261 : 1 +state 8262 deadlock observe3Greater1 observeIGreater1 + action 0 + 8262 : 1 +state 8263 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8264 observe3Greater1 observeIGreater1 + action 0 + 8447 : 1 +state 8265 deadlock observe3Greater1 observeIGreater1 + action 0 + 8265 : 1 +state 8266 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8267 observe3Greater1 observeIGreater1 + action 0 + 8448 : 1 +state 8268 deadlock observe3Greater1 observeIGreater1 + action 0 + 8268 : 1 +state 8269 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8270 observe3Greater1 observeIGreater1 + action 0 + 8449 : 1 +state 8271 deadlock observe3Greater1 observeIGreater1 + action 0 + 8271 : 1 +state 8272 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8273 observe3Greater1 observeIGreater1 + action 0 + 8450 : 1 +state 8274 deadlock observe3Greater1 observeIGreater1 + action 0 + 8274 : 1 +state 8275 deadlock observe3Greater1 observeIGreater1 + action 0 + 8275 : 1 +state 8276 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8277 observe3Greater1 observeIGreater1 + action 0 + 8451 : 1 +state 8278 deadlock observe3Greater1 observeIGreater1 + action 0 + 8278 : 1 +state 8279 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8280 observe3Greater1 observeIGreater1 + action 0 + 8452 : 1 +state 8281 deadlock observe3Greater1 observeIGreater1 + action 0 + 8281 : 1 +state 8282 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8283 observe3Greater1 observeIGreater1 + action 0 + 8453 : 1 +state 8284 deadlock observe3Greater1 observeIGreater1 + action 0 + 8284 : 1 +state 8285 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8286 observe3Greater1 observeIGreater1 + action 0 + 8454 : 1 +state 8287 deadlock observe3Greater1 observeIGreater1 + action 0 + 8287 : 1 +state 8288 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8288 : 1 +state 8289 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8290 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8455 : 1 +state 8291 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8291 : 1 +state 8292 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8293 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8456 : 1 +state 8294 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8294 : 1 +state 8295 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8296 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8457 : 1 +state 8297 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8297 : 1 +state 8298 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8299 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8458 : 1 +state 8300 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8300 : 1 +state 8301 deadlock observe4Greater1 observeIGreater1 + action 0 + 8301 : 1 +state 8302 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8303 observe4Greater1 observeIGreater1 + action 0 + 8459 : 1 +state 8304 deadlock observe4Greater1 observeIGreater1 + action 0 + 8304 : 1 +state 8305 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8306 observe4Greater1 observeIGreater1 + action 0 + 8460 : 1 +state 8307 deadlock observe4Greater1 observeIGreater1 + action 0 + 8307 : 1 +state 8308 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8309 observe4Greater1 observeIGreater1 + action 0 + 8461 : 1 +state 8310 deadlock observe4Greater1 observeIGreater1 + action 0 + 8310 : 1 +state 8311 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8312 observe4Greater1 observeIGreater1 + action 0 + 8462 : 1 +state 8313 deadlock observe4Greater1 observeIGreater1 + action 0 + 8313 : 1 +state 8314 deadlock observe4Greater1 observeIGreater1 + action 0 + 8314 : 1 +state 8315 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8316 observe4Greater1 observeIGreater1 + action 0 + 8463 : 1 +state 8317 deadlock observe4Greater1 observeIGreater1 + action 0 + 8317 : 1 +state 8318 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8319 observe4Greater1 observeIGreater1 + action 0 + 8464 : 1 +state 8320 deadlock observe4Greater1 observeIGreater1 + action 0 + 8320 : 1 +state 8321 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8322 observe4Greater1 observeIGreater1 + action 0 + 8465 : 1 +state 8323 deadlock observe4Greater1 observeIGreater1 + action 0 + 8323 : 1 +state 8324 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8325 observe4Greater1 observeIGreater1 + action 0 + 8466 : 1 +state 8326 deadlock observe4Greater1 observeIGreater1 + action 0 + 8326 : 1 +state 8327 observe1Greater1 observeIGreater1 + action 0 + 8467 : 1 +state 8328 observe1Greater1 observeIGreater1 + action 0 + 8468 : 1 +state 8329 observe1Greater1 observeIGreater1 + action 0 + 8469 : 1 +state 8330 observe1Greater1 observeIGreater1 + action 0 + 8470 : 1 +state 8331 observe1Greater1 observeIGreater1 + action 0 + 8471 : 1 +state 8332 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8472 : 1 +state 8333 observe1Greater1 observeIGreater1 + action 0 + 8473 : 1 +state 8334 observe1Greater1 observeIGreater1 + action 0 + 8474 : 1 +state 8335 observe1Greater1 observeIGreater1 + action 0 + 8475 : 1 +state 8336 observe1Greater1 observeIGreater1 + action 0 + 8476 : 1 +state 8337 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8477 : 1 +state 8338 observe1Greater1 observeIGreater1 + action 0 + 8478 : 1 +state 8339 observe1Greater1 observeIGreater1 + action 0 + 8479 : 1 +state 8340 observe1Greater1 observeIGreater1 + action 0 + 8480 : 1 +state 8341 observe1Greater1 observeIGreater1 + action 0 + 8481 : 1 +state 8342 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8482 : 1 +state 8343 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8483 : 1 +state 8344 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8484 : 1 +state 8345 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8485 : 1 +state 8346 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8486 : 1 +state 8347 observe1Greater1 observeIGreater1 + action 0 + 8487 : 1 +state 8348 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8488 : 1 +state 8349 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8489 : 1 +state 8350 observe1Greater1 observeIGreater1 + action 0 + 8490 : 1 +state 8351 observe1Greater1 observeIGreater1 + action 0 + 8491 : 1 +state 8352 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8492 : 1 +state 8353 observe1Greater1 observeIGreater1 + action 0 + 8493 : 1 +state 8354 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8494 : 1 +state 8355 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8495 : 1 +state 8356 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8496 : 1 +state 8357 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8497 : 1 +state 8358 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8498 : 1 +state 8359 observe1Greater1 observeIGreater1 + action 0 + 8499 : 1 +state 8360 observe1Greater1 observeIGreater1 + action 0 + 8500 : 1 +state 8361 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8501 : 1 +state 8362 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8502 : 1 +state 8363 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8503 : 1 +state 8364 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8504 : 1 +state 8365 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8505 : 1 +state 8366 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8506 : 1 +state 8367 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8507 : 1 +state 8368 observe2Greater1 observeIGreater1 + action 0 + 8508 : 1 +state 8369 observe2Greater1 observeIGreater1 + action 0 + 8509 : 1 +state 8370 observe2Greater1 observeIGreater1 + action 0 + 8510 : 1 +state 8371 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8511 : 1 +state 8372 observe2Greater1 observeIGreater1 + action 0 + 8512 : 1 +state 8373 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8513 : 1 +state 8374 observe2Greater1 observeIGreater1 + action 0 + 8514 : 1 +state 8375 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8515 : 1 +state 8376 observe2Greater1 observeIGreater1 + action 0 + 8516 : 1 +state 8377 observe2Greater1 observeIGreater1 + action 0 + 8517 : 1 +state 8378 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8518 : 1 +state 8379 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8519 : 1 +state 8380 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8520 : 1 +state 8381 observe3Greater1 observeIGreater1 + action 0 + 8521 : 1 +state 8382 observe3Greater1 observeIGreater1 + action 0 + 8522 : 1 +state 8383 observe1Greater1 observeIGreater1 + action 0 + 8523 : 1 +state 8384 observe2Greater1 observeIGreater1 + action 0 + 8524 : 1 +state 8385 observe3Greater1 observeIGreater1 + action 0 + 8525 : 1 +state 8386 observe4Greater1 observeIGreater1 + action 0 + 8526 : 1 +state 8387 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8527 : 1 +state 8388 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8528 : 1 +state 8389 observe4Greater1 observeIGreater1 + action 0 + 8529 : 1 +state 8390 observe4Greater1 observeIGreater1 + action 0 + 8530 : 1 +state 8391 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8531 : 1 +state 8392 observe3Greater1 observeIGreater1 + action 0 + 8532 : 1 +state 8393 observe3Greater1 observeIGreater1 + action 0 + 8533 : 1 +state 8394 observe3Greater1 observeIGreater1 + action 0 + 8534 : 1 +state 8395 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8535 : 1 +state 8396 observe3Greater1 observeIGreater1 + action 0 + 8536 : 1 +state 8397 observe3Greater1 observeIGreater1 + action 0 + 8537 : 1 +state 8398 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8538 : 1 +state 8399 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8539 : 1 +state 8400 observe4Greater1 observeIGreater1 + action 0 + 8540 : 1 +state 8401 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8541 : 1 +state 8402 observe4Greater1 observeIGreater1 + action 0 + 8542 : 1 +state 8403 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8543 : 1 +state 8404 observe4Greater1 observeIGreater1 + action 0 + 8544 : 1 +state 8405 observe4Greater1 observeIGreater1 + action 0 + 8545 : 1 +state 8406 observe4Greater1 observeIGreater1 + action 0 + 8546 : 1 +state 8407 observe2Greater1 observeIGreater1 + action 0 + 8547 : 1 +state 8408 observe2Greater1 observeIGreater1 + action 0 + 8548 : 1 +state 8409 observe2Greater1 observeIGreater1 + action 0 + 8549 : 1 +state 8410 observe2Greater1 observeIGreater1 + action 0 + 8550 : 1 +state 8411 observe2Greater1 observeIGreater1 + action 0 + 8551 : 1 +state 8412 observe2Greater1 observeIGreater1 + action 0 + 8552 : 1 +state 8413 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8553 : 1 +state 8414 observe2Greater1 observeIGreater1 + action 0 + 8554 : 1 +state 8415 observe2Greater1 observeIGreater1 + action 0 + 8555 : 1 +state 8416 observe2Greater1 observeIGreater1 + action 0 + 8556 : 1 +state 8417 observe2Greater1 observeIGreater1 + action 0 + 8557 : 1 +state 8418 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8558 : 1 +state 8419 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8559 : 1 +state 8420 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8560 : 1 +state 8421 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8561 : 1 +state 8422 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8562 : 1 +state 8423 observe2Greater1 observeIGreater1 + action 0 + 8563 : 1 +state 8424 observe2Greater1 observeIGreater1 + action 0 + 8564 : 1 +state 8425 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8565 : 1 +state 8426 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8566 : 1 +state 8427 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8567 : 1 +state 8428 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8568 : 1 +state 8429 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8569 : 1 +state 8430 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8570 : 1 +state 8431 observe3Greater1 observeIGreater1 + action 0 + 8571 : 1 +state 8432 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8572 : 1 +state 8433 observe3Greater1 observeIGreater1 + action 0 + 8573 : 1 +state 8434 observe3Greater1 observeIGreater1 + action 0 + 8574 : 1 +state 8435 observe3Greater1 observeIGreater1 + action 0 + 8575 : 1 +state 8436 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8576 : 1 +state 8437 observe3Greater1 observeIGreater1 + action 0 + 8577 : 1 +state 8438 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8578 : 1 +state 8439 observe4Greater1 observeIGreater1 + action 0 + 8579 : 1 +state 8440 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8580 : 1 +state 8441 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8581 : 1 +state 8442 observe4Greater1 observeIGreater1 + action 0 + 8582 : 1 +state 8443 observe4Greater1 observeIGreater1 + action 0 + 8583 : 1 +state 8444 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8584 : 1 +state 8445 observe4Greater1 observeIGreater1 + action 0 + 8585 : 1 +state 8446 observe4Greater1 observeIGreater1 + action 0 + 8586 : 1 +state 8447 observe3Greater1 observeIGreater1 + action 0 + 8587 : 1 +state 8448 observe3Greater1 observeIGreater1 + action 0 + 8588 : 1 +state 8449 observe3Greater1 observeIGreater1 + action 0 + 8589 : 1 +state 8450 observe3Greater1 observeIGreater1 + action 0 + 8590 : 1 +state 8451 observe3Greater1 observeIGreater1 + action 0 + 8591 : 1 +state 8452 observe3Greater1 observeIGreater1 + action 0 + 8592 : 1 +state 8453 observe3Greater1 observeIGreater1 + action 0 + 8593 : 1 +state 8454 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8594 : 1 +state 8455 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8595 : 1 +state 8456 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8596 : 1 +state 8457 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8597 : 1 +state 8458 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8598 : 1 +state 8459 observe4Greater1 observeIGreater1 + action 0 + 8599 : 1 +state 8460 observe4Greater1 observeIGreater1 + action 0 + 8600 : 1 +state 8461 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8601 : 1 +state 8462 observe4Greater1 observeIGreater1 + action 0 + 8602 : 1 +state 8463 observe4Greater1 observeIGreater1 + action 0 + 8603 : 1 +state 8464 observe4Greater1 observeIGreater1 + action 0 + 8604 : 1 +state 8465 observe4Greater1 observeIGreater1 + action 0 + 8605 : 1 +state 8466 observe4Greater1 observeIGreater1 + action 0 + 8606 : 1 +state 8467 deadlock observe1Greater1 observeIGreater1 + action 0 + 8467 : 1 +state 8468 deadlock observe1Greater1 observeIGreater1 + action 0 + 8468 : 1 +state 8469 deadlock observe1Greater1 observeIGreater1 + action 0 + 8469 : 1 +state 8470 deadlock observe1Greater1 observeIGreater1 + action 0 + 8470 : 1 +state 8471 deadlock observe1Greater1 observeIGreater1 + action 0 + 8471 : 1 +state 8472 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8472 : 1 +state 8473 deadlock observe1Greater1 observeIGreater1 + action 0 + 8473 : 1 +state 8474 deadlock observe1Greater1 observeIGreater1 + action 0 + 8474 : 1 +state 8475 deadlock observe1Greater1 observeIGreater1 + action 0 + 8475 : 1 +state 8476 deadlock observe1Greater1 observeIGreater1 + action 0 + 8476 : 1 +state 8477 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8477 : 1 +state 8478 deadlock observe1Greater1 observeIGreater1 + action 0 + 8478 : 1 +state 8479 deadlock observe1Greater1 observeIGreater1 + action 0 + 8479 : 1 +state 8480 deadlock observe1Greater1 observeIGreater1 + action 0 + 8480 : 1 +state 8481 deadlock observe1Greater1 observeIGreater1 + action 0 + 8481 : 1 +state 8482 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8482 : 1 +state 8483 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8483 : 1 +state 8484 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8484 : 1 +state 8485 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8485 : 1 +state 8486 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8486 : 1 +state 8487 deadlock observe1Greater1 observeIGreater1 + action 0 + 8487 : 1 +state 8488 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8488 : 1 +state 8489 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8489 : 1 +state 8490 deadlock observe1Greater1 observeIGreater1 + action 0 + 8490 : 1 +state 8491 deadlock observe1Greater1 observeIGreater1 + action 0 + 8491 : 1 +state 8492 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8492 : 1 +state 8493 deadlock observe1Greater1 observeIGreater1 + action 0 + 8493 : 1 +state 8494 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8494 : 1 +state 8495 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8495 : 1 +state 8496 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8496 : 1 +state 8497 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8497 : 1 +state 8498 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8498 : 1 +state 8499 deadlock observe1Greater1 observeIGreater1 + action 0 + 8499 : 1 +state 8500 deadlock observe1Greater1 observeIGreater1 + action 0 + 8500 : 1 +state 8501 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8501 : 1 +state 8502 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8502 : 1 +state 8503 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8503 : 1 +state 8504 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8504 : 1 +state 8505 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8505 : 1 +state 8506 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8506 : 1 +state 8507 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8507 : 1 +state 8508 deadlock observe2Greater1 observeIGreater1 + action 0 + 8508 : 1 +state 8509 deadlock observe2Greater1 observeIGreater1 + action 0 + 8509 : 1 +state 8510 deadlock observe2Greater1 observeIGreater1 + action 0 + 8510 : 1 +state 8511 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8511 : 1 +state 8512 deadlock observe2Greater1 observeIGreater1 + action 0 + 8512 : 1 +state 8513 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8513 : 1 +state 8514 deadlock observe2Greater1 observeIGreater1 + action 0 + 8514 : 1 +state 8515 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8515 : 1 +state 8516 deadlock observe2Greater1 observeIGreater1 + action 0 + 8516 : 1 +state 8517 deadlock observe2Greater1 observeIGreater1 + action 0 + 8517 : 1 +state 8518 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8518 : 1 +state 8519 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8519 : 1 +state 8520 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8520 : 1 +state 8521 deadlock observe3Greater1 observeIGreater1 + action 0 + 8521 : 1 +state 8522 deadlock observe3Greater1 observeIGreater1 + action 0 + 8522 : 1 +state 8523 deadlock observe1Greater1 observeIGreater1 + action 0 + 8523 : 1 +state 8524 deadlock observe2Greater1 observeIGreater1 + action 0 + 8524 : 1 +state 8525 deadlock observe3Greater1 observeIGreater1 + action 0 + 8525 : 1 +state 8526 deadlock observe4Greater1 observeIGreater1 + action 0 + 8526 : 1 +state 8527 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8527 : 1 +state 8528 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8528 : 1 +state 8529 deadlock observe4Greater1 observeIGreater1 + action 0 + 8529 : 1 +state 8530 deadlock observe4Greater1 observeIGreater1 + action 0 + 8530 : 1 +state 8531 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8531 : 1 +state 8532 deadlock observe3Greater1 observeIGreater1 + action 0 + 8532 : 1 +state 8533 deadlock observe3Greater1 observeIGreater1 + action 0 + 8533 : 1 +state 8534 deadlock observe3Greater1 observeIGreater1 + action 0 + 8534 : 1 +state 8535 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8535 : 1 +state 8536 deadlock observe3Greater1 observeIGreater1 + action 0 + 8536 : 1 +state 8537 deadlock observe3Greater1 observeIGreater1 + action 0 + 8537 : 1 +state 8538 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8538 : 1 +state 8539 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8539 : 1 +state 8540 deadlock observe4Greater1 observeIGreater1 + action 0 + 8540 : 1 +state 8541 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8541 : 1 +state 8542 deadlock observe4Greater1 observeIGreater1 + action 0 + 8542 : 1 +state 8543 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8543 : 1 +state 8544 deadlock observe4Greater1 observeIGreater1 + action 0 + 8544 : 1 +state 8545 deadlock observe4Greater1 observeIGreater1 + action 0 + 8545 : 1 +state 8546 deadlock observe4Greater1 observeIGreater1 + action 0 + 8546 : 1 +state 8547 deadlock observe2Greater1 observeIGreater1 + action 0 + 8547 : 1 +state 8548 deadlock observe2Greater1 observeIGreater1 + action 0 + 8548 : 1 +state 8549 deadlock observe2Greater1 observeIGreater1 + action 0 + 8549 : 1 +state 8550 deadlock observe2Greater1 observeIGreater1 + action 0 + 8550 : 1 +state 8551 deadlock observe2Greater1 observeIGreater1 + action 0 + 8551 : 1 +state 8552 deadlock observe2Greater1 observeIGreater1 + action 0 + 8552 : 1 +state 8553 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8553 : 1 +state 8554 deadlock observe2Greater1 observeIGreater1 + action 0 + 8554 : 1 +state 8555 deadlock observe2Greater1 observeIGreater1 + action 0 + 8555 : 1 +state 8556 deadlock observe2Greater1 observeIGreater1 + action 0 + 8556 : 1 +state 8557 deadlock observe2Greater1 observeIGreater1 + action 0 + 8557 : 1 +state 8558 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8558 : 1 +state 8559 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8559 : 1 +state 8560 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8560 : 1 +state 8561 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8561 : 1 +state 8562 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8562 : 1 +state 8563 deadlock observe2Greater1 observeIGreater1 + action 0 + 8563 : 1 +state 8564 deadlock observe2Greater1 observeIGreater1 + action 0 + 8564 : 1 +state 8565 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8565 : 1 +state 8566 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8566 : 1 +state 8567 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8567 : 1 +state 8568 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8568 : 1 +state 8569 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8569 : 1 +state 8570 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8570 : 1 +state 8571 deadlock observe3Greater1 observeIGreater1 + action 0 + 8571 : 1 +state 8572 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8572 : 1 +state 8573 deadlock observe3Greater1 observeIGreater1 + action 0 + 8573 : 1 +state 8574 deadlock observe3Greater1 observeIGreater1 + action 0 + 8574 : 1 +state 8575 deadlock observe3Greater1 observeIGreater1 + action 0 + 8575 : 1 +state 8576 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8576 : 1 +state 8577 deadlock observe3Greater1 observeIGreater1 + action 0 + 8577 : 1 +state 8578 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8578 : 1 +state 8579 deadlock observe4Greater1 observeIGreater1 + action 0 + 8579 : 1 +state 8580 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8580 : 1 +state 8581 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8581 : 1 +state 8582 deadlock observe4Greater1 observeIGreater1 + action 0 + 8582 : 1 +state 8583 deadlock observe4Greater1 observeIGreater1 + action 0 + 8583 : 1 +state 8584 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8584 : 1 +state 8585 deadlock observe4Greater1 observeIGreater1 + action 0 + 8585 : 1 +state 8586 deadlock observe4Greater1 observeIGreater1 + action 0 + 8586 : 1 +state 8587 deadlock observe3Greater1 observeIGreater1 + action 0 + 8587 : 1 +state 8588 deadlock observe3Greater1 observeIGreater1 + action 0 + 8588 : 1 +state 8589 deadlock observe3Greater1 observeIGreater1 + action 0 + 8589 : 1 +state 8590 deadlock observe3Greater1 observeIGreater1 + action 0 + 8590 : 1 +state 8591 deadlock observe3Greater1 observeIGreater1 + action 0 + 8591 : 1 +state 8592 deadlock observe3Greater1 observeIGreater1 + action 0 + 8592 : 1 +state 8593 deadlock observe3Greater1 observeIGreater1 + action 0 + 8593 : 1 +state 8594 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8594 : 1 +state 8595 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8595 : 1 +state 8596 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8596 : 1 +state 8597 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8597 : 1 +state 8598 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8598 : 1 +state 8599 deadlock observe4Greater1 observeIGreater1 + action 0 + 8599 : 1 +state 8600 deadlock observe4Greater1 observeIGreater1 + action 0 + 8600 : 1 +state 8601 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8601 : 1 +state 8602 deadlock observe4Greater1 observeIGreater1 + action 0 + 8602 : 1 +state 8603 deadlock observe4Greater1 observeIGreater1 + action 0 + 8603 : 1 +state 8604 deadlock observe4Greater1 observeIGreater1 + action 0 + 8604 : 1 +state 8605 deadlock observe4Greater1 observeIGreater1 + action 0 + 8605 : 1 +state 8606 deadlock observe4Greater1 observeIGreater1 + action 0 + 8606 : 1 diff --git a/resources/examples/testfiles/ma/jobscheduler.drn b/resources/examples/testfiles/ma/jobscheduler.drn new file mode 100644 index 000000000..6f2e61a39 --- /dev/null +++ b/resources/examples/testfiles/ma/jobscheduler.drn @@ -0,0 +1,71 @@ +// Exported by storm +// Original model type: Markov Automaton +@type: Markov Automaton +@parameters + +@reward_models +avg_waiting_time +@nr_states +17 +@model +state 0 !0 [1] init + action 0 [0] + 1 : 1 + action 1 [0] + 2 : 1 + action 2 [0] + 3 : 1 +state 1 !3 [1] + action 0 [0] + 4 : 0.333333 + 5 : 0.666667 +state 2 !4 [1] + action 0 [0] + 4 : 0.25 + 6 : 0.75 +state 3 !5 [1] + action 0 [0] + 5 : 0.4 + 6 : 0.6 +state 4 !0 [0.666667] one_job_finished slowest_before_fastest + action 0 [0] + 7 : 1 +state 5 !0 [0.666667] one_job_finished + action 0 [0] + 8 : 1 +state 6 !0 [0.666667] one_job_finished + action 0 [0] + 9 : 1 +state 7 !5 [0.666667] one_job_finished slowest_before_fastest + action 0 [0] + 10 : 0.4 + 11 : 0.6 +state 8 !4 [0.666667] one_job_finished + action 0 [0] + 10 : 0.25 + 12 : 0.75 +state 9 !3 [0.666667] one_job_finished + action 0 [0] + 11 : 0.333333 + 12 : 0.666667 +state 10 !0 [0.333333] half_of_jobs_finished slowest_before_fastest + action 0 [0] + 13 : 1 +state 11 !0 [0.333333] half_of_jobs_finished + action 0 [0] + 14 : 1 +state 12 !0 [0.333333] half_of_jobs_finished + action 0 [0] + 15 : 1 +state 13 !3 [0.333333] half_of_jobs_finished slowest_before_fastest + action 0 [0] + 16 : 1 +state 14 !2 [0.333333] half_of_jobs_finished + action 0 [0] + 16 : 1 +state 15 !1 [0.333333] half_of_jobs_finished + action 0 [0] + 16 : 1 +state 16 !1 [0] all_jobs_finished deadlock + action 0 [0] + 16 : 1 diff --git a/resources/examples/testfiles/mdp/two_dice.drn b/resources/examples/testfiles/mdp/two_dice.drn index 74d13d03b..7e88bc459 100644 --- a/resources/examples/testfiles/mdp/two_dice.drn +++ b/resources/examples/testfiles/mdp/two_dice.drn @@ -3,6 +3,8 @@ @type: MDP @parameters +@reward_models +coinflips @nr_states 169 @model diff --git a/src/test/storm/parser/DirectEncodingParserTest.cpp b/src/test/storm/parser/DirectEncodingParserTest.cpp index 07d63b017..93bd34e04 100644 --- a/src/test/storm/parser/DirectEncodingParserTest.cpp +++ b/src/test/storm/parser/DirectEncodingParserTest.cpp @@ -1,23 +1,24 @@ #include "gtest/gtest.h" #include "storm-config.h" +#include "storm/parser/DirectEncodingParser.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/Mdp.h" -#include "storm/parser/DirectEncodingParser.h" +#include "storm/models/sparse/MarkovAutomaton.h" -TEST(DirectEncodingParserTest, CtmcParsing) { - std::shared_ptr> modelPtr = storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/ctmc/cluster2.drn"); +TEST(DirectEncodingParserTest, DtmcParsing) { + std::shared_ptr> modelPtr = storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.drn"); // Test if parsed correctly. - ASSERT_EQ(storm::models::ModelType::Ctmc, modelPtr->getType()); - ASSERT_EQ(276ul, modelPtr->getNumberOfStates()); - ASSERT_EQ(1120ul, modelPtr->getNumberOfTransitions()); + ASSERT_EQ(storm::models::ModelType::Dtmc, modelPtr->getType()); + ASSERT_EQ(8607ul, modelPtr->getNumberOfStates()); + ASSERT_EQ(15113ul, modelPtr->getNumberOfTransitions()); ASSERT_TRUE(modelPtr->hasLabel("init")); ASSERT_EQ(1ul, modelPtr->getInitialStates().getNumberOfSetBits()); - ASSERT_TRUE(modelPtr->hasLabel("premium")); - ASSERT_EQ(64ul, modelPtr->getStates("premium").getNumberOfSetBits()); - ASSERT_TRUE(modelPtr->hasLabel("minimum")); - ASSERT_EQ(132ul, modelPtr->getStates("minimum").getNumberOfSetBits()); + ASSERT_TRUE(modelPtr->hasLabel("observeIGreater1")); + ASSERT_EQ(4650ul, modelPtr->getStates("observeIGreater1").getNumberOfSetBits()); + ASSERT_TRUE(modelPtr->hasLabel("observe0Greater1")); + ASSERT_EQ(1260ul, modelPtr->getStates("observe0Greater1").getNumberOfSetBits()); } TEST(DirectEncodingParserTest, MdpParsing) { @@ -36,3 +37,36 @@ TEST(DirectEncodingParserTest, MdpParsing) { ASSERT_EQ(2ul, modelPtr->getStates("eleven").getNumberOfSetBits()); } +TEST(DirectEncodingParserTest, CtmcParsing) { + std::shared_ptr> modelPtr = storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/ctmc/cluster2.drn"); + + // Test if parsed correctly. + ASSERT_EQ(storm::models::ModelType::Ctmc, modelPtr->getType()); + ASSERT_EQ(276ul, modelPtr->getNumberOfStates()); + ASSERT_EQ(1120ul, modelPtr->getNumberOfTransitions()); + ASSERT_TRUE(modelPtr->hasLabel("init")); + ASSERT_EQ(1ul, modelPtr->getInitialStates().getNumberOfSetBits()); + ASSERT_TRUE(modelPtr->hasLabel("premium")); + ASSERT_EQ(64ul, modelPtr->getStates("premium").getNumberOfSetBits()); + ASSERT_TRUE(modelPtr->hasLabel("minimum")); + ASSERT_EQ(132ul, modelPtr->getStates("minimum").getNumberOfSetBits()); +} + +TEST(DirectEncodingParserTest, MarkovAutomatonParsing) { + std::shared_ptr> modelPtr = storm::parser::DirectEncodingParser::parseModel(STORM_TEST_RESOURCES_DIR "/ma/jobscheduler.drn"); + std::shared_ptr> ma = modelPtr->as>(); + + // Test if parsed correctly. + ASSERT_EQ(storm::models::ModelType::MarkovAutomaton, modelPtr->getType()); + ASSERT_EQ(17ul, ma->getNumberOfStates()); + ASSERT_EQ(25ul, ma->getNumberOfTransitions()); + ASSERT_EQ(19ul, ma->getNumberOfChoices()); + ASSERT_EQ(10ul, ma->getMarkovianStates().getNumberOfSetBits()); + ASSERT_EQ(5, ma->getMaximalExitRate()); + ASSERT_TRUE(ma->hasRewardModel("avg_waiting_time")); + ASSERT_TRUE(modelPtr->hasLabel("init")); + ASSERT_EQ(1ul, modelPtr->getInitialStates().getNumberOfSetBits()); + ASSERT_TRUE(modelPtr->hasLabel("one_job_finished")); + ASSERT_EQ(6ul, modelPtr->getStates("one_job_finished").getNumberOfSetBits()); +} + From 14bad02bc4dc790610e94975c308ad31e749a313 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 29 Mar 2018 15:02:00 +0200 Subject: [PATCH 225/647] fixes to player 1 choice labeling --- src/storm/abstraction/MenuGameRefiner.cpp | 38 +++++++++++-------- .../abstraction/GameBasedMdpModelChecker.cpp | 8 ++++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index f8209ee99..6a1dd8cdc 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -394,11 +394,8 @@ namespace storm { // Derive predicates from lower choice. storm::dd::Bdd lowerChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; - lowerChoice.template toAdd().exportToDot("lower.dot"); storm::dd::Bdd lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); - lowerChoice1.template toAdd().exportToDot("lower1.dot"); storm::dd::Bdd lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - lowerChoice2.template toAdd().exportToDot("lower2.dot"); bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero(); if (lowerChoicesDifferent) { @@ -610,7 +607,7 @@ namespace storm { // Add variable update expression. predicates.back().emplace_back(allVariableUpdateExpression); - + // Add the guard of the choice. predicates.back().emplace_back(abstractor.get().getGuard(currentAction).changeManager(expressionManager).substitute(substitution)); @@ -649,14 +646,14 @@ namespace storm { for (auto const& predicate : step) { interpolatingSolver.add(predicate); } - ++stepCounter; - storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); // If the result already became unsatisfiable if (result == storm::solver::SmtSolver::CheckResult::Unsat) { - STORM_LOG_TRACE("Trace formula became unsatisfiable after step " << (stepCounter - 1) << "."); + STORM_LOG_TRACE("Trace formula became unsatisfiable after step " << stepCounter << "."); break; } + + ++stepCounter; } // Now encode the trace as an SMT problem. @@ -666,14 +663,14 @@ namespace storm { std::vector interpolants; std::vector prefix; - for (uint64_t step = 0; step + 1 < stepCounter; ++step) { + for (uint64_t step = 0; step < stepCounter; ++step) { prefix.push_back(step); storm::expressions::Expression interpolant = interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager()); if (!interpolant.isTrue() && !interpolant.isFalse()) { STORM_LOG_DEBUG("Derived new predicate (based on interpolation): " << interpolant); interpolants.push_back(interpolant); } else { - STORM_LOG_TRACE("Found interpolant is '" << interpolant << "'."); + STORM_LOG_ASSERT(false, "The found interpolant is '" << interpolant << "', which shouldn't happen."); } } return boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); @@ -843,6 +840,7 @@ namespace storm { bool considerDeviation = (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::NearestMaximalDeviation || pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) && lowerValues && upperValues; bool foundPivotState = false; ValueType pivotStateDeviation = storm::utility::zero(); + auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); while (!dijkstraQueue.empty()) { auto distanceStatePair = *dijkstraQueue.begin(); @@ -875,8 +873,7 @@ namespace storm { if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } - } - + } // If it is indeed a pivot state, we can abort the search here. if (isPivotState) { if (considerDeviation && foundPivotState) { @@ -905,7 +902,8 @@ namespace storm { if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t minPlayer2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); uint64_t minPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor); - + STORM_LOG_ASSERT(player2Grouping[minPlayer2Successor] <= minPlayer2Choice && minPlayer2Choice < player2Grouping[minPlayer2Successor + 1], "Illegal choice for player 2."); + for (auto const& entry : transitionMatrix.getRow(minPlayer2Choice)) { uint64_t player1Successor = entry.getColumn(); if (!relevantStates.get(player1Successor)) { @@ -925,7 +923,8 @@ namespace storm { if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t maxPlayer2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); uint64_t maxPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor); - + STORM_LOG_ASSERT(player2Grouping[maxPlayer2Successor] <= maxPlayer2Choice && maxPlayer2Choice < player2Grouping[maxPlayer2Successor + 1], "Illegal choice for player 2."); + for (auto const& entry : transitionMatrix.getRow(maxPlayer2Choice)) { uint64_t player1Successor = entry.getColumn(); if (!relevantStates.get(player1Successor)) { @@ -936,7 +935,7 @@ namespace storm { if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { - result.predecessors[player1Successor] = std::make_pair(currentState, maxPlayer2Successor); + result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[maxPlayer2Successor]); } dijkstraQueue.emplace(alternateDistance, player1Successor); } @@ -977,7 +976,8 @@ namespace storm { storm::dd::Bdd maxPlayer2Strategy = game.getManager().getBddZero(); if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState); - minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[transitionMatrix.getRowGroupIndices()[player2State]], abstractionInformation.getPlayer1VariableCount()); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); @@ -990,7 +990,8 @@ namespace storm { } if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState); - maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[transitionMatrix.getRowGroupIndices()[player2State]], abstractionInformation.getPlayer1VariableCount()); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); @@ -1001,6 +1002,11 @@ namespace storm { maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); } } +// symbolicPivotState.template toAdd().exportToDot("pivot.dot"); +// minPlayer1Strategy.template toAdd().exportToDot("minpl1.dot"); +// minPlayer2Strategy.template toAdd().exportToDot("minpl2.dot"); +// maxPlayer1Strategy.template toAdd().exportToDot("maxpl1.dot"); +// maxPlayer2Strategy.template toAdd().exportToDot("maxpl2.dot"); boost::optional predicates; if (useInterpolation) { predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 35d838d55..eeaffd6c3 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -689,6 +689,14 @@ namespace storm { player1Groups[player1State + 1] = player2State; } + // Lift the player 1 labeling from rows to row groups (player 2 states). + for (uint64_t player1State = 0; player1State < player1Groups.size() - 1; ++player1State) { + for (uint64_t player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) { + player1Labeling[player2State] = player1Labeling[player2RowGrouping[player2State]]; + } + } + player1Labeling.resize(player2RowGrouping.size() - 1); + // Create explicit representations of important state sets. storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); From a31929c00fd52ac8ee03a5f1f4908cc8eb971a8c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 29 Mar 2018 17:05:53 +0200 Subject: [PATCH 226/647] Travis: build portable version of Storm --- travis/build_helper.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/travis/build_helper.sh b/travis/build_helper.sh index 6da9ada64..15a6dafeb 100755 --- a/travis/build_helper.sh +++ b/travis/build_helper.sh @@ -114,10 +114,10 @@ echo Normalized C++ Standard library location: $(readlink -f $(echo '#include Date: Thu, 29 Mar 2018 19:18:14 +0200 Subject: [PATCH 227/647] first working version of sparse game-based abstraction refinement --- src/storm/abstraction/MenuGameRefiner.cpp | 87 ++++++++++++-- src/storm/abstraction/MenuGameRefiner.h | 12 +- .../abstraction/GameBasedMdpModelChecker.cpp | 110 +++++++++++------- src/storm/solver/GameSolver.h | 6 +- src/storm/solver/StandardGameSolver.cpp | 76 ++++++++---- src/storm/solver/StandardGameSolver.h | 6 +- src/storm/utility/graph.cpp | 2 +- 7 files changed, 218 insertions(+), 81 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 6a1dd8cdc..aad16cc2d 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -6,6 +6,7 @@ #include "storm/storage/BitVector.h" #include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" #include "storm/abstraction/ExplicitGameStrategyPair.h" +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Odd.h" @@ -667,11 +668,12 @@ namespace storm { prefix.push_back(step); storm::expressions::Expression interpolant = interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager()); if (!interpolant.isTrue() && !interpolant.isFalse()) { - STORM_LOG_DEBUG("Derived new predicate (based on interpolation): " << interpolant); + STORM_LOG_DEBUG("Derived new predicate (based on interpolation at step " << step << " out of " << stepCounter << "): " << interpolant); interpolants.push_back(interpolant); - } else { - STORM_LOG_ASSERT(false, "The found interpolant is '" << interpolant << "', which shouldn't happen."); } +// else { +// STORM_LOG_ASSERT(step == 0false, "The found interpolant (based on interpolation at step " << step << " out of " << stepCounter << ") is '" << interpolant << "', which shouldn't happen."); +// } } return boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); } else { @@ -805,7 +807,7 @@ namespace storm { } template - boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair, std::vector const* lowerValues = nullptr, std::vector const* upperValues = nullptr) { + boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair, std::vector const* lowerValues = nullptr, std::vector const* upperValues = nullptr) { STORM_LOG_ASSERT(!lowerValues || upperValues, "Expected none or both value results."); STORM_LOG_ASSERT(!upperValues || lowerValues, "Expected none or both value results."); @@ -954,7 +956,7 @@ namespace storm { // Compute the set of states whose result we have for the min and max case. storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); - boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, minStrategyPair, maxStrategyPair); // If there was no pivot state, continue the search. if (!optionalPivotStateResult) { @@ -1002,11 +1004,76 @@ namespace storm { maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); } } -// symbolicPivotState.template toAdd().exportToDot("pivot.dot"); -// minPlayer1Strategy.template toAdd().exportToDot("minpl1.dot"); -// minPlayer2Strategy.template toAdd().exportToDot("minpl2.dot"); -// maxPlayer1Strategy.template toAdd().exportToDot("maxpl1.dot"); -// maxPlayer2Strategy.template toAdd().exportToDot("maxpl2.dot"); + + boost::optional predicates; + if (useInterpolation) { + predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); + } + if (!predicates) { + predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + } + STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); + + std::vector preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource()); + performRefinement(createGlobalRefinement(preparedPredicates)); + return true; + } + + template + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + + // Compute the set of states whose result we have for the min and max case. + storm::storage::BitVector relevantStates(odd.getTotalOffset(), true); + + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, minStrategyPair, maxStrategyPair, &quantitativeResult.getMin().getValues(), &quantitativeResult.getMax().getValues()); + + // If there was no pivot state, continue the search. + if (!optionalPivotStateResult) { + STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); + return false; + } + + // Otherwise, we can refine. + auto const& pivotStateResult = optionalPivotStateResult.get(); + STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << "."); + + // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques. + auto const& abstractionInformation = abstractor.get().getAbstractionInformation(); + uint64_t pivotState = pivotStateResult.pivotState; + storm::dd::Bdd symbolicPivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables()); + storm::dd::Bdd minPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd minPlayer2Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer2Strategy = game.getManager().getBddZero(); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + boost::optional predicates; if (useInterpolation) { predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 5e7be4d2d..a38ec0bf0 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -91,7 +91,10 @@ namespace storm { class ExplicitQualitativeGameResultMinMax; class ExplicitGameStrategyPair; - + + template + class ExplicitQuantitativeResultMinMax; + template class MenuGameRefiner { public: @@ -121,6 +124,13 @@ namespace storm { */ bool refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const; + /*! + * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. + * + * @param True if predicates for refinement could be derived, false otherwise. + */ + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const; + /*! * Refines the abstractor based on the quantitative result by trying to derive suitable predicates. * diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index eeaffd6c3..bd77c5cd5 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -391,30 +391,34 @@ namespace storm { } template - ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair) { + ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair, ExplicitQuantitativeResult const* startingQuantitativeResult = nullptr, ExplicitGameStrategyPair const* startingStrategyPair = nullptr) { - bool player1Min = player1Direction == storm::OptimizationDirection::Minimize; bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; - auto const& player1Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer1States(); auto const& player1Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer1States(); auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); - - // Determine which row groups to keep. - storm::storage::BitVector player2MaybeStates = ~(player2Prob0States | player2Prob1States); - // Create the sub-game. - storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); - std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, player1Prob1States); + // If there are no maybe states, we construct the quantitative result from the qualitative result alone. + if (maybeStates.empty()) { + ExplicitQuantitativeResult result(maybeStates.size()); + storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); + return result; + } + + // Otherwise, we need to solve a (sub)game. + + // Create the game by selecting all maybe player 2 states (non-prob0/1) of all maybe player 1 states. std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); uint64_t position = 0; uint64_t previousPlayer2States = 0; + storm::storage::BitVector player2MaybeStates(transitionMatrix.getRowGroupCount()); for (auto state : maybeStates) { subPlayer1Groups[position] = previousPlayer2States; bool hasMaybePlayer2Successor = false; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { - if (player2MaybeStates.get(player2State)) { + if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) { + player2MaybeStates.set(player2State); hasMaybePlayer2Successor = true; ++previousPlayer2States; } @@ -423,23 +427,57 @@ namespace storm { ++position; } subPlayer1Groups.back() = previousPlayer2States; - - // Solve the sub-game. + + // Create the player 2 matrix using the maybe player 2 states. + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); + std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, player1Prob1States); + + // Set up game solver. auto gameSolver = storm::solver::GameSolverFactory().create(env, subPlayer1Groups, submatrix); - gameSolver->setTrackSchedulers(true); - std::vector lowerValues(maybeStates.getNumberOfSetBits()); - gameSolver->solveGame(env, player1Direction, player2Direction, lowerValues, b); + + // Prepare the value storage for the maybe states. If the starting values were given, extract them now. + std::vector values(maybeStates.getNumberOfSetBits()); + if (startingQuantitativeResult) { + storm::utility::vector::selectVectorValues(values, maybeStates, startingQuantitativeResult->getValues()); + } + + // Prepare scheduler storage. + std::vector player1Scheduler(subPlayer1Groups.size() - 1); + std::vector player2Scheduler(submatrix.getRowGroupCount()); + if (startingStrategyPair) { + // If the starting strategy pair was provided, we need to extract the choices of the maybe states here. + uint64_t maybeStatePosition = 0; + previousPlayer2States = 0; + for (auto state : maybeStates) { + uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); + + uint64_t previousPlayer2StatesForState = 0; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player2MaybeStates.get(player2State)) { + if (player2State == chosenPlayer2State) { + player1Scheduler[maybeStatePosition] = previousPlayer2StatesForState; + } + + // Copy over the player 2 action (modulo making it local) as all rows for the state are taken. + player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices()[player2State]; + + ++previousPlayer2StatesForState; + ++previousPlayer2States; + } + } + + ++maybeStatePosition; + } + } + + // Solve actual game and track schedulers. + gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler); // Create combined result for all states. ExplicitQuantitativeResult result(maybeStates.size()); storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); - storm::utility::vector::setVectorValues(result.getValues(), maybeStates, lowerValues); - - STORM_LOG_ASSERT(gameSolver->hasSchedulers(), "Expected to have schedulers available after solving game."); - - std::vector const& player1Scheduler = gameSolver->getPlayer1SchedulerChoices(); - std::vector const& player2Scheduler = gameSolver->getPlayer2SchedulerChoices(); - + storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); + // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. uint64_t previousPlayer1MaybeStates = 0; uint64_t previousPlayer2MaybeStates = 0; @@ -650,6 +688,7 @@ namespace storm { STORM_LOG_TRACE("Using sparse solving."); // (0) Start by transforming the necessary symbolic elements to explicit ones. + auto translationStart = std::chrono::high_resolution_clock::now(); storm::dd::Odd odd = game.getReachableStates().createOdd(); std::vector> labelingVariableSets = {game.getPlayer1Variables(), game.getPlayer2Variables()}; @@ -701,6 +740,8 @@ namespace storm { storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); + auto translationEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Translation to explicit representation completed in " << std::chrono::duration_cast(translationEnd - translationStart).count() << "ms."); // Prepare the two strategies. abstraction::ExplicitGameStrategyPair minStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); @@ -715,12 +756,6 @@ namespace storm { } auto qualitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); - -// std::cout << transitionMatrix << std::endl; -// std::cout << labeling.size() << std::endl; -// std::cout << initialStates << std::endl; -// std::cout << constraintStates << std::endl; -// std::cout << targetStates << std::endl; // (2) compute the states for which we have to determine quantitative information. storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()); @@ -751,12 +786,10 @@ namespace storm { if (!qualitativeRefinement) { // At this point, we know that we cannot answer the query without further numeric computation. STORM_LOG_TRACE("Starting numerical solution step."); - - auto quantitativeStart = std::chrono::high_resolution_clock::now(); - ExplicitQuantitativeResultMinMax quantitativeResult; // (7) Solve the min values and check whether we can give the answer already. + auto quantitativeStart = std::chrono::high_resolution_clock::now(); quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); if (result) { @@ -764,12 +797,11 @@ namespace storm { } // (8) Solve the max values and check whether we can give the answer already. - quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair)); + quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, &quantitativeResult.getMin(), &minStrategyPair)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); if (result) { return result; } - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); @@ -780,15 +812,13 @@ namespace storm { } // Make sure that all strategies are still valid strategies. - STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() == targetStates.getNumberOfSetBits() && minStrategyPair.getNumberOfUndefinedPlayer2States() == 0, "Minimal strategy pair has undefined choices for some relevant states."); - STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() == targetStates.getNumberOfSetBits() && maxStrategyPair.getNumberOfUndefinedPlayer2States() == 0, "Maximal strategy pair has undefined choices for some relevant states."); - - exit(-1); + STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); + STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << maxStrategyPair.getNumberOfUndefinedPlayer1States() << "."); auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); -// // (10) If we arrived at this point, it means that we have all qualitative and quantitative -// // information about the game, but we could not yet answer the query. In this case, we need to refine. -// refiner.refine(game, transitionMatrixBdd, quantitativeResult); + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. + refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); } diff --git a/src/storm/solver/GameSolver.h b/src/storm/solver/GameSolver.h index 6c724e33c..68f7c3559 100644 --- a/src/storm/solver/GameSolver.h +++ b/src/storm/solver/GameSolver.h @@ -39,8 +39,12 @@ namespace storm { * @param player2Dir Sets whether player 2 wants to minimize or maximize. * @param x The initial guess of the solution. For correctness, the guess has to be less (or equal) to the final solution (unless both players minimize) * @param b The vector to add after matrix-vector multiplication. + * @param player1Choices If provided along with the storage for player 2 choices, the scheduler decisions + * are tracked within these two vectors. + * @param player2Choices If provided along with the storage for player 1 choices, the scheduler decisions + * are tracked within these two vectors. */ - virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const = 0; + virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const = 0; /*! * Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 3d9e4975d..c57ff38b8 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -57,12 +57,12 @@ namespace storm { } template - bool StandardGameSolver::solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices, std::vector* player2Choices) const { switch (getMethod(env, std::is_same::value)) { case GameMethod::ValueIteration: - return solveGameValueIteration(env, player1Dir, player2Dir, x, b); + return solveGameValueIteration(env, player1Dir, player2Dir, x, b, player1Choices, player2Choices); case GameMethod::PolicyIteration: - return solveGamePolicyIteration(env, player1Dir, player2Dir, x, b); + return solveGamePolicyIteration(env, player1Dir, player2Dir, x, b, player1Choices, player2Choices); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); } @@ -70,21 +70,39 @@ namespace storm { } template - bool StandardGameSolver::solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* providedPlayer1Choices, std::vector* providedPlayer2Choices) const { // Create the initial choice selections. - std::vector player1Choices; + std::vector* player1Choices; + std::unique_ptr> localPlayer1Choices; + std::vector* player2Choices; + std::unique_ptr> localPlayer2Choices; + + if (providedPlayer1Choices && providedPlayer2Choices) { + player1Choices = providedPlayer1Choices; + player2Choices = providedPlayer2Choices; + } else { + localPlayer1Choices = std::make_unique>(); + player1Choices = localPlayer1Choices.get(); + localPlayer2Choices = std::make_unique>(); + player2Choices = localPlayer2Choices.get(); + } + if (this->hasSchedulerHints()) { - player1Choices = this->player1ChoicesHint.get(); + *player1Choices = this->player1ChoicesHint.get(); } else if (this->player1RepresentedByMatrix()) { // Player 1 represented by matrix. - player1Choices = std::vector(this->getPlayer1Matrix().getRowGroupCount(), 0); + *player1Choices = std::vector(this->getPlayer1Matrix().getRowGroupCount(), 0); } else { // Player 1 represented by grouping of player 2 states. - player1Choices = this->getPlayer1Grouping(); - player1Choices.resize(player1Choices.size() - 1); + *player1Choices = this->getPlayer1Grouping(); + player1Choices->resize(player1Choices->size() - 1); + } + if (this->hasSchedulerHints()) { + *player2Choices = this->player2ChoicesHint.get(); + } else if (!(providedPlayer1Choices && providedPlayer2Choices)) { + player2Choices->resize(this->player2Matrix.getRowGroupCount()); } - std::vector player2Choices = this->hasSchedulerHints() ? this->player2ChoicesHint.get() : std::vector(this->player2Matrix.getRowGroupCount(), 0); if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(this->player2Matrix.getRowGroupCount()); @@ -119,7 +137,7 @@ namespace storm { // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; - getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); + getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { submatrix.convertToEquationSystem(); } @@ -140,14 +158,14 @@ namespace storm { // FIXME: we need to remove the 0- and 1- states to make the solution unique. submatrixSolver->solveEquations(environmentOfSolver, x, subB); - bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, player1Choices, player2Choices); + bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); // If the scheduler did not improve, we are done. if (!schedulerImproved) { status = Status::Converged; } else { // Update the solver. - getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); + getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); submatrix.convertToEquationSystem(); submatrixSolver->setMatrix(std::move(submatrix)); } @@ -160,9 +178,9 @@ namespace storm { reportStatus(status, iterations); // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulersSet()) { - this->player1SchedulerChoices = std::move(player1Choices); - this->player2SchedulerChoices = std::move(player2Choices); + if (this->isTrackSchedulersSet() && !(providedPlayer1Choices && providedPlayer2Choices)) { + this->player1SchedulerChoices = std::move(*player1Choices); + this->player2SchedulerChoices = std::move(*player2Choices); } if (!this->isCachingEnabled()) { @@ -182,7 +200,7 @@ namespace storm { } template - bool StandardGameSolver::solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices, std::vector* player2Choices) const { if (!multiplierPlayer2Matrix) { multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); @@ -202,7 +220,9 @@ namespace storm { std::vector& reducedPlayer2Result = *auxiliaryP2RowGroupVector; - bool trackSchedulersInValueIteration = this->isTrackSchedulersSet() && !this->hasUniqueSolution(); + bool trackingSchedulersInProvidedStorage = player1Choices && player2Choices; + bool trackSchedulers = this->isTrackSchedulersSet() || trackingSchedulersInProvidedStorage; + bool trackSchedulersInValueIteration = trackSchedulers && !this->hasUniqueSolution(); if (this->hasSchedulerHints()) { // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; @@ -221,11 +241,11 @@ namespace storm { submatrixSolver->solveEquations(env, x, *auxiliaryP1RowGroupVector); // If requested, we store the scheduler for retrieval. Initialize the schedulers to the hint we have. - if (trackSchedulersInValueIteration) { + if (trackSchedulersInValueIteration && !trackingSchedulersInProvidedStorage) { this->player1SchedulerChoices = this->player1ChoicesHint.get(); this->player2SchedulerChoices = this->player2ChoicesHint.get(); } - } else if (trackSchedulersInValueIteration) { + } else if (trackSchedulersInValueIteration && !trackingSchedulersInProvidedStorage) { // If requested, we store the scheduler for retrieval. Create empty schedulers here so we can fill them // during VI. this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); @@ -240,7 +260,9 @@ namespace storm { Status status = Status::InProgress; while (status == Status::InProgress) { - multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, trackSchedulersInValueIteration ? &this->player1SchedulerChoices.get() : nullptr, trackSchedulersInValueIteration ? &this->player2SchedulerChoices.get() : nullptr); + multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, + trackSchedulersInValueIteration ? (trackingSchedulersInProvidedStorage ? player1Choices : &this->player1SchedulerChoices.get()) : nullptr, + trackSchedulersInValueIteration ? (trackingSchedulersInProvidedStorage ? player2Choices : &this->player2SchedulerChoices.get()) : nullptr); // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { @@ -262,10 +284,14 @@ namespace storm { } // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulersSet() && this->hasUniqueSolution()) { - this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); - this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); - extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); + if (trackSchedulers && this->hasUniqueSolution()) { + if (trackingSchedulersInProvidedStorage) { + extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); + } else { + this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); + this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); + extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); + } } if (!this->isCachingEnabled()) { diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 338966d27..1af23601f 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -19,7 +19,7 @@ namespace storm { StandardGameSolver(std::vector const& player1Groups, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); StandardGameSolver(std::vector&& player1Groups, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); - virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const override; + virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const override; virtual void repeatedMultiply(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; virtual void clearCache() const override; @@ -27,8 +27,8 @@ namespace storm { private: GameMethod getMethod(Environment const& env, bool isExactMode) const; - bool solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; - bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; + bool solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const; + bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const; // Computes p2Matrix * x + b, reduces the result w.r.t. player 2 choices, and then reduces the result w.r.t. player 1 choices. void multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& player2ReducedResult, std::vector& player1ReducedResult, std::vector* player1SchedulerChoices = nullptr, std::vector* player2SchedulerChoices = nullptr) const; diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index eb582f980..6e4c185ea 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1395,7 +1395,7 @@ namespace storm { // If we were asked to produce strategies, we propagate that by triggering another iteration. // We only do this if at least one strategy will be produced. - produceStrategiesInIteration = !produceStrategiesInIteration && ((player1Strategy && player1Direction == OptimizationDirection::Maximize) || (player2Strategy && player2Direction == OptimizationDirection::Maximize)); + produceStrategiesInIteration = !produceStrategiesInIteration && (player1Strategy || player2Strategy); } else { result.player1States = player1Solution; result.player2States = player2Solution; From 3ad85ba0e694ef24c8400067781dc671d440b56b Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 30 Mar 2018 23:12:00 +0200 Subject: [PATCH 228/647] fixes and improvements for game-based abstraction --- .../abstraction/ExpressionTranslator.cpp | 2 +- src/storm/abstraction/MenuGameRefiner.cpp | 197 ++++++++++++------ src/storm/abstraction/MenuGameRefiner.h | 5 +- .../prism/PrismMenuGameAbstractor.cpp | 28 +-- src/storm/adapters/GmmxxAdapter.cpp | 4 +- .../abstraction/GameBasedMdpModelChecker.cpp | 151 +++++++------- .../abstraction/GameBasedMdpModelChecker.h | 23 +- .../settings/modules/AbstractionSettings.cpp | 10 + .../settings/modules/AbstractionSettings.h | 8 + src/storm/storage/SparseMatrix.cpp | 2 + src/storm/storage/dd/Odd.cpp | 27 +++ src/storm/storage/dd/Odd.h | 13 ++ .../expressions/EquivalenceChecker.cpp | 16 +- src/storm/utility/graph.cpp | 32 +-- src/storm/utility/graph.h | 14 +- 15 files changed, 340 insertions(+), 192 deletions(-) diff --git a/src/storm/abstraction/ExpressionTranslator.cpp b/src/storm/abstraction/ExpressionTranslator.cpp index 76dd8a2a3..8bf792278 100644 --- a/src/storm/abstraction/ExpressionTranslator.cpp +++ b/src/storm/abstraction/ExpressionTranslator.cpp @@ -118,7 +118,7 @@ namespace storm { // At this point, none of the predicates was found to be equivalent, but there is no need to split as the subexpressions are not valid predicates. - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator."); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator (" << expression << ")."); } return boost::any(); } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index aad16cc2d..b570bf50c 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -63,14 +63,17 @@ namespace storm { } template - MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), addedAllGuardsFlag(false), pivotSelectionHeuristic(storm::settings::getModule().getPivotSelectionHeuristic()), splitter(), equivalenceChecker(std::move(smtSolver)) { + MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), rankPredicates(false), addedAllGuardsFlag(false), pivotSelectionHeuristic(), splitter(), equivalenceChecker(std::move(smtSolver)) { - equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); + auto const& abstractionSettings = storm::settings::getModule(); + pivotSelectionHeuristic = abstractionSettings.getPivotSelectionHeuristic(); AbstractionSettings::SplitMode splitMode = storm::settings::getModule().getSplitMode(); splitAll = splitMode == AbstractionSettings::SplitMode::All; splitPredicates = splitMode == AbstractionSettings::SplitMode::NonGuard; + rankPredicates = abstractionSettings.isRankRefinementPredicatesSet(); + equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); if (storm::settings::getModule().isAddAllGuardsSet()) { std::vector guards; @@ -82,7 +85,7 @@ namespace storm { } } performRefinement(createGlobalRefinement(preprocessPredicates(guards, RefinementPredicates::Source::InitialGuard))); - + addedAllGuardsFlag = true; } } @@ -298,6 +301,9 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { if (lower[predicateIndex] != upper[predicateIndex]) { possibleRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify()); + if (!rankPredicates) { + break; + } } } ++orderedUpdateIndex; @@ -307,49 +313,54 @@ namespace storm { STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates."); - // Since we can choose any of the deviation predicates to perform the split, we go through the remaining - // updates and build all deviation predicates. We can then check whether any of the possible refinement - // predicates also eliminates another deviation. - std::vector otherRefinementPredicates; - for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) { - storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; - storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; - - bool deviates = lower != upper; - if (deviates) { - std::map newVariableUpdates = abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first); - for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { - if (lower[predicateIndex] != upper[predicateIndex]) { - otherRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify()); + if (rankPredicates) { + // Since we can choose any of the deviation predicates to perform the split, we go through the remaining + // updates and build all deviation predicates. We can then check whether any of the possible refinement + // predicates also eliminates another deviation. + std::vector otherRefinementPredicates; + for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) { + storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; + storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; + + bool deviates = lower != upper; + if (deviates) { + std::map newVariableUpdates = abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first); + for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { + if (lower[predicateIndex] != upper[predicateIndex]) { + otherRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify()); + } } } } - } - - // Finally, go through the refinement predicates and see how many deviations they cover. - std::vector refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0); - for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - refinementPredicateIndexToCount[index] = 1; - } - for (auto const& otherPredicate : otherRefinementPredicates) { + + // Finally, go through the refinement predicates and see how many deviations they cover. + std::vector refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0); for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) { - ++refinementPredicateIndexToCount[index]; + refinementPredicateIndexToCount[index] = 1; + } + for (auto const& otherPredicate : otherRefinementPredicates) { + for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { + if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) { + ++refinementPredicateIndexToCount[index]; + } } } - } - - // Find predicate that covers the most deviations. - uint64_t chosenPredicateIndex = 0; - for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) { - chosenPredicateIndex = index; + + // Find predicate that covers the most deviations. + uint64_t chosenPredicateIndex = 0; + for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { + if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) { + chosenPredicateIndex = index; + } } + newPredicate = possibleRefinementPredicates[chosenPredicateIndex]; + STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ", (equivalent to " << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1) << " other refinement predicates)."); + } else { + newPredicate = possibleRefinementPredicates.front(); + STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << "."); } - newPredicate = possibleRefinementPredicates[chosenPredicateIndex]; STORM_LOG_ASSERT(newPredicate.isInitialized(), "Could not derive new predicate as there is no deviation."); - STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ", (equivalent to " << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1) << " other refinement predicates)"); } return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {newPredicate}); @@ -633,6 +644,9 @@ namespace storm { template boost::optional derivePredicatesFromInterpolation(storm::expressions::ExpressionManager& interpolationManager, AbstractionInformation const& abstractionInformation, std::vector> const& trace, std::map const& variableSubstitution) { + + auto start = std::chrono::high_resolution_clock::now(); + boost::optional predicates; // Create solver and interpolation groups. storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); @@ -671,16 +685,15 @@ namespace storm { STORM_LOG_DEBUG("Derived new predicate (based on interpolation at step " << step << " out of " << stepCounter << "): " << interpolant); interpolants.push_back(interpolant); } -// else { -// STORM_LOG_ASSERT(step == 0false, "The found interpolant (based on interpolation at step " << step << " out of " << stepCounter << ") is '" << interpolant << "', which shouldn't happen."); -// } } - return boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); + predicates = boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); } else { STORM_LOG_TRACE("Trace formula is satisfiable, not using interpolation."); } - - return boost::none; + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Deriving predicates using interpolation from witness of size " << trace.size() << " took " << std::chrono::duration_cast(end - start).count() << "ms."); + + return predicates; } template @@ -843,6 +856,8 @@ namespace storm { bool foundPivotState = false; ValueType pivotStateDeviation = storm::utility::zero(); auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); + + uint64_t pivotStates = 0; while (!dijkstraQueue.empty()) { auto distanceStatePair = *dijkstraQueue.begin(); @@ -878,6 +893,7 @@ namespace storm { } // If it is indeed a pivot state, we can abort the search here. if (isPivotState) { + if (considerDeviation && foundPivotState) { ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState]; if (deviationOfCurrentState > pivotStateDeviation) { @@ -913,7 +929,7 @@ namespace storm { } ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); - if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { + if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[minPlayer2Successor]); @@ -934,7 +950,7 @@ namespace storm { } ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); - if ((probabilityDistances && alternateDistance > distances[player1Successor]) || (!probabilityDistances && alternateDistance < distances[player1Successor])) { + if (probabilityDistances ? alternateDistance > distances[player1Successor] : !probabilityDistances && alternateDistance < distances[player1Successor]) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[maxPlayer2Successor]); @@ -945,6 +961,12 @@ namespace storm { } } + std::cout << "found " << pivotStates << " pivots" << std::endl; + + if (foundPivotState) { + return result; + } + // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, // which can happen when trying to refine using the qualitative result only. return boost::none; @@ -1004,6 +1026,7 @@ namespace storm { maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); } } + auto end = std::chrono::high_resolution_clock::now(); boost::optional predicates; if (useInterpolation) { @@ -1012,6 +1035,7 @@ namespace storm { if (!predicates) { predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } + end = std::chrono::high_resolution_clock::now(); STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); std::vector preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource()); @@ -1027,11 +1051,7 @@ namespace storm { boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, minStrategyPair, maxStrategyPair, &quantitativeResult.getMin().getValues(), &quantitativeResult.getMax().getValues()); - // If there was no pivot state, continue the search. - if (!optionalPivotStateResult) { - STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); - return false; - } + STORM_LOG_THROW(optionalPivotStateResult, storm::exceptions::InvalidStateException, "Did not find pivot state to proceed."); // Otherwise, we can refine. auto const& pivotStateResult = optionalPivotStateResult.get(); @@ -1121,6 +1141,12 @@ namespace storm { return true; } + struct VariableSetHash { + std::size_t operator()(std::set const& set) const { + return set.size(); + } + }; + template std::vector MenuGameRefiner::preprocessPredicates(std::vector const& predicates, RefinementPredicates::Source const& source) const { bool split = source == RefinementPredicates::Source::WeakestPrecondition && splitPredicates; @@ -1128,37 +1154,80 @@ namespace storm { split |= splitAll; if (split) { + auto start = std::chrono::high_resolution_clock::now(); AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); std::vector cleanedAtoms; + std::unordered_map, std::vector, VariableSetHash> predicateClasses; + for (auto const& predicate : predicates) { - // Split the predicates. std::vector atoms = splitter.split(predicate); - // Check which of the atoms are redundant in the sense that they are equivalent to a predicate we already have. + // Put the atoms into the right class. for (auto const& atom : atoms) { - // Check whether the newly found atom is equivalent to an atom we already have in the predicate - // set or in the set that is to be added. - bool addAtom = true; - for (auto const& oldPredicate : abstractionInformation.getPredicates()) { - if (equivalenceChecker.areEquivalent(atom, oldPredicate) || equivalenceChecker.areEquivalent(atom, !oldPredicate)) { - addAtom = false; + std::set vars = atom.getVariables(); + predicateClasses[vars].push_back(atom); + } + } + + // Now clean the classes in the sense that redundant predicates are cleaned. + for (auto& predicateClass : predicateClasses) { + std::vector cleanedAtomsOfClass; + + for (auto const& predicate : predicateClass.second) { + bool addPredicate = true; + for (auto const& atom : cleanedAtomsOfClass) { + if (predicate.areSame(atom)) { + addPredicate = false; break; } - } - for (auto const& addedAtom : cleanedAtoms) { - if (equivalenceChecker.areEquivalent(addedAtom, atom) || equivalenceChecker.areEquivalent(addedAtom, !atom)) { - addAtom = false; + + if (addPredicate && equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) { + addPredicate = false; break; } } - - if (addAtom) { - cleanedAtoms.push_back(atom); + if (addPredicate) { + cleanedAtomsOfClass.push_back(predicate); } } + + predicateClass.second = std::move(cleanedAtomsOfClass); + } + + std::unordered_map, std::vector, VariableSetHash> oldPredicateClasses; + for (auto const& oldPredicate : abstractionInformation.getPredicates()) { + std::set vars = oldPredicate.getVariables(); + + oldPredicateClasses[vars].push_back(oldPredicate); + } + + for (auto const& predicateClass : predicateClasses) { + auto oldPredicateClassIt = oldPredicateClasses.find(predicateClass.first); + if (oldPredicateClassIt != oldPredicateClasses.end()) { + for (auto const& newAtom : predicateClass.second) { + for (auto const& oldPredicate : oldPredicateClassIt->second) { + bool addAtom = true; + if (newAtom.areSame(oldPredicate)) { + addAtom = false; + break; + } + if (equivalenceChecker.areEquivalentModuloNegation(newAtom, oldPredicate)) { + addAtom = false; + break; + } + if (addAtom) { + cleanedAtoms.push_back(newAtom); + } + } + } + } else { + cleanedAtoms.insert(cleanedAtoms.end(), predicateClass.second.begin(), predicateClass.second.end()); + } } + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Preprocessing predicates took " << std::chrono::duration_cast(end - start).count() << "ms."); return cleanedAtoms; } else { diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index a38ec0bf0..1db5ed8df 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -78,7 +78,7 @@ namespace storm { ExplicitPivotStateResult() = default; uint64_t pivotState; - + /// The distance with which the state in question is reached. ValueType distance; @@ -177,6 +177,9 @@ namespace storm { /// A flag indicating whether predicates derived from weakest preconditions shall be split before using them for refinement. bool splitPredicates; + /// A flag indicating whether predicates are to be ranked. + bool rankPredicates; + /// A flag indicating whether all guards have been used to refine the abstraction. bool addedAllGuardsFlag; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 718207120..e7bfe8522 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -81,7 +81,7 @@ namespace storm { STORM_LOG_THROW(predicate.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expecting a predicate of type bool."); predicateIndices.push_back(abstractionInformation.getOrAddPredicate(predicate)); } - + // Refine all abstract modules. for (auto& module : modules) { module.refine(predicateIndices); @@ -171,27 +171,29 @@ namespace storm { storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - + + // Cut transition relation to the reachable states for backward search. + transitionRelation &= reachableStates; + relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { - // Cut transition relation to the reachable states for backward search. - transitionRelation &= reachableStates; - + // Get the target state BDD. storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); - + // In the presence of target states, we keep only states that can reach the target states. reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - + + // Include all successors of reachable states, because the backward search otherwise potentially + // cuts probability 0 choices of these states. + reachableStates = reachableStates || reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + // Cut the transition relation to the 'extended backward reachable states', so we have the appropriate self- // loops of (now) deadlock states. transitionRelation &= reachableStates; - - // Include all successors of reachable states, because the backward search otherwise potentially - // cuts probability 0 choices of these states. - reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.stop(); - + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); } @@ -212,7 +214,7 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates).template toAdd(); + storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= commandUpdateProbabilitiesAdd; transitionMatrix += deadlockTransitions; diff --git a/src/storm/adapters/GmmxxAdapter.cpp b/src/storm/adapters/GmmxxAdapter.cpp index 4210a00ee..ee5873eea 100644 --- a/src/storm/adapters/GmmxxAdapter.cpp +++ b/src/storm/adapters/GmmxxAdapter.cpp @@ -13,7 +13,7 @@ namespace storm { template std::unique_ptr> GmmxxAdapter::toGmmxxSparseMatrix(storm::storage::SparseMatrix const& matrix) { uint_fast64_t realNonZeros = matrix.getEntryCount(); - STORM_LOG_DEBUG("Converting " << matrix.getRowCount() << "x" << matrix.getColumnCount() << " matrix with " << realNonZeros << " non-zeros to gmm++ format."); + STORM_LOG_TRACE("Converting " << matrix.getRowCount() << "x" << matrix.getColumnCount() << " matrix with " << realNonZeros << " non-zeros to gmm++ format."); // Prepare the resulting matrix. std::unique_ptr> result(new gmm::csr_matrix(matrix.getRowCount(), matrix.getColumnCount())); @@ -37,7 +37,7 @@ namespace storm { std::swap(result->ir, columns); std::swap(result->pr, values); - STORM_LOG_DEBUG("Done converting matrix to gmm++ format."); + STORM_LOG_TRACE("Done converting matrix to gmm++ format."); return result; } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index bd77c5cd5..a1900236c 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -54,6 +54,7 @@ namespace storm { using storm::abstraction::ExplicitQuantitativeResult; using storm::abstraction::ExplicitQuantitativeResultMinMax; using storm::abstraction::ExplicitGameStrategyPair; + using detail::PreviousExplicitResult; template GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { @@ -62,13 +63,16 @@ namespace storm { storm::prism::Program const& originalProgram = model.asPrismProgram(); STORM_LOG_THROW(originalProgram.getModelType() == storm::prism::Program::ModelType::DTMC || originalProgram.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::NotSupportedException, "Currently only DTMCs/MDPs are supported by the game-based model checker."); + auto flattenStart = std::chrono::high_resolution_clock::now(); // Flatten the modules if there is more than one. if (originalProgram.getNumberOfModules() > 1) { preprocessedModel = originalProgram.flattenModules(this->smtSolverFactory); } else { preprocessedModel = originalProgram; } - + auto flattenEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Flattened model in " << std::chrono::duration_cast(flattenEnd - flattenStart).count() << "ms."); + STORM_LOG_TRACE("Game-based model checker got program " << preprocessedModel.asPrismProgram()); } else { storm::jani::Model const& originalModel = model.asJaniModel(); @@ -391,22 +395,31 @@ namespace storm { } template - ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair, ExplicitQuantitativeResult const* startingQuantitativeResult = nullptr, ExplicitGameStrategyPair const* startingStrategyPair = nullptr) { + ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair, storm::dd::Odd const& odd, ExplicitQuantitativeResult const* startingQuantitativeResult = nullptr, ExplicitGameStrategyPair const* startingStrategyPair = nullptr, boost::optional> const& previousResult = boost::none) { bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; auto const& player1Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer1States(); auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); - // If there are no maybe states, we construct the quantitative result from the qualitative result alone. + ExplicitQuantitativeResult result(maybeStates.size()); + storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); + + // If there are no maybe states, there is nothing we need to solve. if (maybeStates.empty()) { - ExplicitQuantitativeResult result(maybeStates.size()); - storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); return result; } + + // If there is a previous result, unpack the previous values with respect to the new ODD. + if (previousResult) { + previousResult.get().odd.oldToNewIndex(odd, [&previousResult,&result,player2Min] (uint64_t oldOffset, uint64_t newOffset) { + result.getValues()[newOffset] = player2Min ? previousResult.get().values.getMin().getValues()[oldOffset] : previousResult.get().values.getMax().getValues()[oldOffset]; + }); + } // Otherwise, we need to solve a (sub)game. - + STORM_LOG_TRACE("Solving " << maybeStates.getNumberOfSetBits()<< " maybe states."); + // Create the game by selecting all maybe player 2 states (non-prob0/1) of all maybe player 1 states. std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); uint64_t position = 0; @@ -440,6 +453,10 @@ namespace storm { if (startingQuantitativeResult) { storm::utility::vector::selectVectorValues(values, maybeStates, startingQuantitativeResult->getValues()); } + if (previousResult) { + STORM_LOG_ASSERT(!startingQuantitativeResult, "Cannot take two different hints."); + storm::utility::vector::selectVectorValues(values, maybeStates, result.getValues()); + } // Prepare scheduler storage. std::vector player1Scheduler(subPlayer1Groups.size() - 1); @@ -473,9 +490,7 @@ namespace storm { // Solve actual game and track schedulers. gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler); - // Create combined result for all states. - ExplicitQuantitativeResult result(maybeStates.size()); - storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); + // Set values according to quantitative result (qualitative result has already been taken care of). storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. @@ -526,19 +541,19 @@ namespace storm { } abstractor->addTerminalStates(targetStateExpression); abstractor->setTargetStates(targetStateExpression); + // Create a refiner that can be used to refine the abstraction when needed. storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); refiner.refine(initialPredicates); - + storm::dd::Bdd globalConstraintStates = abstractor->getStates(constraintExpression); storm::dd::Bdd globalTargetStates = abstractor->getStates(targetStateExpression); // Enter the main-loop of abstraction refinement. boost::optional> previousSymbolicQualitativeResult = boost::none; boost::optional> previousSymbolicMinQuantitativeResult = boost::none; - boost::optional previousExplicitQualitativeResult = boost::none; - // boost::optional> previousExplicitMinQuantitativeResult = boost::none; + boost::optional> previousExplicitResult = boost::none; for (uint_fast64_t iterations = 0; iterations < maximalNumberOfAbstractions; ++iterations) { auto iterationStart = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Starting iteration " << iterations << "."); @@ -568,7 +583,7 @@ namespace storm { if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousSymbolicQualitativeResult, previousSymbolicMinQuantitativeResult); } else { - result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousExplicitQualitativeResult); + result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousExplicitResult); } if (result) { @@ -684,7 +699,7 @@ namespace storm { } template - std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional& previousQualitativeResult) { + std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult) { STORM_LOG_TRACE("Using sparse solving."); // (0) Start by transforming the necessary symbolic elements to explicit ones. @@ -749,7 +764,7 @@ namespace storm { // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). auto qualitativeStart = std::chrono::high_resolution_clock::now(); - ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, minStrategyPair, maxStrategyPair); + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousResult, odd, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, minStrategyPair, maxStrategyPair); std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); if (result) { return result; @@ -782,22 +797,23 @@ namespace storm { return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); } + ExplicitQuantitativeResultMinMax quantitativeResult; + // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. if (!qualitativeRefinement) { // At this point, we know that we cannot answer the query without further numeric computation. STORM_LOG_TRACE("Starting numerical solution step."); - ExplicitQuantitativeResultMinMax quantitativeResult; - + // (7) Solve the min values and check whether we can give the answer already. auto quantitativeStart = std::chrono::high_resolution_clock::now(); - quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair)); + quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair, odd, nullptr, nullptr, this->reuseQuantitativeResults ? previousResult : boost::none)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); if (result) { return result; } // (8) Solve the max values and check whether we can give the answer already. - quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, &quantitativeResult.getMin(), &minStrategyPair)); + quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); if (result) { return result; @@ -821,6 +837,33 @@ namespace storm { refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + + if (this->reuseQuantitativeResults) { + PreviousExplicitResult nextPreviousResult; + nextPreviousResult.values = std::move(quantitativeResult); + nextPreviousResult.odd = odd; + + // We transform the offset choices for the states to their labels, so we can more easily identify + // them in the next iteration. + nextPreviousResult.minPlayer1Labels.resize(odd.getTotalOffset()); + nextPreviousResult.maxPlayer1Labels.resize(odd.getTotalOffset()); + for (uint64_t player1State = 0; player1State < odd.getTotalOffset(); ++player1State) { + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(player1State)) { + nextPreviousResult.minPlayer1Labels[player1State] = player1Labeling[minStrategyPair.getPlayer1Strategy().getChoice(player1State)]; + } else { + nextPreviousResult.minPlayer1Labels[player1State] = std::numeric_limits::max(); + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(player1State)) { + nextPreviousResult.maxPlayer1Labels[player1State] = player1Labeling[maxStrategyPair.getPlayer1Strategy().getChoice(player1State)]; + } else { + nextPreviousResult.minPlayer1Labels[player1State] = std::numeric_limits::max(); + } + } + + previousResult = std::move(nextPreviousResult); + + STORM_LOG_TRACE("Prepared next previous result to reuse values."); + } } return nullptr; @@ -885,64 +928,17 @@ namespace storm { } template - ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair) { + ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair) { ExplicitQualitativeGameResultMinMax result; - -// if (reuseQualitativeResults) { -// // Depending on the player 1 direction, we choose a different order of operations. -// if (player1Direction == storm::OptimizationDirection::Minimize) { -// // (1) min/min: compute prob0 using the game functions -// result.prob0Min = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); -// -// // (2) min/min: compute prob1 using the MDP functions -// storm::dd::Bdd candidates = game.getReachableStates() && !result.prob0Min.player1States; -// storm::dd::Bdd prob1MinMinMdp = storm::utility::graph::performProb1A(game, transitionMatrixBdd, previousQualitativeResult ? previousQualitativeResult.get().prob1Min.player1States : targetStates, candidates); -// -// // (3) min/min: compute prob1 using the game functions -// result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MinMinMdp)); -// -// // (4) min/max: compute prob 0 using the game functions -// result.prob0Max = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); -// -// // (5) min/max: compute prob 1 using the game functions -// // We know that only previous prob1 states can now be prob 1 states again, because the upper bound -// // values can only decrease over iterations. -// boost::optional> prob1Candidates; -// if (previousQualitativeResult) { -// prob1Candidates = previousQualitativeResult.get().prob1Max.player1States; -// } -// result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true, prob1Candidates); -// } else { -// // (1) max/max: compute prob0 using the game functions -// result.prob0Max = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); -// -// // (2) max/max: compute prob1 using the MDP functions, reuse prob1 states of last iteration to constrain the candidate states. -// storm::dd::Bdd candidates = game.getReachableStates() && !result.prob0Max.player1States; -// if (previousQualitativeResult) { -// candidates &= previousQualitativeResult.get().prob1Max.player1States; -// } -// storm::dd::Bdd prob1MaxMaxMdp = storm::utility::graph::performProb1E(game, transitionMatrixBdd, constraintStates, targetStates, candidates); -// -// // (3) max/max: compute prob1 using the game functions, reuse prob1 states from the MDP precomputation -// result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true, boost::make_optional(prob1MaxMaxMdp)); -// -// // (4) max/min: compute prob0 using the game functions -// result.prob0Min = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true); -// -// // (5) max/min: compute prob1 using the game functions, use prob1 from max/max as the candidate set -// result.prob1Min = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, true, true, boost::make_optional(prob1MaxMaxMdp)); -// } -// } else { - result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair.getPlayer1Strategy(), &minStrategyPair.getPlayer2Strategy()); - result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair.getPlayer1Strategy(), &minStrategyPair.getPlayer2Strategy()); - result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair.getPlayer1Strategy(), &maxStrategyPair.getPlayer2Strategy()); - result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair.getPlayer1Strategy(), &maxStrategyPair.getPlayer2Strategy()); -// } - - STORM_LOG_TRACE("Qualitative precomputation completed."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); + + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); + result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); + result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); + result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); + + STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); + STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); return result; } @@ -1003,9 +999,8 @@ namespace storm { result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); } - STORM_LOG_TRACE("Qualitative precomputation completed."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); STORM_LOG_ASSERT(checkQualitativeStrategies(result, targetStates), "Qualitative strategies appear to be broken."); return result; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index b54a510c8..0319e48c5 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -6,11 +6,13 @@ #include "storm/storage/prism/Program.h" #include "storm/storage/dd/DdType.h" +#include "storm/storage/dd/Odd.h" #include "storm/storage/SymbolicModelDescription.h" #include "storm/abstraction/SymbolicQualitativeGameResult.h" #include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitQuantitativeResult.h" #include "storm/logic/Bound.h" @@ -40,9 +42,6 @@ namespace storm { class ExplicitQualitativeGameResult; class ExplicitQualitativeGameResultMinMax; - template - class ExplicitQuantitativeResult; - template class ExplicitQuantitativeResultMinMax; @@ -56,6 +55,18 @@ namespace storm { using storm::abstraction::SymbolicQualitativeGameResultMinMax; using storm::abstraction::ExplicitQualitativeGameResult; using storm::abstraction::ExplicitQualitativeGameResultMinMax; + using storm::abstraction::ExplicitQuantitativeResult; + using storm::abstraction::ExplicitQuantitativeResultMinMax; + + namespace detail { + template + struct PreviousExplicitResult { + ExplicitQuantitativeResultMinMax values; + std::vector minPlayer1Labels; + std::vector maxPlayer1Labels; + storm::dd::Odd odd; + }; + } template class GameBasedMdpModelChecker : public AbstractModelChecker { @@ -75,7 +86,7 @@ namespace storm { virtual bool canHandle(CheckTask const& checkTask) const override; virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) override; - + private: /*! * Performs the core part of the abstraction-refinement loop. @@ -83,7 +94,7 @@ namespace storm { std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); - std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional& previousQualitativeResult); + std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult); /*! * Retrieves the initial predicates for the abstraction. @@ -101,7 +112,7 @@ namespace storm { */ SymbolicQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); - ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional const& previousQualitativeResult, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); + ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const; diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 341571ef6..8a7f92468 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -24,6 +24,7 @@ namespace storm { const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; const std::string AbstractionSettings::solveModeOptionName = "solve"; const std::string AbstractionSettings::maximalAbstractionOptionName = "maxabs"; + const std::string AbstractionSettings::rankRefinementPredicatesOptionName = "rankpred"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -80,6 +81,11 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("off").build()) .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, rankRefinementPredicatesOptionName, true, "Sets whether to rank the refinement predicates if there are multiple.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -166,6 +172,10 @@ namespace storm { return this->getOption(maximalAbstractionOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); } + bool AbstractionSettings::isRankRefinementPredicatesSet() const { + return this->getOption(rankRefinementPredicatesOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 90a7ea668..7fe212fbd 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -116,6 +116,13 @@ namespace storm { */ uint_fast64_t getMaximalAbstractionCount() const; + /* + * Determines whether refinement predicates are to be ranked. + * + * @return True iff the refinement predicates are to be ranked. + */ + bool isRankRefinementPredicatesSet() const; + const static std::string moduleName; private: @@ -130,6 +137,7 @@ namespace storm { const static std::string restrictToRelevantStatesOptionName; const static std::string solveModeOptionName; const static std::string maximalAbstractionOptionName; + const static std::string rankRefinementPredicatesOptionName; }; } diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 3f0f25828..e27fae045 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -970,6 +970,7 @@ namespace storm { // Copy over selected entries. rowGroupCount = 0; index_type rowCount = 0; + subEntries = 0; for (auto index : rowGroupConstraint) { if (!this->hasTrivialRowGrouping()) { matrixBuilder.newRowGroup(rowCount); @@ -985,6 +986,7 @@ namespace storm { matrixBuilder.addNextValue(rowCount, rowGroupCount, storm::utility::zero()); insertedDiagonalElement = true; } + ++subEntries; matrixBuilder.addNextValue(rowCount, columnBitsSetBeforeIndex[it->getColumn()], it->getValue()); } } diff --git a/src/storm/storage/dd/Odd.cpp b/src/storm/storage/dd/Odd.cpp index 0a0712b2b..ff3a1a3ef 100644 --- a/src/storm/storage/dd/Odd.cpp +++ b/src/storm/storage/dd/Odd.cpp @@ -90,6 +90,33 @@ namespace storm { expandValuesToVectorRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), oldValues, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), newValues); } } + + void Odd::oldToNewIndex(storm::dd::Odd const& newOdd, std::function const& callback) const { + STORM_LOG_ASSERT(this->getHeight() < newOdd.getHeight(), "Expected increase in height."); + oldToNewIndexRec(0, *this, 0, newOdd, callback); + } + + void Odd::oldToNewIndexRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::function const& callback) { + if (oldOdd.getTotalOffset() == 0 || newOdd.getTotalOffset() == 0) { + return; + } + + if (oldOdd.isTerminalNode()) { + if (oldOdd.getThenOffset() != 0) { + if (newOdd.isTerminalNode()) { + if (newOdd.getThenOffset() != 0) { + callback(oldOffset, newOffset); + } + } else { + oldToNewIndexRec(oldOffset, oldOdd, newOffset, newOdd.getElseSuccessor(), callback); + oldToNewIndexRec(oldOffset, oldOdd, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), callback); + } + } + } else { + oldToNewIndexRec(oldOffset, oldOdd.getElseSuccessor(), newOffset, newOdd.getElseSuccessor(), callback); + oldToNewIndexRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), callback); + } + } void Odd::exportToDot(std::string const& filename) const { std::ofstream dotFile; diff --git a/src/storm/storage/dd/Odd.h b/src/storm/storage/dd/Odd.h index d62bf1844..ac23142f4 100644 --- a/src/storm/storage/dd/Odd.h +++ b/src/storm/storage/dd/Odd.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace storm { namespace storage { @@ -116,6 +117,16 @@ namespace storm { template void expandExplicitVector(storm::dd::Odd const& newOdd, std::vector const& oldValues, std::vector& newValues) const; + /*! + * Translates the indices of the old ODD to that of the new ODD by calling the callback for each old-new + * offset pair. Note that for each old offset, there may be multiple new offsets. The new ODD is expected + * to extend the old ODD by adding layers *at the bottom*. + * + * @param newOdd The new ODD to use. + * @param callback The callback function. + */ + void oldToNewIndex(storm::dd::Odd const& newOdd, std::function const& callback) const; + /*! * Exports the ODD in the dot format to the given file. * @@ -155,6 +166,8 @@ namespace storm { template static void expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, std::vector const& oldValues, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::vector& newValues); + static void oldToNewIndexRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::function const& callback); + // The then- and else-nodes. std::shared_ptr elseNode; std::shared_ptr thenNode; diff --git a/src/storm/storage/expressions/EquivalenceChecker.cpp b/src/storm/storage/expressions/EquivalenceChecker.cpp index c00d4fae6..5d1ffad56 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.cpp +++ b/src/storm/storage/expressions/EquivalenceChecker.cpp @@ -21,14 +21,26 @@ namespace storm { bool EquivalenceChecker::areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { this->smtSolver->push(); - this->smtSolver->add((first && !second) || (!first && second)); + this->smtSolver->add(!storm::expressions::iff(first, second)); bool equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; this->smtSolver->pop(); return equivalent; } bool EquivalenceChecker::areEquivalentModuloNegation(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { - return this->areEquivalent(first, second) || this->areEquivalent(first, !second); + this->smtSolver->push(); + this->smtSolver->add(!storm::expressions::iff(first, second)); + bool equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + if (equivalent) { + this->smtSolver->pop(); + return true; + } + this->smtSolver->pop(); + this->smtSolver->push(); + this->smtSolver->add(!storm::expressions::iff(first, !second)); + equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + this->smtSolver->pop(); + return equivalent; } } diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 6e4c185ea..4844abb83 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -9,7 +9,7 @@ #include "storm/storage/dd/Add.h" #include "storm/storage/dd/DdManager.h" -#include "storm/abstraction/ExplicitGameStrategy.h" +#include "storm/abstraction/ExplicitGameStrategyPair.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/models/symbolic/DeterministicModel.h" @@ -1085,7 +1085,7 @@ namespace storm { } template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy) { + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair) { ExplicitGameProb01Result result(psiStates, storm::storage::BitVector(transitionMatrix.getRowGroupCount())); @@ -1163,7 +1163,7 @@ namespace storm { result.player2States.complement(); // Generate player 1 strategy if required. - if (player1Strategy) { + if (strategyPair) { for (auto player1State : result.player1States) { if (player1Direction == storm::OptimizationDirection::Minimize) { // At least one player 2 successor is a state with probability 0, find it. @@ -1176,16 +1176,16 @@ namespace storm { } } STORM_LOG_ASSERT(foundProb0Successor, "Expected at least one state 2 successor with probability 0."); - player1Strategy->setChoice(player1State, player2State); + strategyPair->getPlayer1Strategy().setChoice(player1State, player2State); } else { // Since all player 2 successors are states with probability 0, just pick any. - player1Strategy->setChoice(player1State, player1Groups[player1State]); + strategyPair->getPlayer1Strategy().setChoice(player1State, player1Groups[player1State]); } } } // Generate player 2 strategy if required. - if (player2Strategy) { + if (strategyPair) { for (auto player2State : result.player2States) { if (player2Direction == storm::OptimizationDirection::Minimize) { // At least one distribution only has successors with probability 0, find it. @@ -1207,10 +1207,10 @@ namespace storm { } STORM_LOG_ASSERT(foundProb0SuccessorDistribution, "Expected at least one distribution with only successors with probability 0."); - player2Strategy->setChoice(player2State, row); + strategyPair->getPlayer2Strategy().setChoice(player2State, row); } else { // Since all player 1 successors are states with probability 0, just pick any. - player2Strategy->setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State]); + strategyPair->getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State]); } } } @@ -1286,7 +1286,7 @@ namespace storm { } template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy, boost::optional const& player1Candidates) { + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair, boost::optional const& player1Candidates) { // During the execution, the two state sets in the result hold the potential player 1/2 states. ExplicitGameProb01Result result; @@ -1349,8 +1349,8 @@ namespace storm { if (addPlayer2State) { player2Solution.set(player2Predecessor); - if (produceStrategiesInIteration && player2Strategy) { - player2Strategy->setChoice(player2Predecessor, validChoice); + if (produceStrategiesInIteration) { + strategyPair->getPlayer2Strategy().setChoice(player2Predecessor, validChoice); } // Check whether the addition of the player 2 state changes the state of the (single) @@ -1377,8 +1377,8 @@ namespace storm { if (addPlayer1State) { player1Solution.set(player1Predecessor); - if (produceStrategiesInIteration && player1Strategy) { - player1Strategy->setChoice(player1Predecessor, validChoice); + if (produceStrategiesInIteration) { + strategyPair->getPlayer1Strategy().setChoice(player1Predecessor, validChoice); } stack.emplace_back(player1Predecessor); @@ -1395,7 +1395,7 @@ namespace storm { // If we were asked to produce strategies, we propagate that by triggering another iteration. // We only do this if at least one strategy will be produced. - produceStrategiesInIteration = !produceStrategiesInIteration && (player1Strategy || player2Strategy); + produceStrategiesInIteration = !produceStrategiesInIteration && strategyPair; } else { result.player1States = player1Solution; result.player2States = player2Solution; @@ -1680,9 +1680,9 @@ namespace storm { template std::pair performProb01Min(storm::models::sparse::NondeterministicModel> const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); #endif - template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy); + template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair); - template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy, storm::abstraction::ExplicitGameStrategy* player2Strategy, boost::optional const& player1Candidates); + template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair, boost::optional const& player1Candidates); template std::vector getTopologicalSort(storm::storage::SparseMatrix const& matrix) ; diff --git a/src/storm/utility/graph.h b/src/storm/utility/graph.h index e99fd0ba6..3793b42d8 100644 --- a/src/storm/utility/graph.h +++ b/src/storm/utility/graph.h @@ -50,7 +50,7 @@ namespace storm { } namespace abstraction { - class ExplicitGameStrategy; + class ExplicitGameStrategyPair; } namespace utility { @@ -651,13 +651,11 @@ namespace storm { * @param psiStates The psi states of the model. * @param player1Direction The optimization direction of player 1. * @param player2Direction The optimization direction of player 2. - * @param player1Strategy If not null, a player 1 strategy is synthesized and the corresponding choices - * are written to this strategy. - * @param player2Strategy If not null, a player 2 strategy is synthesized and the corresponding choices + * @param strategyPair If not null, player 1 and t2 strategies are synthesized and the corresponding choices * are written to this strategy. */ template - ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy = nullptr, storm::abstraction::ExplicitGameStrategy* player2Strategy = nullptr); + ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair = nullptr); /*! * Computes the set of states that have probability 1 given the strategies of the two players. @@ -670,14 +668,12 @@ namespace storm { * @param psiStates The psi states of the model. * @param player1Direction The optimization direction of player 1. * @param player2Direction The optimization direction of player 2. - * @param player1Strategy If not null, a player 1 strategy is synthesized and the corresponding choices - * are written to this strategy. - * @param player2Strategy If not null, a player 2 strategy is synthesized and the corresponding choices + * @param strategyPair If not null, player 1 and t2 strategies are synthesized and the corresponding choices * are written to this strategy. * @param player1Candidates If given, this set constrains the candidates of player 1 states that are considered. */ template - ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategy* player1Strategy = nullptr, storm::abstraction::ExplicitGameStrategy* player2Strategy = nullptr, boost::optional const& player1Candidates = boost::none); + ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair = nullptr, boost::optional const& player1Candidates = boost::none); /*! * Performs a topological sort of the states of the system according to the given transitions. From 72c1e79ccd9a9c70149a5969dd74b0f885333121 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Sat, 31 Mar 2018 13:18:31 +0200 Subject: [PATCH 229/647] Mention -pc flag in error message --- src/storm/storage/prism/Program.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index aea47fd09..41a9693bc 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -1124,7 +1124,7 @@ namespace storm { if (this->getModelType() == Program::ModelType::DTMC || this->getModelType() == Program::ModelType::MDP) { STORM_LOG_THROW(!hasMarkovianCommand, storm::exceptions::WrongFormatException, "Discrete-time model must not have Markovian commands."); } else if (this->getModelType() == Program::ModelType::CTMC) { - STORM_LOG_THROW(!hasProbabilisticCommand, storm::exceptions::WrongFormatException, "The input model is a CTMC, but uses probabilistic commands like they are used in PRISM. Please use Markovian commands instead or turn on the PRISM compatibility mode using the appropriate flag."); + STORM_LOG_THROW(!hasProbabilisticCommand, storm::exceptions::WrongFormatException, "The input model is a CTMC, but uses probabilistic commands like they are used in PRISM. Please use Markovian commands instead or turn on the PRISM compatibility mode using the flag '-pc'."); } // Now check the reward models. From 1169195be78930cdb9685780782f3c91d9bd950c Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 31 Mar 2018 17:24:45 +0200 Subject: [PATCH 230/647] some fixes (in particular for warnings) --- src/storm/abstraction/MenuGameRefiner.cpp | 34 ++++++++++++------- src/storm/builder/DdJaniModelBuilder.cpp | 2 +- .../SparseExplorationModelChecker.cpp | 2 +- .../DynamicStatePriorityQueue.h | 2 +- ...ministicModelBisimulationDecomposition.cpp | 2 +- ...ministicModelBisimulationDecomposition.cpp | 2 +- .../storage/jani/ParallelComposition.cpp | 2 +- src/storm/storage/jani/ParallelComposition.h | 2 +- 8 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index b570bf50c..91fbb17e0 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -639,6 +639,7 @@ namespace storm { } predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution)); + return std::make_pair(predicates, stepVariableToCopiedVariableMap); } @@ -649,11 +650,13 @@ namespace storm { boost::optional predicates; // Create solver and interpolation groups. + auto assertionStart = std::chrono::high_resolution_clock::now(); storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); uint64_t stepCounter = 0; auto traceIt = trace.rbegin(); auto traceIte = trace.rend(); for (; traceIt != traceIte; ++traceIt) { + auto iterationStart = std::chrono::high_resolution_clock::now(); auto const& step = *traceIt; interpolatingSolver.push(); @@ -661,15 +664,13 @@ namespace storm { for (auto const& predicate : step) { interpolatingSolver.add(predicate); } - storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); - // If the result already became unsatisfiable - if (result == storm::solver::SmtSolver::CheckResult::Unsat) { - STORM_LOG_TRACE("Trace formula became unsatisfiable after step " << stepCounter << "."); - break; - } + auto iterationEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Asserting step of trace formula took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); ++stepCounter; } + auto assertionEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Asserting trace formula until unsatisfiability took " << std::chrono::duration_cast(assertionEnd - assertionStart).count() << "ms."); // Now encode the trace as an SMT problem. storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); @@ -691,7 +692,12 @@ namespace storm { STORM_LOG_TRACE("Trace formula is satisfiable, not using interpolation."); } auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Deriving predicates using interpolation from witness of size " << trace.size() << " took " << std::chrono::duration_cast(end - start).count() << "ms."); + + if (predicates) { + STORM_LOG_TRACE("Deriving predicates using interpolation from witness of size " << trace.size() << " took " << std::chrono::duration_cast(end - start).count() << "ms."); + } else { + STORM_LOG_TRACE("Tried deriving predicates using interpolation but failed in " << std::chrono::duration_cast(end - start).count() << "ms."); + } return predicates; } @@ -712,8 +718,11 @@ namespace storm { std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState); - + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from symbolic most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } @@ -725,8 +734,11 @@ namespace storm { std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, pivotStateResult, odd); - + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } @@ -856,8 +868,6 @@ namespace storm { bool foundPivotState = false; ValueType pivotStateDeviation = storm::utility::zero(); auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); - - uint64_t pivotStates = 0; while (!dijkstraQueue.empty()) { auto distanceStatePair = *dijkstraQueue.begin(); @@ -961,8 +971,6 @@ namespace storm { } } - std::cout << "found " << pivotStates << " pivots" << std::endl; - if (foundPivotState) { return result; } diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 507cde01a..091c3fe6d 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -1275,7 +1275,7 @@ namespace storm { // Finally treat the transient assignments. std::map> transientEdgeAssignments; if (!this->transientVariables.empty()) { - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = sourceLocationAndGuard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } ); } diff --git a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp index c5dc5e036..73e880662 100644 --- a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp +++ b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp @@ -341,7 +341,7 @@ namespace storm { }); } else if (explorationInformation.useProbabilityHeuristic()) { std::transform(row.begin(), row.end(), probabilities.begin(), - [&bounds, &explorationInformation] (storm::storage::MatrixEntry const& entry) { + [] (storm::storage::MatrixEntry const& entry) { return entry.getValue(); }); } diff --git a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h index 0ac38769d..4065ee265 100644 --- a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h +++ b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h @@ -17,7 +17,7 @@ namespace storm { namespace stateelimination { struct PriorityComparator { - bool operator()(std::pair const& first, std::pair const& second) { + bool operator()(std::pair const& first, std::pair const& second) const { return (first.second < second.second) || (first.second == second.second && first.first < second.first) ; } }; diff --git a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp index 2a73744cf..6cbd57f09 100644 --- a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp @@ -419,7 +419,7 @@ namespace storm { // the sorting is over. Otherwise, this interferes with the data used in the sorting process. storm::storage::sparse::state_type originalBlockIndex = block.getBeginIndex(); auto split = this->partition.splitBlock(block, - [&weakStateLabels,&block,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { + [&weakStateLabels,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { return weakStateLabels[this->partition.getPosition(state1) - originalBlockIndex] < weakStateLabels[this->partition.getPosition(state2) - originalBlockIndex]; }, [this, &splitterQueue, &block] (bisimulation::Block& newBlock) { diff --git a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp index 473ae556a..019ec40c2 100644 --- a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp @@ -367,7 +367,7 @@ namespace storm { bool result = quotientDistributionsLess(state1, state2); return result; }, - [this, &block, &splitterQueue, &newBlocks] (Block& newBlock) { + [&newBlocks] (Block& newBlock) { newBlocks.push_back(&newBlock); }); diff --git a/src/storm/storage/jani/ParallelComposition.cpp b/src/storm/storage/jani/ParallelComposition.cpp index d81db1d91..0d439e0ce 100644 --- a/src/storm/storage/jani/ParallelComposition.cpp +++ b/src/storm/storage/jani/ParallelComposition.cpp @@ -116,7 +116,7 @@ namespace storm { return !(vector1 == vector2); } - bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) { + bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const { STORM_LOG_THROW(vector1.size() == vector2.size(), storm::exceptions::WrongFormatException, "Cannot compare synchronization vectors of different size."); for (uint64_t i = 0; i < vector1.size(); ++i) { if (vector1.getInput(i) < vector2.getInput(i)) { diff --git a/src/storm/storage/jani/ParallelComposition.h b/src/storm/storage/jani/ParallelComposition.h index c3d41717c..381ace5f8 100644 --- a/src/storm/storage/jani/ParallelComposition.h +++ b/src/storm/storage/jani/ParallelComposition.h @@ -62,7 +62,7 @@ namespace storm { bool operator!=(SynchronizationVector const& vector1, SynchronizationVector const& vector2); struct SynchronizationVectorLexicographicalLess { - bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2); + bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const; }; std::ostream& operator<<(std::ostream& stream, SynchronizationVector const& synchronizationVector); From 03a94016b36f618f60a9d9d57d5615a264e1cedc Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 2 Apr 2018 13:01:44 +0200 Subject: [PATCH 231/647] workaround for bug in clang (bug report filed) --- src/storm/utility/constants.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index 2a968422f..6086f1bf9 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -163,13 +163,26 @@ namespace storm { template ValueType minimum(std::vector const& values) { - return minmax(values).first; + assert(!values.empty()); + ValueType min = values.front(); + for (auto const& vt : values) { + if (vt < min) { + min = vt; + } + } + return min; } - template ValueType maximum(std::vector const& values) { - return minmax(values).second; + assert(!values.empty()); + ValueType max = values.front(); + for (auto const& vt : values) { + if (vt > max) { + max = vt; + } + } + return max; } template @@ -896,7 +909,7 @@ namespace storm { template bool isZero(int const& value); template bool isConstant(int const& value); template bool isInfinity(int const& value); - + // uint32_t template uint32_t one(); template uint32_t zero(); @@ -905,7 +918,7 @@ namespace storm { template bool isZero(uint32_t const& value); template bool isConstant(uint32_t const& value); template bool isInfinity(uint32_t const& value); - + // storm::storage::sparse::state_type template storm::storage::sparse::state_type one(); template storm::storage::sparse::state_type zero(); @@ -914,11 +927,11 @@ namespace storm { template bool isZero(storm::storage::sparse::state_type const& value); template bool isConstant(storm::storage::sparse::state_type const& value); template bool isInfinity(storm::storage::sparse::state_type const& value); - + // other instantiations template unsigned long convertNumber(long const&); template double convertNumber(long const&); - + #if defined(STORM_HAVE_CLN) // Instantiations for (CLN) rational number. template storm::ClnRationalNumber one(); @@ -942,7 +955,7 @@ namespace storm { template storm::ClnRationalNumber min(storm::ClnRationalNumber const& first, storm::ClnRationalNumber const& second); template std::string to_string(storm::ClnRationalNumber const& value); #endif - + #if defined(STORM_HAVE_GMP) // Instantiations for (GMP) rational number. template storm::GmpRationalNumber one(); @@ -965,10 +978,10 @@ namespace storm { template storm::GmpRationalNumber min(storm::GmpRationalNumber const& first, storm::GmpRationalNumber const& second); template std::string to_string(storm::GmpRationalNumber const& value); #endif - + #if defined(STORM_HAVE_CARL) && defined(STORM_HAVE_GMP) && defined(STORM_HAVE_CLN) #endif - + #ifdef STORM_HAVE_CARL // Instantiations for rational function. template RationalFunction one(); From 21c970f8f75a4f61abc50602fcdca6ab36a55123 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 2 Apr 2018 13:02:17 +0200 Subject: [PATCH 232/647] added dd-to-sparse engine that builds the model as a DD and then transforms the whole model to a sparse representation --- src/storm-cli-utilities/model-handling.h | 21 ++++++++++++++++++++- src/storm/settings/modules/CoreSettings.cpp | 4 +++- src/storm/settings/modules/CoreSettings.h | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index c279dc742..35390c7cb 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -217,7 +217,7 @@ namespace storm { auto buildSettings = storm::settings::getModule(); std::shared_ptr result; if (input.model) { - if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { + if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::DdSparse || engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { result = buildModelDd(input); } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) { result = buildModelSparse(input, buildSettings); @@ -350,6 +350,25 @@ namespace storm { result = std::make_unique>, bool>>(symbolicModel->template toValueType(), !std::is_same::value); } + if (result && result->first->isSymbolicModel() && storm::settings::getModule().getEngine() == storm::settings::modules::CoreSettings::Engine::DdSparse) { + // Mark as changed. + result->second = true; + + std::shared_ptr> symbolicModel = result->first->template as>(); + if (symbolicModel->isOfType(storm::models::ModelType::Dtmc)) { + storm::transformer::SymbolicDtmcToSparseDtmcTransformer transformer; + result->first = transformer.translate(*symbolicModel->template as>()); + } else if (symbolicModel->isOfType(storm::models::ModelType::Ctmc)) { + storm::transformer::SymbolicCtmcToSparseCtmcTransformer transformer; + result->first = transformer.translate(*symbolicModel->template as>()); + } else if (symbolicModel->isOfType(storm::models::ModelType::Mdp)) { + storm::transformer::SymbolicMdpToSparseMdpTransformer transformer; + result->first = transformer.translate(*symbolicModel->template as>()); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The translation to a sparse model is not supported for the given model type."); + } + } + return *result; } diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index 9bcd4d77c..8419f209f 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -39,7 +39,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model.").setShortName(counterexampleOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, dontFixDeadlockOptionName, false, "If the model contains deadlock states, they need to be fixed by setting this option.").setShortName(dontFixDeadlockOptionShortName).build()); - std::vector engines = {"sparse", "hybrid", "dd", "expl", "abs"}; + std::vector engines = {"sparse", "hybrid", "dd", "dd-to-sparse", "expl", "abs"}; this->addOption(storm::settings::OptionBuilder(moduleName, engineOptionName, false, "Sets which engine is used for model building and model checking.").setShortName(engineOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("sparse").build()).build()); @@ -164,6 +164,8 @@ namespace storm { engine = CoreSettings::Engine::Hybrid; } else if (engineStr == "dd") { engine = CoreSettings::Engine::Dd; + } else if (engineStr == "dd-to-sparse") { + engine = CoreSettings::Engine::DdSparse; } else if (engineStr == "expl") { engine = CoreSettings::Engine::Exploration; } else if (engineStr == "abs") { diff --git a/src/storm/settings/modules/CoreSettings.h b/src/storm/settings/modules/CoreSettings.h index afd16cd78..8a07a48d0 100644 --- a/src/storm/settings/modules/CoreSettings.h +++ b/src/storm/settings/modules/CoreSettings.h @@ -28,7 +28,7 @@ namespace storm { public: // An enumeration of all engines. enum class Engine { - Sparse, Hybrid, Dd, Exploration, AbstractionRefinement + Sparse, Hybrid, Dd, DdSparse, Exploration, AbstractionRefinement }; /*! From 64cd0ae212c911d1f3ce534b8984a9067ff98695 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 2 Apr 2018 13:09:46 +0200 Subject: [PATCH 233/647] optimizations to trace formula generation --- src/storm/abstraction/MenuGameAbstractor.h | 1 + src/storm/abstraction/MenuGameRefiner.cpp | 322 ++++++++++++++---- src/storm/abstraction/MenuGameRefiner.h | 8 +- .../abstraction/jani/AutomatonAbstractor.cpp | 5 + .../abstraction/jani/AutomatonAbstractor.h | 5 + src/storm/abstraction/jani/EdgeAbstractor.cpp | 12 + src/storm/abstraction/jani/EdgeAbstractor.h | 8 + .../jani/JaniMenuGameAbstractor.cpp | 7 +- .../abstraction/jani/JaniMenuGameAbstractor.h | 5 + .../abstraction/prism/CommandAbstractor.cpp | 12 + .../abstraction/prism/CommandAbstractor.h | 8 + .../abstraction/prism/ModuleAbstractor.cpp | 5 + .../abstraction/prism/ModuleAbstractor.h | 5 + .../prism/PrismMenuGameAbstractor.cpp | 5 + .../prism/PrismMenuGameAbstractor.h | 5 + 15 files changed, 341 insertions(+), 72 deletions(-) diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index ee753bebc..7e957e406 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -37,6 +37,7 @@ namespace storm { virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const = 0; std::vector> getVariableUpdates(uint64_t player1Choice) const; virtual std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const = 0; + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const = 0; virtual storm::expressions::Expression getInitialExpression() const = 0; /*! diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 91fbb17e0..a821dc8e5 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -12,6 +12,7 @@ #include "storm/storage/dd/Odd.h" #include "storm/utility/dd.h" #include "storm/utility/solver.h" +#include "storm/utility/shortestPaths.h" #include "storm/solver/MathsatSmtSolver.h" @@ -478,6 +479,10 @@ namespace storm { for (auto& predicate : predicates.back()) { predicate = predicate.changeManager(expressionManager); } + // Add ranges of variables. + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager)); + } // Perform a backward search for an initial state. storm::dd::Bdd currentState = pivotState; @@ -526,7 +531,10 @@ namespace storm { for (auto& predicate : predicates.back()) { predicate = predicate.changeManager(expressionManager).substitute(substitution); } - + // Add ranges of variables. + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager).substitute(substitution)); + } // Move backwards one step. lastSubstitution = std::move(substitution); currentState = predecessorTransition.existsAbstract(variablesToAbstract); @@ -540,13 +548,34 @@ namespace storm { const uint64_t ExplicitPivotStateResult::NO_PREDECESSOR = std::numeric_limits::max(); template - std::pair>, std::map> MenuGameRefiner::buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const { + std::pair, std::vector> MenuGameRefiner::buildReversedLabeledPath(ExplicitPivotStateResult const& pivotStateResult) const { - std::vector> predicates; + std::pair, std::vector> result; + result.first.emplace_back(pivotStateResult.pivotState); + + uint64_t currentState = pivotStateResult.predecessors[pivotStateResult.pivotState].first; + uint64_t currentAction = pivotStateResult.predecessors[pivotStateResult.pivotState].second; + while (currentState != ExplicitPivotStateResult::NO_PREDECESSOR) { + STORM_LOG_ASSERT(currentAction != ExplicitPivotStateResult::NO_PREDECESSOR, "Expected predecessor action."); + result.first.emplace_back(currentState); + result.second.emplace_back(currentAction); + currentAction = pivotStateResult.predecessors[currentState].second; + currentState = pivotStateResult.predecessors[currentState].first; + } + + STORM_LOG_ASSERT(result.first.size() == result.second.size() + 1, "Path size mismatch."); + return result; + } + + template + std::pair>, std::map> MenuGameRefiner::buildTraceFromReversedLabeledPath(storm::expressions::ExpressionManager& expressionManager, std::vector const& reversedPath, std::vector const& reversedLabels, storm::dd::Odd const& odd, std::vector const* stateToOffset) const { + STORM_LOG_ASSERT(reversedPath.size() == reversedLabels.size() + 1, "Path size mismatch."); + std::vector> predicates; + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression(); - + std::set oldVariables = initialExpression.getVariables(); for (auto const& predicate : abstractionInformation.getPredicates()) { std::set usedVariables = predicate.getVariables(); @@ -557,94 +586,128 @@ namespace storm { for (auto const& variable : oldVariables) { oldToNewVariables[variable] = expressionManager.getVariable(variable.getName()); } - std::map lastSubstitution; + std::map currentSubstitution; for (auto const& variable : oldToNewVariables) { - lastSubstitution[variable.second] = variable.second; + currentSubstitution[variable.second] = variable.second; } std::map stepVariableToCopiedVariableMap; - // The state valuation also includes the bottom state, so we need to reserve one more than the number of - // predicates here. - storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(pivotStateResult.pivotState, abstractionInformation.getNumberOfPredicates() + 1); + auto pathIt = reversedPath.rbegin(); + + // Decode initial state. The state valuation also includes the bottom state, so we need to reserve one more + // than the number of predicates here. + storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + 1); + ++pathIt; - // Decode pivot state. + // Add all predicates of initial block. predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation)); for (auto& predicate : predicates.back()) { predicate = predicate.changeManager(expressionManager); } - // Perform a backward traversal from the pivot state along the chosen predecessors until there is no more - // predecessors. - uint64_t currentState = pivotStateResult.predecessors[pivotStateResult.pivotState].first; - uint64_t currentAction = pivotStateResult.predecessors[pivotStateResult.pivotState].second; - while (currentState != ExplicitPivotStateResult::NO_PREDECESSOR) { - // Create a new copy of each variable to use for this step. - std::map substitution; - for (auto const& variablePair : oldToNewVariables) { - storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variablePair.second); - substitution[variablePair.second] = variableCopy; - stepVariableToCopiedVariableMap[variableCopy] = variablePair.second; + // Add ranges of further constraints. + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager)); + } + + // Add initial expression. + predicates.back().push_back(initialExpression.changeManager(expressionManager)); + + // Traverse the path and construct necessary formula parts. + auto actionIt = reversedLabels.rbegin(); + for (; pathIt != reversedPath.rend(); ++pathIt) { + + // Add new predicate frame. + predicates.emplace_back(); + + // Add guard of action. + predicates.back().emplace_back(abstractor.get().getGuard(*actionIt).changeManager(expressionManager).substitute(currentSubstitution)); + + // Determine which variables are affected by the updates of the player 1 choice. + std::set const& assignedVariables = abstractor.get().getAssignedVariables(*actionIt); + + // Create new instances of the affected variables. + std::map newVariableMaps; + for (auto const& variable : assignedVariables) { + storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variable); + newVariableMaps[oldToNewVariables.at(variable)] = variableCopy; + stepVariableToCopiedVariableMap[variableCopy] = variable; } - // Retrieve the variable updates that the predecessor needs to perform to get to the current state. - auto variableUpdateVector = abstractor.get().getVariableUpdates(currentAction); + // Retrieves the possible updates to the variables. + auto variableUpdateVector = abstractor.get().getVariableUpdates(*actionIt); + + // Encode these updates. storm::expressions::Expression allVariableUpdateExpression; for (auto const& variableUpdates : variableUpdateVector) { storm::expressions::Expression variableUpdateExpression; - for (auto const& oldNewVariablePair : oldToNewVariables) { - storm::expressions::Variable const& newVariable = oldNewVariablePair.second; - - // If the variable was set, use its update expression. - auto updateIt = variableUpdates.find(oldNewVariablePair.first); - if (updateIt != variableUpdates.end()) { - auto const& update = *updateIt; - - if (update.second.hasBooleanType()) { - variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution)); - } else { - variableUpdateExpression = variableUpdateExpression && lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution); - } + for (auto const& update : variableUpdates) { + if (update.second.hasBooleanType()) { + variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(newVariableMaps.at(update.first), update.second.changeManager(expressionManager).substitute(currentSubstitution)); } else { - // Otherwise, make sure that the new variable maintains the old value. - if (newVariable.hasBooleanType()) { - variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable)); - } else { - variableUpdateExpression = variableUpdateExpression && lastSubstitution.at(newVariable) == substitution.at(newVariable); - } + variableUpdateExpression = variableUpdateExpression && newVariableMaps.at(update.first) == update.second.changeManager(expressionManager).substitute(currentSubstitution); } } allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression; } - - // Add variable update expression. predicates.back().emplace_back(allVariableUpdateExpression); - - // Add the guard of the choice. - predicates.back().emplace_back(abstractor.get().getGuard(currentAction).changeManager(expressionManager).substitute(substitution)); - // Retrieve the predicate valuation in the predecessor. - extendedPredicateValuation = odd.getEncoding(currentState, abstractionInformation.getNumberOfPredicates() + 1); - predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation)); - for (auto& predicate : predicates.back()) { - predicate = predicate.changeManager(expressionManager).substitute(substitution); + // Incorporate the new variables in the current substitution. + for (auto const& variablePair : newVariableMaps) { + currentSubstitution[variablePair.first] = variablePair.second; } - // Move backwards one step. - lastSubstitution = std::move(substitution); - - std::pair predecessorPair = pivotStateResult.predecessors[currentState]; - currentState = predecessorPair.first; - currentAction = predecessorPair.second; + // Decode current state. + extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + 1); + + // Encode the predicates whose value might have changed. + // FIXME: could be optimized by precomputation. + for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.getNumberOfPredicates(); ++predicateIndex) { + auto const& predicate = abstractionInformation.getPredicateByIndex(predicateIndex); + std::set usedVariables = predicate.getVariables(); + + bool containsAssignedVariables = false; + for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) { + if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) { + break; + } + + if (*usedIt == *assignedIt) { + containsAssignedVariables = true; + break; + } + + if (*usedIt < *assignedIt) { + ++usedIt; + } else { + ++assignedIt; + } + } + + if (containsAssignedVariables) { + auto transformedPredicate = predicate.changeManager(expressionManager).substitute(currentSubstitution); + predicates.back().emplace_back(extendedPredicateValuation.get(predicateIndex + 1) ? transformedPredicate : !transformedPredicate); + } + } + + // Enforce ranges of all assigned variables. +// for (auto const& variablePair : newVariableMaps) { +// for (auto const& ) +// } + + ++actionIt; } - predicates.back().push_back(initialExpression.changeManager(expressionManager).substitute(lastSubstitution)); + std::reverse(predicates.begin(), predicates.end()); return std::make_pair(predicates, stepVariableToCopiedVariableMap); } - - template - boost::optional derivePredicatesFromInterpolation(storm::expressions::ExpressionManager& interpolationManager, AbstractionInformation const& abstractionInformation, std::vector> const& trace, std::map const& variableSubstitution) { + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationFromTrace(storm::expressions::ExpressionManager& interpolationManager, std::vector> const& trace, std::map const& variableSubstitution) const { + + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); auto start = std::chrono::high_resolution_clock::now(); boost::optional predicates; @@ -656,7 +719,6 @@ namespace storm { auto traceIt = trace.rbegin(); auto traceIte = trace.rend(); for (; traceIt != traceIte; ++traceIt) { - auto iterationStart = std::chrono::high_resolution_clock::now(); auto const& step = *traceIt; interpolatingSolver.push(); @@ -664,13 +726,11 @@ namespace storm { for (auto const& predicate : step) { interpolatingSolver.add(predicate); } - auto iterationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Asserting step of trace formula took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); ++stepCounter; } auto assertionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Asserting trace formula until unsatisfiability took " << std::chrono::duration_cast(assertionEnd - assertionStart).count() << "ms."); + STORM_LOG_TRACE("Asserting trace formula took " << std::chrono::duration_cast(assertionEnd - assertionStart).count() << "ms."); // Now encode the trace as an SMT problem. storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); @@ -682,11 +742,18 @@ namespace storm { for (uint64_t step = 0; step < stepCounter; ++step) { prefix.push_back(step); storm::expressions::Expression interpolant = interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager()); - if (!interpolant.isTrue() && !interpolant.isFalse()) { + if (interpolant.isFalse()) { + // If the interpolant is false, it means that the prefix has become unsatisfiable. + break; + } + if (!interpolant.isTrue()) { STORM_LOG_DEBUG("Derived new predicate (based on interpolation at step " << step << " out of " << stepCounter << "): " << interpolant); interpolants.push_back(interpolant); } } + + STORM_LOG_ASSERT(!interpolants.empty(), "Expected to have non-empty set of interpolants."); + predicates = boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); } else { STORM_LOG_TRACE("Trace formula is satisfiable, not using interpolation."); @@ -723,7 +790,7 @@ namespace storm { auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from symbolic most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); - return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } template @@ -735,11 +802,18 @@ namespace storm { // Build the trace of the most probable path in terms of which predicates hold in each step. auto start = std::chrono::high_resolution_clock::now(); - std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, pivotStateResult, odd); + std::pair, std::vector> labeledReversedPath = buildReversedLabeledPath(pivotStateResult); + + // If the initial state is the pivot state, we can stop here. + if (labeledReversedPath.first.size() == 1) { + return boost::none; + } + + std::pair>, std::map> traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(*interpolationManager, labeledReversedPath.first, labeledReversedPath.second, odd); auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); - return storm::abstraction::derivePredicatesFromInterpolation(*interpolationManager, abstractionInformation, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } template @@ -980,9 +1054,112 @@ namespace storm { return boost::none; } + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationReversedPath(storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector const& reversedPath, std::vector const& stateToOffset, std::vector const& reversedLabels) const { + + // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); + std::pair>, std::map> traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(interpolationManager, reversedPath, reversedLabels, odd, &stateToOffset); + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + + return derivePredicatesFromInterpolationFromTrace(interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationKShortestPaths(storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ValueType minProbability, ValueType maxProbability, ExplicitGameStrategyPair const& maxStrategyPair) const { + + // Extract the underlying DTMC of the max strategy pair. + + // Start by determining which states are reachable. + storm::storage::BitVector reachableStatesInMaxFragment(initialStates); + std::vector stack(initialStates.begin(), initialStates.end()); + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor); + for (auto const& successorEntry : transitionMatrix.getRow(player2Choice)) { + if (!reachableStatesInMaxFragment.get(successorEntry.getColumn())) { + reachableStatesInMaxFragment.set(successorEntry.getColumn()); + if (!targetStates.get(successorEntry.getColumn())) { + stack.push_back(successorEntry.getColumn()); + } + } + } + } + + uint64_t numberOfReachableStates = reachableStatesInMaxFragment.getNumberOfSetBits(); + std::vector reachableStatesWithLowerIndex = reachableStatesInMaxFragment.getNumberOfSetBitsBeforeIndices(); + + // Now construct the matrix just for these entries. + storm::storage::SparseMatrixBuilder builder(numberOfReachableStates, numberOfReachableStates); + storm::storage::BitVector dtmcInitialStates(numberOfReachableStates); + typename storm::utility::ksp::ShortestPathsGenerator::StateProbMap targetProbabilities; + std::vector stateToOffset(numberOfReachableStates); + std::vector dtmcPlayer1Labels(numberOfReachableStates); + uint64_t currentRow = 0; + for (auto currentState : reachableStatesInMaxFragment) { + stateToOffset[currentRow] = currentState; + if (targetStates.get(currentState)) { + targetProbabilities[currentRow] = storm::utility::one(); + builder.addNextValue(currentRow, currentRow, storm::utility::one()); + } else { + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + dtmcPlayer1Labels[currentRow] = player1Labeling[player2Successor]; + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor); + + for (auto const& successorEntry : transitionMatrix.getRow(player2Choice)) { + builder.addNextValue(currentRow, reachableStatesWithLowerIndex[successorEntry.getColumn()], successorEntry.getValue()); + } + } + + if (initialStates.get(currentState)) { + dtmcInitialStates.set(currentRow); + } + ++currentRow; + } + storm::storage::SparseMatrix dtmcMatrix = builder.build(); + + // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Use a path generator to compute k-shortest-paths. + storm::utility::ksp::ShortestPathsGenerator pathGenerator(dtmcMatrix, targetProbabilities, dtmcInitialStates, storm::utility::ksp::MatrixFormat::straight); + uint64_t currentShortestPath = 1; + bool considerNextPath = true; + + boost::optional result; + + while (currentShortestPath < 100 && considerNextPath) { + auto reversedPath = pathGenerator.getPathAsList(currentShortestPath); + std::vector reversedLabels; + for (auto stateIt = reversedPath.rbegin(); stateIt != reversedPath.rend() - 1; ++stateIt) { + reversedLabels.push_back(player1Labeling[maxStrategyPair.getPlayer1Strategy().getChoice(stateToOffset[*stateIt])]); + } + + boost::optional pathPredicates = derivePredicatesFromInterpolationReversedPath(odd, *interpolationManager, reversedPath, stateToOffset, reversedLabels); + if (pathPredicates) { + if (!result) { + result = RefinementPredicates(RefinementPredicates::Source::Interpolation, pathPredicates.get().getPredicates()); + } else { + result.get().addPredicates(pathPredicates.get().getPredicates()); + } + } + ++currentShortestPath; + } + + exit(-1); + return result; + } + template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { +// boost::optional kShortestPathPredicates = derivePredicatesFromInterpolationKShortestPaths(odd, transitionMatrix, player1Grouping, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, storm::utility::zero(), storm::utility::one(), maxStrategyPair); + // Compute the set of states whose result we have for the min and max case. storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); @@ -1054,6 +1231,11 @@ namespace storm { template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + ValueType lower = quantitativeResult.getMin().getRange(initialStates).first; + ValueType upper = quantitativeResult.getMax().getRange(initialStates).second; + +// boost::optional kShortestPathPredicates = derivePredicatesFromInterpolationKShortestPaths(odd, transitionMatrix, player1Grouping, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, lower, upper, maxStrategyPair); + // Compute the set of states whose result we have for the min and max case. storm::storage::BitVector relevantStates(odd.getTotalOffset(), true); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 1db5ed8df..a3269ac91 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -157,12 +157,18 @@ namespace storm { */ std::vector createGlobalRefinement(std::vector const& predicates) const; + boost::optional derivePredicatesFromInterpolationFromTrace(storm::expressions::ExpressionManager& interpolationManager, std::vector> const& trace, std::map const& variableSubstitution) const; + boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& spanningTree, storm::dd::Bdd const& pivotState) const; - std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; + std::pair, std::vector> buildReversedLabeledPath(ExplicitPivotStateResult const& pivotStateResult) const; + std::pair>, std::map> buildTraceFromReversedLabeledPath(storm::expressions::ExpressionManager& expressionManager, std::vector const& reversedPath, std::vector const& reversedLabels, storm::dd::Odd const& odd, std::vector const* stateToOffset = nullptr) const; boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; + boost::optional derivePredicatesFromInterpolationKShortestPaths(storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ValueType minProbability, ValueType maxProbability, ExplicitGameStrategyPair const& maxStrategyPair) const; + boost::optional derivePredicatesFromInterpolationReversedPath(storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector const& reversedPath, std::vector const& stateToOffset, std::vector const& player1Labels) const; + void performRefinement(std::vector const& refinementCommands) const; /// The underlying abstractor to refine. diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index 5ab326657..f5c8030da 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -61,6 +61,11 @@ namespace storm { return edges[player1Choice].getVariableUpdates(auxiliaryChoice); } + template + std::set const& AutomatonAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return edges[player1Choice].getAssignedVariables(); + } + template GameBddResult AutomatonAbstractor::abstract() { // First, we retrieve the abstractions of all commands. diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index e9ff1d76a..658d154f4 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -68,6 +68,11 @@ namespace storm { */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + std::set const& getAssignedVariables(uint64_t player1Choice) const; + /*! * Computes the abstraction of the module wrt. to the current set of predicates. * diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index 8f0ab300e..a1fbe6fe9 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -36,6 +36,13 @@ namespace storm { // Assert the guard of the command. smtSolver->add(edge.getGuard()); + + // Construct assigned variables. + for (auto const& destination : edge.getDestinations()) { + for (auto const& assignment : destination.getOrderedAssignments()) { + assignedVariables.insert(assignment.getExpressionVariable()); + } + } } template @@ -75,6 +82,11 @@ namespace storm { return edge.get().getDestination(auxiliaryChoice).getAsVariableToExpressionMap(); } + template + std::set const& EdgeAbstractor::getAssignedVariables() const { + return assignedVariables; + } + template void EdgeAbstractor::recomputeCachedBdd() { if (useDecomposition) { diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index f3dfa531c..22cc7c40d 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -83,6 +83,11 @@ namespace storm { */ std::map getVariableUpdates(uint64_t auxiliaryChoice) const; + /*! + * Retrieves the assigned variables. + */ + std::set const& getAssignedVariables() const; + /*! * Computes the abstraction of the edge wrt. to the current set of predicates. * @@ -230,6 +235,9 @@ namespace storm { // The concrete edge this abstract command refers to. std::reference_wrapper edge; + // The variables to which this edge assigns expressions. + std::set assignedVariables; + // The local expression-related information. LocalExpressionInformation localExpressionInformation; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index a5bc90ed0..b41ccf418 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -129,6 +129,11 @@ namespace storm { return automata.front().getVariableUpdates(player1Choice, auxiliaryChoice); } + template + std::set const& JaniMenuGameAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return automata.front().getAssignedVariables(player1Choice); + } + template std::pair JaniMenuGameAbstractor::getPlayer1ChoiceRange() const { return std::make_pair(0, automata.front().getNumberOfEdges()); @@ -219,7 +224,7 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates).template toAdd(); + storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= edgeDecoratorAdd; transitionMatrix += deadlockTransitions; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 0a366c625..3a02583b4 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -86,6 +86,11 @@ namespace storm { */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const override; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const override; + /*! * Retrieves the range of player 1 choices. */ diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 15b68685e..1c632e4c9 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -36,6 +36,13 @@ namespace storm { // Assert the guard of the command. smtSolver->add(command.getGuardExpression()); + + // Construct assigned variables. + for (auto const& update : command.getUpdates()) { + for (auto const& assignment : update.getAssignments()) { + assignedVariables.insert(assignment.getVariable()); + } + } } template @@ -75,6 +82,11 @@ namespace storm { return command.get().getUpdate(auxiliaryChoice).getAsVariableToExpressionMap(); } + template + std::set const& CommandAbstractor::getAssignedVariables() const { + return assignedVariables; + } + template void CommandAbstractor::recomputeCachedBdd() { if (useDecomposition) { diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index d5c725921..cb448bad8 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -81,6 +81,11 @@ namespace storm { */ std::map getVariableUpdates(uint64_t auxiliaryChoice) const; + /*! + * Retrieves the assigned variables. + */ + std::set const& getAssignedVariables() const; + /*! * Computes the abstraction of the command wrt. to the current set of predicates. * @@ -223,6 +228,9 @@ namespace storm { // The concrete command this abstract command refers to. std::reference_wrapper command; + // The variables to which this command assigns expressions. + std::set assignedVariables; + // The local expression-related information. LocalExpressionInformation localExpressionInformation; diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index b5180ecf4..84c6d9523 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -55,6 +55,11 @@ namespace storm { return commands[player1Choice].getVariableUpdates(auxiliaryChoice); } + template + std::set const& ModuleAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return commands[player1Choice].getAssignedVariables(); + } + template GameBddResult ModuleAbstractor::abstract() { // First, we retrieve the abstractions of all commands. diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index 8aef43562..a8d5c94cd 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -71,6 +71,11 @@ namespace storm { */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + std::set const& getAssignedVariables(uint64_t player1Choice) const; + /*! * Computes the abstraction of the module wrt. to the current set of predicates. * diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index e7bfe8522..7908a5a5e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -125,6 +125,11 @@ namespace storm { return modules.front().getVariableUpdates(player1Choice, auxiliaryChoice); } + template + std::set const& PrismMenuGameAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return modules.front().getAssignedVariables(player1Choice); + } + template std::pair PrismMenuGameAbstractor::getPlayer1ChoiceRange() const { return std::make_pair(0, modules.front().getCommands().size()); diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index ce5f7ac42..21d64cd30 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -85,6 +85,11 @@ namespace storm { * 1 choice and auxiliary choice. */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const override; + + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const override; /*! * Retrieves the range of player 1 choices. From dc92696cc3bc10376fb3220add60748f737500d7 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sat, 31 Mar 2018 16:31:54 +0200 Subject: [PATCH 234/647] Jani: make edge-index encoding static functions --- src/storm/storage/jani/Model.cpp | 4 ++-- src/storm/storage/jani/Model.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 37031bb4b..7c0709516 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -1156,11 +1156,11 @@ namespace storm { return false; } - uint64_t Model::encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) const { + uint64_t Model::encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) { return automatonIndex << 32 | edgeIndex; } - std::pair Model::decodeAutomatonAndEdgeIndices(uint64_t index) const { + std::pair Model::decodeAutomatonAndEdgeIndices(uint64_t index) { return std::make_pair(index >> 32, index & ((1ull << 32) - 1)); } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index f45f78b29..0cfeb772e 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -452,8 +452,8 @@ namespace storm { /*! * Encode and decode a tuple of automaton and edge index in one 64-bit index. */ - uint64_t encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) const; - std::pair decodeAutomatonAndEdgeIndices(uint64_t index) const; + static uint64_t encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex); + static std::pair decodeAutomatonAndEdgeIndices(uint64_t index); /*! * Creates a new model that only contains the selected edges. The edge indices encode the automata and From 4d4b1788533f8939f27c6c07e4c10ade6c32b43c Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sat, 31 Mar 2018 16:32:30 +0200 Subject: [PATCH 235/647] counterexamples options: add silent and open to outside --- .../SMTMinimalLabelSetGenerator.h | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 8a8edb0e6..dfd9942b8 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1647,6 +1647,7 @@ namespace storm { bool checkThresholdFeasible; bool encodeReachability; bool useDynamicConstraints; + bool silent = false; }; /*! @@ -1848,7 +1849,7 @@ namespace storm { #endif } - static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { + static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool silent = false) { auto startTime = std::chrono::high_resolution_clock::now(); // Create sub-model that only contains the choices allowed by the given command set. @@ -1914,12 +1915,17 @@ namespace storm { } auto endTime = std::chrono::high_resolution_clock::now(); - std::cout << std::endl << "Extended command for lower bounded property to size " << commandSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + if (!silent) { + std::cout << std::endl << "Extended command for lower bounded property to size " << commandSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + } + } - static boost::container::flat_set computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { + static boost::container::flat_set computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); - std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; + if (!options.silent) { + std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; + } STORM_LOG_THROW(formula->isProbabilityOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); @@ -1967,7 +1973,9 @@ namespace storm { // This means that from all states in prob0E(psi) we need to include labels such that \sigma_0 // is actually included in the resulting model. This prevents us from guaranteeing the minimality of // the returned counterexample, so we warn about that. - STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); + if (!options.silent) { + STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); + } // Modify bound appropriately. comparisonType = storm::logic::invertPreserveStrictness(comparisonType); @@ -1985,13 +1993,15 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, boost::container::flat_set(), true); + auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); - std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + if (!options.silent) { + std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + } // Extend the command set properly. if (lowerBoundedFormula) { - extendLabelSetLowerBound(model, labelSet, phiStates, psiStates); + extendLabelSetLowerBound(model, labelSet, phiStates, psiStates, options.silent); } return labelSet; } From 461668bc84fb4215cbb3aeb26a6cd010d1f25040 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 2 Apr 2018 21:54:49 +0200 Subject: [PATCH 236/647] change default value of an option for abstraction --- src/storm/settings/modules/AbstractionSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 8a7f92468..404298782 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -79,7 +79,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, restrictToRelevantStatesOptionName, true, "Sets whether to restrict to relevant states during the abstraction.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) - .setDefaultValueString("off").build()) + .setDefaultValueString("on").build()) .build()); this->addOption(storm::settings::OptionBuilder(moduleName, rankRefinementPredicatesOptionName, true, "Sets whether to rank the refinement predicates if there are multiple.") From 2468de47f9f9d0e10a6e2a909dc727c8bf484ff4 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Tue, 3 Apr 2018 11:12:27 +0200 Subject: [PATCH 237/647] jani -- get expression manager signature now looks more like prism -- get (expression) manager --- src/storm/storage/jani/Model.cpp | 8 ++------ src/storm/storage/jani/Model.h | 7 +------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 7c0709516..da95f426f 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -689,14 +689,10 @@ namespace storm { return false; } - storm::expressions::ExpressionManager& Model::getExpressionManager() { + storm::expressions::ExpressionManager& Model::getExpressionManager() const { return *expressionManager; } - - storm::expressions::ExpressionManager const& Model::getExpressionManager() const { - return *expressionManager; - } - + uint64_t Model::addAutomaton(Automaton const& automaton) { auto it = automatonToIndex.find(automaton.getName()); STORM_LOG_THROW(it == automatonToIndex.end(), storm::exceptions::WrongFormatException, "Automaton with name '" << automaton.getName() << "' already exists."); diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 0cfeb772e..2dc69d147 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -228,13 +228,8 @@ namespace storm { /*! * Retrieves the manager responsible for the expressions in the JANI model. */ - storm::expressions::ExpressionManager& getExpressionManager(); + storm::expressions::ExpressionManager& getExpressionManager() const; - /*! - * Retrieves the manager responsible for the expressions in the JANI model. - */ - storm::expressions::ExpressionManager const& getExpressionManager() const; - /*! * Adds the given automaton to the automata of this model. */ From f5511f4213e624ec43389e2c7ae50a06a652e52b Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 28 Mar 2018 18:01:29 +0200 Subject: [PATCH 238/647] removed obsolete 'inplace' setting for multiplier --- src/storm/settings/modules/MultiplierSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/MultiplierSettings.cpp b/src/storm/settings/modules/MultiplierSettings.cpp index befa91086..d386bbf3a 100644 --- a/src/storm/settings/modules/MultiplierSettings.cpp +++ b/src/storm/settings/modules/MultiplierSettings.cpp @@ -15,7 +15,7 @@ namespace storm { const std::string MultiplierSettings::multiplierTypeOptionName = "type"; MultiplierSettings::MultiplierSettings() : ModuleSettings(moduleName) { - std::vector multiplierTypes = {"native", "inplace", "gmmxx"}; + std::vector multiplierTypes = {"native", "gmmxx"}; this->addOption(storm::settings::OptionBuilder(moduleName, multiplierTypeOptionName, true, "Sets which type of multiplier is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplier.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplierTypes)).setDefaultValueString("gmmxx").build()).build()); From 7cdc7bd21d5cfd7e1593eeb9389bdea17f5121c9 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 3 Apr 2018 17:00:52 +0200 Subject: [PATCH 239/647] progress measurement can now correctly handle the case where maxcount = 0 --- src/storm/utility/ProgressMeasurement.cpp | 7 ++++--- src/storm/utility/ProgressMeasurement.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/storm/utility/ProgressMeasurement.cpp b/src/storm/utility/ProgressMeasurement.cpp index ff9abdc53..4a0715323 100644 --- a/src/storm/utility/ProgressMeasurement.cpp +++ b/src/storm/utility/ProgressMeasurement.cpp @@ -1,6 +1,7 @@ #include "storm/utility/ProgressMeasurement.h" #include +#include #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" @@ -9,7 +10,7 @@ namespace storm { namespace utility { - ProgressMeasurement::ProgressMeasurement(std::string const& itemName) : itemName(itemName), maxCount(0) { + ProgressMeasurement::ProgressMeasurement(std::string const& itemName) : itemName(itemName), maxCount(std::numeric_limits::max()) { delay = storm::settings::getModule().getShowProgressDelay(); } @@ -48,7 +49,7 @@ namespace storm { } bool ProgressMeasurement::isMaxCountSet() const { - return this->maxCount > 0; + return this->maxCount < std::numeric_limits::max(); } uint64_t ProgressMeasurement::getMaxCount() const { @@ -61,7 +62,7 @@ namespace storm { } void ProgressMeasurement::unsetMaxCount() { - this->maxCount = 0; + this->maxCount = std::numeric_limits::max(); } uint64_t ProgressMeasurement::getShowProgressDelay() const { diff --git a/src/storm/utility/ProgressMeasurement.h b/src/storm/utility/ProgressMeasurement.h index 904294ef5..089758583 100644 --- a/src/storm/utility/ProgressMeasurement.h +++ b/src/storm/utility/ProgressMeasurement.h @@ -92,7 +92,7 @@ namespace storm { // A name for what this is measuring (iterations, states, ...) std::string itemName; - // The maximal count that can be achieved. Zero means unspecified. + // The maximal count that can be achieved. numeric_limits::max() means unspecified. uint64_t maxCount; // The last displayed count From 7002138aeb5e9326b3508add138c40f89fec19ab Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 3 Apr 2018 17:01:59 +0200 Subject: [PATCH 240/647] removed setPrecision in solver interface since this is now covered via storm::Environment --- src/storm/solver/AbstractEquationSolver.cpp | 5 ----- src/storm/solver/AbstractEquationSolver.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/storm/solver/AbstractEquationSolver.cpp b/src/storm/solver/AbstractEquationSolver.cpp index 5b16cd096..69a2d0fad 100644 --- a/src/storm/solver/AbstractEquationSolver.cpp +++ b/src/storm/solver/AbstractEquationSolver.cpp @@ -273,11 +273,6 @@ namespace storm { } } - template - void AbstractEquationSolver::setPrecision(ValueType const& precision) { - STORM_LOG_DEBUG("Setting solver precision for a solver that does not support precisions."); - } - template class AbstractEquationSolver; template class AbstractEquationSolver; diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index c71bed0a7..9f9efb411 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -177,8 +177,6 @@ namespace storm { * Shows progress if this solver is asked to do so. */ void showProgressIterative(uint64_t iterations, boost::optional const& bound = boost::none) const; - - virtual void setPrecision(ValueType const& precision); protected: /*! From 4e60f3e13760189784a96f5fc08f7fc8bb7e4ede Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 3 Apr 2018 17:22:55 +0200 Subject: [PATCH 241/647] updated changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70d880e56..54be35d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ Version 1.2.x ### Version 1.2.2 (to be released) - `storm-dft`: improvements in Galileo parser - `storm-dft`: test cases for DFT analysis +- Sound value iteration (SVI) for DTMCs and MDPs +- Topological solver for linear equation systems and MinMax equation systems. + ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. From 32d19e6f0e94abfdb323c312f06b9d044c5bbec0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Apr 2018 11:05:50 +0200 Subject: [PATCH 242/647] debug output in git version parsing --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cd46d914..801a824c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,22 +402,32 @@ endif(DOXYGEN_FOUND) # try to obtain the current version from git. include(GetGitRevisionDescription) +message (STATUS "Storm - git hash ${STORM_VERSION_GIT_HASH}") +message (STATUS "Storm - git version refspec ${STORM_VERSION_REFSPEC}") +message (STATUS "Storm - git version string ${STORM_GIT_VERSION_STRING}") get_git_head_revision(STORM_VERSION_REFSPEC STORM_VERSION_GIT_HASH) git_describe_checkout(STORM_GIT_VERSION_STRING) +message (STATUS "Storm - git hash ${STORM_VERSION_GIT_HASH}") +message (STATUS "Storm - git version refspec ${STORM_VERSION_REFSPEC}") +message (STATUS "Storm - git version string ${STORM_GIT_VERSION_STRING}") # parse the git tag into variables # start with major.minor.patch string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)$" STORM_VERSION_MATCH "${STORM_GIT_VERSION_STRING}") +message (STATUS "Storm - version match ${STORM_VERSION_MATCH}") set(STORM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(STORM_VERSION_MINOR "${CMAKE_MATCH_2}") set(STORM_VERSION_PATCH "${CMAKE_MATCH_3}") set(STORM_GIT_VERSION_REST "${CMAKE_MATCH_4}") +message (STATUS "Storm - version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}") # parse rest of the form (-label)-commitsahead-hash-appendix string(REGEX MATCH "^(\\-([a-z][a-z0-9\\.]+))?\\-([0-9]+)\\-([a-z0-9]+)(\\-.*)?$" STORM_VERSION_REST_MATCH "${STORM_GIT_VERSION_REST}") +message (STATUS "Storm - version rest match ${STORM_VERSION_REST_MATCH}") set(STORM_VERSION_LABEL "${CMAKE_MATCH_2}") # might be empty set(STORM_VERSION_COMMITS_AHEAD "${CMAKE_MATCH_3}") set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") set(STORM_VERSION_APPENDIX "${CMAKE_MATCH_5}") # might be empty +message (STATUS "Storm - version rest ${STORM_VERSION_LABEL} / ${STORM_VERSION_COMMITS_AHEAD} / ${STORM_VERSION_TAG_HASH} / STORM_VERSION_APPENDIX") # now check whether the git version lookup failed if (STORM_VERSION_MAJOR MATCHES "NOTFOUND") From 869271259e3fa850180041bfc25cef92f37dfb42 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Apr 2018 14:29:29 +0200 Subject: [PATCH 243/647] updated git version retrieval cmake plugin --- .../macros/GetGitRevisionDescription.cmake | 52 ++++++++----------- .../macros/GetGitRevisionDescription.cmake.in | 13 +++-- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/resources/cmake/macros/GetGitRevisionDescription.cmake b/resources/cmake/macros/GetGitRevisionDescription.cmake index 3653b95be..8ab03bc5f 100644 --- a/resources/cmake/macros/GetGitRevisionDescription.cmake +++ b/resources/cmake/macros/GetGitRevisionDescription.cmake @@ -18,6 +18,12 @@ # and adjusting the output so that it tests false if there was no exact # matching tag. # +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: @@ -37,10 +43,10 @@ set(__get_git_revision_description YES) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file -get_filename_component(_gitdescmoddir GetGitRevisionDescription.cmake PATH) +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) function(get_git_head_revision _refspecvar _hashvar) - set(GIT_PARENT_DIR ${PROJECT_SOURCE_DIR}) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(GIT_DIR "${GIT_PARENT_DIR}/.git") while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") @@ -71,7 +77,7 @@ function(get_git_head_revision _refspecvar _hashvar) set(HEAD_FILE "${GIT_DATA}/HEAD") configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/resources/cmake/macros/GetGitRevisionDescription.cmake.in" + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY) include("${GIT_DATA}/grabRef.cmake") @@ -110,7 +116,7 @@ function(git_describe _var) ${hash} ${ARGN} WORKING_DIRECTORY - "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE @@ -124,7 +130,12 @@ function(git_describe _var) set(${_var} "${out}" PARENT_SCOPE) endfunction() -function(git_describe_checkout _var) +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() @@ -138,39 +149,20 @@ function(git_describe_checkout _var) return() endif() - # TODO sanitize - #if((${ARGN}" MATCHES "&&") OR - # (ARGN MATCHES "||") OR - # (ARGN MATCHES "\\;")) - # message("Please report the following error to the project!") - # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") - #endif() - - #message(STATUS "Arguments to execute_process: ${ARGN}") - execute_process(COMMAND "${GIT_EXECUTABLE}" - describe - --tags - --dirty=-dirty - --long - ${ARGN} + diff-index --quiet HEAD -- WORKING_DIRECTORY - "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT res EQUAL 0) - set(out "${out}-${res}-NOTFOUND") + if(res EQUAL 0) + set(${_var} "CLEAN" PARENT_SCOPE) + else() + set(${_var} "DIRTY" PARENT_SCOPE) endif() - - set(${_var} "${out}" PARENT_SCOPE) endfunction() - -function(git_get_exact_tag _var) - git_describe(out --exact-match ${ARGN}) - set(${_var} "${out}" PARENT_SCOPE) -endfunction() \ No newline at end of file diff --git a/resources/cmake/macros/GetGitRevisionDescription.cmake.in b/resources/cmake/macros/GetGitRevisionDescription.cmake.in index 30a115594..6d8b708ef 100644 --- a/resources/cmake/macros/GetGitRevisionDescription.cmake.in +++ b/resources/cmake/macros/GetGitRevisionDescription.cmake.in @@ -1,4 +1,4 @@ -# +# # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) @@ -23,9 +23,12 @@ if(HEAD_CONTENTS MATCHES "ref") string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") - configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - set(HEAD_HASH "${HEAD_REF}") + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() endif() else() # detached HEAD @@ -35,4 +38,4 @@ endif() if(NOT HEAD_HASH) file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) string(STRIP "${HEAD_HASH}" HEAD_HASH) -endif() \ No newline at end of file +endif() From 237d390e403d89f332d3f03a87ad15c68bc454d5 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Apr 2018 14:30:09 +0200 Subject: [PATCH 244/647] reworked version retrieval slightly --- CMakeLists.txt | 33 ++++++++++++------------------- src/storm/utility/storm-version.h | 14 +++++++++++-- storm-version.cpp.in | 7 ++++--- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 801a824c6..d5c8aa732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,42 +402,26 @@ endif(DOXYGEN_FOUND) # try to obtain the current version from git. include(GetGitRevisionDescription) -message (STATUS "Storm - git hash ${STORM_VERSION_GIT_HASH}") -message (STATUS "Storm - git version refspec ${STORM_VERSION_REFSPEC}") -message (STATUS "Storm - git version string ${STORM_GIT_VERSION_STRING}") get_git_head_revision(STORM_VERSION_REFSPEC STORM_VERSION_GIT_HASH) -git_describe_checkout(STORM_GIT_VERSION_STRING) -message (STATUS "Storm - git hash ${STORM_VERSION_GIT_HASH}") -message (STATUS "Storm - git version refspec ${STORM_VERSION_REFSPEC}") -message (STATUS "Storm - git version string ${STORM_GIT_VERSION_STRING}") +git_describe(STORM_GIT_VERSION_STRING) # parse the git tag into variables # start with major.minor.patch string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)$" STORM_VERSION_MATCH "${STORM_GIT_VERSION_STRING}") -message (STATUS "Storm - version match ${STORM_VERSION_MATCH}") set(STORM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(STORM_VERSION_MINOR "${CMAKE_MATCH_2}") set(STORM_VERSION_PATCH "${CMAKE_MATCH_3}") set(STORM_GIT_VERSION_REST "${CMAKE_MATCH_4}") -message (STATUS "Storm - version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}") # parse rest of the form (-label)-commitsahead-hash-appendix string(REGEX MATCH "^(\\-([a-z][a-z0-9\\.]+))?\\-([0-9]+)\\-([a-z0-9]+)(\\-.*)?$" STORM_VERSION_REST_MATCH "${STORM_GIT_VERSION_REST}") -message (STATUS "Storm - version rest match ${STORM_VERSION_REST_MATCH}") set(STORM_VERSION_LABEL "${CMAKE_MATCH_2}") # might be empty set(STORM_VERSION_COMMITS_AHEAD "${CMAKE_MATCH_3}") set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") set(STORM_VERSION_APPENDIX "${CMAKE_MATCH_5}") # might be empty -message (STATUS "Storm - version rest ${STORM_VERSION_LABEL} / ${STORM_VERSION_COMMITS_AHEAD} / ${STORM_VERSION_TAG_HASH} / STORM_VERSION_APPENDIX") -# now check whether the git version lookup failed -if (STORM_VERSION_MAJOR MATCHES "NOTFOUND") - include(version.cmake) - set(STORM_VERSION_LABEL "") - set(STORM_VERSION_COMMITS_AHEAD 0) - set(STORM_VERSION_GIT_HASH "") - set(STORM_VERSION_DIRTY boost::none) - message(WARNING "Storm - git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") -else() + +set(STORM_VERSION_DIRTY boost::none) +if (NOT "${STORM_GIT_VERSION_STRING}" STREQUAL "") if ("${STORM_VERSION_APPENDIX}" MATCHES "^.*dirty.*$") set(STORM_VERSION_DIRTY "true") else() @@ -445,6 +429,15 @@ else() endif() endif() +# now check whether the git version lookup failed +set(STORM_VERSION_SOURCE "VersionSource::Git") +if (STORM_GIT_VERSION_STRING MATCHES "NOTFOUND") + set(STORM_VERSION_SOURCE "VersionSource::Static") + set(STORM_VERSION_COMMITS_AHEAD "boost::none") + include(version.cmake) + message(WARNING "Storm - git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") +endif() + # check whether there is a label ('alpha', 'pre', etc.) if ("${STORM_VERSION_LABEL}" STREQUAL "") set(STORM_VERSION_LABEL_STRING "") diff --git a/src/storm/utility/storm-version.h b/src/storm/utility/storm-version.h index 72f047906..b6b1d3d2e 100644 --- a/src/storm/utility/storm-version.h +++ b/src/storm/utility/storm-version.h @@ -24,11 +24,18 @@ namespace storm { /// Flag indicating if the version of Storm is a development version. const static bool versionDev; + enum class VersionSource { + Git, Static + }; + + /// The source of the versioning information. + const static VersionSource versionSource; + /// The short hash of the git commit this build is based on const static std::string gitRevisionHash; /// How many commits passed since the tag was last set. - const static unsigned commitsAhead; + const static boost::optional commitsAhead; /// 0 iff there no files were modified in the checkout, 1 otherwise. If none, no information about dirtyness is given. const static boost::optional dirty; @@ -60,8 +67,11 @@ namespace storm { static std::string longVersionString() { std::stringstream sstream; sstream << "Version " << shortVersionString(); + if (versionSource == VersionSource::Static) { + sstream << " (derived statically)"; + } if (commitsAhead) { - sstream << " (+ " << commitsAhead << " commits)"; + sstream << " (+ " << commitsAhead.get() << " commits)"; } if (!gitRevisionHash.empty()) { sstream << " build from revision " << gitRevisionHash; diff --git a/storm-version.cpp.in b/storm-version.cpp.in index 9ff273d4b..6e3706bae 100644 --- a/storm-version.cpp.in +++ b/storm-version.cpp.in @@ -1,5 +1,4 @@ -//AUTO GENERATED -- DO NOT CHANGE -// TODO resolve issues when placing this in the build order directly. +// AUTO GENERATED -- DO NOT CHANGE #include "storm/utility/storm-version.h" namespace storm { @@ -10,8 +9,9 @@ namespace storm { const unsigned StormVersion::versionPatch = @STORM_VERSION_DEV_PATCH@; const std::string StormVersion::versionLabel = "@STORM_VERSION_LABEL@"; const bool StormVersion::versionDev = @STORM_VERSION_DEV@; + const StormVersion::VersionSource StormVersion::versionSource = @STORM_VERSION_SOURCE@; const std::string StormVersion::gitRevisionHash = "@STORM_VERSION_GIT_HASH@"; - const unsigned StormVersion::commitsAhead = @STORM_VERSION_COMMITS_AHEAD@; + const boost::optional StormVersion::commitsAhead = @STORM_VERSION_COMMITS_AHEAD@; const boost::optional StormVersion::dirty = @STORM_VERSION_DIRTY@; const std::string StormVersion::systemName = "@CMAKE_SYSTEM_NAME@"; const std::string StormVersion::systemVersion = "@CMAKE_SYSTEM_VERSION@"; @@ -21,5 +21,6 @@ namespace storm { #else const std::string StormVersion::cxxFlags = "@CMAKE_CXX_FLAGS@" " " "@CMAKE_CXX_FLAGS_DEBUG@"; #endif + } } From 06e3d4a331a04c20c1625483345b9b2a769aaea1 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Apr 2018 22:56:36 +0200 Subject: [PATCH 245/647] fixing issues in gmmxx TBB multiply-and-reduce --- src/storm/solver/GmmxxMultiplier.cpp | 44 +++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index 9618e2495..a11675b75 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -210,9 +210,13 @@ namespace storm { } void operator()(tbb::blocked_range const& range) const { + typedef std::vector VectorType; + typedef gmm::csr_matrix MatrixType; + + bool min = dir == OptimizationDirection::Minimize; auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); - + auto itr = mat_row_const_begin(matrix) + *groupIt; typename std::vector::const_iterator bIt; if (b) { @@ -224,12 +228,13 @@ namespace storm { } auto resultIt = result.begin() + range.begin(); - + + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { - if (choices) { - *choiceIt = 0; - } - ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. @@ -239,25 +244,36 @@ namespace storm { ++bIt; } - ++itr; + currentValue += vect_sp(gmm::linalg_traits::row(itr), x); - for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr) { - ValueType newValue = vect_sp(gmm::linalg_traits>::row(itr), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); - if (b) { - newValue += *bIt; - ++bIt; + if (choices) { + selectedChoice = currentRow - *groupIt; + if (*choiceIt == selectedChoice) { + oldSelectedChoiceValue = currentValue; } + } + + ++itr; + ++currentRow; + + for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr, ++bIt, ++currentRow) { + ValueType newValue = b ? *bIt : storm::utility::zero(); + newValue += vect_sp(gmm::linalg_traits::row(itr), x); - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (min ? newValue < currentValue : newValue > currentValue) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(mat_row_const_begin(matrix), itr) - *groupIt; + selectedChoice = currentRow - *groupIt; } } } } + // Finally write value to target vector. *resultIt = currentValue; + if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } } From 3a464d7a6baf57e86888b94b9e02d9f85380ee7a Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 6 Apr 2018 10:53:10 +0200 Subject: [PATCH 246/647] Fixed issue for clang3.8 --- .../AbstractAbstractionRefinementModelChecker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp index 1fdcf2907..01ea1feda 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp @@ -488,7 +488,7 @@ namespace storm { auto timeInMilliseconds = std::chrono::duration_cast(end - start).count(); STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template @@ -598,7 +598,7 @@ namespace storm { } STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template @@ -644,7 +644,7 @@ namespace storm { auto timeInMilliseconds = std::chrono::duration_cast(end - start).count(); STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template From e019bf19d152285c9a6a94f88a3fa95143db23e9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 6 Apr 2018 14:50:46 +0200 Subject: [PATCH 247/647] fixing Z3 hint handling --- resources/3rdparty/CMakeLists.txt | 4 ++-- resources/cmake/find_modules/FindZ3.cmake | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index 979c5cbe8..5957f3b51 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -157,9 +157,9 @@ if(Z3_FOUND) endif() if(STORM_HAVE_Z3_OPTIMIZE) - message (STATUS "Storm - Linking with Z3. (Z3 version supports optimization)") + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version supports optimization)") else() - message (STATUS "Storm - Linking with Z3. (Z3 version does not support optimization)") + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version does not support optimization)") endif() add_imported_library(z3 SHARED ${Z3_LIBRARIES} ${Z3_INCLUDE_DIRS}) diff --git a/resources/cmake/find_modules/FindZ3.cmake b/resources/cmake/find_modules/FindZ3.cmake index cf838874d..d0978b3bc 100644 --- a/resources/cmake/find_modules/FindZ3.cmake +++ b/resources/cmake/find_modules/FindZ3.cmake @@ -10,7 +10,7 @@ # find include dir by searching for a concrete file, which definitely must be in it find_path(Z3_INCLUDE_DIR NAMES z3++.h - PATHS ENV PATH INCLUDE "/usr/include/z3" "/usr/local/include/z3/" "${Z3_ROOT}/include" + PATHS ENV PATH INCLUDE "${Z3_ROOT}/include" "/usr/include/z3" "/usr/local/include/z3/" ) # find library @@ -44,4 +44,4 @@ ENDIF (NOT Z3_FIND_QUIETLY) #message(${Z3_LIBRARY}) # make the set variables only visible in advanced mode -mark_as_advanced(Z3_LIBRARY Z3_INCLUDE_DIR Z3_SOLVER, Z3_EXEC) \ No newline at end of file +mark_as_advanced(Z3_LIBRARY Z3_INCLUDE_DIR Z3_SOLVER, Z3_EXEC) From 7636a0339dc4afe91cafc0a6d28856574e80a4ff Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 6 Apr 2018 15:16:39 +0200 Subject: [PATCH 248/647] removed warning for missing naming capabilities in Z3 LP solver --- src/storm/solver/Z3LpSolver.cpp | 2 -- src/storm/transformer/SymbolicToSparseTransformer.cpp | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/storm/solver/Z3LpSolver.cpp b/src/storm/solver/Z3LpSolver.cpp index 1dcc1a7f0..0c4bbc3e8 100644 --- a/src/storm/solver/Z3LpSolver.cpp +++ b/src/storm/solver/Z3LpSolver.cpp @@ -26,7 +26,6 @@ namespace storm { template Z3LpSolver::Z3LpSolver(std::string const& name, OptimizationDirection const& optDir) : LpSolver(optDir) { - STORM_LOG_WARN_COND(name == "", "Z3 does not support names for solvers"); z3::config config; config.set("model", true); context = std::unique_ptr(new z3::context(config)); @@ -137,7 +136,6 @@ namespace storm { void Z3LpSolver::addConstraint(std::string const& name, storm::expressions::Expression const& constraint) { STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException, "Illegal constraint is not a relational expression."); STORM_LOG_THROW(constraint.getOperator() != storm::expressions::OperatorType::NotEqual, storm::exceptions::InvalidArgumentException, "Illegal constraint uses inequality operator."); - STORM_LOG_WARN_COND(name == "", "Z3 does not support names for constraints"); solver->add(expressionAdapter->translateExpression(constraint)); } diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp index 8ebac17de..cf3b46ab3 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.cpp +++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp @@ -68,6 +68,11 @@ namespace storm { storm::models::sparse::StateLabeling labelling(transitionMatrix.getRowGroupCount()); labelling.addLabel("init", symbolicMdp.getInitialStates().toVector(odd)); + symbolicMdp.getDeadlockStates().template toAdd().exportToDot("deadlock.dot"); + std::cout << "height " << odd.getHeight() << std::endl; + for (auto const& var : symbolicMdp.getDeadlockStates().getContainedMetaVariables()) { + std::cout << "var " << var.getName() << " = " << symbolicMdp.getManager().getMetaVariable(var).getNumberOfDdVariables() << " dd vars" << std::endl; + } labelling.addLabel("deadlock", symbolicMdp.getDeadlockStates().toVector(odd)); for(auto const& label : symbolicMdp.getLabels()) { labelling.addLabel(label, symbolicMdp.getStates(label).toVector(odd)); From 93bf17f54bb08282f205dc0d736cb26931d6ea59 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 6 Apr 2018 15:45:16 +0200 Subject: [PATCH 249/647] remove debug output --- src/storm/transformer/SymbolicToSparseTransformer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp index cf3b46ab3..8ebac17de 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.cpp +++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp @@ -68,11 +68,6 @@ namespace storm { storm::models::sparse::StateLabeling labelling(transitionMatrix.getRowGroupCount()); labelling.addLabel("init", symbolicMdp.getInitialStates().toVector(odd)); - symbolicMdp.getDeadlockStates().template toAdd().exportToDot("deadlock.dot"); - std::cout << "height " << odd.getHeight() << std::endl; - for (auto const& var : symbolicMdp.getDeadlockStates().getContainedMetaVariables()) { - std::cout << "var " << var.getName() << " = " << symbolicMdp.getManager().getMetaVariable(var).getNumberOfDdVariables() << " dd vars" << std::endl; - } labelling.addLabel("deadlock", symbolicMdp.getDeadlockStates().toVector(odd)); for(auto const& label : symbolicMdp.getLabels()) { labelling.addLabel(label, symbolicMdp.getStates(label).toVector(odd)); From ede791cff7893962958cba00d678fbf0e5933e52 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 6 Apr 2018 15:59:02 +0200 Subject: [PATCH 250/647] fixing bug in Z3 LP solver --- src/storm/solver/Z3LpSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/Z3LpSolver.cpp b/src/storm/solver/Z3LpSolver.cpp index 0c4bbc3e8..bd37e1baa 100644 --- a/src/storm/solver/Z3LpSolver.cpp +++ b/src/storm/solver/Z3LpSolver.cpp @@ -127,7 +127,7 @@ namespace storm { template storm::expressions::Variable Z3LpSolver::addBinaryVariable(std::string const& name, ValueType objectiveFunctionCoefficient) { storm::expressions::Variable newVariable = this->manager->declareVariable(name, this->manager->getIntegerType()); - solver->add(expressionAdapter->translateExpression((newVariable.getExpression() >= this->manager->rational(storm::utility::one())) && (newVariable.getExpression() <= this->manager->rational(storm::utility::one())))); + solver->add(expressionAdapter->translateExpression((newVariable.getExpression() >= this->manager->rational(storm::utility::zero())) && (newVariable.getExpression() <= this->manager->rational(storm::utility::one())))); optimizationFunction = optimizationFunction + this->manager->rational(objectiveFunctionCoefficient) * newVariable; return newVariable; } From 692587495fcec5c14ec556c56b852ffcdca8f0fa Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 7 Apr 2018 11:22:43 +0200 Subject: [PATCH 251/647] fixed bug in quotient extraction --- .../storage/dd/bisimulation/QuotientExtractor.cpp | 10 ++++++++-- src/storm/storage/dd/cudd/InternalCuddBdd.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index a4c3b014a..1ba224331 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -1006,7 +1006,10 @@ namespace storm { STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); storm::dd::Bdd quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero(); - storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeVariableSet) && reachableStates; + + std::set blockPrimeAndNondeterminismVariables = model.getNondeterminismVariables(); + blockPrimeAndNondeterminismVariables.insert(blockPrimeVariableSet.begin(), blockPrimeVariableSet.end()); + storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeAndNondeterminismVariables) && reachableStates; start = std::chrono::high_resolution_clock::now(); std::unordered_map> quotientRewardModels; @@ -1127,7 +1130,10 @@ namespace storm { STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); storm::dd::Bdd quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero(); - storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(model.getColumnVariables()) && reachableStates; + + std::set columnAndNondeterminismVariables = model.getColumnVariables(); + columnAndNondeterminismVariables.insert(model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end()); + storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(columnAndNondeterminismVariables) && reachableStates; start = std::chrono::high_resolution_clock::now(); std::unordered_map> quotientRewardModels; diff --git a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp index 5fc12e567..b69040372 100644 --- a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp @@ -294,7 +294,7 @@ namespace storm { } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) { return; } - + // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentRowLevel == maxLevel) { result.set(currentRowOffset, true); From 618d300914e866f14406d5a6c5eac29a7f27ea92 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 9 Apr 2018 18:45:47 +0200 Subject: [PATCH 252/647] fixed minor issue in MILP minimal label set generation --- src/storm/counterexamples/MILPMinimalLabelSetGenerator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h b/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h index 758740de8..861f86f83 100644 --- a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h @@ -341,7 +341,7 @@ namespace storm { std::list const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state); for (uint_fast64_t row : relevantChoicesForState) { for (auto const& successorEntry : mdp.getTransitionMatrix().getRow(row)) { - if (stateInformation.relevantStates.get(successorEntry.getColumn())) { + if (stateInformation.relevantStates.get(successorEntry.getColumn()) && resultingMap.find(std::make_pair(state, successorEntry.getColumn())) == resultingMap.end()) { variableNameBuffer.str(""); variableNameBuffer.clear(); variableNameBuffer << "t" << state << "to" << successorEntry.getColumn(); From c18340b76a5435e424e5ef935fc2bf6cafb3619c Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 9 Apr 2018 22:08:04 +0200 Subject: [PATCH 253/647] added mod as binary operation in expressions and slightly extended JANI support for filters --- src/storm/adapters/AddExpressionAdapter.cpp | 3 ++ src/storm/parser/ExpressionCreator.cpp | 3 +- src/storm/parser/ExpressionCreator.h | 2 +- src/storm/parser/ExpressionParser.cpp | 22 ++++++----- src/storm/parser/ExpressionParser.h | 22 ++++++----- src/storm/parser/JaniParser.cpp | 35 +++++++++++++---- .../BinaryNumericalFunctionExpression.cpp | 38 ++++++++++++++----- .../BinaryNumericalFunctionExpression.h | 2 +- src/storm/storage/expressions/Expression.cpp | 5 +++ src/storm/storage/expressions/Expression.h | 1 + .../expressions/LinearityCheckVisitor.cpp | 1 + .../storage/expressions/OperatorType.cpp | 1 + src/storm/storage/expressions/OperatorType.h | 1 + .../storage/expressions/ToCppVisitor.cpp | 7 ++++ .../expressions/ToExprtkStringVisitor.cpp | 7 ++++ .../expressions/ToRationalNumberVisitor.cpp | 5 ++- src/storm/storage/jani/JSONExporter.cpp | 2 + 17 files changed, 116 insertions(+), 41 deletions(-) diff --git a/src/storm/adapters/AddExpressionAdapter.cpp b/src/storm/adapters/AddExpressionAdapter.cpp index f792584a8..c713cae38 100644 --- a/src/storm/adapters/AddExpressionAdapter.cpp +++ b/src/storm/adapters/AddExpressionAdapter.cpp @@ -111,6 +111,9 @@ namespace storm { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power: result = leftResult.pow(rightResult); break; + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Modulo: + result = leftResult.mod(rightResult); + break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate expression containing power operator."); } diff --git a/src/storm/parser/ExpressionCreator.cpp b/src/storm/parser/ExpressionCreator.cpp index 6266206ef..b96dd5080 100644 --- a/src/storm/parser/ExpressionCreator.cpp +++ b/src/storm/parser/ExpressionCreator.cpp @@ -120,11 +120,12 @@ namespace storm { return manager.boolean(false); } - storm::expressions::Expression ExpressionCreator::createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const { + storm::expressions::Expression ExpressionCreator::createPowerModuloExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const { if (this->createExpressions) { try { switch (operatorType) { case storm::expressions::OperatorType::Power: return e1 ^ e2; break; + case storm::expressions::OperatorType::Modulo: return e1 % e2; break; default: STORM_LOG_ASSERT(false, "Invalid operation."); break; } } catch (storm::exceptions::InvalidTypeException const& e) { diff --git a/src/storm/parser/ExpressionCreator.h b/src/storm/parser/ExpressionCreator.h index bf454c552..20bcc5854 100644 --- a/src/storm/parser/ExpressionCreator.h +++ b/src/storm/parser/ExpressionCreator.h @@ -67,7 +67,7 @@ namespace storm { storm::expressions::Expression createEqualsExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createPlusExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; - storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; + storm::expressions::Expression createPowerModuloExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createUnaryExpression(boost::optional const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; storm::expressions::Expression createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const; storm::expressions::Expression createIntegerLiteralExpression(int value, bool& pass) const; diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm/parser/ExpressionParser.cpp index 492fb337d..64e185b54 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm/parser/ExpressionParser.cpp @@ -36,7 +36,7 @@ namespace boost { namespace storm { namespace parser { - ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerOperator_(), invalidIdentifiers_(invalidIdentifiers_) { + ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerModuloOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerModuloOperator_(), invalidIdentifiers_(invalidIdentifiers_) { expressionCreator = new ExpressionCreator(manager); @@ -58,11 +58,13 @@ namespace storm { minMaxExpression.name("min/max expression"); if (allowBacktracking) { - prefixPowerExpression = ((prefixPowerOperator_ >> qi::lit("(")) >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; + prefixPowerModuloExpression = ((prefixPowerModuloOperator_ >> qi::lit("(")) >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)] + | (qi::lit("func") >> qi::lit("(") >> prefixPowerModuloOperator_ >> qi::lit(",") >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; } else { - prefixPowerExpression = ((prefixPowerOperator_ >> qi::lit("(")) > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; + prefixPowerModuloExpression = ((prefixPowerModuloOperator_ >> qi::lit("(")) > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)] + | ((qi::lit("func") >> qi::lit("(")) > prefixPowerModuloOperator_ > qi::lit(",") > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; } - prefixPowerExpression.name("pow expression"); + prefixPowerModuloExpression.name("power/modulo expression"); identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionCreator::getIdentifierExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_pass)]; identifierExpression.name("identifier expression"); @@ -73,23 +75,23 @@ namespace storm { | qi::int_[qi::_val = phoenix::bind(&ExpressionCreator::createIntegerLiteralExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_pass)]; literalExpression.name("literal expression"); - atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | identifierExpression | literalExpression; + atomicExpression = floorCeilExpression | prefixPowerModuloExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | identifierExpression | literalExpression; atomicExpression.name("atomic expression"); unaryExpression = (-unaryOperator_ >> atomicExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createUnaryExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_2, qi::_pass)]; unaryExpression.name("unary expression"); if (allowBacktracking) { - infixPowerExpression = unaryExpression[qi::_val = qi::_1] >> -(infixPowerOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + infixPowerModuloExpression = unaryExpression[qi::_val = qi::_1] >> -(infixPowerModuloOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } else { - infixPowerExpression = unaryExpression[qi::_val = qi::_1] > -(infixPowerOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + infixPowerModuloExpression = unaryExpression[qi::_val = qi::_1] > -(infixPowerModuloOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } - infixPowerExpression.name("power expression"); + infixPowerModuloExpression.name("power/modulo expression"); if (allowBacktracking) { - multiplicationExpression = infixPowerExpression[qi::_val = qi::_1] >> *(multiplicationOperator_ >> infixPowerExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + multiplicationExpression = infixPowerModuloExpression[qi::_val = qi::_1] >> *(multiplicationOperator_ >> infixPowerModuloExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } else { - multiplicationExpression = infixPowerExpression[qi::_val = qi::_1] > *(multiplicationOperator_ > infixPowerExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + multiplicationExpression = infixPowerModuloExpression[qi::_val = qi::_1] > *(multiplicationOperator_ > infixPowerModuloExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } multiplicationExpression.name("multiplication expression"); diff --git a/src/storm/parser/ExpressionParser.h b/src/storm/parser/ExpressionParser.h index da3282b1b..3c5b093fd 100644 --- a/src/storm/parser/ExpressionParser.h +++ b/src/storm/parser/ExpressionParser.h @@ -149,15 +149,16 @@ namespace storm { // A parser used for recognizing the operators at the "multiplication" precedence level. multiplicationOperatorStruct multiplicationOperator_; - struct infixPowerOperatorStruct : qi::symbols { - infixPowerOperatorStruct() { + struct infixPowerModuloOperatorStruct : qi::symbols { + infixPowerModuloOperatorStruct() { add - ("^", storm::expressions::OperatorType::Power); + ("^", storm::expressions::OperatorType::Power) + ("%", storm::expressions::OperatorType::Modulo); } }; // A parser used for recognizing the operators at the "power" precedence level. - infixPowerOperatorStruct infixPowerOperator_; + infixPowerModuloOperatorStruct infixPowerModuloOperator_; struct unaryOperatorStruct : qi::symbols { unaryOperatorStruct() { @@ -192,15 +193,16 @@ namespace storm { // A parser used for recognizing the operators at the "min/max" precedence level. minMaxOperatorStruct minMaxOperator_; - struct prefixPowerOperatorStruct : qi::symbols { - prefixPowerOperatorStruct() { + struct prefixPowerModuloOperatorStruct : qi::symbols { + prefixPowerModuloOperatorStruct() { add - ("pow", storm::expressions::OperatorType::Power); + ("pow", storm::expressions::OperatorType::Power) + ("mod", storm::expressions::OperatorType::Modulo); } }; // A parser used for recognizing the operators at the "power" precedence level. - prefixPowerOperatorStruct prefixPowerOperator_; + prefixPowerModuloOperatorStruct prefixPowerModuloOperator_; ExpressionCreator* expressionCreator; @@ -218,8 +220,8 @@ namespace storm { qi::rule, Skipper> equalityExpression; qi::rule, Skipper> plusExpression; qi::rule, Skipper> multiplicationExpression; - qi::rule, Skipper> prefixPowerExpression; - qi::rule, Skipper> infixPowerExpression; + qi::rule, Skipper> prefixPowerModuloExpression; + qi::rule, Skipper> infixPowerModuloExpression; qi::rule unaryExpression; qi::rule atomicExpression; qi::rule literalExpression; diff --git a/src/storm/parser/JaniParser.cpp b/src/storm/parser/JaniParser.cpp index 3de6bb2cc..a428ce4fa 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm/parser/JaniParser.cpp @@ -140,9 +140,9 @@ namespace storm { auto prop = this->parseProperty(propertyEntry, globalVars, constants); properties.emplace(prop.getName(), prop); } catch (storm::exceptions::NotSupportedException const& ex) { - STORM_LOG_WARN("Cannot handle property " << ex.what()); + STORM_LOG_WARN("Cannot handle property: " << ex.what()); } catch (storm::exceptions::NotImplementedException const& ex) { - STORM_LOG_WARN("Cannot handle property " << ex.what()); + STORM_LOG_WARN("Cannot handle property: " << ex.what()); } } } @@ -433,6 +433,12 @@ namespace storm { assert(args.size() == 2); storm::logic::BinaryBooleanStateFormula::OperatorType oper = opString == "∧" ? storm::logic::BinaryBooleanStateFormula::OperatorType::And : storm::logic::BinaryBooleanStateFormula::OperatorType::Or; return std::make_shared(oper, args[0], args[1]); + } else if (opString == "⇒") { + assert(bound == boost::none); + std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + assert(args.size() == 2); + std::shared_ptr tmp = std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); + return std::make_shared(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, tmp, args[1]); } else if (opString == "¬") { assert(bound == boost::none); std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, ""); @@ -514,12 +520,27 @@ namespace storm { } STORM_LOG_THROW(expressionStructure.count("states") == 1, storm::exceptions::InvalidJaniException, "Filter must have a states description"); - STORM_LOG_THROW(expressionStructure.at("states").count("op") > 0, storm::exceptions::NotImplementedException, "We only support properties where the filter has initial states"); - std::string statesDescr = getString(expressionStructure.at("states").at("op"), "Filtered states in property named " + name); - STORM_LOG_THROW(statesDescr == "initial", storm::exceptions::NotImplementedException, "Only initial states are allowed as set of states we are interested in."); + std::shared_ptr statesFormula; + if (expressionStructure.at("states").count("op") > 0) { + std::string statesDescr = getString(expressionStructure.at("states").at("op"), "Filtered states in property named " + name); + if (statesDescr == "initial") { + statesFormula = std::make_shared("init"); + } + } + if (!statesFormula) { + try { + // Try to parse the states as formula. + statesFormula = parseFormula(expressionStructure.at("states"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); + } catch (storm::exceptions::NotSupportedException const& ex) { + throw ex; + } catch (storm::exceptions::NotImplementedException const& ex) { + throw ex; + } + } + STORM_LOG_THROW(statesFormula, storm::exceptions::NotImplementedException, "Could not derive states formula."); STORM_LOG_THROW(expressionStructure.count("values") == 1, storm::exceptions::InvalidJaniException, "Values as input for a filter must be given"); auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); - return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft), comment); + return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), comment); } std::shared_ptr JaniParser::parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription) { @@ -805,7 +826,7 @@ namespace storm { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return arguments[0] && arguments[1]; } else if (opstring == "⇒") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); diff --git a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp index 2cd3c2f61..92ed03c5c 100644 --- a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp +++ b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp @@ -6,11 +6,13 @@ #include "storm/storage/expressions/IntegerLiteralExpression.h" #include "storm/storage/expressions/RationalLiteralExpression.h" #include "storm/storage/expressions/ExpressionVisitor.h" + #include "storm/utility/macros.h" +#include "storm/utility/constants.h" +#include "storm/utility/NumberTraits.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/InvalidStateException.h" - namespace storm { namespace expressions { BinaryNumericalFunctionExpression::BinaryNumericalFunctionExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& firstOperand, std::shared_ptr const& secondOperand, OperatorType operatorType) : BinaryExpression(manager, type, firstOperand, secondOperand), operatorType(operatorType) { @@ -31,6 +33,7 @@ namespace storm { case OperatorType::Min: result = storm::expressions::OperatorType::Min; break; case OperatorType::Max: result = storm::expressions::OperatorType::Max; break; case OperatorType::Power: result = storm::expressions::OperatorType::Power; break; + case OperatorType::Modulo: result = storm::expressions::OperatorType::Modulo; break; } return result; } @@ -49,6 +52,7 @@ namespace storm { case OperatorType::Min: result = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: result = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: result = static_cast(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break; + case OperatorType::Modulo: result = firstOperandEvaluation % secondOperandEvaluation; break; } return result; } @@ -67,6 +71,7 @@ namespace storm { case OperatorType::Min: result = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: result = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: result = std::pow(firstOperandEvaluation, secondOperandEvaluation); break; + case OperatorType::Modulo: result = std::fmod(firstOperandEvaluation, secondOperandEvaluation); break; } return result; } @@ -79,7 +84,7 @@ namespace storm { if (this->hasIntegerType()) { int_fast64_t firstOperandEvaluation = firstOperandSimplified->evaluateAsInt(); int_fast64_t secondOperandEvaluation = secondOperandSimplified->evaluateAsInt(); - int_fast64_t newValue = 0; + boost::optional newValue; switch (this->getOperatorType()) { case OperatorType::Plus: newValue = firstOperandEvaluation + secondOperandEvaluation; break; case OperatorType::Minus: newValue = firstOperandEvaluation - secondOperandEvaluation; break; @@ -87,28 +92,40 @@ namespace storm { case OperatorType::Min: newValue = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: newValue = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: newValue = static_cast(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break; - case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break; + case OperatorType::Modulo: newValue = firstOperandEvaluation % secondOperandEvaluation; break; + case OperatorType::Divide: break; // do not simplify division. + } + if (newValue) { + return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), newValue.get())); } - return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), newValue)); } else if (this->hasRationalType()) { storm::RationalNumber firstOperandEvaluation = firstOperandSimplified->evaluateAsRational(); storm::RationalNumber secondOperandEvaluation = secondOperandSimplified->evaluateAsRational(); - storm::RationalNumber newValue = 0; + boost::optional newValue; switch (this->getOperatorType()) { case OperatorType::Plus: newValue = firstOperandEvaluation + secondOperandEvaluation; break; case OperatorType::Minus: newValue = firstOperandEvaluation - secondOperandEvaluation; break; case OperatorType::Times: newValue = firstOperandEvaluation * secondOperandEvaluation; break; case OperatorType::Min: newValue = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: newValue = std::max(firstOperandEvaluation, secondOperandEvaluation); break; + case OperatorType::Divide: newValue = firstOperandEvaluation / secondOperandEvaluation; break; case OperatorType::Power: { - STORM_LOG_THROW(carl::isInteger(secondOperandEvaluation), storm::exceptions::InvalidStateException, "Can not simplify pow() with fractional exponent."); - std::size_t exponent = carl::toInt(secondOperandEvaluation); - newValue = carl::pow(firstOperandEvaluation, exponent); + if (carl::isInteger(secondOperandEvaluation)) { + std::size_t exponent = carl::toInt(secondOperandEvaluation); + newValue = carl::pow(firstOperandEvaluation, exponent); + } break; } - case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break; + case OperatorType::Modulo: { + if (carl::isInteger(firstOperandEvaluation) && carl::isInteger(secondOperandEvaluation)) { + newValue = storm::utility::mod(storm::utility::numerator(firstOperandEvaluation), storm::utility::numerator(secondOperandEvaluation)); + } + break; + } + } + if (newValue) { + return std::shared_ptr(new RationalLiteralExpression(this->getManager(), newValue.get())); } - return std::shared_ptr(new RationalLiteralExpression(this->getManager(), newValue)); } } @@ -137,6 +154,7 @@ namespace storm { case OperatorType::Min: stream << "min(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")"; break; case OperatorType::Max: stream << "max(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")"; break; case OperatorType::Power: stream << *this->getFirstOperand() << " ^ " << *this->getSecondOperand(); break; + case OperatorType::Modulo: stream << *this->getFirstOperand() << " % " << *this->getSecondOperand(); break; } stream << ")"; } diff --git a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h index 1e9adb028..1879b141d 100644 --- a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h +++ b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h @@ -11,7 +11,7 @@ namespace storm { /*! * An enum type specifying the different operators applicable. */ - enum class OperatorType {Plus, Minus, Times, Divide, Min, Max, Power}; + enum class OperatorType {Plus, Minus, Times, Divide, Min, Max, Power, Modulo}; /*! * Constructs a binary numerical function expression with the given return type, operands and operator. diff --git a/src/storm/storage/expressions/Expression.cpp b/src/storm/storage/expressions/Expression.cpp index 1537e633e..2ec1604a7 100644 --- a/src/storm/storage/expressions/Expression.cpp +++ b/src/storm/storage/expressions/Expression.cpp @@ -277,6 +277,11 @@ namespace storm { return Expression(std::shared_ptr(new BinaryNumericalFunctionExpression(first.getBaseExpression().getManager(), first.getType().power(second.getType()), first.getBaseExpressionPointer(), second.getBaseExpressionPointer(), BinaryNumericalFunctionExpression::OperatorType::Power))); } + Expression operator%(Expression const& first, Expression const& second) { + assertSameManager(first.getBaseExpression(), second.getBaseExpression()); + return Expression(std::shared_ptr(new BinaryNumericalFunctionExpression(first.getBaseExpression().getManager(), first.getType().power(second.getType()), first.getBaseExpressionPointer(), second.getBaseExpressionPointer(), BinaryNumericalFunctionExpression::OperatorType::Modulo))); + } + Expression operator&&(Expression const& first, Expression const& second) { if (!first.isInitialized()) { return second; diff --git a/src/storm/storage/expressions/Expression.h b/src/storm/storage/expressions/Expression.h index 98a2e6417..99d409e2e 100644 --- a/src/storm/storage/expressions/Expression.h +++ b/src/storm/storage/expressions/Expression.h @@ -33,6 +33,7 @@ namespace storm { friend Expression operator*(Expression const& first, Expression const& second); friend Expression operator/(Expression const& first, Expression const& second); friend Expression operator^(Expression const& first, Expression const& second); + friend Expression operator%(Expression const& first, Expression const& second); friend Expression operator&&(Expression const& first, Expression const& second); friend Expression operator||(Expression const& first, Expression const& second); friend Expression operator!(Expression const& first); diff --git a/src/storm/storage/expressions/LinearityCheckVisitor.cpp b/src/storm/storage/expressions/LinearityCheckVisitor.cpp index 9eeb3ea56..86650acea 100644 --- a/src/storm/storage/expressions/LinearityCheckVisitor.cpp +++ b/src/storm/storage/expressions/LinearityCheckVisitor.cpp @@ -77,6 +77,7 @@ namespace storm { case BinaryNumericalFunctionExpression::OperatorType::Min: return LinearityStatus::NonLinear; break; case BinaryNumericalFunctionExpression::OperatorType::Max: return LinearityStatus::NonLinear; break; case BinaryNumericalFunctionExpression::OperatorType::Power: return LinearityStatus::NonLinear; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: return LinearityStatus::NonLinear; break; } STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal binary numerical expression operator."); } diff --git a/src/storm/storage/expressions/OperatorType.cpp b/src/storm/storage/expressions/OperatorType.cpp index 1036869bc..bba61a653 100644 --- a/src/storm/storage/expressions/OperatorType.cpp +++ b/src/storm/storage/expressions/OperatorType.cpp @@ -16,6 +16,7 @@ namespace storm { case OperatorType::Min: stream << "min"; break; case OperatorType::Max: stream << "max"; break; case OperatorType::Power: stream << "^"; break; + case OperatorType::Modulo: stream << "%"; break; case OperatorType::Equal: stream << "="; break; case OperatorType::NotEqual: stream << "!="; break; case OperatorType::Less: stream << "<"; break; diff --git a/src/storm/storage/expressions/OperatorType.h b/src/storm/storage/expressions/OperatorType.h index f056f494a..e334b8104 100644 --- a/src/storm/storage/expressions/OperatorType.h +++ b/src/storm/storage/expressions/OperatorType.h @@ -19,6 +19,7 @@ namespace storm { Min, Max, Power, + Modulo, Equal, NotEqual, Less, diff --git a/src/storm/storage/expressions/ToCppVisitor.cpp b/src/storm/storage/expressions/ToCppVisitor.cpp index b68de7132..70b76a467 100644 --- a/src/storm/storage/expressions/ToCppVisitor.cpp +++ b/src/storm/storage/expressions/ToCppVisitor.cpp @@ -142,6 +142,13 @@ namespace storm { expression.getSecondOperand()->accept(*this, data); stream << ")"; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: + stream << "("; + expression.getFirstOperand()->accept(*this, data); + stream << " % "; + expression.getSecondOperand()->accept(*this, data); + stream << ")"; + break; } return boost::none; } diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index d9098af2b..b7e9c39f2 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -100,6 +100,13 @@ namespace storm { expression.getSecondOperand()->accept(*this, data); stream << ")"; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: + stream << "("; + expression.getFirstOperand()->accept(*this, data); + stream << "%"; + expression.getSecondOperand()->accept(*this, data); + stream << ")"; + break; case BinaryNumericalFunctionExpression::OperatorType::Max: stream << "max("; expression.getFirstOperand()->accept(*this, data); diff --git a/src/storm/storage/expressions/ToRationalNumberVisitor.cpp b/src/storm/storage/expressions/ToRationalNumberVisitor.cpp index 15a8d61eb..89408f9d3 100644 --- a/src/storm/storage/expressions/ToRationalNumberVisitor.cpp +++ b/src/storm/storage/expressions/ToRationalNumberVisitor.cpp @@ -48,6 +48,7 @@ namespace storm { RationalNumberType firstOperandAsRationalNumber = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); RationalNumberType secondOperandAsRationalNumber = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); RationalNumberType result; + uint_fast64_t exponentAsInteger; switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: result = firstOperandAsRationalNumber + secondOperandAsRationalNumber; @@ -75,10 +76,12 @@ namespace storm { break; case BinaryNumericalFunctionExpression::OperatorType::Power: STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalNumber), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer."); - uint_fast64_t exponentAsInteger = storm::utility::convertNumber(secondOperandAsRationalNumber); + exponentAsInteger = storm::utility::convertNumber(secondOperandAsRationalNumber); result = storm::utility::pow(firstOperandAsRationalNumber, exponentAsInteger); return result; break; + default: + STORM_LOG_ASSERT(false, "Illegal operator type."); } // Return a dummy. This point must, however, never be reached. diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 5fde8267a..0c0c212a0 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -455,6 +455,8 @@ namespace storm { return "max"; case OpType::Power: return "pow"; + case OpType::Modulo: + return "mod"; case OpType::Equal: return "="; case OpType::NotEqual: From 0fed84c5a9aef3a16b573ab16cb034b40ce97bd0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Apr 2018 09:06:50 +0200 Subject: [PATCH 254/647] removed superfluous return --- src/storm/models/sparse/StateLabeling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/models/sparse/StateLabeling.cpp b/src/storm/models/sparse/StateLabeling.cpp index e80556108..bcb00b7a9 100644 --- a/src/storm/models/sparse/StateLabeling.cpp +++ b/src/storm/models/sparse/StateLabeling.cpp @@ -50,7 +50,7 @@ namespace storm { } void StateLabeling::addLabelToState(std::string const& label, storm::storage::sparse::state_type state) { - return ItemLabeling::addLabelToItem(label, state); + ItemLabeling::addLabelToItem(label, state); } bool StateLabeling::getStateHasLabel(std::string const& label, storm::storage::sparse::state_type state) const { From 759ea3604fb9696f7a17b110500517ecfe4719f0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Apr 2018 14:05:58 +0200 Subject: [PATCH 255/647] fixed expression to ExprTk translation for rational literals (pointed out by Joachim Klein) --- src/storm/storage/expressions/ToExprtkStringVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index b7e9c39f2..82d489d2b 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -220,7 +220,7 @@ namespace storm { } boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { - stream << "(" << expression.getValue() << ")"; + stream << "(" << expression.getValueAsDouble() << ")"; return boost::any(); } } From 533e48bdbcfd975c2b6978871b8080110aa3e21f Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Apr 2018 14:12:46 +0200 Subject: [PATCH 256/647] increasing precision for rational to ExprTk rational literal conversion --- src/storm/storage/expressions/ToExprtkStringVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index 82d489d2b..2feb06290 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -220,7 +220,7 @@ namespace storm { } boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { - stream << "(" << expression.getValueAsDouble() << ")"; + stream << std::setprecision(15) << "(" << expression.getValueAsDouble() << ")"; return boost::any(); } } From 844608488a97d7920549220c5a609f6c40c8388f Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Apr 2018 14:20:46 +0200 Subject: [PATCH 257/647] using max_digits10 to increase precision enough to uniquely identify double (as proposed by Joachim) --- src/storm/storage/expressions/ToExprtkStringVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index 2feb06290..b3b0df9c3 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -220,7 +220,7 @@ namespace storm { } boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { - stream << std::setprecision(15) << "(" << expression.getValueAsDouble() << ")"; + stream << std::scientific << std::setprecision(std::numeric_limits::max_digits10) << "(" << expression.getValueAsDouble() << ")"; return boost::any(); } } From c9496a255b25c4bf1a2c6163d56e278802ecf4a7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 13 Apr 2018 11:25:47 +0200 Subject: [PATCH 258/647] corrected tests (pointed out by jklein) --- src/test/storm/utility/KSPTest.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/storm/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp index df8b4f212..35b449f01 100644 --- a/src/test/storm/utility/KSPTest.cpp +++ b/src/test/storm/utility/KSPTest.cpp @@ -39,7 +39,7 @@ TEST(KSPTest, singleTarget) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); double dist = spg.getDistance(100); - EXPECT_DOUBLE_EQ(1.5231305000339649e-06, dist); + EXPECT_NEAR(1.5231305000339662e-06, dist, 1e-12); } TEST(KSPTest, reentry) { @@ -47,11 +47,11 @@ TEST(KSPTest, reentry) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); double dist = spg.getDistance(100); - EXPECT_DOUBLE_EQ(1.5231305000339649e-06, dist); + EXPECT_NEAR(1.5231305000339662e-06, dist, 1e-12); // get another distance to ensure re-entry is no problem double dist2 = spg.getDistance(500); - EXPECT_DOUBLE_EQ(3.0462610000679282e-08, dist2); + EXPECT_NEAR(3.0462610000679315e-08, dist2, 1e-12); } TEST(KSPTest, groupTarget) { @@ -60,13 +60,13 @@ TEST(KSPTest, groupTarget) { auto spg = storm::utility::ksp::ShortestPathsGenerator(*model, groupTarget); double dist1 = spg.getDistance(8); - EXPECT_DOUBLE_EQ(0.00018449245583999996, dist1); + EXPECT_NEAR(0.00018449245583999996, dist1, 1e-12); double dist2 = spg.getDistance(9); - EXPECT_DOUBLE_EQ(0.00018449245583999996, dist2); + EXPECT_NEAR(0.00018449245583999996, dist2, 1e-12); double dist3 = spg.getDistance(12); - EXPECT_DOUBLE_EQ(7.5303043199999984e-06, dist3); + EXPECT_NEAR(7.5303043199999984e-06, dist3, 1e-12); } TEST(KSPTest, kTooLargeException) { @@ -81,7 +81,7 @@ TEST(KSPTest, kspStateSet) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); storm::storage::BitVector referenceBV(model->getNumberOfStates(), false); - for (auto s : std::vector{0, 1, 3, 5, 7, 10, 14, 19, 25, 29, 33, 36, 40, 44, 50, 56, 62, 70, 77, 85, 92, 98, 104, 112, 119, 127, 134, 140, 146, 154, 161, 169, 176, 182, 188, 196, 203, 211, 218, 224, 230, 238, 245, 253, 260, 266, 272, 281, 288, 296}) { + for (auto s : std::vector{0, 1, 2, 4, 6, 9, 12, 17, 22, 30, 37, 45, 52, 58, 65, 70, 74, 77, 81, 85, 92, 98, 104, 112, 119, 127, 134, 140, 146, 154, 161, 169, 176, 182, 188, 196, 203, 211, 218, 224, 230, 238, 245, 253, 260, 266, 272, 281, 288, 296}) { referenceBV.set(s, true); } @@ -95,8 +95,8 @@ TEST(KSPTest, kspPathAsList) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); // TODO: use path that actually has a loop or something to make this more interesting - auto reference = storm::utility::ksp::OrderedStateList{296, 288, 281, 272, 266, 260, 253, 245, 238, 230, 224, 218, 211, 203, 196, 188, 182, 176, 169, 161, 154, 146, 140, 134, 127, 119, 112, 104, 98, 92, 85, 77, 70, 62, 56, 50, 44, 36, 29, 40, 33, 25, 19, 14, 10, 7, 5, 3, 1, 0}; + auto reference = storm::utility::ksp::OrderedStateList{296, 288, 281, 272, 266, 260, 253, 245, 238, 230, 224, 218, 211, 203, 196, 188, 182, 176, 169, 161, 154, 146, 140, 134, 127, 119, 112, 104, 98, 92, 85, 77, 70, 81, 74, 65, 58, 52, 45, 37, 30, 22, 17, 12, 9, 6, 4, 2, 1, 0}; auto list = spg.getPathAsList(7); - + EXPECT_EQ(reference, list); } From 6d445e38af9560f5889457ef3bec8edee9d258c4 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 17 Apr 2018 15:04:42 +0200 Subject: [PATCH 259/647] fixes github issue #18 --- .../UnaryNumericalFunctionExpression.cpp | 10 ++++++++++ src/storm/utility/constants.cpp | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp b/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp index 3ed20d7b6..770c7b9f1 100644 --- a/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp +++ b/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp @@ -74,6 +74,7 @@ namespace storm { operandEvaluation = operandSimplified->evaluateAsRational(); } + bool rationalToInteger = this->getOperatorType() == OperatorType::Floor || this->getOperatorType() == OperatorType::Ceil; if (operandSimplified->hasIntegerType()) { int_fast64_t value = 0; switch (this->getOperatorType()) { @@ -82,6 +83,15 @@ namespace storm { case OperatorType::Ceil: value = std::ceil(boost::get(operandEvaluation)); break; } return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), value)); + } else if (rationalToInteger) { + int_fast64_t value = 0; + switch (this->getOperatorType()) { + case OperatorType::Floor: value = storm::utility::convertNumber(storm::RationalNumber(carl::floor(boost::get(operandEvaluation)))); break; + case OperatorType::Ceil: value = storm::utility::convertNumber(storm::RationalNumber(carl::ceil(boost::get(operandEvaluation)))); break; + default: + STORM_LOG_ASSERT(false, "Unexpected rational to integer conversion."); + } + return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), value)); } else { storm::RationalNumber value = storm::utility::zero(); switch (this->getOperatorType()) { diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index 6086f1bf9..6c0d1c814 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -324,7 +324,12 @@ namespace storm { uint_fast64_t convertNumber(ClnRationalNumber const& number) { return carl::toInt(number); } - + + template<> + int_fast64_t convertNumber(ClnRationalNumber const& number) { + return carl::toInt(number); + } + template<> ClnRationalNumber convertNumber(double const& number) { return carl::rationalize(number); @@ -516,7 +521,12 @@ namespace storm { uint_fast64_t convertNumber(GmpRationalNumber const& number){ return carl::toInt(number); } - + + template<> + int_fast64_t convertNumber(GmpRationalNumber const& number){ + return carl::toInt(number); + } + template<> GmpRationalNumber convertNumber(double const& number){ return carl::rationalize(number); From 4378279c6419541e7100270937c849e5c5d53fea Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 17 Apr 2018 16:28:03 +0200 Subject: [PATCH 260/647] fixes second half of github issue #18 --- src/storm/parser/ExpressionParser.h | 2 ++ src/storm/parser/PrismParser.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/storm/parser/ExpressionParser.h b/src/storm/parser/ExpressionParser.h index 3c5b093fd..cb415c53e 100644 --- a/src/storm/parser/ExpressionParser.h +++ b/src/storm/parser/ExpressionParser.h @@ -18,6 +18,8 @@ namespace storm { template struct RationalPolicies : boost::spirit::qi::strict_real_policies { static const bool expect_dot = true; + static const bool allow_leading_dot = true; + static const bool allow_trailing_dot = false; template static bool parse_nan(It&, It const&, Attr&) { return false; } diff --git a/src/storm/parser/PrismParser.cpp b/src/storm/parser/PrismParser.cpp index e54e02b18..ca59981cb 100644 --- a/src/storm/parser/PrismParser.cpp +++ b/src/storm/parser/PrismParser.cpp @@ -116,7 +116,7 @@ namespace storm { booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > -((qi::lit("init") > expression_[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)]; booleanVariableDefinition.name("boolean variable definition"); - integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expression_ > qi::lit("..") > expression_ > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expression_[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; + integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")) > expression_ > qi::lit("..") > expression_ > qi::lit("]") > -(qi::lit("init") > expression_[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; integerVariableDefinition.name("integer variable definition"); variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]); From 2658a02604d47ef52950e93c5cecd2ee6682564c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 18 Apr 2018 16:31:14 +0200 Subject: [PATCH 261/647] Fixed compiler warnings for unused lambda captures --- src/storm-dft/storage/BucketPriorityQueue.cpp | 2 +- src/storm/builder/DdJaniModelBuilder.cpp | 2 +- .../modelchecker/exploration/SparseExplorationModelChecker.cpp | 2 +- .../DeterministicModelBisimulationDecomposition.cpp | 2 +- .../NondeterministicModelBisimulationDecomposition.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/storm-dft/storage/BucketPriorityQueue.cpp b/src/storm-dft/storage/BucketPriorityQueue.cpp index 3fccf05f9..c9b2adf24 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.cpp +++ b/src/storm-dft/storage/BucketPriorityQueue.cpp @@ -9,7 +9,7 @@ namespace storm { template BucketPriorityQueue::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio) : lowerValue(lowerValue), logBase(std::log(ratio)), nrBuckets(nrBuckets), nrUnsortedItems(0), buckets(nrBuckets), currentBucket(nrBuckets) { - compare = ([this](HeuristicPointer a, HeuristicPointer b) { + compare = ([](HeuristicPointer a, HeuristicPointer b) { return *a < *b; }); } diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 507cde01a..091c3fe6d 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -1275,7 +1275,7 @@ namespace storm { // Finally treat the transient assignments. std::map> transientEdgeAssignments; if (!this->transientVariables.empty()) { - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = sourceLocationAndGuard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } ); } diff --git a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp index c5dc5e036..73e880662 100644 --- a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp +++ b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp @@ -341,7 +341,7 @@ namespace storm { }); } else if (explorationInformation.useProbabilityHeuristic()) { std::transform(row.begin(), row.end(), probabilities.begin(), - [&bounds, &explorationInformation] (storm::storage::MatrixEntry const& entry) { + [] (storm::storage::MatrixEntry const& entry) { return entry.getValue(); }); } diff --git a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp index 2a73744cf..a084de9ba 100644 --- a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp @@ -419,7 +419,7 @@ namespace storm { // the sorting is over. Otherwise, this interferes with the data used in the sorting process. storm::storage::sparse::state_type originalBlockIndex = block.getBeginIndex(); auto split = this->partition.splitBlock(block, - [&weakStateLabels,&block,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { + [&weakStateLabels, originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { return weakStateLabels[this->partition.getPosition(state1) - originalBlockIndex] < weakStateLabels[this->partition.getPosition(state2) - originalBlockIndex]; }, [this, &splitterQueue, &block] (bisimulation::Block& newBlock) { diff --git a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp index 473ae556a..019ec40c2 100644 --- a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp @@ -367,7 +367,7 @@ namespace storm { bool result = quotientDistributionsLess(state1, state2); return result; }, - [this, &block, &splitterQueue, &newBlocks] (Block& newBlock) { + [&newBlocks] (Block& newBlock) { newBlocks.push_back(&newBlock); }); From ec411ffc780293c1c88a005aca94f157bd718e36 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 18 Apr 2018 16:32:20 +0200 Subject: [PATCH 262/647] Typos --- .../modelchecker/dft/DFTModelChecker.cpp | 6 ++-- src/storm-dft/storage/dft/DFT.cpp | 29 +++++++++---------- src/storm/models/sparse/MarkovAutomaton.cpp | 14 ++++----- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 31ba6789d..8d277d60d 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -54,14 +54,14 @@ namespace storm { case storm::storage::DFTElementType::AND: STORM_LOG_TRACE("top modularisation called AND"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = dfts.size(); nrM = dfts.size(); break; case storm::storage::DFTElementType::OR: STORM_LOG_TRACE("top modularisation called OR"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = 0; nrM = dfts.size(); invResults = true; @@ -69,7 +69,7 @@ namespace storm { case storm::storage::DFTElementType::VOT: STORM_LOG_TRACE("top modularisation called VOT"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = std::static_pointer_cast const>(dft.getTopLevelGate())->threshold(); nrM = dfts.size(); if(nrK <= nrM/2) { diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 81784ea96..ad89354f3 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -293,22 +293,22 @@ namespace storm { } return max; } - + template DFT DFT::optimize() const { std::vector modIdea = findModularisationRewrite(); STORM_LOG_DEBUG("Modularisation idea: " << storm::utility::vector::toString(modIdea)); - + if (modIdea.empty()) { // No rewrite needed return *this; } - + std::vector> rewriteIds; rewriteIds.push_back(modIdea); - + storm::builder::DFTBuilder builder; - + // Accumulate elements which must be rewritten std::set rewriteSet; for (std::vector rewrites : rewriteIds) { @@ -320,7 +320,7 @@ namespace storm { builder.copyElement(elem); } } - + // Add rewritten elements for (std::vector rewrites : rewriteIds) { STORM_LOG_ASSERT(rewrites.size() > 1, "No rewritten elements."); @@ -359,7 +359,7 @@ namespace storm { STORM_LOG_ASSERT(false, "Dft type can not be rewritten."); break; } - + // Add parent with the new child newParent and all its remaining children childrenNames.clear(); childrenNames.push_back(newParentName); @@ -371,7 +371,7 @@ namespace storm { } builder.copyGate(originalParent, childrenNames); } - + builder.setTopLevel(mElements[mTopLevelIndex]->name()); // TODO use reference? DFT newDft = builder.build(); @@ -750,11 +750,10 @@ namespace storm { // suitable parent gate! - Lets check the independent submodules of the children auto const& children = std::static_pointer_cast>(e)->children(); for(auto const& child : children) { - - + auto ISD = std::static_pointer_cast>(child)->independentSubDft(true); // In the ISD, check for other children: - + std::vector rewrite = {e->id(), child->id()}; for(size_t isdElemId : ISD) { if(isdElemId == child->id()) continue; @@ -765,13 +764,13 @@ namespace storm { if(rewrite.size() > 2 && rewrite.size() < children.size() - 1) { return rewrite; } - - } + + } } - } + } return {}; } - + template std::tuple, std::vector, std::vector> DFT::getSortedParentAndDependencyIds(size_t index) const { diff --git a/src/storm/models/sparse/MarkovAutomaton.cpp b/src/storm/models/sparse/MarkovAutomaton.cpp index 9c077e2c4..587a28a7b 100644 --- a/src/storm/models/sparse/MarkovAutomaton.cpp +++ b/src/storm/models/sparse/MarkovAutomaton.cpp @@ -181,7 +181,7 @@ namespace storm { // Get number of choices in current state uint_fast64_t numberChoices = this->getTransitionMatrix().getRowGroupIndices()[state + 1] - this->getTransitionMatrix().getRowGroupIndices()[state]; if (isMarkovianState(state)) { - STORM_LOG_ASSERT(numberChoices == 1, "Wrong number of choices for markovian state."); + STORM_LOG_ASSERT(numberChoices == 1, "Wrong number of choices for Markovian state."); } if (numberChoices > 1) { STORM_LOG_ASSERT(isProbabilisticState(state), "State is not probabilistic."); @@ -211,7 +211,7 @@ namespace storm { storm::storage::FlexibleSparseMatrix flexibleMatrix(this->getTransitionMatrix()); storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(this->getTransitionMatrix().transpose()); storm::solver::stateelimination::StateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions); - + for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { STORM_LOG_ASSERT(!this->isHybridState(state), "State is hybrid."); if (this->isProbabilisticState(state)) { @@ -220,7 +220,7 @@ namespace storm { STORM_LOG_TRACE("Flexible matrix after eliminating state " << state << ":" << std::endl << flexibleMatrix); } } - + // Create the rate matrix for the CTMC storm::storage::SparseMatrixBuilder transitionMatrixBuilder(0, 0, 0, false, false); // Remember state to keep @@ -230,7 +230,7 @@ namespace storm { // State is eliminated and can be discarded keepStates.set(state, false); } else { - STORM_LOG_ASSERT(this->isMarkovianState(state), "State is not markovian."); + STORM_LOG_ASSERT(this->isMarkovianState(state), "State is not Markovian."); // Copy transitions for (uint_fast64_t row = flexibleMatrix.getRowGroupIndices()[state]; row < flexibleMatrix.getRowGroupIndices()[state + 1]; ++row) { for (auto const& entry : flexibleMatrix.getRow(row)) { @@ -240,20 +240,20 @@ namespace storm { } } } - + storm::storage::SparseMatrix rateMatrix = transitionMatrixBuilder.build(); rateMatrix = rateMatrix.getSubmatrix(false, keepStates, keepStates, false); STORM_LOG_TRACE("New CTMC matrix:" << std::endl << rateMatrix); // Construct CTMC storm::models::sparse::StateLabeling stateLabeling = this->getStateLabeling().getSubLabeling(keepStates); - + //TODO update reward models and choice labels according to kept states STORM_LOG_WARN_COND(this->getRewardModels().empty(), "Conversion of MA to CTMC does not preserve rewards."); std::unordered_map rewardModels = this->getRewardModels(); STORM_LOG_WARN_COND(!this->hasChoiceLabeling(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasStateValuations(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasChoiceOrigins(), "Conversion of MA to CTMC does not preserve choice labels."); - + return std::make_shared>(std::move(rateMatrix), std::move(stateLabeling), std::move(rewardModels)); } From 300ccd731f3f2cbd0106ee612874411bcc640848 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 18 Apr 2018 16:32:45 +0200 Subject: [PATCH 263/647] Use to_string in DRN exporter --- src/storm/utility/DirectEncodingExporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/utility/DirectEncodingExporter.cpp b/src/storm/utility/DirectEncodingExporter.cpp index 9953a4108..ec29cbe1e 100644 --- a/src/storm/utility/DirectEncodingExporter.cpp +++ b/src/storm/utility/DirectEncodingExporter.cpp @@ -73,7 +73,7 @@ namespace storm { } if(rewardModelEntry.second.hasStateRewards()) { - os << rewardModelEntry.second.getStateRewardVector().at(group); + os << storm::utility::to_string(rewardModelEntry.second.getStateRewardVector().at(group)); } else { os << "0"; } From b8794fd9c809a7a2fc5fd3936ccfaae68d5f7930 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 19 Apr 2018 13:58:55 +0300 Subject: [PATCH 264/647] Made the default multiplier matching the selected equation solver. --- src/storm/solver/Multiplier.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 26bb4d85b..38d81fee4 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -58,6 +58,21 @@ namespace storm { template std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { + auto type = env.solver().multiplier().getType(); + + // Adjust the multiplier type if an eqsolver was specified but not a multiplier + if (!env.solver().isLinearEquationSolverTypeSetFromDefaultValue() && env.solver().multiplier().isTypeSetFromDefault()) { + bool changed = false; + if (env.solver().getLinearEquationSolverType() == EquationSolverType::Gmmxx && type != MultiplierType::Gmmxx) { + type = MultiplierType::Gmmxx; + changed = true; + } else if (env.solver().getLinearEquationSolverType() == EquationSolverType::Native && type != MultiplierType::Native) { + type = MultiplierType::Native; + changed = true; + } + STORM_LOG_INFO_COND(!changed, "Selecting '" + toString(type) + "' as the multiplier type to match the selected equation solver. If you want to override this, please explicitly specify a different multiplier type."); + } + switch (env.solver().multiplier().getType()) { case MultiplierType::Gmmxx: return std::make_unique>(matrix); From 331e82da1e53604b608642149d0744a91776b86c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 19 Apr 2018 16:26:23 +0200 Subject: [PATCH 265/647] Travis: use movesrwth docker containers --- .travis.yml | 16 ++++++++-------- travis/build.sh | 6 +++--- travis/build_carl.sh | 2 +- travis/generate_travis.py | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index e790a1123..060741118 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,8 +48,8 @@ jobs: - travis/build_carl.sh after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit carl mvolk/carl:travis-debug; - - docker push mvolk/carl:travis-debug; + - docker commit carl movesrwth/carl:travis-debug; + - docker push movesrwth/carl:travis-debug; # ubuntu-17.10 - DefaultReleaseTravis - stage: Build Carl os: linux @@ -61,8 +61,8 @@ jobs: - travis/build_carl.sh after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit carl mvolk/carl:travis; - - docker push mvolk/carl:travis; + - docker commit carl movesrwth/carl:travis; + - docker push movesrwth/carl:travis; ### # Stage: Build (1st run) @@ -341,8 +341,8 @@ jobs: - find build -iname '*err*.log' -type f -print -exec cat {} \; after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit storm mvolk/storm:travis-debug; - - docker push mvolk/storm:travis-debug; + - docker commit storm movesrwth/storm:travis-debug; + - docker push movesrwth/storm:travis-debug; # ubuntu-17.10 - DefaultReleaseTravis - stage: Test all os: linux @@ -358,8 +358,8 @@ jobs: - find build -iname '*err*.log' -type f -print -exec cat {} \; after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit storm mvolk/storm:travis; - - docker push mvolk/storm:travis; + - docker commit storm movesrwth/storm:travis; + - docker push movesrwth/storm:travis; allow_failures: - stage: Build (1st run) os: linux diff --git a/travis/build.sh b/travis/build.sh index 49a1007bd..9dca49549 100755 --- a/travis/build.sh +++ b/travis/build.sh @@ -28,13 +28,13 @@ linux) set -e case "$CONFIG" in *DebugTravis) - docker run -d -it --name storm --privileged mvolk/carl:travis-debug + docker run -d -it --name storm --privileged movesrwth/carl:travis-debug ;; *ReleaseTravis) - docker run -d -it --name storm --privileged mvolk/carl:travis + docker run -d -it --name storm --privileged movesrwth/carl:travis ;; *) - docker run -d -it --name storm --privileged mvolk/storm-basesystem:$LINUX + docker run -d -it --name storm --privileged movesrwth/storm-basesystem:$LINUX ;; esac # Copy local content into container diff --git a/travis/build_carl.sh b/travis/build_carl.sh index 5054e3d6d..2918a4af7 100755 --- a/travis/build_carl.sh +++ b/travis/build_carl.sh @@ -12,7 +12,7 @@ linux) docker rm -f carl &>/dev/null # Run container set -e - docker run -d -it --name carl --privileged mvolk/storm-basesystem:$LINUX + docker run -d -it --name carl --privileged movesrwth/storm-basesystem:$LINUX # Copy local content into container docker cp travis/build_carl_helper.sh carl:/opt/ set +e diff --git a/travis/generate_travis.py b/travis/generate_travis.py index 52a81a678..9d2f254a0 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -92,11 +92,11 @@ if __name__ == "__main__": buildConfig += " after_success:\n" buildConfig += ' - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD";\n' if "Debug" in build_type: - buildConfig += " - docker commit carl mvolk/carl:travis-debug;\n" - buildConfig += " - docker push mvolk/carl:travis-debug;\n" + buildConfig += " - docker commit carl movesrwth/carl:travis-debug;\n" + buildConfig += " - docker push movesrwth/carl:travis-debug;\n" elif "Release" in build_type: - buildConfig += " - docker commit carl mvolk/carl:travis;\n" - buildConfig += " - docker push mvolk/carl:travis;\n" + buildConfig += " - docker commit carl movesrwth/carl:travis;\n" + buildConfig += " - docker push movesrwth/carl:travis;\n" else: assert False s += buildConfig @@ -160,11 +160,11 @@ if __name__ == "__main__": buildConfig += " after_success:\n" buildConfig += ' - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD";\n' if "Debug" in build_type: - buildConfig += " - docker commit storm mvolk/storm:travis-debug;\n" - buildConfig += " - docker push mvolk/storm:travis-debug;\n" + buildConfig += " - docker commit storm movesrwth/storm:travis-debug;\n" + buildConfig += " - docker push movesrwth/storm:travis-debug;\n" elif "Release" in build_type: - buildConfig += " - docker commit storm mvolk/storm:travis;\n" - buildConfig += " - docker push mvolk/storm:travis;\n" + buildConfig += " - docker commit storm movesrwth/storm:travis;\n" + buildConfig += " - docker push movesrwth/storm:travis;\n" else: assert False s += buildConfig From df52f3fbb46f60333c738ba52d1608a82327dbb1 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 20 Apr 2018 11:16:02 +0200 Subject: [PATCH 266/647] Travis: move timeout into docker container as suggested by jklein --- travis/build.sh | 4 ++-- travis/build_carl.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/travis/build.sh b/travis/build.sh index 9dca49549..52fe4d64f 100755 --- a/travis/build.sh +++ b/travis/build.sh @@ -43,14 +43,14 @@ linux) set +e # Execute main process - timeout $TIMEOUT_LINUX docker exec storm bash -c " + docker exec storm bash -c " export CONFIG=$CONFIG; export COMPILER=$COMPILER; export N_JOBS=$N_JOBS; export STLARG=; export OS=$OS; cd /opt/storm; - travis/build_helper.sh $1" + timeout $TIMEOUT_LINUX ./travis/build_helper.sh $1" EXITCODE=$? ;; diff --git a/travis/build_carl.sh b/travis/build_carl.sh index 2918a4af7..37be2a986 100755 --- a/travis/build_carl.sh +++ b/travis/build_carl.sh @@ -18,14 +18,14 @@ linux) set +e # Execute main process - timeout $TIMEOUT_LINUX docker exec carl bash -c " + docker exec carl bash -c " export CONFIG=$CONFIG; export COMPILER=$COMPILER; export N_JOBS=$N_JOBS; export STLARG=; export OS=$OS; cd /opt/; - ./build_carl_helper.sh" + timeout $TIMEOUT_LINUX ./build_carl_helper.sh" ;; osx) From eaf13b1d69c98ce7a3ab98b59417895c15d9645c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 20 Apr 2018 17:56:30 +0200 Subject: [PATCH 267/647] Travis: use absolute path --- travis/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/build.sh b/travis/build.sh index 52fe4d64f..2873a6ec7 100755 --- a/travis/build.sh +++ b/travis/build.sh @@ -38,7 +38,7 @@ linux) ;; esac # Copy local content into container - docker exec storm mkdir opt/storm + docker exec storm mkdir /opt/storm docker cp . storm:/opt/storm set +e From 60b1ef5a57159e059f9a5ce9138efb01d49cb3a7 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 25 Apr 2018 17:17:12 +0200 Subject: [PATCH 268/647] Travis: test against Ubuntu 18.04 --- .travis.yml | 132 ++++++++++++++++++++++++++++++++++++++ travis/generate_travis.py | 2 + 2 files changed, 134 insertions(+) diff --git a/.travis.yml b/.travis.yml index 060741118..d6e942eec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -124,6 +124,34 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (1st run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - rm -rf build + - travis/install_linux.sh + script: + - travis/build.sh Build1 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (1st run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - rm -rf build + - travis/install_linux.sh + script: + - travis/build.sh Build1 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; ### # Stage: Build (2nd run) @@ -181,6 +209,32 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (2nd run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build2 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (2nd run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build2 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; ### # Stage: Build (3rd run) @@ -238,6 +292,32 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (3rd run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build3 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (3rd run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build3 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; ### # Stage: Build (4th run) @@ -295,6 +375,32 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (4th run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh BuildLast + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (4th run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh BuildLast + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; ### # Stage: Test all @@ -360,6 +466,32 @@ jobs: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - docker commit storm movesrwth/storm:travis; - docker push movesrwth/storm:travis; + # ubuntu-18.04 - DefaultDebug + - stage: Test all + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh TestAll + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Test all + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh TestAll + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; allow_failures: - stage: Build (1st run) os: linux diff --git a/travis/generate_travis.py b/travis/generate_travis.py index 9d2f254a0..ade78cbca 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -7,6 +7,8 @@ configs_linux = [ ("debian-9", "gcc", "DefaultRelease"), ("ubuntu-17.10", "gcc", "DefaultDebugTravis"), ("ubuntu-17.10", "gcc", "DefaultReleaseTravis"), + ("ubuntu-18.04", "gcc", "DefaultDebug"), + ("ubuntu-18.04", "gcc", "DefaultRelease"), ] # Configurations for Mac From bb6fb04f72256da82a1a6d19bd1c5c8559a2e0b3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 26 Apr 2018 09:26:17 +0200 Subject: [PATCH 269/647] fixing volatile k-shortest path test that returns different (yet correct) results on different machines/compilers because of double imprecisions --- src/test/storm/utility/KSPTest.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/test/storm/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp index 35b449f01..5ac954314 100644 --- a/src/test/storm/utility/KSPTest.cpp +++ b/src/test/storm/utility/KSPTest.cpp @@ -80,23 +80,26 @@ TEST(KSPTest, kspStateSet) { auto model = buildExampleModel(); storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); - storm::storage::BitVector referenceBV(model->getNumberOfStates(), false); - for (auto s : std::vector{0, 1, 2, 4, 6, 9, 12, 17, 22, 30, 37, 45, 52, 58, 65, 70, 74, 77, 81, 85, 92, 98, 104, 112, 119, 127, 134, 140, 146, 154, 161, 169, 176, 182, 188, 196, 203, 211, 218, 224, 230, 238, 245, 253, 260, 266, 272, 281, 288, 296}) { - referenceBV.set(s, true); - } - auto bv = spg.getStates(7); - - EXPECT_EQ(referenceBV, bv); + EXPECT_EQ(50, bv.getNumberOfSetBits()); + + // The result may sadly depend on the compiler/system, so checking a particular outcome is not feasible. +// storm::storage::BitVector referenceBV(model->getNumberOfStates(), false); +// for (auto s : std::vector{0, 1, 2, 4, 6, 9, 12, 17, 22, 30, 37, 45, 52, 58, 65, 70, 74, 77, 81, 85, 92, 98, 104, 112, 119, 127, 134, 140, 146, 154, 161, 169, 176, 182, 188, 196, 203, 211, 218, 224, 230, 238, 245, 253, 260, 266, 272, 281, 288, 296}) { +// referenceBV.set(s, true); +// } +// +// EXPECT_EQ(referenceBV, bv); } TEST(KSPTest, kspPathAsList) { auto model = buildExampleModel(); storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); - // TODO: use path that actually has a loop or something to make this more interesting - auto reference = storm::utility::ksp::OrderedStateList{296, 288, 281, 272, 266, 260, 253, 245, 238, 230, 224, 218, 211, 203, 196, 188, 182, 176, 169, 161, 154, 146, 140, 134, 127, 119, 112, 104, 98, 92, 85, 77, 70, 81, 74, 65, 58, 52, 45, 37, 30, 22, 17, 12, 9, 6, 4, 2, 1, 0}; auto list = spg.getPathAsList(7); + EXPECT_EQ(50, list.size()); - EXPECT_EQ(reference, list); + // TODO: use path that actually has a loop or something to make this more interesting +// auto reference = storm::utility::ksp::OrderedStateList{296, 288, 281, 272, 266, 260, 253, 245, 238, 230, 224, 218, 211, 203, 196, 188, 182, 176, 169, 161, 154, 146, 140, 134, 127, 119, 112, 104, 98, 92, 85, 77, 70, 81, 74, 65, 58, 52, 45, 37, 30, 22, 17, 12, 9, 6, 4, 2, 1, 0}; +// EXPECT_EQ(reference, list); } From a67b1a73da16dc4988e6919d857e035b95e5d983 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 2 May 2018 15:58:36 +0200 Subject: [PATCH 270/647] Fixed issues in storm-gspn cmdline --- src/storm-gspn-cli/storm-gspn.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index c1931e468..021634fc1 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -44,6 +44,7 @@ void initializeSettings() { // Register all known settings modules. storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); @@ -92,7 +93,7 @@ int main(const int argc, const char **argv) { auto gspn = parser.parse(storm::settings::getModule().getGspnFilename()); std::string formulaString = ""; - if (!storm::settings::getModule().isPropertySet()) { + if (storm::settings::getModule().isPropertySet()) { formulaString = storm::settings::getModule().getProperty(); } boost::optional> propertyFilter; From 5b678f524ae804578d589caa40bbdc3d2547688b Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 2 May 2018 20:51:54 +0200 Subject: [PATCH 271/647] removed old spurious output --- src/storm/parser/JaniParser.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/storm/parser/JaniParser.cpp b/src/storm/parser/JaniParser.cpp index a428ce4fa..10f98ff35 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm/parser/JaniParser.cpp @@ -168,7 +168,6 @@ namespace storm { if (piStructure.count("lower") > 0) { pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, {}); // TODO substitute constants. - std::cout << "have lower bound" << std::endl; STORM_LOG_THROW(!pi.lowerBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as lower bounds"); } if (piStructure.count("lower-exclusive") > 0) { @@ -177,7 +176,6 @@ namespace storm { } if (piStructure.count("upper") > 0) { - std::cout << "have upper bound" << std::endl; pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval", {}, {}); // TODO substitute constants. STORM_LOG_THROW(!pi.upperBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as upper bounds"); From fdcbd6369ca5312a0630a4f748cb9a035041b7ee Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 2 May 2018 20:52:16 +0200 Subject: [PATCH 272/647] simple sanity check for bounded integers in jani --- src/storm/parser/JaniParser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storm/parser/JaniParser.cpp b/src/storm/parser/JaniParser.cpp index 10f98ff35..725ab0a9d 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm/parser/JaniParser.cpp @@ -706,6 +706,9 @@ namespace storm { } STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); + if(!lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { + STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ")"); + } return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, lowerboundExpr, upperboundExpr); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scopeDescription << ") "); From 56df741d321353fa31f33946e1ce8cf6212877e5 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 2 May 2018 23:38:06 +0200 Subject: [PATCH 273/647] formula parser does not depend on jani model --- src/storm/parser/FormulaParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm/parser/FormulaParser.cpp b/src/storm/parser/FormulaParser.cpp index d9d7cd518..d8b9c2df2 100644 --- a/src/storm/parser/FormulaParser.cpp +++ b/src/storm/parser/FormulaParser.cpp @@ -5,7 +5,6 @@ #include "storm/parser/SpiritErrorHandler.h" #include "storm/storage/prism/Program.h" -#include "storm/storage/jani/Model.h" #include "storm/logic/Formulas.h" From 33ac2e07933873bed14cef64dc8112c54e5b511b Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 2 May 2018 23:41:08 +0200 Subject: [PATCH 274/647] make jani models copyable --- src/storm/storage/jani/Automaton.cpp | 132 +++--------- src/storm/storage/jani/Automaton.h | 74 +------ src/storm/storage/jani/Edge.cpp | 16 ++ src/storm/storage/jani/Edge.h | 4 + src/storm/storage/jani/EdgeContainer.cpp | 200 ++++++++++++++++++ src/storm/storage/jani/EdgeContainer.h | 125 +++++++++++ src/storm/storage/jani/EdgeDestination.cpp | 4 + src/storm/storage/jani/EdgeDestination.h | 2 + src/storm/storage/jani/Model.cpp | 5 +- .../storage/jani/TemplateEdgeContainer.cpp | 12 ++ .../storage/jani/TemplateEdgeContainer.h | 16 ++ 11 files changed, 417 insertions(+), 173 deletions(-) create mode 100644 src/storm/storage/jani/EdgeContainer.cpp create mode 100644 src/storm/storage/jani/EdgeContainer.h create mode 100644 src/storm/storage/jani/TemplateEdgeContainer.cpp create mode 100644 src/storm/storage/jani/TemplateEdgeContainer.h diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 8715a27a8..f4c65c759 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -12,47 +12,7 @@ namespace storm { namespace jani { - namespace detail { - Edges::Edges(iterator it, iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - - Edges::iterator Edges::begin() const { - return it; - } - - Edges::iterator Edges::end() const { - return ite; - } - - bool Edges::empty() const { - return it == ite; - } - - std::size_t Edges::size() const { - return std::distance(it, ite); - } - - ConstEdges::ConstEdges(const_iterator it, const_iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - - ConstEdges::const_iterator ConstEdges::begin() const { - return it; - } - - ConstEdges::const_iterator ConstEdges::end() const { - return ite; - } - - bool ConstEdges::empty() const { - return it == ite; - } - std::size_t ConstEdges::size() const { - return std::distance(it, ite); - } - } Automaton::Automaton(std::string const& name, storm::expressions::Variable const& locationExpressionVariable) : name(name), locationExpressionVariable(locationExpressionVariable) { // Add a sentinel element to the mapping from locations to starting indices. @@ -176,7 +136,7 @@ namespace storm { } Edge const& Automaton::getEdge(uint64_t index) const { - return edges[index]; + return edges.getConcreteEdges()[index]; } Automaton::Edges Automaton::getEdgesFromLocation(std::string const& name) { @@ -307,42 +267,30 @@ namespace storm { void Automaton::addEdge(Edge const& edge) { STORM_LOG_THROW(edge.getSourceLocationIndex() < locations.size(), storm::exceptions::InvalidArgumentException, "Cannot add edge with unknown source location index '" << edge.getSourceLocationIndex() << "'."); - - // Find the right position for the edge and insert it properly. - auto posIt = edges.begin(); - std::advance(posIt, locationToStartingIndex[edge.getSourceLocationIndex() + 1]); - edges.insert(posIt, edge); - + assert(validate()); + + edges.insertEdge(edge, locationToStartingIndex[edge.getSourceLocationIndex()], locationToStartingIndex[edge.getSourceLocationIndex() + 1]); + // Update the set of action indices of this automaton. + actionIndices.insert(edge.getActionIndex()); + // Now update the starting indices of all subsequent locations. for (uint64_t locationIndex = edge.getSourceLocationIndex() + 1; locationIndex < locationToStartingIndex.size(); ++locationIndex) { ++locationToStartingIndex[locationIndex]; } - // Sort all edges form the source location of the newly introduced edge by their action indices. - auto it = edges.begin(); - std::advance(it, locationToStartingIndex[edge.getSourceLocationIndex()]); - auto ite = edges.begin(); - std::advance(ite, locationToStartingIndex[edge.getSourceLocationIndex() + 1]); - std::sort(it, ite, [] (Edge const& a, Edge const& b) { return a.getActionIndex() < b.getActionIndex(); } ); - - // Update the set of action indices of this automaton. - actionIndices.insert(edge.getActionIndex()); + } std::vector& Automaton::getEdges() { - return edges; + return edges.getConcreteEdges(); } std::vector const& Automaton::getEdges() const { - return edges; + return edges.getConcreteEdges(); } std::set Automaton::getActionIndices() const { - std::set result; - for (auto const& edge : edges) { - result.insert(edge.getActionIndex()); - } - return result; + return edges.getActionIndices(); } uint64_t Automaton::getNumberOfLocations() const { @@ -426,35 +374,22 @@ namespace storm { this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution)); - for (auto& templateEdge : templateEdges) { - templateEdge->substitute(substitution); - } - for (auto& edge : this->getEdges()) { - edge.substitute(substitution); - } + edges.substitute(substitution); } void Automaton::registerTemplateEdge(std::shared_ptr const& te) { - templateEdges.insert(te); + edges.insertTemplateEdge(te); } void Automaton::changeAssignmentVariables(std::map> const& remapping) { for (auto& location : locations) { location.changeAssignmentVariables(remapping); } - for (auto& templateEdge : templateEdges) { - templateEdge->changeAssignmentVariables(remapping); - } + edges.changeAssignmentVariables(remapping); } void Automaton::finalize(Model const& containingModel) { //simplifyIndexedAssignments(); - templateEdges.clear(); - for (auto& edge : edges) { - templateEdges.insert(edge.getTemplateEdge()); - } - for (auto& templateEdge : templateEdges) { - templateEdge->finalize(containingModel); - } + edges.finalize(containingModel); } bool Automaton::containsVariablesOnlyInProbabilitiesOrTransientAssignments(std::set const& variables) const { @@ -481,9 +416,7 @@ namespace storm { } void Automaton::pushEdgeAssignmentsToDestinations() { - for (auto& templateEdge : templateEdges) { - templateEdge->pushAssignmentsToDestinations(); - } + edges.pushAssignmentsToDestinations(); } bool Automaton::hasTransientEdgeDestinationAssignments() const { @@ -496,25 +429,20 @@ namespace storm { } void Automaton::liftTransientEdgeDestinationAssignments() { - for (auto& templateEdge : templateEdges) { - templateEdge->liftTransientDestinationAssignments(); - } + edges.liftTransientDestinationAssignments(); } - void Automaton::simplifyIndexedAssignments() { - // TODO has to be fixed. - for (auto& edge : edges) { - edge.simplifyIndexedAssignments(variables); + bool Automaton::validate() const { + assert(locationToStartingIndex.size() == locations.size() + 1); + for(uint64_t i = 0; i < locations.size(); i++) { + assert(locationToStartingIndex[i] <= locationToStartingIndex[i+1]); } + return true; } + bool Automaton::usesAssignmentLevels() const { - for (auto const& edge : this->getEdges()) { - if (edge.usesAssignmentLevels()) { - return true; - } - } - return false; + return edges.usesAssignmentLevels(); } bool Automaton::isLinear() const { @@ -523,18 +451,16 @@ namespace storm { for (auto const& location : this->getLocations()) { result &= location.isLinear(); } - - for (auto const& templateEdge : templateEdges) { - result &= templateEdge->isLinear(); + if (result) { + return edges.isLinear(); } - - return result; + return false; } void Automaton::restrictToEdges(boost::container::flat_set const& edgeIndices) { - std::vector oldEdges = this->edges; + std::vector oldEdges = this->edges.getConcreteEdges(); - this->edges.clear(); + this->edges.clearConcreteEdges(); actionIndices.clear(); for (auto& e : locationToStartingIndex) { e = 0; diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index 3ca635f7b..c549ecca8 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -7,6 +7,8 @@ #include #include "storm/storage/jani/VariableSet.h" +#include "storm/storage/jani/TemplateEdgeContainer.h" +#include "storm/storage/jani/EdgeContainer.h" namespace storm { @@ -16,73 +18,8 @@ namespace storm { class Edge; class TemplateEdge; class Location; - - namespace detail { - class Edges { - public: - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - - Edges(iterator it, iterator ite); - - /*! - * Retrieves an iterator to the edges. - */ - iterator begin() const; - - /*! - * Retrieves an end iterator to the edges. - */ - iterator end() const; - - /*! - * Determines whether this set of edges is empty. - */ - bool empty() const; - - /*! - * Retrieves the number of edges. - */ - std::size_t size() const; - - private: - iterator it; - iterator ite; - }; - - class ConstEdges { - public: - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - - ConstEdges(const_iterator it, const_iterator ite); - - /*! - * Retrieves an iterator to the edges. - */ - const_iterator begin() const; - - /*! - * Retrieves an end iterator to the edges. - */ - const_iterator end() const; - /*! - * Determines whether this set of edges is empty. - */ - bool empty() const; - /*! - * Retrieves the number of edges. - */ - std::size_t size() const; - - private: - const_iterator it; - const_iterator ite; - }; - } - class Model; class Automaton { @@ -262,6 +199,8 @@ namespace storm { * Adds an edge to the automaton. */ void addEdge(Edge const& edge); + + bool validate() const; /*! * Retrieves the edges of the automaton. @@ -401,10 +340,7 @@ namespace storm { std::unordered_map locationToIndex; /// All edges of the automaton - std::vector edges; - - /// The templates for the contained edges. - std::unordered_set> templateEdges; + EdgeContainer edges; /// A mapping from location indices to the starting indices. If l is mapped to i, it means that the edges /// leaving location l start at index i of the edges vector. diff --git a/src/storm/storage/jani/Edge.cpp b/src/storm/storage/jani/Edge.cpp index 18fb35f4f..4460b2a65 100644 --- a/src/storm/storage/jani/Edge.cpp +++ b/src/storm/storage/jani/Edge.cpp @@ -116,8 +116,24 @@ namespace storm { } } + void Edge::setTemplateEdge(std::shared_ptr const& newTe) { + templateEdge = newTe; + uint64_t i = 0; + std::vector newdestinations; + + assert(destinations.size() == newTe->getNumberOfDestinations()); + for (auto& destination : destinations) { + newdestinations.emplace_back(destination.getLocationIndex(), destination.getProbability(), newTe->getDestination(i)); + //destination.updateTemplateEdgeDestination(newTe->getDestination(i)); + ++i; + } + destinations = newdestinations; + } + std::shared_ptr const& Edge::getTemplateEdge() { return templateEdge; } + + } } diff --git a/src/storm/storage/jani/Edge.h b/src/storm/storage/jani/Edge.h index 5585296e6..002b97d40 100644 --- a/src/storm/storage/jani/Edge.h +++ b/src/storm/storage/jani/Edge.h @@ -112,6 +112,10 @@ namespace storm { void simplifyIndexedAssignments(VariableSet const& localVars); std::shared_ptr const& getTemplateEdge(); + + void setTemplateEdge(std::shared_ptr const& newTe); + + void assertValid() const; private: /// The index of the source location. diff --git a/src/storm/storage/jani/EdgeContainer.cpp b/src/storm/storage/jani/EdgeContainer.cpp new file mode 100644 index 000000000..b7a9ca1ec --- /dev/null +++ b/src/storm/storage/jani/EdgeContainer.cpp @@ -0,0 +1,200 @@ +#include "storm/storage/jani/EdgeContainer.h" +#include "storm/storage/jani/Edge.h" +#include "storm/storage/jani/TemplateEdge.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/Model.h" + + + +namespace storm { + namespace jani { + namespace detail { + Edges::Edges(iterator it, iterator ite) : it(it), ite(ite) { + // Intentionally left empty. + } + + Edges::iterator Edges::begin() const { + return it; + } + + Edges::iterator Edges::end() const { + return ite; + } + + bool Edges::empty() const { + return it == ite; + } + + std::size_t Edges::size() const { + return std::distance(it, ite); + } + + ConstEdges::ConstEdges(const_iterator it, const_iterator ite) : it(it), ite(ite) { + // Intentionally left empty. + } + + ConstEdges::const_iterator ConstEdges::begin() const { + return it; + } + + ConstEdges::const_iterator ConstEdges::end() const { + return ite; + } + + bool ConstEdges::empty() const { + return it == ite; + } + + std::size_t ConstEdges::size() const { + return std::distance(it, ite); + } + } + + EdgeContainer::EdgeContainer(EdgeContainer const& other) { + edges = other.getConcreteEdges(); + //templates = other.templates; + std::map, std::shared_ptr> map; + for (auto const& te : other.templates) { + auto newTe = std::make_shared(*te); + this->templates.insert(newTe); + map[te] = newTe; + } + + for (auto& e : edges) { + if(map.count(e.getTemplateEdge()) == 0) { + e.setTemplateEdge(std::make_shared(*(e.getTemplateEdge()))); + } else { + e.setTemplateEdge(map[e.getTemplateEdge()]); + } + } + + + + } + + void EdgeContainer::finalize(Model const& containingModel) { + templates.clear(); + for (auto& edge : edges) { + templates.insert(edge.getTemplateEdge()); + } + for (auto& templateEdge : templates) { + templateEdge->finalize(containingModel); + } + } + + void EdgeContainer::clearConcreteEdges() { + edges.clear(); + } + + void EdgeContainer::liftTransientDestinationAssignments() { + for (auto& templateEdge : templates) { + templateEdge->liftTransientDestinationAssignments(); + } + } + + void EdgeContainer::substitute(std::map const& substitution) { + for (auto& templateEdge : templates) { + templateEdge->substitute(substitution); + } + for (auto& edge : edges) { + edge.substitute(substitution); + } + } + + bool EdgeContainer::isLinear() const { + for (auto const& templateEdge : templates) { + if (!templateEdge->isLinear()) { + return false; + } + } + return true; + } + + + bool EdgeContainer::usesAssignmentLevels() const { + for (auto const& edge : edges) { + if (edge.usesAssignmentLevels()) { + return true; + } + } + return false; + + } + + + + std::vector & EdgeContainer::getConcreteEdges() { + return edges; + } + + std::vector const& EdgeContainer::getConcreteEdges() const { + return edges; + } + + std::set EdgeContainer::getActionIndices() const { + std::set result; + for (auto const& edge : edges) { + result.insert(edge.getActionIndex()); + } + return result; + } + + /** + * Insert an edge, then sort the range between locstart and locend according to the action index. + * @param e + * @param locStart index where to start + * @param locEnd index where to end + */ + void EdgeContainer::insertEdge(Edge const &e, uint64_t locStart, uint64_t locEnd) { + assert(locStart <= locEnd); + // Find the right position for the edge and insert it properly. + auto posIt = edges.begin(); + std::advance(posIt, locEnd); + edges.insert(posIt, e); + + // Sort all edges form the source location of the newly introduced edge by their action indices. + auto it = edges.begin(); + std::advance(it, locStart); + auto ite = edges.begin(); + std::advance(ite, locEnd + 1); + std::sort(it, ite, [] (Edge const& a, Edge const& b) { return a.getActionIndex() < b.getActionIndex(); } ); + + } + + void EdgeContainer::insertTemplateEdge(std::shared_ptr const &te) { + templates.insert(te); + } + + void EdgeContainer::pushAssignmentsToDestinations() { + for (auto& templateEdge : templates) { + templateEdge->pushAssignmentsToDestinations(); + } + } + + void EdgeContainer::changeAssignmentVariables(std::map> const& remapping) { + for (auto& templateEdge : templates) { + templateEdge->changeAssignmentVariables(remapping); + } + } + + size_t EdgeContainer::size() const { + return edges.size(); + } + + EdgeContainer::iterator EdgeContainer::begin() { + return edges.begin(); + } + EdgeContainer::iterator EdgeContainer::end() { + return edges.end(); + } + EdgeContainer::const_iterator EdgeContainer::begin() const { + return edges.begin(); + } + EdgeContainer::const_iterator EdgeContainer::end() const { + return edges.end(); + } + + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h new file mode 100644 index 000000000..f4738e1e0 --- /dev/null +++ b/src/storm/storage/jani/EdgeContainer.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include +#include +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/jani/TemplateEdgeContainer.h" + +namespace storm { + namespace jani { + + class Edge; + class TemplateEdge; + class Variable; + class Model; + + namespace detail { + class Edges { + public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + Edges(iterator it, iterator ite); + + /*! + * Retrieves an iterator to the edges. + */ + iterator begin() const; + + /*! + * Retrieves an end iterator to the edges. + */ + iterator end() const; + + /*! + * Determines whether this set of edges is empty. + */ + bool empty() const; + + /*! + * Retrieves the number of edges. + */ + std::size_t size() const; + + private: + iterator it; + iterator ite; + }; + + + class ConstEdges { + public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + ConstEdges(const_iterator it, const_iterator ite); + + /*! + * Retrieves an iterator to the edges. + */ + const_iterator begin() const; + + /*! + * Retrieves an end iterator to the edges. + */ + const_iterator end() const; + + /*! + * Determines whether this set of edges is empty. + */ + bool empty() const; + + /*! + * Retrieves the number of edges. + */ + std::size_t size() const; + + private: + const_iterator it; + const_iterator ite; + }; + } + + + class EdgeContainer { + public: + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + + EdgeContainer() = default; + EdgeContainer(EdgeContainer const& other); + + void clearConcreteEdges(); + std::vector const& getConcreteEdges() const; + std::vector & getConcreteEdges(); + size_t size() const; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + std::set getActionIndices() const; + + void substitute(std::map const& substitution); + void liftTransientDestinationAssignments(); + void pushAssignmentsToDestinations(); + void insertEdge(Edge const& e, uint64_t locStart, uint64_t locEnd); + void insertTemplateEdge(std::shared_ptr const& te); + bool isLinear() const; + bool usesAssignmentLevels() const; + void finalize(Model const& containingModel); + + void changeAssignmentVariables(std::map> const& remapping); + + + private: + std::vector edges; + TemplateEdgeContainer templates; + }; + } +} + diff --git a/src/storm/storage/jani/EdgeDestination.cpp b/src/storm/storage/jani/EdgeDestination.cpp index 81efbfff5..62b92c1f0 100644 --- a/src/storm/storage/jani/EdgeDestination.cpp +++ b/src/storm/storage/jani/EdgeDestination.cpp @@ -58,5 +58,9 @@ namespace storm { TemplateEdgeDestination const& EdgeDestination::getTemplateEdgeDestination() const { return templateEdgeDestination.get(); } + + void EdgeDestination::updateTemplateEdgeDestination(TemplateEdgeDestination const& newTed) { + templateEdgeDestination = newTed; + } } } diff --git a/src/storm/storage/jani/EdgeDestination.h b/src/storm/storage/jani/EdgeDestination.h index 7cefe9c7a..62dd6114e 100644 --- a/src/storm/storage/jani/EdgeDestination.h +++ b/src/storm/storage/jani/EdgeDestination.h @@ -66,6 +66,8 @@ namespace storm { * Retrieves the template destination for this destination. */ TemplateEdgeDestination const& getTemplateEdgeDestination() const; + + void updateTemplateEdgeDestination(TemplateEdgeDestination const& newTed); private: // The index of the destination location. diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index da95f426f..47533126c 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -212,11 +212,14 @@ namespace storm { if (!SynchronizationVector::isNoActionInput(actionName)) { components.push_back(i); uint64_t actionIndex = oldModel.getActionIndex(actionName); + // store that automaton occurs in the sync vector. participatingAutomataAndActions.push_back(std::make_pair(composedAutomata[i], actionIndex)); + // Store for later that this action is one of the possible actions that synchronise synchronizingActionIndices[i].insert(actionIndex); } } - + + // What is the action label that should be attached to the composed actions uint64_t resultingActionIndex = Model::SILENT_ACTION_INDEX; if (vector.getOutput() != Model::SILENT_ACTION_NAME) { if (newModel.hasAction(vector.getOutput())) { diff --git a/src/storm/storage/jani/TemplateEdgeContainer.cpp b/src/storm/storage/jani/TemplateEdgeContainer.cpp new file mode 100644 index 000000000..81ce8f874 --- /dev/null +++ b/src/storm/storage/jani/TemplateEdgeContainer.cpp @@ -0,0 +1,12 @@ +#include "storm/storage/jani/TemplateEdgeContainer.h" +#include "storm/storage/jani/TemplateEdge.h" + +namespace storm { + namespace jani { + TemplateEdgeContainer::TemplateEdgeContainer(TemplateEdgeContainer const &other) { + for (auto const& te : other) { + this->insert(std::make_shared(*te)); + } + } + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/TemplateEdgeContainer.h b/src/storm/storage/jani/TemplateEdgeContainer.h new file mode 100644 index 000000000..293302594 --- /dev/null +++ b/src/storm/storage/jani/TemplateEdgeContainer.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace storm { + namespace jani { + + class TemplateEdge; + + struct TemplateEdgeContainer : public std::unordered_set> { + TemplateEdgeContainer() = default; + TemplateEdgeContainer(TemplateEdgeContainer const& other); + }; + } +} \ No newline at end of file From 1c9f7b0f2f2cb4c0ac680a6dd9dfc9183b2c2923 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 2 May 2018 23:42:00 +0200 Subject: [PATCH 275/647] translate prism to jani with a suffix for location names etc when doing this for multiple models --- src/storm/storage/prism/Program.cpp | 8 ++++---- src/storm/storage/prism/Program.h | 4 ++-- src/storm/storage/prism/ToJaniConverter.cpp | 8 ++++---- src/storm/storage/prism/ToJaniConverter.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index 41a9693bc..228df8541 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -1711,16 +1711,16 @@ namespace storm { return Command(newCommandIndex, false, actionIndex, actionName, newGuard, newUpdates, this->getFilename(), 0); } - storm::jani::Model Program::toJani(bool allVariablesGlobal) const { + storm::jani::Model Program::toJani(bool allVariablesGlobal, std::string suffix) const { ToJaniConverter converter; - storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal); + storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix); STORM_LOG_WARN_COND(!converter.labelsWereRenamed(), "Labels were renamed in PRISM-to-JANI conversion, but the mapping is not stored."); return resultingModel; } - std::pair> Program::toJaniWithLabelRenaming(bool allVariablesGlobal) const { + std::pair> Program::toJaniWithLabelRenaming(bool allVariablesGlobal, std::string suffix) const { ToJaniConverter converter; - storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal); + storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix); return std::make_pair(resultingModel, converter.getLabelRenaming()); } diff --git a/src/storm/storage/prism/Program.h b/src/storm/storage/prism/Program.h index 7dedc6667..4d6d303fc 100644 --- a/src/storm/storage/prism/Program.h +++ b/src/storm/storage/prism/Program.h @@ -603,13 +603,13 @@ namespace storm { /*! * Converts the PRISM model into an equivalent JANI model. */ - storm::jani::Model toJani(bool allVariablesGlobal = false) const; + storm::jani::Model toJani(bool allVariablesGlobal = false, std::string suffix = "") const; /*! * Converts the PRISM model into an equivalent JANI model and retrieves possible label renamings that had * to be performed in the process. */ - std::pair> toJaniWithLabelRenaming(bool allVariablesGlobal = false) const; + std::pair> toJaniWithLabelRenaming(bool allVariablesGlobal = false, std::string suffix = "") const; private: /*! diff --git a/src/storm/storage/prism/ToJaniConverter.cpp b/src/storm/storage/prism/ToJaniConverter.cpp index 7719b08e5..9712a52a7 100644 --- a/src/storm/storage/prism/ToJaniConverter.cpp +++ b/src/storm/storage/prism/ToJaniConverter.cpp @@ -13,7 +13,7 @@ namespace storm { namespace prism { - storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal) { + storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal, std::string suffix) { std::shared_ptr manager = program.getManager().getSharedPointer(); // Start by creating an empty JANI model. @@ -95,11 +95,11 @@ namespace storm { } } - // Go through the labels and construct assignments to transient variables that are added to the loctions. + // Go through the labels and construct assignments to transient variables that are added to the locations. std::vector transientLocationAssignments; for (auto const& label : program.getLabels()) { bool renameLabel = manager->hasVariable(label.getName()) || program.hasRewardModel(label.getName()); - std::string finalLabelName = renameLabel ? "label_" + label.getName() : label.getName(); + std::string finalLabelName = renameLabel ? "label_" + label.getName() + suffix : label.getName(); if (renameLabel) { STORM_LOG_WARN_COND(!renameLabel, "Label '" << label.getName() << "' was renamed to '" << finalLabelName << "' in PRISM-to-JANI conversion, as another variable with that name already exists."); labelRenaming[label.getName()] = finalLabelName; @@ -161,7 +161,7 @@ namespace storm { // Keep track of the action indices contained in this module. std::set actionIndicesOfModule; - storm::jani::Automaton automaton(module.getName(), manager->declareIntegerVariable("_loc_prism2jani_" + module.getName())); + storm::jani::Automaton automaton(module.getName(), manager->declareIntegerVariable("_loc_prism2jani_" + module.getName() + "_" + suffix)); for (auto const& variable : module.getIntegerVariables()) { storm::jani::BoundedIntegerVariable newIntegerVariable = *storm::jani::makeBoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.hasInitialValue() ? boost::make_optional(variable.getInitialValueExpression()) : boost::none, false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()); std::set const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()]; diff --git a/src/storm/storage/prism/ToJaniConverter.h b/src/storm/storage/prism/ToJaniConverter.h index 2ab5c0509..e68c9612e 100644 --- a/src/storm/storage/prism/ToJaniConverter.h +++ b/src/storm/storage/prism/ToJaniConverter.h @@ -14,7 +14,7 @@ namespace storm { class ToJaniConverter { public: - storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false); + storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false, std::string suffix = ""); bool labelsWereRenamed() const; std::map const& getLabelRenaming() const; From 61f31fb91974d4bf474276fd2a4ff90989f0e3f9 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 3 May 2018 00:00:10 +0200 Subject: [PATCH 276/647] improved handling of capacities by switching to boost::optional --- src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp | 2 +- src/storm-gspn/parser/PnmlParser.cpp | 5 ++--- src/storm-gspn/storage/gspn/GspnBuilder.cpp | 2 +- src/storm-gspn/storage/gspn/GspnBuilder.h | 2 +- src/storm-gspn/storage/gspn/Place.cpp | 2 +- src/storm-gspn/storage/gspn/Place.h | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index 2ab73ac91..ae17ca59b 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -212,7 +212,7 @@ namespace storm { STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } - builder.addPlace(-1, initialTokens, placeName); + builder.addPlace(boost::none, initialTokens, placeName); } bool ignoreTransitionAttribute(std::string const& name) { diff --git a/src/storm-gspn/parser/PnmlParser.cpp b/src/storm-gspn/parser/PnmlParser.cpp index 71757defc..189e34266 100644 --- a/src/storm-gspn/parser/PnmlParser.cpp +++ b/src/storm-gspn/parser/PnmlParser.cpp @@ -104,7 +104,7 @@ namespace storm { std::string placeName; // the first entry is false if the corresponding information was not found in the pnml file std::pair numberOfInitialTokens(false, defaultNumberOfInitialTokens); - std::pair capacity(false, defaultCapacity); + std::pair> capacity(false, boost::none); // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -150,10 +150,9 @@ namespace storm { } if (!capacity.first) { // no information about the capacity is found - // use default capacity STORM_PRINT_AND_LOG("unknown capacity (place=" + placeName + ")\n"); } - builder.addPlace(capacity.first ? capacity.second : -1, numberOfInitialTokens.first ? numberOfInitialTokens.second : 0, placeName); + builder.addPlace(capacity.second, numberOfInitialTokens.first ? numberOfInitialTokens.second : 0, placeName); } void PnmlParser::traverseTransition(xercesc::DOMNode const* const node) { diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.cpp b/src/storm-gspn/storage/gspn/GspnBuilder.cpp index 5303a89c6..e273768ea 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.cpp +++ b/src/storm-gspn/storage/gspn/GspnBuilder.cpp @@ -13,7 +13,7 @@ namespace storm { gspnName = name; } - uint_fast64_t GspnBuilder::addPlace(int_fast64_t const& capacity, uint_fast64_t const& initialTokens, std::string const& name) { + uint_fast64_t GspnBuilder::addPlace(boost::optional capacity, uint_fast64_t const& initialTokens, std::string const& name) { auto newId = places.size(); auto place = storm::gspn::Place(newId); place.setCapacity(capacity); diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.h b/src/storm-gspn/storage/gspn/GspnBuilder.h index 79fb2e712..a9a99699f 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.h +++ b/src/storm-gspn/storage/gspn/GspnBuilder.h @@ -25,7 +25,7 @@ namespace storm { * A capacity of -1 indicates an unbounded place. * @param initialTokens The number of inital tokens in the place. */ - uint_fast64_t addPlace(int_fast64_t const& capacity = 1, uint_fast64_t const& initialTokens = 0, std::string const& name = ""); + uint_fast64_t addPlace(boost::optional capacity = 1, uint_fast64_t const& initialTokens = 0, std::string const& name = ""); void setPlaceLayoutInfo(uint64_t placeId, LayoutInfo const& layoutInfo); diff --git a/src/storm-gspn/storage/gspn/Place.cpp b/src/storm-gspn/storage/gspn/Place.cpp index a78b7c585..d60ace5f6 100644 --- a/src/storm-gspn/storage/gspn/Place.cpp +++ b/src/storm-gspn/storage/gspn/Place.cpp @@ -29,7 +29,7 @@ namespace storm { return this->numberOfInitialTokens; } - void Place::setCapacity(uint64_t cap) { + void Place::setCapacity(boost::optional cap) { this->capacity = cap; } diff --git a/src/storm-gspn/storage/gspn/Place.h b/src/storm-gspn/storage/gspn/Place.h index e995f6a93..55c9da6fb 100644 --- a/src/storm-gspn/storage/gspn/Place.h +++ b/src/storm-gspn/storage/gspn/Place.h @@ -54,9 +54,9 @@ namespace storm { * Sets the capacity of tokens of this place. * * @param capacity The capacity of this place. A non-negative number represents the capacity. - * The value -1 indicates that the capacity is not set. + * boost::none indicates that the flag is not set. */ - void setCapacity(uint64_t capacity); + void setCapacity(boost::optional capacity); /*! * Returns the capacity of tokens of this place. From d77f4e7564821dad857a893f66488895cfb013ec Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 3 May 2018 00:00:45 +0200 Subject: [PATCH 277/647] gspn pnml export for capacities --- src/storm-gspn/storage/gspn/GSPN.cpp | 5 +++++ src/storm-gspn/storage/gspn/Place.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/storm-gspn/storage/gspn/GSPN.cpp b/src/storm-gspn/storage/gspn/GSPN.cpp index f26c71540..37ac640b0 100644 --- a/src/storm-gspn/storage/gspn/GSPN.cpp +++ b/src/storm-gspn/storage/gspn/GSPN.cpp @@ -533,6 +533,11 @@ namespace storm { stream << space3 << "" << std::endl; stream << space4 << "Default," << place.getNumberOfInitialTokens() << "" << std::endl; stream << space3 << "" << std::endl; + if(place.hasRestrictedCapacity()) { + stream << space3 << "" << std::endl; + stream << space4 << "Default," << place.getCapacity() << "" << std::endl; + stream << space3 << "" << std::endl; + } stream << space2 << "" << std::endl; } diff --git a/src/storm-gspn/storage/gspn/Place.cpp b/src/storm-gspn/storage/gspn/Place.cpp index d60ace5f6..ca9a4a9e1 100644 --- a/src/storm-gspn/storage/gspn/Place.cpp +++ b/src/storm-gspn/storage/gspn/Place.cpp @@ -34,6 +34,7 @@ namespace storm { } uint64_t Place::getCapacity() const { + assert(hasRestrictedCapacity()); return capacity.get(); } From 61925d1c98b022fd7d07e54bf4d717ae0462b7ea Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 6 May 2018 22:17:00 +0200 Subject: [PATCH 278/647] add option for sparse model builder to add a state encoding out-of-bounds state valuations to enable analysis of buggy models --- src/storm-cli-utilities/model-handling.h | 1 + src/storm/builder/BuilderOptions.cpp | 13 +++++++++++-- src/storm/builder/BuilderOptions.h | 18 +++++++++++++++--- src/storm/generator/JaniNextStateGenerator.cpp | 9 +++++++-- src/storm/generator/NextStateGenerator.cpp | 7 +++++++ src/storm/generator/NextStateGenerator.h | 3 +++ .../generator/PrismNextStateGenerator.cpp | 8 ++++++-- src/storm/generator/VariableInformation.cpp | 17 +++++++++++++++-- src/storm/generator/VariableInformation.h | 8 ++++++-- src/storm/settings/modules/BuildSettings.cpp | 6 ++++++ src/storm/settings/modules/BuildSettings.h | 6 ++++++ 11 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 35390c7cb..d03cfe630 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -190,6 +190,7 @@ namespace storm { options.setBuildChoiceOrigins(counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet()); options.setBuildAllLabels(buildSettings.isBuildFullModelSet()); options.setBuildAllRewardModels(buildSettings.isBuildFullModelSet()); + options.setAddOutOfBoundsState(buildSettings.isBuildOutOfBoundsStateSet()); if (buildSettings.isBuildFullModelSet()) { options.clearTerminalStates(); } diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index 00718e3f1..33152ca36 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -36,7 +36,7 @@ namespace storm { return boost::get(labelOrExpression); } - BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), showProgress(false), showProgressDelay(0) { + BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) { // Intentionally left empty. } @@ -159,7 +159,11 @@ namespace storm { bool BuilderOptions::isBuildAllLabelsSet() const { return buildAllLabels; } - + + bool BuilderOptions::isAddOutOfBoundsStateSet() const { + return addOutOfBoundsState; + } + BuilderOptions& BuilderOptions::setBuildAllRewardModels(bool newValue) { buildAllRewardModels = newValue; return *this; @@ -229,5 +233,10 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::setAddOutOfBoundsState(bool newValue) { + addOutOfBoundsState = newValue; + return *this; + } + } } diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index fe56994c7..c6106172b 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -107,6 +107,7 @@ namespace storm { bool isBuildAllLabelsSet() const; bool isExplorationChecksSet() const; bool isShowProgressSet() const; + bool isAddOutOfBoundsStateSet() const; uint64_t getShowProgressDelay() const; /** @@ -155,7 +156,15 @@ namespace storm { * @return this */ BuilderOptions& setExplorationChecks(bool newValue = true); - + + /** + * Should a state for out of bounds be constructed + * @param newValue The new value (default true) + * @return this + */ + BuilderOptions& setAddOutOfBoundsState(bool newValue = true); + + private: /// A flag that indicates whether all reward models are to be built. In this case, the reward model names are /// to be ignored. @@ -188,10 +197,13 @@ namespace storm { /// A flag that stores whether exploration checks are to be performed. bool explorationChecks; - + + /// A flag indicating that the an additional state for out of bounds should be created. + bool addOutOfBoundsState; + /// A flag that stores whether the progress of exploration is to be printed. bool showProgress; - + /// The delay for printing progress information. uint64_t showProgressDelay; }; diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 3217180f6..a1a683b5b 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -52,7 +52,7 @@ namespace storm { // Now we are ready to initialize the variable information. this->checkValid(); - this->variableInformation = VariableInformation(model, this->parallelAutomata); + this->variableInformation = VariableInformation(model, this->parallelAutomata, options.isAddOutOfBoundsStateSet()); // Create a proper evalator. this->evaluator = std::make_unique>(model.getManager()); @@ -256,10 +256,15 @@ namespace storm { ++integerIt; } int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getAssignedExpression()); - if (this->options.isExplorationChecksSet()) { + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) { + return this->outOfBoundsState; + } + } else if (this->options.isExplorationChecksSet()) { STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); } + newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); STORM_LOG_ASSERT(static_cast(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); } diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index 2be706715..bea64b0bf 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -1,3 +1,4 @@ +#include #include "storm/generator/NextStateGenerator.h" #include "storm/adapters/RationalFunctionAdapter.h" @@ -99,6 +100,12 @@ namespace storm { result.addLabelToState("deadlock", index); } } + + if (stateStorage.stateToId.contains(outOfBoundsState)) { + STORM_LOG_THROW(!result.containsLabel("out_of_bounds"),storm::exceptions::WrongFormatException, "Label 'out_of_bounds' is reserved when adding out of bounds states."); + result.addLabel("out_of_bounds"); + result.addLabelToState("out_of_bounds", stateStorage.stateToId.getValue(outOfBoundsState)); + } return result; } diff --git a/src/storm/generator/NextStateGenerator.h b/src/storm/generator/NextStateGenerator.h index 54f7f1024..ce1dd1f7b 100644 --- a/src/storm/generator/NextStateGenerator.h +++ b/src/storm/generator/NextStateGenerator.h @@ -95,6 +95,9 @@ namespace storm { /// A comparator used to compare constants. storm::utility::ConstantsComparator comparator; + + /// A state that encodes the outOfBoundsState + CompressedState outOfBoundsState; }; } } diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index e5f4dc4e1..1de65ce30 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -33,7 +33,7 @@ namespace storm { // Only after checking validity of the program, we initialize the variable information. this->checkValid(); - this->variableInformation = VariableInformation(program); + this->variableInformation = VariableInformation(program, options.isAddOutOfBoundsStateSet()); // Create a proper evalator. this->evaluator = std::make_unique>(program.getManager()); @@ -318,7 +318,11 @@ namespace storm { ++integerIt; } int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getExpression()); - if (this->options.isExplorationChecksSet()) { + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) { + return this->outOfBoundsState; + } + } else if (this->options.isExplorationChecksSet()) { STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); } diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 26bd2ecf8..5da944839 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -13,6 +13,7 @@ #include "storm/exceptions/WrongFormatException.h" #include +#include namespace storm { namespace generator { @@ -29,7 +30,13 @@ namespace storm { // Intentionally left empty. } - VariableInformation::VariableInformation(storm::prism::Program const& program) : totalBitOffset(0) { + VariableInformation::VariableInformation(storm::prism::Program const& program, bool outOfBoundsState) : totalBitOffset(0) { + if(outOfBoundsState) { + deadlockBit = 0; + ++totalBitOffset; + } else { + deadlockBit = boost::none; + } for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, true); ++totalBitOffset; @@ -58,7 +65,7 @@ namespace storm { sortVariables(); } - VariableInformation::VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata) : totalBitOffset(0) { + VariableInformation::VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata, bool outOfBoundsState) : totalBitOffset(0) { // Check that the model does not contain non-transient unbounded integer or non-transient real variables. STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains global non-transient real variables."); STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient unbounded integer variables."); @@ -66,6 +73,12 @@ namespace storm { STORM_LOG_THROW(!automaton.getVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient unbounded integer variables in automaton '" << automaton.getName() << "'."); STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'."); } + if(outOfBoundsState) { + deadlockBit = 0; + ++totalBitOffset; + } else { + deadlockBit = boost::none; + } for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) { if (!variable.isTransient()) { diff --git a/src/storm/generator/VariableInformation.h b/src/storm/generator/VariableInformation.h index 764881e80..2e51f7db7 100644 --- a/src/storm/generator/VariableInformation.h +++ b/src/storm/generator/VariableInformation.h @@ -3,6 +3,7 @@ #include #include +#include #include "storm/storage/expressions/Variable.h" @@ -74,8 +75,8 @@ namespace storm { // A structure storing information about the used variables of the program. struct VariableInformation { - VariableInformation(storm::prism::Program const& program); - VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata); + VariableInformation(storm::prism::Program const& program, bool outOfBoundsState = false); + VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata, bool outOfBoundsState = false); VariableInformation() = default; uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const; @@ -91,8 +92,11 @@ namespace storm { /// The integer variables. std::vector integerVariables; + private: + boost::optional deadlockBit; + /*! * Sorts the variables to establish a known ordering. */ diff --git a/src/storm/settings/modules/BuildSettings.cpp b/src/storm/settings/modules/BuildSettings.cpp index a813b08fa..536dd26ea 100644 --- a/src/storm/settings/modules/BuildSettings.cpp +++ b/src/storm/settings/modules/BuildSettings.cpp @@ -29,6 +29,7 @@ namespace storm { const std::string fullModelBuildOptionName = "buildfull"; const std::string buildChoiceLabelOptionName = "buildchoicelab"; const std::string buildStateValuationsOptionName = "buildstateval"; + const std::string buildOutOfBoundsStateOptionName = "buildoutofboundsstate"; BuildSettings::BuildSettings() : ModuleSettings(moduleName) { std::vector explorationOrders = {"dfs", "bfs"}; @@ -42,6 +43,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(explorationOrders)).setDefaultValueString("bfs").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, explorationChecksOptionName, false, "If set, additional checks (if available) are performed during model exploration to debug the model.").setShortName(explorationChecksOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, buildOutOfBoundsStateOptionName, false, "If set, a state for out-of-bounds valuations is added").build()); } @@ -74,6 +76,10 @@ namespace storm { return this->getOption(buildStateValuationsOptionName).getHasOptionBeenSet(); } + bool BuildSettings::isBuildOutOfBoundsStateSet() const { + return this->getOption(buildOutOfBoundsStateOptionName).getHasOptionBeenSet(); + } + storm::builder::ExplorationOrder BuildSettings::getExplorationOrder() const { std::string explorationOrderAsString = this->getOption(explorationOrderOptionName).getArgumentByName("name").getValueAsString(); diff --git a/src/storm/settings/modules/BuildSettings.h b/src/storm/settings/modules/BuildSettings.h index 4ef0f5193..e9ec41dc1 100644 --- a/src/storm/settings/modules/BuildSettings.h +++ b/src/storm/settings/modules/BuildSettings.h @@ -75,6 +75,12 @@ namespace storm { */ bool isBuildStateValuationsSet() const; + /*! + * Retrieves whether out of bounds state should be added + * @return + */ + bool isBuildOutOfBoundsStateSet() const; + // The name of the module. static const std::string moduleName; From 89f3aac33fba08401e86eac4d4a8bb9e9b805471 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 6 May 2018 22:18:15 +0200 Subject: [PATCH 279/647] add error messages for sparse model building when lower bounds for variables are above upper bounds --- src/storm/generator/VariableInformation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 5da944839..7f7ce0708 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -13,7 +13,6 @@ #include "storm/exceptions/WrongFormatException.h" #include -#include namespace storm { namespace generator { @@ -44,6 +43,7 @@ namespace storm { for (auto const& integerVariable : program.getGlobalIntegerVariables()) { int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException, "Lower bound must not be above upper bound"); uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true); totalBitOffset += bitwidth; @@ -56,6 +56,7 @@ namespace storm { for (auto const& integerVariable : module.getIntegerVariables()) { int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException, "Lower bound must not be above upper bound"); uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth); totalBitOffset += bitwidth; From 7a2a46cae951ffb7fc0876b77aa2d78af82b3575 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 6 May 2018 22:18:51 +0200 Subject: [PATCH 280/647] fix warning about non-const comparison operator in set --- src/storm/storage/jani/ParallelComposition.cpp | 2 +- src/storm/storage/jani/ParallelComposition.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/jani/ParallelComposition.cpp b/src/storm/storage/jani/ParallelComposition.cpp index d81db1d91..0d439e0ce 100644 --- a/src/storm/storage/jani/ParallelComposition.cpp +++ b/src/storm/storage/jani/ParallelComposition.cpp @@ -116,7 +116,7 @@ namespace storm { return !(vector1 == vector2); } - bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) { + bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const { STORM_LOG_THROW(vector1.size() == vector2.size(), storm::exceptions::WrongFormatException, "Cannot compare synchronization vectors of different size."); for (uint64_t i = 0; i < vector1.size(); ++i) { if (vector1.getInput(i) < vector2.getInput(i)) { diff --git a/src/storm/storage/jani/ParallelComposition.h b/src/storm/storage/jani/ParallelComposition.h index c3d41717c..381ace5f8 100644 --- a/src/storm/storage/jani/ParallelComposition.h +++ b/src/storm/storage/jani/ParallelComposition.h @@ -62,7 +62,7 @@ namespace storm { bool operator!=(SynchronizationVector const& vector1, SynchronizationVector const& vector2); struct SynchronizationVectorLexicographicalLess { - bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2); + bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const; }; std::ostream& operator<<(std::ostream& stream, SynchronizationVector const& synchronizationVector); From 5b6383b5efab3bf080d405e8cb59d56a194eb29f Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 6 May 2018 22:28:30 +0200 Subject: [PATCH 281/647] fix gspn export to pnml --- src/storm-gspn/storage/gspn/GSPN.cpp | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/storm-gspn/storage/gspn/GSPN.cpp b/src/storm-gspn/storage/gspn/GSPN.cpp index 37ac640b0..c622cc4fe 100644 --- a/src/storm-gspn/storage/gspn/GSPN.cpp +++ b/src/storm-gspn/storage/gspn/GSPN.cpp @@ -620,6 +620,60 @@ namespace storm { } } + // add arcs for immediate transitions + for (const auto &trans : timedTransitions) { + // add input arcs + for (auto const& inEntry : trans.getInputPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << inEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + + // add inhibition arcs + for (auto const& inhEntry : trans.getInhibitionPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << inhEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + + // add output arcs + for (auto const& outEntry : trans.getOutputPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << outEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + } + stream << space << "" << std::endl; stream << "" << std::endl; } From e6090d2d2cc4f9d4e993c7bfe2927dc8169079bb Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 8 May 2018 08:57:22 +0200 Subject: [PATCH 282/647] Removed unused code --- src/storm-gspn-cli/storm-gspn.cpp | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 021634fc1..602b353a0 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -125,25 +125,6 @@ int main(const int argc, const char **argv) { // auto builder = storm::builder::ExplicitGspnModelBuilder<>(); // auto ma = builder.translateGspn(gspn, formula); // -// // write gspn into output file -// if (!outputFile.empty()) { -// std::ofstream file; -// file.open(outputFile); -// if (outputType == "pnml") { -// gspn.toPnml(file); -// } -// if (outputType == "pnpro") { -// gspn.toPnpro(file); -// } -// if (outputType == "dot") { -// gspn.writeDotToStream(file); -// } -// if (outputType == "ma") { -// ma.writeDotToStream(file); -// } -// file.close(); -// } - // All operations have now been performed, so we clean up everything and terminate. storm::utility::cleanUp(); return 0; From 0726dfc7a0dcf2de8a5fd3c3daf757387aba3cfb Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Fri, 11 May 2018 11:20:22 +0200 Subject: [PATCH 283/647] bugfix only add label out of bounds is option is set and state is present --- src/storm/generator/NextStateGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index bea64b0bf..e02d2ee13 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -101,7 +101,7 @@ namespace storm { } } - if (stateStorage.stateToId.contains(outOfBoundsState)) { + if (this->options.isAddOutOfBoundsStateSet() && stateStorage.stateToId.contains(outOfBoundsState)) { STORM_LOG_THROW(!result.containsLabel("out_of_bounds"),storm::exceptions::WrongFormatException, "Label 'out_of_bounds' is reserved when adding out of bounds states."); result.addLabel("out_of_bounds"); result.addLabelToState("out_of_bounds", stateStorage.stateToId.getValue(outOfBoundsState)); From c517ec14b1f5380b8fd067e74c4688f8e84c85e4 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Fri, 11 May 2018 11:20:58 +0200 Subject: [PATCH 284/647] support for liveness cex in jani --- .../SMTMinimalLabelSetGenerator.h | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index dfd9942b8..1ede56684 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1887,11 +1887,17 @@ namespace storm { } if (onlyProb0ESuccessors) { - auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(choice); - hasLabeledChoice |= !labelSet.empty(); + uint64_t labelSetSize = 0; + if (model.getChoiceOrigins()->isPrismChoiceOrigins()) { + labelSetSize = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(choice).size(); + } else { + assert(model.getChoiceOrigins()->isJaniChoiceOrigins()); + labelSetSize = model.getChoiceOrigins()->asJaniChoiceOrigins().getEdgeIndexSet(choice).size(); + } + hasLabeledChoice |= (labelSetSize != 0); - if (smallestCommandChoice == 0 || labelSet.size() < smallestCommandSetSize) { - smallestCommandSetSize = labelSet.size(); + if (smallestCommandChoice == 0 || labelSetSize < smallestCommandSetSize) { + smallestCommandSetSize = labelSetSize; smallestCommandChoice = choice; } } @@ -1899,9 +1905,15 @@ namespace storm { if (hasLabeledChoice) { // Take all labels of the selected choice. - auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(smallestCommandChoice); - commandSet.insert(labelSet.begin(), labelSet.end()); - + if (model.getChoiceOrigins()->isPrismChoiceOrigins()) { + auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(smallestCommandChoice); + commandSet.insert(labelSet.begin(), labelSet.end()); + } else { + assert(model.getChoiceOrigins()->isJaniChoiceOrigins()); + auto const& labelSet = model.getChoiceOrigins()->asJaniChoiceOrigins().getEdgeIndexSet(smallestCommandChoice); + commandSet.insert(labelSet.begin(), labelSet.end()); + } + // Check for which successor states choices need to be added for (auto const& successorEntry : model.getTransitionMatrix().getRow(smallestCommandChoice)) { if (!storm::utility::isZero(successorEntry.getValue())) { From e7926b10c2a4ea2c6d3918a91e248f184826cc11 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Fri, 11 May 2018 11:21:45 +0200 Subject: [PATCH 285/647] allow counterexamples for true jani models --- src/storm/settings/modules/CounterexampleGeneratorSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp b/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp index 2525f19b0..0eaf656bb 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp @@ -53,7 +53,7 @@ namespace storm { bool CounterexampleGeneratorSettings::check() const { // Ensure that the model was given either symbolically or explicitly. - STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule().isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM format."); + STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule().isPrismInputSet() || storm::settings::getModule().isJaniInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM/JANI format."); if (isMinimalCommandSetGenerationSet()) { STORM_LOG_WARN_COND(isUseMaxSatBasedMinimalCommandSetGenerationSet() || !isEncodeReachabilitySet(), "Encoding reachability is only available for the MaxSat-based minimal command set generation, so selecting it has no effect."); From d66047e3b76ac457604231575437301535bd1835 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 14 May 2018 07:59:21 +0200 Subject: [PATCH 286/647] few fixes to jani game-based abstraction --- src/storm/abstraction/jani/EdgeAbstractor.cpp | 14 ++++++++++++-- .../abstraction/jani/JaniMenuGameAbstractor.cpp | 2 +- src/storm/adapters/MathsatExpressionAdapter.h | 4 +++- src/storm/storage/jani/Automaton.cpp | 4 ++-- src/storm/storage/jani/Model.cpp | 6 +++++- src/storm/storage/prism/Program.cpp | 6 +++++- 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index a1fbe6fe9..ebd7b5839 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -639,7 +639,13 @@ namespace storm { template BottomStateResult EdgeAbstractor::getBottomStateTransitions(storm::dd::Bdd const& reachableStates, uint_fast64_t numberOfPlayer2Variables, boost::optional> const& locationVariables) { // Compute the reachable states that have this edge enabled. - storm::dd::Bdd reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); + storm::dd::Bdd reachableStatesWithEdge; + if (locationVariables) { + reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); + } else { + reachableStatesWithEdge = (reachableStates && abstractGuard).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); + } + STORM_LOG_TRACE("Computing bottom state transitions of edge with guard " << edge.get().getGuard()); BottomStateResult result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero()); @@ -653,7 +659,11 @@ namespace storm { // Use the state abstractor to compute the set of abstract states that has this edge enabled but still // has a transition to a bottom state. bottomStateAbstractor.constrain(reachableStatesWithEdge); - result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex()); + if (locationVariables) { + result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex()); + } else { + result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge; + } // If the result is empty one time, we can skip the bottom state computation from now on. if (result.states.isZero()) { diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index b41ccf418..4b30c61bd 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -38,7 +38,7 @@ namespace storm { JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager())), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { // Check whether the model is linear as the abstraction requires this. - STORM_LOG_THROW(model.isLinear(), storm::exceptions::WrongFormatException, "Cannot create abstract model from non-linear model."); + STORM_LOG_WARN_COND(model.isLinear(), "The model appears to contain non-linear expressions, which may cause malfunctioning of the abstraction."); // For now, we assume that there is a single module. If the program has more than one module, it needs // to be flattened before the procedure. diff --git a/src/storm/adapters/MathsatExpressionAdapter.h b/src/storm/adapters/MathsatExpressionAdapter.h index 4b4d7cb57..0b111a10f 100644 --- a/src/storm/adapters/MathsatExpressionAdapter.h +++ b/src/storm/adapters/MathsatExpressionAdapter.h @@ -273,7 +273,9 @@ namespace storm { } else if (msat_is_rational_type(env, msat_term_get_type(term))) { return manager.rational(storm::utility::convertNumber(termString)); } - } + } else if (msat_term_is_term_ite(env, term)) { + return storm::expressions::ite(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)), translateExpression(msat_term_get_arg(term, 2))); + } // If all other cases did not apply, we cannot represent the term in our expression framework. char* termAsCString = msat_term_repr(term); diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index f4c65c759..7d856e56c 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -452,9 +452,9 @@ namespace storm { result &= location.isLinear(); } if (result) { - return edges.isLinear(); + result &= edges.isLinear(); } - return false; + return result; } void Automaton::restrictToEdges(boost::container::flat_set const& edgeIndices) { diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 47533126c..a6491a884 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -462,7 +462,11 @@ namespace storm { // Assert the values of the constants. for (auto const& constant : this->getConstants()) { if (constant.isDefined()) { - solver->add(constant.getExpressionVariable() == constant.getExpression()); + if (constant.isBooleanConstant()) { + solver->add(storm::expressions::iff(constant.getExpressionVariable(), constant.getExpression())); + } else { + solver->add(constant.getExpressionVariable() == constant.getExpression()); + } } } // Assert the bounds of the global variables. diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index 228df8541..cda98bc09 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -1381,7 +1381,11 @@ namespace storm { // Assert the values of the constants. for (auto const& constant : this->getConstants()) { if (constant.isDefined()) { - solver->add(constant.getExpressionVariable() == constant.getExpression()); + if (constant.getType().isBooleanType()) { + solver->add(storm::expressions::iff(constant.getExpressionVariable(),constant.getExpression())); + } else { + solver->add(constant.getExpressionVariable() == constant.getExpression()); + } } } From 4ec2bc0583fe32a66fe0d2e9ded208e4c863c241 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 14 May 2018 16:42:27 +0200 Subject: [PATCH 287/647] fixed bug in jani model generation --- src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp | 11 +++++------ .../abstraction/prism/PrismMenuGameAbstractor.cpp | 9 +++------ src/storm/generator/JaniNextStateGenerator.cpp | 5 ++++- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 4b30c61bd..35c61caeb 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -184,21 +184,20 @@ namespace storm { initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + // Cut transition relation to the reachable states for backward search. + transitionRelation &= reachableStates; + relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { - // Cut transition relation to the reachable states for backward search. - transitionRelation &= reachableStates; - // Get the target state BDD. storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); // In the presence of target states, we keep only states that can reach the target states. reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - // Cut the transition relation to the 'extended backward reachable states', so we have the appropriate self- - // loops of (now) deadlock states. + // Cut the transition relation source blocks to the backward reachable states. transitionRelation &= reachableStates; - + // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 7908a5a5e..3490c5a45 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -182,23 +182,20 @@ namespace storm { relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { - // Get the target state BDD. storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); // In the presence of target states, we keep only states that can reach the target states. reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + // Cut the transition relation source blocks to the backward reachable states. + transitionRelation &= reachableStates; + // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. reachableStates = reachableStates || reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - // Cut the transition relation to the 'extended backward reachable states', so we have the appropriate self- - // loops of (now) deadlock states. - transitionRelation &= reachableStates; - relevantStatesWatch.stop(); - STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); } diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index a1a683b5b..256e3933e 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -432,6 +432,9 @@ namespace storm { // As long as there is one feasible combination of commands, keep on expanding it. bool done = false; while (!done) { + currentDistribution.clear(); + nextDistribution.clear(); + std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); currentDistribution.add(state, storm::utility::one()); @@ -504,7 +507,7 @@ namespace storm { if (this->options.isExplorationChecksSet()) { // Check that the resulting distribution is in fact a distribution. - STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some command (actually sum to " << probabilitySum << ")."); + STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some edge (actually sum to " << probabilitySum << ")."); } // Now, check whether there is one more command combination to consider. From ceea5198d63c3af8fc7bf2f461339904423d83bc Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 15 May 2018 15:07:02 +0200 Subject: [PATCH 288/647] fixed detection of unreachability of target state in MaxSAT-based high-level counterexample generation --- src/storm/counterexamples/SMTMinimalLabelSetGenerator.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 1ede56684..f66205fbf 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1785,7 +1785,10 @@ namespace storm { } if (options.useDynamicConstraints) { - if (maximalReachabilityProbability == storm::utility::zero()) { + // Determine which of the two analysis techniques to call by performing a reachability analysis. + storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(subModel->getTransitionMatrix(), subModel->getInitialStates(), phiStates, psiStates); + + if (reachableStates.isDisjointFrom(psiStates)) { // If there was no target state reachable, analyze the solution and guide the solver into the right direction. analyzeZeroProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); } else { From fa0da0bc7fd000848ac59fe014c51be34e3e825d Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 15 May 2018 22:16:51 +0200 Subject: [PATCH 289/647] fixes to parser --- .../abstraction/GameBasedMdpModelChecker.cpp | 4 ++-- src/storm/parser/ExpressionParser.cpp | 22 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index a1900236c..7657c0ceb 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -522,13 +522,13 @@ namespace storm { STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException, "The game-based abstraction refinement model checker can only compute the result for the initial states."); // Optimization: do not compute both bounds if not necessary (e.g. if bound given and exceeded, etc.) - + // Set up initial predicates. std::vector initialPredicates = getInitialPredicates(constraintExpression, targetStateExpression); // Derive the optimization direction for player 1 (assuming menu-game abstraction). storm::OptimizationDirection player1Direction = getPlayer1Direction(checkTask); - + // Create the abstractor. std::shared_ptr> abstractor; if (preprocessedModel.isPrismProgram()) { diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm/parser/ExpressionParser.cpp index 64e185b54..5d824d82d 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm/parser/ExpressionParser.cpp @@ -95,7 +95,11 @@ namespace storm { } multiplicationExpression.name("multiplication expression"); - plusExpression = multiplicationExpression[qi::_val = qi::_1] > *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + plusExpression = multiplicationExpression[qi::_val = qi::_1] >> *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + plusExpression = multiplicationExpression[qi::_val = qi::_1] > *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } plusExpression.name("plus expression"); if (allowBacktracking) { @@ -105,7 +109,11 @@ namespace storm { } relativeExpression.name("relative expression"); - equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } equalityExpression.name("equality expression"); if (allowBacktracking) { @@ -122,7 +130,11 @@ namespace storm { } orExpression.name("or expression"); - iteExpression = orExpression[qi::_val = qi::_1] > -(qi::lit("?") > iteExpression > qi::lit(":") > iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + iteExpression = orExpression[qi::_val = qi::_1] >> -(qi::lit("?") >> iteExpression >> qi::lit(":") >> iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + iteExpression = orExpression[qi::_val = qi::_1] > -(qi::lit("?") > iteExpression > qi::lit(":") > iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } iteExpression.name("if-then-else expression"); expression %= iteExpression; @@ -138,12 +150,12 @@ namespace storm { debug(relativeExpression); debug(plusExpression); debug(multiplicationExpression); - debug(infixPowerExpression); + debug(infixPowerModuloExpression); debug(unaryExpression); debug(atomicExpression); debug(literalExpression); debug(identifierExpression); - */ + */ if (enableErrorHandling) { // Enable error reporting. From 87843e084eb0b220acebd4fb9766ad2c7467a616 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 16 May 2018 15:53:35 +0200 Subject: [PATCH 290/647] several fixes related to game-based abstraction --- src/storm/abstraction/MenuGameRefiner.cpp | 17 +++++--- src/storm/abstraction/StateSetAbstractor.cpp | 2 +- .../abstraction/ValidBlockAbstractor.cpp | 10 +++-- src/storm/abstraction/ValidBlockAbstractor.h | 2 + .../jani/JaniMenuGameAbstractor.cpp | 4 ++ .../abstraction/prism/ModuleAbstractor.cpp | 5 ++- .../prism/PrismMenuGameAbstractor.cpp | 4 ++ src/storm/adapters/MathsatExpressionAdapter.h | 42 ++++++++++++++++++- .../abstraction/GameBasedMdpModelChecker.cpp | 7 ++-- src/storm/solver/MathsatSmtSolver.cpp | 8 +++- .../expressions/EquivalenceChecker.cpp | 1 + src/storm/storage/jani/Automaton.cpp | 21 ++++++++++ src/storm/storage/jani/Automaton.h | 6 +++ src/storm/storage/jani/Model.cpp | 15 +++++++ src/storm/storage/jani/Model.h | 6 +++ src/storm/storage/prism/InitialConstruct.cpp | 4 +- src/storm/storage/prism/Program.cpp | 1 + src/storm/utility/constants.h | 2 + 18 files changed, 139 insertions(+), 18 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index a821dc8e5..b75a6380a 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1362,18 +1362,21 @@ namespace storm { } // Now clean the classes in the sense that redundant predicates are cleaned. + uint64_t checkCounter = 0; for (auto& predicateClass : predicateClasses) { std::vector cleanedAtomsOfClass; for (auto const& predicate : predicateClass.second) { bool addPredicate = true; for (auto const& atom : cleanedAtomsOfClass) { + ++checkCounter; if (predicate.areSame(atom)) { addPredicate = false; break; } - if (addPredicate && equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) { + ++checkCounter; + if (equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) { addPredicate = false; break; } @@ -1397,19 +1400,21 @@ namespace storm { auto oldPredicateClassIt = oldPredicateClasses.find(predicateClass.first); if (oldPredicateClassIt != oldPredicateClasses.end()) { for (auto const& newAtom : predicateClass.second) { + bool addAtom = true; for (auto const& oldPredicate : oldPredicateClassIt->second) { - bool addAtom = true; + ++checkCounter; if (newAtom.areSame(oldPredicate)) { addAtom = false; break; } + ++checkCounter; if (equivalenceChecker.areEquivalentModuloNegation(newAtom, oldPredicate)) { addAtom = false; break; } - if (addAtom) { - cleanedAtoms.push_back(newAtom); - } + } + if (addAtom) { + cleanedAtoms.push_back(newAtom); } } } else { @@ -1417,7 +1422,7 @@ namespace storm { } } auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Preprocessing predicates took " << std::chrono::duration_cast(end - start).count() << "ms."); + STORM_LOG_TRACE("Preprocessing predicates took " << std::chrono::duration_cast(end - start).count() << "ms (" << checkCounter << " checks)."); return cleanedAtoms; } else { diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index 48e2042a9..86a3b8412 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -23,8 +23,8 @@ namespace storm { // Extract the variables of the predicate, so we know which variables were used when abstracting. std::set usedVariables = predicate.getVariables(); concretePredicateVariables.insert(usedVariables.begin(), usedVariables.end()); - localExpressionInformation.relate(usedVariables); } + localExpressionInformation.relate(concretePredicateVariables); } template diff --git a/src/storm/abstraction/ValidBlockAbstractor.cpp b/src/storm/abstraction/ValidBlockAbstractor.cpp index dcfdcf20c..16364b156 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.cpp +++ b/src/storm/abstraction/ValidBlockAbstractor.cpp @@ -34,6 +34,13 @@ namespace storm { return validBlocks; } + template + void ValidBlockAbstractor::constrain(storm::expressions::Expression const& constraint) { + for (uint64_t i = 0; i < smtSolvers.size(); ++i) { + smtSolvers[i]->add(constraint); + } + } + template void ValidBlockAbstractor::refine(std::vector const& predicates) { for (auto const& predicate : predicates) { @@ -114,13 +121,10 @@ namespace storm { template storm::dd::Bdd ValidBlockAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, uint64_t blockIndex) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); -// std::cout << "new model ----------------" << std::endl; for (auto const& variableIndexPair : relevantVariablesAndPredicates[blockIndex]) { if (model.getBooleanValue(variableIndexPair.first)) { -// std::cout << this->getAbstractionInformation().getPredicateByIndex(variableIndexPair.second) << " is true" << std::endl; result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { -// std::cout << this->getAbstractionInformation().getPredicateByIndex(variableIndexPair.second) << " is false" << std::endl; result &= !this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } } diff --git a/src/storm/abstraction/ValidBlockAbstractor.h b/src/storm/abstraction/ValidBlockAbstractor.h index 6e0b28ab4..33f7fb590 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.h +++ b/src/storm/abstraction/ValidBlockAbstractor.h @@ -33,6 +33,8 @@ namespace storm { void refine(std::vector const& predicates); + void constrain(storm::expressions::Expression const& constraint); + private: /*! * Checks which parts of the valid blocks need to be recomputed. diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 35c61caeb..b32df498a 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -48,6 +48,7 @@ namespace storm { for (auto const& range : this->model.get().getAllRangeExpressions()) { abstractionInformation.addConstraint(range); initialStateAbstractor.constrain(range); + validBlockAbstractor.constrain(range); } uint_fast64_t totalNumberOfCommands = 0; @@ -181,6 +182,9 @@ namespace storm { // Do a reachability analysis on the raw transition relation. storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); + if (!model.get().hasTrivialInitialStatesExpression()) { + initialStates &= validBlockAbstractor.getValidBlocks(); + } initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index 84c6d9523..e8dc2795e 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -26,8 +26,10 @@ namespace storm { ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { // For each concrete command, we create an abstract counterpart. + uint64_t counter = 0; for (auto const& command : module.getCommands()) { commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition); + ++counter; } } @@ -83,7 +85,8 @@ namespace storm { BottomStateResult ModuleAbstractor::getBottomStateTransitions(storm::dd::Bdd const& reachableStates, uint_fast64_t numberOfPlayer2Variables) { BottomStateResult result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero()); - for (auto& command : commands) { + for (uint64_t index = 0; index < commands.size(); ++index) { + auto& command = commands[index]; BottomStateResult commandBottomStateResult = command.getBottomStateTransitions(reachableStates, numberOfPlayer2Variables); result.states |= commandBottomStateResult.states; result.transitions |= commandBottomStateResult.transitions; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 3490c5a45..b9b6b8ab9 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -45,6 +45,7 @@ namespace storm { for (auto const& range : this->program.get().getAllRangeExpressions()) { abstractionInformation.addConstraint(range); initialStateAbstractor.constrain(range); + validBlockAbstractor.constrain(range); } uint_fast64_t totalNumberOfCommands = 0; @@ -174,6 +175,9 @@ namespace storm { // Do a reachability analysis on the raw transition relation. storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); + if (program.get().hasInitialConstruct()) { + initialStates &= validBlockAbstractor.getValidBlocks(); + } initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/adapters/MathsatExpressionAdapter.h b/src/storm/adapters/MathsatExpressionAdapter.h index 0b111a10f..e99c7d0c5 100644 --- a/src/storm/adapters/MathsatExpressionAdapter.h +++ b/src/storm/adapters/MathsatExpressionAdapter.h @@ -58,11 +58,13 @@ namespace storm { * @return An equivalent term for MathSAT. */ msat_term translateExpression(storm::expressions::Expression const& expression) { + additionalConstraints.clear(); msat_term result = boost::any_cast(expression.getBaseExpression().accept(*this, boost::none)); if (MSAT_ERROR_TERM(result)) { std::string errorMessage(msat_last_error_message(env)); STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException, "Could not translate expression to MathSAT's format. (Message: " << errorMessage << ")"); } + return result; } @@ -82,6 +84,17 @@ namespace storm { return msat_make_constant(env, variableExpressionPair->second); } + bool hasAdditionalConstraints() const { + return !additionalConstraints.empty(); + } + + /*! + * Retrieves additional constraints that were created because of encodings using auxiliary variables. + */ + std::vector const& getAdditionalConstraints() const { + return additionalConstraints; + } + /*! * Retrieves the variable that is associated with the given MathSAT variable declaration. * @@ -118,6 +131,12 @@ namespace storm { msat_term result = leftResult; int_fast64_t exponent; + int_fast64_t modulus; + storm::expressions::Variable freshAuxiliaryVariable; + msat_term modVariable; + msat_term lower; + msat_term upper; + typename storm::NumberTraits::IntegerType gmpModulus; switch (expression.getOperatorType()) { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: return msat_make_plus(env, leftResult, rightResult); @@ -141,6 +160,23 @@ namespace storm { } } return result; + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Modulo: + modulus = expression.getSecondOperand()->evaluateAsInt(); + STORM_LOG_THROW(modulus > 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative modulus."); + + freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true); + modVariable = msat_make_constant(env, createVariable(freshAuxiliaryVariable)); + + gmpModulus = typename storm::NumberTraits::IntegerType(static_cast(modulus)); + + // Create the constraint that fixes the value of the fresh variable. + additionalConstraints.push_back(msat_make_int_modular_congruence(env, gmpModulus.get_mpz_t(), modVariable, leftResult)); + + // Create the constraint that limits the value of the modulo operation to 0 <= val <= modulus-1. + lower = msat_make_number(env, "-1"); + upper = msat_make_number(env, std::to_string(modulus - 1).c_str()); + additionalConstraints.push_back(msat_make_and(env, msat_make_not(env, msat_make_leq(env, modVariable, lower)), msat_make_leq(env, modVariable, upper))); + return modVariable; default: STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast(expression.getOperatorType()) << "' in expression " << expression << "."); } @@ -313,11 +349,15 @@ namespace storm { // The MathSAT environment used. msat_env& env; + + // A vector of constraints that need to be kept separate, because they were only implicitly part of an + // assertion that was added. + std::vector additionalConstraints; // A mapping of variable names to their declaration in the MathSAT environment. std::unordered_map variableToDeclarationMapping; - // A mapping from MathSAT variable declaration to our variables. + // A mapping from MathSAT variable declarations to our variables. std::unordered_map declarationToVariableMapping; }; #endif diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 7657c0ceb..e6eab03dc 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -574,9 +574,10 @@ namespace storm { } // #ifdef LOCAL_DEBUG - // targetStates.template toAdd().exportToDot("target.dot"); - // abstractor->exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne()); - // game.getReachableStates().template toAdd().exportToDot("reach.dot"); +// initialStates.template toAdd().exportToDot("init.dot"); +// targetStates.template toAdd().exportToDot("target.dot"); +// abstractor->exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne()); +// game.getReachableStates().template toAdd().exportToDot("reach.dot"); // #endif std::unique_ptr result; diff --git a/src/storm/solver/MathsatSmtSolver.cpp b/src/storm/solver/MathsatSmtSolver.cpp index 9b6f7da2b..219efe530 100644 --- a/src/storm/solver/MathsatSmtSolver.cpp +++ b/src/storm/solver/MathsatSmtSolver.cpp @@ -139,7 +139,13 @@ namespace storm { void MathsatSmtSolver::add(storm::expressions::Expression const& e) { #ifdef STORM_HAVE_MSAT - msat_assert_formula(env, expressionAdapter->translateExpression(e)); + msat_term expression = expressionAdapter->translateExpression(e); + msat_assert_formula(env, expression); + if (expressionAdapter->hasAdditionalConstraints()) { + for (auto const& constraint : expressionAdapter->getAdditionalConstraints()) { + msat_assert_formula(env, constraint); + } + } #else STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without MathSAT support."); #endif diff --git a/src/storm/storage/expressions/EquivalenceChecker.cpp b/src/storm/storage/expressions/EquivalenceChecker.cpp index 5d1ffad56..ba286dd63 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.cpp +++ b/src/storm/storage/expressions/EquivalenceChecker.cpp @@ -39,6 +39,7 @@ namespace storm { this->smtSolver->push(); this->smtSolver->add(!storm::expressions::iff(first, !second)); equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + this->smtSolver->pop(); return equivalent; } diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 7d856e56c..88f5f0489 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -351,6 +351,27 @@ namespace storm { return result; } + bool Automaton::hasTrivialInitialStatesExpression() const { + if (this->hasInitialStatesRestriction()) { + return false; + } + + bool result = true; + for (auto const& variable : this->getVariables()) { + if (variable.isTransient()) { + continue; + } + + result &= variable.hasInitExpression(); + + if (!result) { + break; + } + } + + return result; + } + bool Automaton::hasEdgeLabeledWithActionIndex(uint64_t actionIndex) const { return actionIndices.find(actionIndex) != actionIndices.end(); } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index c549ecca8..92c5374bb 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -252,6 +252,12 @@ namespace storm { */ storm::expressions::Expression getInitialStatesExpression() const; + /*! + * Retrieves whether the initial states expression is trivial in the sense that the automaton has no initial + * states restriction and all non-transient variables have initial values. + */ + bool hasTrivialInitialStatesExpression() const; + /*! * Retrieves whether there is an edge labeled with the action with the given index in this automaton. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index a6491a884..8da333cb7 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -928,6 +928,21 @@ namespace storm { return getInitialStatesExpression(allAutomata); } + bool Model::hasTrivialInitialStatesExpression() const { + if (this->hasInitialStatesRestriction()) { + return false; + } + + bool result = true; + for (auto const& automaton : this->getAutomata()) { + result &= automaton.hasTrivialInitialStatesExpression(); + if (!result) { + break; + } + } + return result; + } + storm::expressions::Expression Model::getInitialStatesExpression(std::vector> const& automata) const { // Start with the restriction of variables. storm::expressions::Expression result = initialStatesRestriction; diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 2dc69d147..262ec1288 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -349,6 +349,12 @@ namespace storm { */ storm::expressions::Expression getInitialStatesExpression() const; + /*! + * Retrieves whether the initial states expression is trivial in the sense that no automaton has an initial + * states restriction and all variables have initial values. + */ + bool hasTrivialInitialStatesExpression() const; + /*! * Retrieves the expression defining the legal initial values of the variables. * diff --git a/src/storm/storage/prism/InitialConstruct.cpp b/src/storm/storage/prism/InitialConstruct.cpp index a2bce30e9..715b76752 100644 --- a/src/storm/storage/prism/InitialConstruct.cpp +++ b/src/storm/storage/prism/InitialConstruct.cpp @@ -16,9 +16,9 @@ namespace storm { } std::ostream& operator<<(std::ostream& stream, InitialConstruct const& initialConstruct) { - stream << "initial " << std::endl; + stream << "init " << std::endl; stream << "\t" << initialConstruct.getInitialStatesExpression() << std::endl; - stream << "endinitial" << std::endl; + stream << "endinit" << std::endl; return stream; } } // namespace prism diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index cda98bc09..ad1713a9a 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -1554,6 +1554,7 @@ namespace storm { // Finally, we can create the module and the program and return it. storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, newCommands, this->getFilename(), 0); + return Program(manager, this->getModelType(), this->getConstants(), std::vector(), std::vector(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility, this->getFilename(), 0, true); } diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 360128f00..c74592575 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -16,6 +16,8 @@ #include #include +#include "storm/utility/NumberTraits.h" + namespace storm { // Forward-declare MatrixEntry class. From 7f8a830b5a6675d9c4dcd2ed5d4927667b170a4e Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 16 May 2018 16:02:20 +0200 Subject: [PATCH 291/647] refined detection of trivial initial states restriction of JANI models --- src/storm/storage/jani/Automaton.cpp | 2 +- src/storm/storage/jani/Model.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 88f5f0489..060ae4e9b 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -328,7 +328,7 @@ namespace storm { storm::expressions::Expression result; // Add initial state restriction if there is one. - if (this->hasInitialStatesRestriction()) { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { result = this->getInitialStatesRestriction(); } diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 8da333cb7..bec06e9b3 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -929,7 +929,7 @@ namespace storm { } bool Model::hasTrivialInitialStatesExpression() const { - if (this->hasInitialStatesRestriction()) { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { return false; } From 91bbe85a0768731e5befe958cd7ecd5ac5c06d57 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 16 May 2018 22:55:34 +0200 Subject: [PATCH 292/647] builder options for labeling overlapping guards --- src/storm/builder/BuilderOptions.cpp | 11 ++++++++++- src/storm/builder/BuilderOptions.h | 12 +++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index 33152ca36..d4d729d21 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -36,7 +36,7 @@ namespace storm { return boost::get(labelOrExpression); } - BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) { + BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOverlappingGuardsLabel(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) { // Intentionally left empty. } @@ -164,6 +164,10 @@ namespace storm { return addOutOfBoundsState; } + bool BuilderOptions::isAddOverlappingGuardLabelSet() const { + return addOverlappingGuardsLabel; + } + BuilderOptions& BuilderOptions::setBuildAllRewardModels(bool newValue) { buildAllRewardModels = newValue; return *this; @@ -238,5 +242,10 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::setAddOverlappingGuardsLabel(bool newValue) { + addOverlappingGuardsLabel = newValue; + return *this; + } + } } diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index c6106172b..904d45de6 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -108,6 +108,7 @@ namespace storm { bool isExplorationChecksSet() const; bool isShowProgressSet() const; bool isAddOutOfBoundsStateSet() const; + bool isAddOverlappingGuardLabelSet() const; uint64_t getShowProgressDelay() const; /** @@ -164,6 +165,12 @@ namespace storm { */ BuilderOptions& setAddOutOfBoundsState(bool newValue = true); + /** + * Should a state be labelled for overlapping guards + * @param newValue the new value (default true) + */ + BuilderOptions& setAddOverlappingGuardsLabel(bool newValue = true); + private: /// A flag that indicates whether all reward models are to be built. In this case, the reward model names are @@ -194,10 +201,13 @@ namespace storm { // A flag that indicates whether or not to generate the information from which parts of the model specification // each choice originates. bool buildChoiceOrigins; - + /// A flag that stores whether exploration checks are to be performed. bool explorationChecks; + /// A flag for states with overlapping guards + bool addOverlappingGuardsLabel; + /// A flag indicating that the an additional state for out of bounds should be created. bool addOutOfBoundsState; From f52aab00120087a670d76ca6619f31d29f572a13 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 16 May 2018 22:58:36 +0200 Subject: [PATCH 293/647] fixed out-of-bounds-labelling, added overlapping guards building, and some improved error messages if something goes wrong with highlevel counterex generation --- src/storm/builder/ExplicitModelBuilder.cpp | 3 ++ .../SMTMinimalLabelSetGenerator.h | 31 ++++++++++++++----- src/storm/generator/CompressedState.cpp | 7 +++++ src/storm/generator/CompressedState.h | 2 ++ .../generator/JaniNextStateGenerator.cpp | 4 +++ src/storm/generator/NextStateGenerator.cpp | 30 ++++++++++++++++-- src/storm/generator/NextStateGenerator.h | 10 ++++++ .../generator/PrismNextStateGenerator.cpp | 4 +++ src/storm/generator/VariableInformation.cpp | 23 +++++++++++--- src/storm/generator/VariableInformation.h | 7 +++-- 10 files changed, 106 insertions(+), 15 deletions(-) diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp index 986e04ae7..70e548ae4 100644 --- a/src/storm/builder/ExplicitModelBuilder.cpp +++ b/src/storm/builder/ExplicitModelBuilder.cpp @@ -275,6 +275,7 @@ namespace storm { // (a) the transition matrix // (b) the initial states // (c) the hash map storing the mapping states -> ids + // (d) fix remapping for state-generation labels // Fix (a). transitionMatrixBuilder.replaceColumns(remapping, 0); @@ -287,6 +288,8 @@ namespace storm { // Fix (c). this->stateStorage.stateToId.remap([&remapping] (StateType const& state) { return remapping[state]; } ); + + this->generator->remapStateIds([&remapping] (StateType const& state) { return remapping[state]; }); } } diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index f66205fbf..6b4c440c1 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -458,6 +458,12 @@ namespace storm { // Now check for possible backward cuts. for (auto const& labelSetAndPrecedingLabelSetsPair : precedingLabels) { + bool backwardImplicationAdded = false; +// std::cout << "labelSetAndPrecedingLabelSetsPair.first "; +// for (auto const& e : labelSetAndPrecedingLabelSetsPair.first) { +// std::cout << e << ", "; +// } +// std::cout << std::endl; // Find out the commands for the currently considered label set. storm::expressions::Expression guardConjunction; @@ -510,15 +516,18 @@ namespace storm { // If the solver reports unsat, then we know that the current selection is not enabled in the initial state. if (checkResult == storm::solver::SmtSolver::CheckResult::Unsat) { STORM_LOG_DEBUG("Selection not enabled in initial state."); - + + //std::cout << "not gc: " << !guardConjunction << std::endl; localSolver->add(!guardConjunction); STORM_LOG_DEBUG("Asserted disjunction of negated guards."); // Now check the possible preceding label sets for the essential ones. for (auto const& precedingLabelSet : labelSetAndPrecedingLabelSetsPair.second) { + if (labelSetAndPrecedingLabelSetsPair.first == precedingLabelSet) continue; - + + //std::cout << "push" << std::endl; // Create a restore point so we can easily pop-off all weakest precondition expressions. localSolver->push(); @@ -576,7 +585,9 @@ namespace storm { } } } - + + //std::cout << "pgc: " << preceedingGuardConjunction << std::endl; + // Assert all the guards of the preceding command set. localSolver->add(preceedingGuardConjunction); @@ -624,11 +635,15 @@ namespace storm { assertDisjunction(*localSolver, formulae, symbolicModel.isPrismProgram() ? symbolicModel.asPrismProgram().getManager() : symbolicModel.asJaniModel().getManager()); STORM_LOG_DEBUG("Asserted disjunction of all weakest preconditions."); - - if (localSolver->check() == storm::solver::SmtSolver::CheckResult::Sat) { + storm::solver::SmtSolver::CheckResult result = localSolver->check(); + + if (result == storm::solver::SmtSolver::CheckResult::Sat) { backwardImplications[labelSetAndPrecedingLabelSetsPair.first].insert(precedingLabelSet); + backwardImplicationAdded = true; + } else if (result == storm::solver::SmtSolver::CheckResult::Unknown) { + STORM_LOG_ERROR("The SMT solver does not come to a conclusive answer. Does your model contain integer division?"); } - + localSolver->pop(); } @@ -637,6 +652,7 @@ namespace storm { } else { STORM_LOG_DEBUG("Selection is enabled in initial state."); } + STORM_LOG_ERROR_COND(backwardImplicationAdded, "Error in adding cuts for counterexample generation (backward implication misses a label set)."); } } else if (symbolicModel.isJaniModel()) { STORM_LOG_WARN("Model uses assignment levels, did not assert backward implications."); @@ -1697,6 +1713,7 @@ namespace storm { labelSets[choice] = choiceOrigins.getEdgeIndexSet(choice); } } + assert(labelSets.size() == model.getNumberOfChoices()); // (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set. double maximalReachabilityProbability = 0; @@ -1764,7 +1781,7 @@ namespace storm { solverClock = std::chrono::high_resolution_clock::now(); commandSet = findSmallestCommandSet(*solver, variableInformation, currentBound); totalSolverTime += std::chrono::high_resolution_clock::now() - solverClock; - STORM_LOG_DEBUG("Computed minimal command set of size " << (commandSet.size() + relevancyInformation.knownLabels.size()) << "."); + STORM_LOG_DEBUG("Computed minimal command set of size " << commandSet.size() + relevancyInformation.knownLabels.size() << " (" << commandSet.size() << " + " << relevancyInformation.knownLabels.size() << ") "); // Restrict the given model to the current set of labels and compute the reachability probability. modelCheckingClock = std::chrono::high_resolution_clock::now(); diff --git a/src/storm/generator/CompressedState.cpp b/src/storm/generator/CompressedState.cpp index a785f1c79..175a753fa 100644 --- a/src/storm/generator/CompressedState.cpp +++ b/src/storm/generator/CompressedState.cpp @@ -46,6 +46,13 @@ namespace storm { template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); + CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit) { + CompressedState result(varInfo.getTotalBitOffset(roundTo64Bit)); + assert(varInfo.hasOutOfBoundsBit()); + result.set(varInfo.getOutOfBoundsBit()); + return result; + } + #ifdef STORM_HAVE_CARL template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); diff --git a/src/storm/generator/CompressedState.h b/src/storm/generator/CompressedState.h index 1a785dbaa..6965022f2 100644 --- a/src/storm/generator/CompressedState.h +++ b/src/storm/generator/CompressedState.h @@ -36,6 +36,8 @@ namespace storm { * @return A valuation that corresponds to the compressed state. */ storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); + + CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit = true); } } diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index a1a683b5b..2df1784a1 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -320,6 +320,10 @@ namespace storm { // If the model is a deterministic model, we need to fuse the choices into one. if (this->isDeterministicModel() && totalNumberOfChoices > 1) { Choice globalChoice; + + if (this->options.isAddOverlappingGuardLabelSet()) { + this->overlappingGuardStates->push_back(stateToIdCallback(*this->state)); + } // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs // this is equal to the number of choices, which is why we initialize it like this here. diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index e02d2ee13..3b3186b68 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -1,4 +1,5 @@ #include +#include #include "storm/generator/NextStateGenerator.h" #include "storm/adapters/RationalFunctionAdapter.h" @@ -18,12 +19,22 @@ namespace storm { template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(nullptr), state(nullptr) { - // Intentionally left empty. + if(variableInformation.hasOutOfBoundsBit()) { + outOfBoundsState = createOutOfBoundsState(variableInformation); + } + if (options.isAddOverlappingGuardLabelSet()) { + overlappingGuardStates = std::vector(); + } } template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(), evaluator(nullptr), state(nullptr) { - // Intentionally left empty. + if(variableInformation.hasOutOfBoundsBit()) { + outOfBoundsState = createOutOfBoundsState(variableInformation); + } + if (options.isAddOverlappingGuardLabelSet()) { + overlappingGuardStates = std::vector(); + } } template @@ -101,6 +112,14 @@ namespace storm { } } + if (this->options.isAddOverlappingGuardLabelSet()) { + STORM_LOG_THROW(!result.containsLabel("overlap_guards"), storm::exceptions::WrongFormatException, "Label 'overlap_guards' is reserved when adding overlapping guard labels"); + result.addLabel("overlap_guards"); + for (auto index : overlappingGuardStates.get()) { + result.addLabelToState("overlap_guards", index); + } + } + if (this->options.isAddOutOfBoundsStateSet() && stateStorage.stateToId.contains(outOfBoundsState)) { STORM_LOG_THROW(!result.containsLabel("out_of_bounds"),storm::exceptions::WrongFormatException, "Label 'out_of_bounds' is reserved when adding out of bounds states."); result.addLabel("out_of_bounds"); @@ -163,6 +182,13 @@ namespace storm { return nullptr; } + template + void NextStateGenerator::remapStateIds(std::function const& remapping) { + if (overlappingGuardStates != boost::none) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Remapping of Ids during model building is not supported for overlapping guard statements."); + } + } + template class NextStateGenerator; #ifdef STORM_HAVE_CARL diff --git a/src/storm/generator/NextStateGenerator.h b/src/storm/generator/NextStateGenerator.h index ce1dd1f7b..7229ca802 100644 --- a/src/storm/generator/NextStateGenerator.h +++ b/src/storm/generator/NextStateGenerator.h @@ -66,6 +66,13 @@ namespace storm { NextStateGeneratorOptions const& getOptions() const; virtual std::shared_ptr generateChoiceOrigins(std::vector& dataForChoiceOrigins) const; + + /*! + * Performs a remapping of all values stored by applying the given remapping. + * + * @param remapping The remapping to apply. + */ + void remapStateIds(std::function const& remapping); protected: /*! @@ -98,6 +105,9 @@ namespace storm { /// A state that encodes the outOfBoundsState CompressedState outOfBoundsState; + + /// A map that stores the indices of states with overlapping guards. + boost::optional> overlappingGuardStates; }; } } diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 1de65ce30..61fe1e80f 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -229,6 +229,10 @@ namespace storm { // If the model is a deterministic model, we need to fuse the choices into one. if (this->isDeterministicModel() && totalNumberOfChoices > 1) { Choice globalChoice; + + if (this->options.isAddOverlappingGuardLabelSet()) { + this->overlappingGuardStates->push_back(stateToIdCallback(*this->state)); + } // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs // this is equal to the number of choices, which is why we initialize it like this here. diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 7f7ce0708..e4befba41 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -31,11 +31,14 @@ namespace storm { VariableInformation::VariableInformation(storm::prism::Program const& program, bool outOfBoundsState) : totalBitOffset(0) { if(outOfBoundsState) { - deadlockBit = 0; + outOfBoundsBit = 0; ++totalBitOffset; } else { - deadlockBit = boost::none; + outOfBoundsBit = boost::none; } + + + for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, true); ++totalBitOffset; @@ -75,11 +78,13 @@ namespace storm { STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'."); } if(outOfBoundsState) { - deadlockBit = 0; + outOfBoundsBit = 0; ++totalBitOffset; } else { - deadlockBit = boost::none; + outOfBoundsBit = boost::none; } + + for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) { if (!variable.isTransient()) { @@ -133,6 +138,16 @@ namespace storm { } return result; } + + bool VariableInformation::hasOutOfBoundsBit() const { + return outOfBoundsBit != boost::none; + } + + uint64_t VariableInformation::getOutOfBoundsBit() const { + assert(hasOutOfBoundsBit()); + return outOfBoundsBit.get(); + } + void VariableInformation::sortVariables() { // Sort the variables so we can make some assumptions when iterating over them (in the next-state generators). diff --git a/src/storm/generator/VariableInformation.h b/src/storm/generator/VariableInformation.h index 2e51f7db7..fac200d1a 100644 --- a/src/storm/generator/VariableInformation.h +++ b/src/storm/generator/VariableInformation.h @@ -93,9 +93,12 @@ namespace storm { /// The integer variables. std::vector integerVariables; - + bool hasOutOfBoundsBit() const; + + uint64_t getOutOfBoundsBit() const; + private: - boost::optional deadlockBit; + boost::optional outOfBoundsBit; /*! * Sorts the variables to establish a known ordering. From 627a79fe35aa9a108a69bac87f6f7b4b783e15b5 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 17 May 2018 09:28:09 +0200 Subject: [PATCH 294/647] fix to restriction to relevant state space in game-based abstraction --- src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp | 11 ++++------- .../abstraction/prism/PrismMenuGameAbstractor.cpp | 8 ++------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index b32df498a..3d0fec9c1 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -188,9 +188,6 @@ namespace storm { initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - // Cut transition relation to the reachable states for backward search. - transitionRelation &= reachableStates; - relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { // Get the target state BDD. @@ -199,9 +196,6 @@ namespace storm { // In the presence of target states, we keep only states that can reach the target states. reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - // Cut the transition relation source blocks to the backward reachable states. - transitionRelation &= reachableStates; - // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); @@ -227,7 +221,10 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); + // Note that we also restrict the successor states of transitions, because there might be successors + // that are not in the relevant we restrict to. + storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs())).template toAdd(); + transitionMatrix *= edgeDecoratorAdd; transitionMatrix += deadlockTransitions; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index b9b6b8ab9..c61f68833 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -181,9 +181,6 @@ namespace storm { initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - // Cut transition relation to the reachable states for backward search. - transitionRelation &= reachableStates; - relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { // Get the target state BDD. @@ -192,9 +189,6 @@ namespace storm { // In the presence of target states, we keep only states that can reach the target states. reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - // Cut the transition relation source blocks to the backward reachable states. - transitionRelation &= reachableStates; - // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. reachableStates = reachableStates || reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); @@ -220,6 +214,8 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. + // Note that we also restrict the successor states of transitions, because there might be successors + // that are not in the relevant we restrict to. storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= commandUpdateProbabilitiesAdd; transitionMatrix += deadlockTransitions; From 433b23d9893532f267c9e4e0889058d51c7f0f8a Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 17 May 2018 16:46:23 +0200 Subject: [PATCH 295/647] more fixes to (JANI) game-based abstraction --- .../abstraction/AbstractionInformation.cpp | 16 ++++++++++++--- .../abstraction/AbstractionInformation.h | 7 ++++++- .../abstraction/ExpressionTranslator.cpp | 2 +- src/storm/abstraction/MenuGameRefiner.cpp | 20 ++++++++++++------- .../jani/JaniMenuGameAbstractor.cpp | 14 ++++++++----- .../prism/PrismMenuGameAbstractor.cpp | 5 ++++- 6 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index d6d375544..5c5737f89 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -140,11 +140,12 @@ namespace storm { template std::vector AbstractionInformation::getPredicatesExcludingBottom(storm::storage::BitVector const& predicateValuation) const { - STORM_LOG_ASSERT(predicateValuation.size() == this->getNumberOfPredicates() + 1, "Size of predicate valuation does not match number of predicates."); + uint64_t offset = 1 + this->getNumberOfDdSourceLocationVariables(); + STORM_LOG_ASSERT(predicateValuation.size() == this->getNumberOfPredicates() + offset, "Size of predicate valuation does not match number of predicates."); std::vector result; for (uint64_t index = 0; index < this->getNumberOfPredicates(); ++index) { - if (predicateValuation[index + 1]) { + if (predicateValuation[index + offset]) { result.push_back(this->getPredicateByIndex(index)); } else { result.push_back(!this->getPredicateByIndex(index)); @@ -539,7 +540,7 @@ namespace storm { } template - storm::expressions::Variable const& AbstractionInformation::getDdLocationVariable(storm::expressions::Variable const& locationExpressionVariable, bool source) { + storm::expressions::Variable const& AbstractionInformation::getDdLocationMetaVariable(storm::expressions::Variable const& locationExpressionVariable, bool source) { auto const& metaVariablePair = locationExpressionToDdVariableMap.at(locationExpressionVariable); if (source) { return metaVariablePair.first; @@ -548,6 +549,15 @@ namespace storm { } } + template + uint64_t AbstractionInformation::getNumberOfDdSourceLocationVariables() const { + uint64_t result = 0; + for (auto const& locationVariableToMetaVariablePair : locationExpressionToDdVariableMap) { + result += ddManager->getMetaVariable(locationVariableToMetaVariablePair.second.first).getNumberOfDdVariables(); + } + return result; + } + template std::set const& AbstractionInformation::getLocationExpressionVariables() const { return locationExpressionVariables; diff --git a/src/storm/abstraction/AbstractionInformation.h b/src/storm/abstraction/AbstractionInformation.h index fa1a1927a..4256f2149 100644 --- a/src/storm/abstraction/AbstractionInformation.h +++ b/src/storm/abstraction/AbstractionInformation.h @@ -485,7 +485,12 @@ namespace storm { /*! * Retrieves the DD variable for the given location expression variable. */ - storm::expressions::Variable const& getDdLocationVariable(storm::expressions::Variable const& locationExpressionVariable, bool source); + storm::expressions::Variable const& getDdLocationMetaVariable(storm::expressions::Variable const& locationExpressionVariable, bool source); + + /*! + * Retrieves the number of DD variables associated with the source location variables. + */ + uint64_t getNumberOfDdSourceLocationVariables() const; /*! * Retrieves the source location variables. diff --git a/src/storm/abstraction/ExpressionTranslator.cpp b/src/storm/abstraction/ExpressionTranslator.cpp index 8bf792278..40e2b995d 100644 --- a/src/storm/abstraction/ExpressionTranslator.cpp +++ b/src/storm/abstraction/ExpressionTranslator.cpp @@ -136,7 +136,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator."); } else { - return abstractionInformation.get().getDdManager().template getIdentity(abstractionInformation.get().getDdLocationVariable(expression.getVariable(), true)); + return abstractionInformation.get().getDdManager().template getIdentity(abstractionInformation.get().getDdLocationMetaVariable(expression.getVariable(), true)); } } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index b75a6380a..1bbdefd6a 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -594,9 +594,12 @@ namespace storm { auto pathIt = reversedPath.rbegin(); - // Decode initial state. The state valuation also includes the bottom state, so we need to reserve one more - // than the number of predicates here. - storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + 1); + // Decode initial state. The state valuation also includes + // * the bottom state, so we need to reserve one more, and + // * the location variables, + // so we need to reserve an appropriate size. + uint64_t predicateValuationOffset = abstractionInformation.getNumberOfDdSourceLocationVariables() + 1; + storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset); ++pathIt; // Add all predicates of initial block. @@ -651,6 +654,9 @@ namespace storm { allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression; } + if (!allVariableUpdateExpression.isInitialized()) { + allVariableUpdateExpression = expressionManager.boolean(true); + } predicates.back().emplace_back(allVariableUpdateExpression); // Incorporate the new variables in the current substitution. @@ -659,7 +665,7 @@ namespace storm { } // Decode current state. - extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + 1); + extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset); // Encode the predicates whose value might have changed. // FIXME: could be optimized by precomputation. @@ -687,7 +693,7 @@ namespace storm { if (containsAssignedVariables) { auto transformedPredicate = predicate.changeManager(expressionManager).substitute(currentSubstitution); - predicates.back().emplace_back(extendedPredicateValuation.get(predicateIndex + 1) ? transformedPredicate : !transformedPredicate); + predicates.back().emplace_back(extendedPredicateValuation.get(predicateIndex + predicateValuationOffset) ? transformedPredicate : !transformedPredicate); } } @@ -1231,8 +1237,8 @@ namespace storm { template bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { - ValueType lower = quantitativeResult.getMin().getRange(initialStates).first; - ValueType upper = quantitativeResult.getMax().getRange(initialStates).second; +// ValueType lower = quantitativeResult.getMin().getRange(initialStates).first; +// ValueType upper = quantitativeResult.getMax().getRange(initialStates).second; // boost::optional kShortestPathPredicates = derivePredicatesFromInterpolationKShortestPaths(odd, transitionMatrix, player1Grouping, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, lower, upper, maxStrategyPair); diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 3d0fec9c1..58d5e02f8 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -192,15 +192,19 @@ namespace storm { if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { // Get the target state BDD. storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); - + // In the presence of target states, we keep only states that can reach the target states. - reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - + auto newReachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + reachableStates = newReachableStates; + // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. - reachableStates |= reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + reachableStates |= (reachableStates && !targetStates).relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); relevantStatesWatch.stop(); + // Restrict transition relation to relevant fragment for computation of deadlock states. + transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()); + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); } @@ -222,7 +226,7 @@ namespace storm { // Construct the transition matrix by cutting away the transitions of unreachable states. // Note that we also restrict the successor states of transitions, because there might be successors - // that are not in the relevant we restrict to. + // that are not in the set of relevant states we restrict to. storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= edgeDecoratorAdd; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index c61f68833..167f437b6 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -191,8 +191,11 @@ namespace storm { // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. - reachableStates = reachableStates || reachableStates.relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + reachableStates |= (reachableStates && !targetStates).relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + // Restrict transition relation to relevant fragment for computation of deadlock states. + transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()); + relevantStatesWatch.stop(); STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); } From 057f8798a697250974ec920b9b33e69b12bcf29f Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 17 May 2018 21:55:45 +0200 Subject: [PATCH 296/647] avoiding bottom state computation when possible --- src/storm/abstraction/MenuGameAbstractor.h | 6 ++++++ src/storm/abstraction/MenuGameRefiner.cpp | 3 ++- src/storm/abstraction/jani/AutomatonAbstractor.cpp | 7 +++++++ src/storm/abstraction/jani/AutomatonAbstractor.h | 2 ++ src/storm/abstraction/jani/EdgeAbstractor.cpp | 5 +++++ src/storm/abstraction/jani/EdgeAbstractor.h | 2 ++ src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp | 7 +++++++ src/storm/abstraction/jani/JaniMenuGameAbstractor.h | 2 ++ src/storm/abstraction/prism/CommandAbstractor.cpp | 5 +++++ src/storm/abstraction/prism/CommandAbstractor.h | 2 ++ src/storm/abstraction/prism/ModuleAbstractor.cpp | 7 +++++++ src/storm/abstraction/prism/ModuleAbstractor.h | 2 ++ src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp | 7 +++++++ src/storm/abstraction/prism/PrismMenuGameAbstractor.h | 2 ++ 14 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 7e957e406..f55a7f236 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -71,6 +71,12 @@ namespace storm { storm::expressions::Expression const& getTargetStateExpression() const; bool hasTargetStateExpression() const; + /*! + * Notifies the abstractor that the guards are predicates, which may be used to improve the bottom state + * computation. + */ + virtual void notifyGuardsArePredicates() = 0; + protected: bool isRestrictToRelevantStatesSet() const; diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 1bbdefd6a..627466d4a 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -86,7 +86,8 @@ namespace storm { } } performRefinement(createGlobalRefinement(preprocessPredicates(guards, RefinementPredicates::Source::InitialGuard))); - + + this->abstractor.get().notifyGuardsArePredicates(); addedAllGuardsFlag = true; } } diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index f5c8030da..b14b4db7b 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -141,6 +141,13 @@ namespace storm { return abstractionInformation.get(); } + template + void AutomatonAbstractor::notifyGuardsArePredicates() { + for (auto& edge : edges) { + edge.notifyGuardIsPredicate(); + } + } + template class AutomatonAbstractor; template class AutomatonAbstractor; #ifdef STORM_HAVE_CARL diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index 658d154f4..9e800b756 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -122,6 +122,8 @@ namespace storm { */ std::size_t getNumberOfEdges() const; + void notifyGuardsArePredicates(); + private: /*! * Retrieves the abstraction information. diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index ebd7b5839..2342a497f 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -722,6 +722,11 @@ namespace storm { return abstractionInformation.get(); } + template + void EdgeAbstractor::notifyGuardIsPredicate() { + skipBottomStates = true; + } + template class EdgeAbstractor; template class EdgeAbstractor; #ifdef STORM_HAVE_CARL diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index 22cc7c40d..7ba7445a5 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -121,6 +121,8 @@ namespace storm { */ storm::jani::Edge const& getConcreteEdge() const; + void notifyGuardIsPredicate(); + private: /*! * Determines the relevant predicates for source as well as successor states wrt. to the given assignments diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 58d5e02f8..ffa590a57 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -268,6 +268,13 @@ namespace storm { void JaniMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { terminalStateExpressions.emplace_back(expression); } + + template + void JaniMenuGameAbstractor::notifyGuardsArePredicates() { + for (auto& automaton : automata) { + automaton.notifyGuardsArePredicates(); + } + } // Explicitly instantiate the class. template class JaniMenuGameAbstractor; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 3a02583b4..916dbd7d6 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -123,6 +123,8 @@ namespace storm { virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + virtual void notifyGuardsArePredicates() override; + protected: using MenuGameAbstractor::exportToDot; diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 1c632e4c9..cfd1bed60 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -696,6 +696,11 @@ namespace storm { return abstractionInformation.get(); } + template + void CommandAbstractor::notifyGuardIsPredicate() { + skipBottomStates = true; + } + template class CommandAbstractor; template class CommandAbstractor; #ifdef STORM_HAVE_CARL diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index cb448bad8..cb6146e73 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -117,6 +117,8 @@ namespace storm { */ storm::prism::Command const& getConcreteCommand() const; + void notifyGuardIsPredicate(); + private: /*! * Determines the relevant predicates for source as well as successor states wrt. to the given assignments diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index e8dc2795e..09e1932cb 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -119,6 +119,13 @@ namespace storm { return abstractionInformation.get(); } + template + void ModuleAbstractor::notifyGuardsArePredicates() { + for (auto& command : commands) { + command.notifyGuardIsPredicate(); + } + } + template class ModuleAbstractor; template class ModuleAbstractor; #ifdef STORM_HAVE_CARL diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index a8d5c94cd..d5d2e9dc7 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -113,6 +113,8 @@ namespace storm { */ std::vector>& getCommands(); + void notifyGuardsArePredicates(); + private: /*! * Retrieves the abstraction information. diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 167f437b6..529ecffad 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -262,6 +262,13 @@ namespace storm { terminalStateExpressions.emplace_back(expression); } + template + void PrismMenuGameAbstractor::notifyGuardsArePredicates() { + for (auto& module : modules) { + module.notifyGuardsArePredicates(); + } + } + // Explicitly instantiate the class. template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 21d64cd30..5815c915a 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -123,6 +123,8 @@ namespace storm { virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + virtual void notifyGuardsArePredicates() override; + protected: using MenuGameAbstractor::exportToDot; From 6b914853829233d24ddf4506618dc7248f096297 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 18 May 2018 11:35:16 +0200 Subject: [PATCH 297/647] Removed redundant file --- src/storm/builder/DdPrismModelBuilder.cp | 1429 ---------------------- 1 file changed, 1429 deletions(-) delete mode 100644 src/storm/builder/DdPrismModelBuilder.cp diff --git a/src/storm/builder/DdPrismModelBuilder.cp b/src/storm/builder/DdPrismModelBuilder.cp deleted file mode 100644 index 26308f45b..000000000 --- a/src/storm/builder/DdPrismModelBuilder.cp +++ /dev/null @@ -1,1429 +0,0 @@ -#include "storm/builder/DdPrismModelBuilder.h" - -#include - -#include "storm/models/symbolic/Dtmc.h" -#include "storm/models/symbolic/Ctmc.h" -#include "storm/models/symbolic/Mdp.h" -#include "storm/models/symbolic/StandardRewardModel.h" - -#include "storm/settings/SettingsManager.h" - -#include "storm/exceptions/InvalidStateException.h" -#include "storm/exceptions/NotSupportedException.h" -#include "storm/exceptions/InvalidArgumentException.h" - -#include "storm/utility/prism.h" -#include "storm/utility/math.h" -#include "storm/utility/dd.h" - -#include "storm/storage/dd/DdManager.h" -#include "storm/storage/prism/Program.h" -#include "storm/storage/prism/Compositions.h" -#include "storm/storage/dd/Add.h" -#include "storm/storage/dd/cudd/CuddAddIterator.h" -#include "storm/storage/dd/Bdd.h" - -#include "storm/settings/modules/CoreSettings.h" - -namespace storm { - namespace builder { - - template - class DdPrismModelBuilder::GenerationInformation { - public: - GenerationInformation(storm::prism::Program const& program) : program(program), manager(std::make_shared>()), rowMetaVariables(), variableToRowMetaVariableMap(std::make_shared>()), rowExpressionAdapter(std::make_shared>(manager, variableToRowMetaVariableMap)), columnMetaVariables(), variableToColumnMetaVariableMap((std::make_shared>())), columnExpressionAdapter(std::make_shared>(manager, variableToColumnMetaVariableMap)), rowColumnMetaVariablePairs(), nondeterminismMetaVariables(), variableToIdentityMap(), allGlobalVariables(), moduleToIdentityMap() { - // Initializes variables and identity DDs. - createMetaVariablesAndIdentities(); - } - - // The program that is currently translated. - storm::prism::Program const& program; - - // The manager used to build the decision diagrams. - std::shared_ptr> manager; - - // The meta variables for the row encoding. - std::set rowMetaVariables; - std::shared_ptr> variableToRowMetaVariableMap; - std::shared_ptr> rowExpressionAdapter; - - // The meta variables for the column encoding. - std::set columnMetaVariables; - std::shared_ptr> variableToColumnMetaVariableMap; - std::shared_ptr> columnExpressionAdapter; - - // All pairs of row/column meta variables. - std::vector> rowColumnMetaVariablePairs; - - // The meta variables used to encode the nondeterminism. - std::vector nondeterminismMetaVariables; - - // The meta variables used to encode the synchronization. - std::vector synchronizationMetaVariables; - - // A set of all variables used for encoding the nondeterminism (i.e. nondetermism + synchronization - // variables). This is handy to abstract from this variable set. - std::set allNondeterminismVariables; - - // As set of all variables used for encoding the synchronization. - std::set allSynchronizationMetaVariables; - - // DDs representing the identity for each variable. - std::map> variableToIdentityMap; - - // A set of all meta variables that correspond to global variables. - std::set allGlobalVariables; - - // DDs representing the identity for each module. - std::map> moduleToIdentityMap; - - // DDs representing the valid ranges of the variables of each module. - std::map> moduleToRangeMap; - - private: - /*! - * Creates the required meta variables and variable/module identities. - */ - void createMetaVariablesAndIdentities() { - // Add synchronization variables. - for (auto const& actionIndex : program.getSynchronizingActionIndices()) { - std::pair variablePair = manager->addMetaVariable(program.getActionName(actionIndex)); - synchronizationMetaVariables.push_back(variablePair.first); - allSynchronizationMetaVariables.insert(variablePair.first); - allNondeterminismVariables.insert(variablePair.first); - } - - // Add nondeterminism variables (number of modules + number of commands). - uint_fast64_t numberOfNondeterminismVariables = program.getModules().size(); - for (auto const& module : program.getModules()) { - numberOfNondeterminismVariables += module.getNumberOfCommands(); - } - for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) { - std::pair variablePair = manager->addMetaVariable("nondet" + std::to_string(i)); - nondeterminismMetaVariables.push_back(variablePair.first); - allNondeterminismVariables.insert(variablePair.first); - } - - // Create meta variables for global program variables. - for (storm::prism::IntegerVariable const& integerVariable : program.getGlobalIntegerVariables()) { - int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt(); - std::pair variablePair = manager->addMetaVariable(integerVariable.getName(), low, high); - - STORM_LOG_TRACE("Created meta variables for global integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Add variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)).template toAdd() * manager->getRange(variablePair.first).template toAdd() * manager->getRange(variablePair.second).template toAdd(); - variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity); - rowColumnMetaVariablePairs.push_back(variablePair); - - allGlobalVariables.insert(integerVariable.getExpressionVariable()); - } - for (storm::prism::BooleanVariable const& booleanVariable : program.getGlobalBooleanVariables()) { - std::pair variablePair = manager->addMetaVariable(booleanVariable.getName()); - - STORM_LOG_TRACE("Created meta variables for global boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Add variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)).template toAdd(); - variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity); - - rowColumnMetaVariablePairs.push_back(variablePair); - allGlobalVariables.insert(booleanVariable.getExpressionVariable()); - } - - // Create meta variables for each of the modules' variables. - for (storm::prism::Module const& module : program.getModules()) { - storm::dd::Bdd moduleIdentity = manager->getBddOne(); - storm::dd::Bdd moduleRange = manager->getBddOne(); - - for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) { - int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt(); - std::pair variablePair = manager->addMetaVariable(integerVariable.getName(), low, high); - STORM_LOG_TRACE("Created meta variables for integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Bdd variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second); - variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd()); - moduleIdentity &= variableIdentity; - moduleRange &= manager->getRange(variablePair.first); - - rowColumnMetaVariablePairs.push_back(variablePair); - } - for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) { - std::pair variablePair = manager->addMetaVariable(booleanVariable.getName()); - STORM_LOG_TRACE("Created meta variables for boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Bdd variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second); - variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd()); - moduleIdentity &= variableIdentity; - moduleRange &= manager->getRange(variablePair.first); - - rowColumnMetaVariablePairs.push_back(variablePair); - } - moduleToIdentityMap[module.getName()] = moduleIdentity.template toAdd(); - moduleToRangeMap[module.getName()] = moduleRange.template toAdd(); - } - } - }; - - template - class ModuleComposer : public storm::prism::CompositionVisitor { - public: - ModuleComposer(typename DdPrismModelBuilder::GenerationInformation& generationInfo) : generationInfo(generationInfo) { - // Intentionally left empty. - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram compose(storm::prism::Composition const& composition) { - return boost::any_cast::ModuleDecisionDiagram>(composition.accept(*this, newSynchronizingActionToOffsetMap())); - } - - std::map newSynchronizingActionToOffsetMap() const { - std::map result; - for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) { - result[actionIndex] = 0; - } - return result; - } - - std::map updateSynchronizingActionToOffsetMap(typename DdPrismModelBuilder::ModuleDecisionDiagram const& sub, std::map const& oldMapping) const { - std::map result = oldMapping; - for (auto const& action : sub.synchronizingActionToDecisionDiagramMap) { - result[action.first] = action.second.numberOfUsedNondeterminismVariables; - } - return result; - } - - virtual boost::any visit(storm::prism::ModuleComposition const& composition, boost::any const& data) override { - STORM_LOG_TRACE("Translating module '" << composition.getModuleName() << "'."); - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - - typename DdPrismModelBuilder::ModuleDecisionDiagram result = DdPrismModelBuilder::createModuleDecisionDiagram(generationInfo, generationInfo.program.getModule(composition.getModuleName()), synchronizingActionToOffsetMap); - - return result; - } - - virtual boost::any visit(storm::prism::RenamingComposition const& composition, boost::any const& data) override { - // Create the mapping from action indices to action indices. - std::map renaming; - for (auto const& namePair : composition.getActionRenaming()) { - STORM_LOG_THROW(generationInfo.program.hasAction(namePair.first), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.first << "'."); - STORM_LOG_THROW(generationInfo.program.hasAction(namePair.second), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.second << "'."); - renaming.emplace(generationInfo.program.getActionIndex(namePair.first), generationInfo.program.getActionIndex(namePair.second)); - } - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& indexPair : renaming) { - auto it = synchronizingActionToOffsetMap.find(indexPair.second); - STORM_LOG_THROW(it != synchronizingActionToOffsetMap.end(), storm::exceptions::InvalidArgumentException, "Invalid action index " << indexPair.second << "."); - newSynchronizingActionToOffsetMap[indexPair.first] = it->second; - } - - // Then, we translate the subcomposition. - typename DdPrismModelBuilder::ModuleDecisionDiagram sub = boost::any_cast::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Perform the renaming and return result. - return rename(sub, renaming); - } - - virtual boost::any visit(storm::prism::HidingComposition const& composition, boost::any const& data) override { - // Create the mapping from action indices to action indices. - std::set actionIndicesToHide; - for (auto const& action : composition.getActionsToHide()) { - STORM_LOG_THROW(generationInfo.program.hasAction(action), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << action << "'."); - actionIndicesToHide.insert(generationInfo.program.getActionIndex(action)); - } - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& index : actionIndicesToHide) { - newSynchronizingActionToOffsetMap[index] = 0; - } - - // Then, we translate the subcomposition. - typename DdPrismModelBuilder::ModuleDecisionDiagram sub = boost::any_cast::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Perform the hiding and return result. - hide(sub, actionIndicesToHide); - return sub; - } - - virtual boost::any visit(storm::prism::SynchronizingParallelComposition const& composition, boost::any const& data) override { - // First, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& action : left.synchronizingActionToDecisionDiagramMap) { - newSynchronizingActionToOffsetMap[action.first] = action.second.numberOfUsedNondeterminismVariables; - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Then, determine the action indices on which we need to synchronize. - std::set leftSynchronizationActionIndices = left.getSynchronizingActionIndices(); - std::set rightSynchronizationActionIndices = right.getSynchronizingActionIndices(); - std::set synchronizationActionIndices; - std::set_intersection(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(), std::inserter(synchronizationActionIndices, synchronizationActionIndices.begin())); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, synchronizationActionIndices); - return left; - } - - virtual boost::any visit(storm::prism::InterleavingParallelComposition const& composition, boost::any const& data) override { - // First, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, data)); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, std::set()); - return left; - } - - virtual boost::any visit(storm::prism::RestrictedParallelComposition const& composition, boost::any const& data) override { - // Construct the synchronizing action indices from the synchronizing action names. - std::set synchronizingActionIndices; - for (auto const& action : composition.getSynchronizingActions()) { - synchronizingActionIndices.insert(generationInfo.program.getActionIndex(action)); - } - - // Then, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& actionIndex : synchronizingActionIndices) { - auto it = left.synchronizingActionToDecisionDiagramMap.find(actionIndex); - if (it != left.synchronizingActionToDecisionDiagramMap.end()) { - newSynchronizingActionToOffsetMap[actionIndex] = it->second.numberOfUsedNondeterminismVariables; - } - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - std::set leftSynchronizationActionIndices = left.getSynchronizingActionIndices(); - bool isContainedInLeft = std::includes(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), synchronizingActionIndices.begin(), synchronizingActionIndices.end()); - STORM_LOG_WARN_COND(isContainedInLeft, "Left subcomposition of composition '" << composition << "' does not include all actions over which to synchronize."); - - std::set rightSynchronizationActionIndices = right.getSynchronizingActionIndices(); - bool isContainedInRight = std::includes(rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(), synchronizingActionIndices.begin(), synchronizingActionIndices.end()); - STORM_LOG_WARN_COND(isContainedInRight, "Right subcomposition of composition '" << composition << "' does not include all actions over which to synchronize."); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, synchronizingActionIndices); - return left; - } - - private: - /*! - * Hides the actions of the given module according to the given set. As a result, the module is modified in - * place. - */ - void hide(typename DdPrismModelBuilder::ModuleDecisionDiagram& sub, std::set const& actionIndicesToHide) const { - STORM_LOG_TRACE("Hiding actions."); - - for (auto const& actionIndex : actionIndicesToHide) { - auto it = sub.synchronizingActionToDecisionDiagramMap.find(actionIndex); - if (it != sub.synchronizingActionToDecisionDiagramMap.end()) { - sub.independentAction = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, sub.independentAction, it->second); - sub.numberOfUsedNondeterminismVariables = std::max(sub.numberOfUsedNondeterminismVariables, sub.independentAction.numberOfUsedNondeterminismVariables); - sub.synchronizingActionToDecisionDiagramMap.erase(it); - } - } - } - - /*! - * Renames the actions of the given module according to the given renaming. - */ - typename DdPrismModelBuilder::ModuleDecisionDiagram rename(typename DdPrismModelBuilder::ModuleDecisionDiagram& sub, std::map const& renaming) const { - STORM_LOG_TRACE("Renaming actions."); - std::map::ActionDecisionDiagram> actionIndexToDdMap; - - // Go through all action DDs with a synchronizing label and rename them if they appear in the renaming. - for (auto& action : sub.synchronizingActionToDecisionDiagramMap) { - auto renamingIt = renaming.find(action.first); - if (renamingIt != renaming.end()) { - // If the action is to be renamed and an action with the target index already exists, we need - // to combine the action DDs. - auto itNewActions = actionIndexToDdMap.find(renamingIt->second); - if (itNewActions != actionIndexToDdMap.end()) { - actionIndexToDdMap[renamingIt->second] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); - - } else { - // In this case, we can simply copy the action over. - actionIndexToDdMap[renamingIt->second] = action.second; - } - } else { - // If the action is not to be renamed, we need to copy it over. However, if some other action - // was renamed to the very same action name before, we need to combine the transitions. - auto itNewActions = actionIndexToDdMap.find(action.first); - if (itNewActions != actionIndexToDdMap.end()) { - actionIndexToDdMap[action.first] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); - } else { - // In this case, we can simply copy the action over. - actionIndexToDdMap[action.first] = action.second; - } - } - } - - return typename DdPrismModelBuilder::ModuleDecisionDiagram(sub.independentAction, actionIndexToDdMap, sub.identity, sub.numberOfUsedNondeterminismVariables); - } - - /*! - * Composes the given modules while synchronizing over the provided action indices. As a result, the first - * module is modified in place and will contain the composition after a call to this method. - */ - void composeInParallel(typename DdPrismModelBuilder::ModuleDecisionDiagram& left, typename DdPrismModelBuilder::ModuleDecisionDiagram& right, std::set const& synchronizationActionIndices) const { - STORM_LOG_TRACE("Composing two modules."); - - // Combine the tau action. - uint_fast64_t numberOfUsedNondeterminismVariables = right.independentAction.numberOfUsedNondeterminismVariables; - left.independentAction = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, left.independentAction, right.independentAction, left.identity, right.identity); - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.independentAction.numberOfUsedNondeterminismVariables); - - // Create an empty action for the case where one of the modules does not have a certain action. - typename DdPrismModelBuilder::ActionDecisionDiagram emptyAction(*generationInfo.manager); - - // Treat all non-tau actions of the left module. - for (auto& action : left.synchronizingActionToDecisionDiagramMap) { - // If we need to synchronize over this action index, we try to do so now. - if (synchronizationActionIndices.find(action.first) != synchronizationActionIndices.end()) { - // If we are to synchronize over an action that does not exist in the second module, the result - // is that the synchronization is the empty action. - if (!right.hasSynchronizingAction(action.first)) { - action.second = emptyAction; - } else { - // Otherwise, the actions of the modules are synchronized. - action.second = DdPrismModelBuilder::combineSynchronizingActions(action.second, right.synchronizingActionToDecisionDiagramMap[action.first]); - } - } else { - // If we don't synchronize over this action, we need to construct the interleaving. - - // If both modules contain the action, we need to mutually multiply the other identity. - if (right.hasSynchronizingAction(action.first)) { - action.second = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, right.synchronizingActionToDecisionDiagramMap[action.first], left.identity, right.identity); - } else { - // If only the first module has this action, we need to use a dummy action decision diagram - // for the second module. - action.second = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, emptyAction, left.identity, right.identity); - } - } - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, action.second.numberOfUsedNondeterminismVariables); - } - - // Treat all non-tau actions of the right module. - for (auto const& actionIndex : right.getSynchronizingActionIndices()) { - // Here, we only need to treat actions that the first module does not have, because we have handled - // this case earlier. - if (!left.hasSynchronizingAction(actionIndex)) { - if (synchronizationActionIndices.find(actionIndex) != synchronizationActionIndices.end()) { - // If we are to synchronize over this action that does not exist in the first module, the - // result is that the synchronization is the empty action. - left.synchronizingActionToDecisionDiagramMap[actionIndex] = emptyAction; - } else { - // If only the second module has this action, we need to use a dummy action decision diagram - // for the first module. - left.synchronizingActionToDecisionDiagramMap[actionIndex] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, emptyAction, right.synchronizingActionToDecisionDiagramMap[actionIndex], left.identity, right.identity); - } - } - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables); - } - - // Combine identity matrices. - left.identity = left.identity * right.identity; - - // Keep track of the number of nondeterminism variables used. - left.numberOfUsedNondeterminismVariables = std::max(left.numberOfUsedNondeterminismVariables, numberOfUsedNondeterminismVariables); - } - - typename DdPrismModelBuilder::GenerationInformation& generationInfo; - }; - - template - DdPrismModelBuilder::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { - // Intentionally left empty. - } - - template - DdPrismModelBuilder::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(std::set()), terminalStates(), negatedTerminalStates() { - this->preserveFormula(formula); - this->setTerminalStatesFromFormula(formula); - } - - template - DdPrismModelBuilder::Options::Options(std::vector> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { - if (formulas.empty()) { - this->buildAllRewardModels = true; - this->buildAllLabels = true; - } else { - for (auto const& formula : formulas) { - this->preserveFormula(*formula); - } - if (formulas.size() == 1) { - this->setTerminalStatesFromFormula(*formulas.front()); - } - } - } - - template - void DdPrismModelBuilder::Options::preserveFormula(storm::logic::Formula const& formula) { - // If we already had terminal states, we need to erase them. - if (terminalStates) { - terminalStates.reset(); - } - if (negatedTerminalStates) { - negatedTerminalStates.reset(); - } - - // If we are not required to build all reward models, we determine the reward models we need to build. - if (!buildAllRewardModels) { - std::set referencedRewardModels = formula.getReferencedRewardModels(); - rewardModelsToBuild.insert(referencedRewardModels.begin(), referencedRewardModels.end()); - } - - // Extract all the labels used in the formula. - std::vector> atomicLabelFormulas = formula.getAtomicLabelFormulas(); - for (auto const& formula : atomicLabelFormulas) { - if (!labelsToBuild) { - labelsToBuild = std::set(); - } - labelsToBuild.get().insert(formula.get()->getLabel()); - } - } - - template - void DdPrismModelBuilder::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { - if (formula.isAtomicExpressionFormula()) { - terminalStates = formula.asAtomicExpressionFormula().getExpression(); - } else if (formula.isAtomicLabelFormula()) { - terminalStates = formula.asAtomicLabelFormula().getLabel(); - } else if (formula.isEventuallyFormula()) { - storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula(); - if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) { - this->setTerminalStatesFromFormula(sub); - } - } else if (formula.isUntilFormula()) { - storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula(); - if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) { - this->setTerminalStatesFromFormula(right); - } - storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula(); - if (left.isAtomicExpressionFormula()) { - negatedTerminalStates = left.asAtomicExpressionFormula().getExpression(); - } else if (left.isAtomicLabelFormula()) { - negatedTerminalStates = left.asAtomicLabelFormula().getLabel(); - } - } else if (formula.isProbabilityOperatorFormula()) { - storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula(); - if (sub.isEventuallyFormula() || sub.isUntilFormula()) { - this->setTerminalStatesFromFormula(sub); - } - } - } - - template - struct DdPrismModelBuilder::SystemResult { - SystemResult(storm::dd::Add const& allTransitionsDd, DdPrismModelBuilder::ModuleDecisionDiagram const& globalModule, storm::dd::Add const& stateActionDd) : allTransitionsDd(allTransitionsDd), globalModule(globalModule), stateActionDd(stateActionDd) { - // Intentionally left empty. - } - - storm::dd::Add allTransitionsDd; - typename DdPrismModelBuilder::ModuleDecisionDiagram globalModule; - storm::dd::Add stateActionDd; - }; - - template - typename DdPrismModelBuilder::UpdateDecisionDiagram DdPrismModelBuilder::createUpdateDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::dd::Add const& guard, storm::prism::Update const& update) { - storm::dd::Add updateDd = generationInfo.manager->template getAddOne(); - - STORM_LOG_TRACE("Translating update " << update); - - // Iterate over all assignments (boolean and integer) and build the DD for it. - std::vector assignments = update.getAssignments(); - std::set assignedVariables; - for (auto const& assignment : assignments) { - // Record the variable as being written. - STORM_LOG_TRACE("Assigning to variable " << generationInfo.variableToRowMetaVariableMap->at(assignment.getVariable()).getName()); - assignedVariables.insert(assignment.getVariable()); - - // Translate the written variable. - auto const& primedMetaVariable = generationInfo.variableToColumnMetaVariableMap->at(assignment.getVariable()); - storm::dd::Add writtenVariable = generationInfo.manager->template getIdentity(primedMetaVariable); - - // Translate the expression that is being assigned. - storm::dd::Add updateExpression = generationInfo.rowExpressionAdapter->translateExpression(assignment.getExpression()); - - // Combine the update expression with the guard. - storm::dd::Add result = updateExpression * guard; - - // Combine the variable and the assigned expression. - storm::dd::Add tmp = result; - result = result.equals(writtenVariable).template toAdd(); - result *= guard; - - // Restrict the transitions to the range of the written variable. - result = result * generationInfo.manager->getRange(primedMetaVariable).template toAdd(); - - updateDd *= result; - } - - // Compute the set of assigned global variables. - std::set assignedGlobalVariables; - std::set_intersection(assignedVariables.begin(), assignedVariables.end(), generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin())); - - // All unassigned boolean variables need to keep their value. - for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) { - if (assignedVariables.find(booleanVariable.getExpressionVariable()) == assignedVariables.end()) { - STORM_LOG_TRACE("Multiplying identity of variable " << booleanVariable.getName()); - updateDd *= generationInfo.variableToIdentityMap.at(booleanVariable.getExpressionVariable()); - } - } - - // All unassigned integer variables need to keep their value. - for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) { - if (assignedVariables.find(integerVariable.getExpressionVariable()) == assignedVariables.end()) { - STORM_LOG_TRACE("Multiplying identity of variable " << integerVariable.getName()); - updateDd *= generationInfo.variableToIdentityMap.at(integerVariable.getExpressionVariable()); - } - } - - return UpdateDecisionDiagram(updateDd, assignedGlobalVariables); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::createCommandDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::prism::Command const& command) { - STORM_LOG_TRACE("Translating guard " << command.getGuardExpression()); - storm::dd::Add guard = generationInfo.rowExpressionAdapter->translateExpression(command.getGuardExpression()) * generationInfo.moduleToRangeMap[module.getName()]; - STORM_LOG_WARN_COND(!guard.isZero(), "The guard '" << command.getGuardExpression() << "' is unsatisfiable."); - - if (!guard.isZero()) { - // Create the DDs representing the individual updates. - std::vector updateResults; - for (storm::prism::Update const& update : command.getUpdates()) { - updateResults.push_back(createUpdateDecisionDiagram(generationInfo, module, guard, update)); - - STORM_LOG_WARN_COND(!updateResults.back().updateDd.isZero(), "Update '" << update << "' does not have any effect."); - } - - // Start by gathering all variables that were written in at least one update. - std::set globalVariablesInSomeUpdate; - - // If the command is labeled, we have to analyze which portion of the global variables was written by - // any of the updates and make all update results equal w.r.t. this set. If the command is not labeled, - // we can already multiply the identities of all global variables. - if (command.isLabeled()) { - std::for_each(updateResults.begin(), updateResults.end(), [&globalVariablesInSomeUpdate] (UpdateDecisionDiagram const& update) { globalVariablesInSomeUpdate.insert(update.assignedGlobalVariables.begin(), update.assignedGlobalVariables.end()); } ); - } else { - globalVariablesInSomeUpdate = generationInfo.allGlobalVariables; - } - - // Then, multiply the missing identities. - for (auto& updateResult : updateResults) { - std::set missingIdentities; - std::set_difference(globalVariablesInSomeUpdate.begin(), globalVariablesInSomeUpdate.end(), updateResult.assignedGlobalVariables.begin(), updateResult.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity for variable " << variable.getName() << "[" << variable.getIndex() << "] to update."); - updateResult.updateDd *= generationInfo.variableToIdentityMap.at(variable); - } - } - - // Now combine the update DDs to the command DD. - storm::dd::Add commandDd = generationInfo.manager->template getAddZero(); - auto updateResultsIt = updateResults.begin(); - for (auto updateIt = command.getUpdates().begin(), updateIte = command.getUpdates().end(); updateIt != updateIte; ++updateIt, ++updateResultsIt) { - storm::dd::Add probabilityDd = generationInfo.rowExpressionAdapter->translateExpression(updateIt->getLikelihoodExpression()); - commandDd += updateResultsIt->updateDd * probabilityDd; - } - - return ActionDecisionDiagram(guard, guard * commandDd, globalVariablesInSomeUpdate); - } else { - return ActionDecisionDiagram(*generationInfo.manager); - } - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::createActionDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, uint_fast64_t synchronizationActionIndex, uint_fast64_t nondeterminismVariableOffset) { - std::vector commandDds; - for (storm::prism::Command const& command : module.getCommands()) { - - // Determine whether the command is relevant for the selected action. - bool relevant = (synchronizationActionIndex == 0 && !command.isLabeled()) || (synchronizationActionIndex && command.isLabeled() && command.getActionIndex() == synchronizationActionIndex); - - if (!relevant) { - continue; - } - - STORM_LOG_TRACE("Translating command " << command); - - // At this point, the command is known to be relevant for the action. - commandDds.push_back(createCommandDecisionDiagram(generationInfo, module, command)); - } - - ActionDecisionDiagram result(*generationInfo.manager); - if (!commandDds.empty()) { - switch (generationInfo.program.getModelType()){ - case storm::prism::Program::ModelType::DTMC: - case storm::prism::Program::ModelType::CTMC: - result = combineCommandsToActionMarkovChain(generationInfo, commandDds); - break; - case storm::prism::Program::ModelType::MDP: - result = combineCommandsToActionMDP(generationInfo, commandDds, nondeterminismVariableOffset); - break; - default: - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type."); - } - } - - return result; - } - - template - std::set DdPrismModelBuilder::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) { - // Start by gathering all variables that were written in at least one action DD. - std::set globalVariablesInActionDd; - std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(), action2.assignedGlobalVariables.end(), std::inserter(globalVariablesInActionDd, globalVariablesInActionDd.begin())); - - std::set missingIdentitiesInAction1; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction1, missingIdentitiesInAction1.begin())); - for (auto const& variable : missingIdentitiesInAction1) { - action1.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - - std::set missingIdentitiesInAction2; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction2, missingIdentitiesInAction2.begin())); - for (auto const& variable : missingIdentitiesInAction2) { - action2.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - - return globalVariablesInActionDd; - } - - template - std::set DdPrismModelBuilder::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, std::vector& actionDds) { - // Start by gathering all variables that were written in at least one action DD. - std::set globalVariablesInActionDd; - for (auto const& commandDd : actionDds) { - globalVariablesInActionDd.insert(commandDd.assignedGlobalVariables.begin(), commandDd.assignedGlobalVariables.end()); - } - - STORM_LOG_TRACE("Equalizing assigned global variables."); - - // Then multiply the transitions of each action with the missing identities. - for (auto& actionDd : actionDds) { - STORM_LOG_TRACE("Equalizing next action."); - std::set missingIdentities; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), actionDd.assignedGlobalVariables.begin(), actionDd.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of variable " << variable.getName() << "."); - actionDd.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - } - return globalVariablesInActionDd; - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineCommandsToActionMarkovChain(GenerationInformation& generationInfo, std::vector& commandDds) { - storm::dd::Add allGuards = generationInfo.manager->template getAddZero(); - storm::dd::Add allCommands = generationInfo.manager->template getAddZero(); - storm::dd::Add temporary; - - // Make all command DDs assign to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds); - - // Then combine the commands to the full action DD and multiply missing identities along the way. - for (auto& commandDd : commandDds) { - // Check for overlapping guards. - temporary = commandDd.guardDd * allGuards; - - // Issue a warning if there are overlapping guards in a non-CTMC model. - STORM_LOG_WARN_COND(temporary.isZero() || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC, "Guard of a command overlaps with previous guards."); - - allGuards += commandDd.guardDd; - allCommands += commandDd.transitionsDd; - } - - return ActionDecisionDiagram(allGuards, allCommands, assignedGlobalVariables); - } - - template - storm::dd::Add DdPrismModelBuilder::encodeChoice(GenerationInformation& generationInfo, uint_fast64_t nondeterminismVariableOffset, uint_fast64_t numberOfBinaryVariables, int_fast64_t value) { - storm::dd::Add result = generationInfo.manager->template getAddZero(); - - STORM_LOG_TRACE("Encoding " << value << " with " << numberOfBinaryVariables << " binary variable(s) starting from offset " << nondeterminismVariableOffset << "."); - - std::map metaVariableNameToValueMap; - for (uint_fast64_t i = nondeterminismVariableOffset; i < nondeterminismVariableOffset + numberOfBinaryVariables; ++i) { - if (value & (1ull << (numberOfBinaryVariables - i - 1))) { - metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 1); - } else { - metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 0); - } - } - - result.setValue(metaVariableNameToValueMap, ValueType(1)); - return result; - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineCommandsToActionMDP(GenerationInformation& generationInfo, std::vector& commandDds, uint_fast64_t nondeterminismVariableOffset) { - storm::dd::Bdd allGuards = generationInfo.manager->getBddZero(); - storm::dd::Add allCommands = generationInfo.manager->template getAddZero(); - - // Make all command DDs assign to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds); - - // Sum all guards, so we can read off the maximal number of nondeterministic choices in any given state. - storm::dd::Add sumOfGuards = generationInfo.manager->template getAddZero(); - for (auto const& commandDd : commandDds) { - sumOfGuards += commandDd.guardDd; - allGuards |= commandDd.guardDd.toBdd(); - } - uint_fast64_t maxChoices = static_cast(sumOfGuards.getMax()); - - STORM_LOG_TRACE("Found " << maxChoices << " local choices."); - - // Depending on the maximal number of nondeterminstic choices, we need to use some variables to encode the nondeterminism. - if (maxChoices == 0) { - return ActionDecisionDiagram(*generationInfo.manager); - } else if (maxChoices == 1) { - // Sum up all commands. - for (auto const& commandDd : commandDds) { - allCommands += commandDd.transitionsDd; - } - return ActionDecisionDiagram(sumOfGuards, allCommands, assignedGlobalVariables); - } else { - // Calculate number of required variables to encode the nondeterminism. - uint_fast64_t numberOfBinaryVariables = static_cast(std::ceil(storm::utility::math::log2(maxChoices))); - - storm::dd::Bdd equalsNumberOfChoicesDd; - std::vector> choiceDds(maxChoices, generationInfo.manager->template getAddZero()); - std::vector> remainingDds(maxChoices, generationInfo.manager->getBddZero()); - - for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) { - // Determine the set of states with exactly currentChoices choices. - equalsNumberOfChoicesDd = sumOfGuards.equals(generationInfo.manager->getConstant(ValueType(currentChoices))); - - // If there is no such state, continue with the next possible number of choices. - if (equalsNumberOfChoicesDd.isZero()) { - continue; - } - - // Reset the previously used intermediate storage. - for (uint_fast64_t j = 0; j < currentChoices; ++j) { - choiceDds[j] = generationInfo.manager->template getAddZero(); - remainingDds[j] = equalsNumberOfChoicesDd; - } - - for (std::size_t j = 0; j < commandDds.size(); ++j) { - // Check if command guard overlaps with equalsNumberOfChoicesDd. That is, there are states with exactly currentChoices - // choices such that one outgoing choice is given by the j-th command. - storm::dd::Bdd guardChoicesIntersection = commandDds[j].guardDd.toBdd() && equalsNumberOfChoicesDd; - - // If there is no such state, continue with the next command. - if (guardChoicesIntersection.isZero()) { - continue; - } - - // Split the nondeterministic choices. - for (uint_fast64_t k = 0; k < currentChoices; ++k) { - // Calculate the overlapping part of command guard and the remaining DD. - storm::dd::Bdd remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k]; - - // Check if we can add some overlapping parts to the current index. - if (!remainingGuardChoicesIntersection.isZero()) { - // Remove overlapping parts from the remaining DD. - remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection; - - // Combine the overlapping part of the guard with command updates and add it to the resulting DD. - choiceDds[k] += remainingGuardChoicesIntersection.template toAdd() * commandDds[j].transitionsDd; - } - - // Remove overlapping parts from the command guard DD - guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection; - - // If the guard DD has become equivalent to false, we can stop here. - if (guardChoicesIntersection.isZero()) { - break; - } - } - } - - // Add the meta variables that encode the nondeterminisim to the different choices. - for (uint_fast64_t j = 0; j < currentChoices; ++j) { - allCommands += encodeChoice(generationInfo, nondeterminismVariableOffset, numberOfBinaryVariables, j) * choiceDds[j]; - } - - // Delete currentChoices out of overlapping DD - sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd(); - } - - return ActionDecisionDiagram(allGuards.template toAdd(), allCommands, assignedGlobalVariables, nondeterminismVariableOffset + numberOfBinaryVariables); - } - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineSynchronizingActions(ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2) { - std::set assignedGlobalVariables; - std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(), action2.assignedGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin())); - return ActionDecisionDiagram(action1.guardDd * action2.guardDd, action1.transitionsDd * action2.transitionsDd, assignedGlobalVariables, std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables)); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2, storm::dd::Add const& identityDd1, storm::dd::Add const& identityDd2) { - - // First extend the action DDs by the other identities. - STORM_LOG_TRACE("Multiplying identities to combine unsynchronized actions."); - action1.transitionsDd = action1.transitionsDd * identityDd2; - action2.transitionsDd = action2.transitionsDd * identityDd1; - - // Then combine the extended action DDs. - return combineUnsynchronizedActions(generationInfo, action1, action2); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) { - STORM_LOG_TRACE("Combining unsynchronized actions."); - - // Make both action DDs write to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, action1, action2); - - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - return ActionDecisionDiagram(action1.guardDd + action2.guardDd, action1.transitionsDd + action2.transitionsDd, assignedGlobalVariables, 0); - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - if (action1.transitionsDd.isZero()) { - return ActionDecisionDiagram(action2.guardDd, action2.transitionsDd, assignedGlobalVariables, action2.numberOfUsedNondeterminismVariables); - } else if (action2.transitionsDd.isZero()) { - return ActionDecisionDiagram(action1.guardDd, action1.transitionsDd, assignedGlobalVariables, action1.numberOfUsedNondeterminismVariables); - } - - // Bring both choices to the same number of variables that encode the nondeterminism. - uint_fast64_t numberOfUsedNondeterminismVariables = std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables); - if (action1.numberOfUsedNondeterminismVariables > action2.numberOfUsedNondeterminismVariables) { - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - - for (uint_fast64_t i = action2.numberOfUsedNondeterminismVariables; i < action1.numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - action2.transitionsDd *= nondeterminismEncoding; - } else if (action2.numberOfUsedNondeterminismVariables > action1.numberOfUsedNondeterminismVariables) { - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - - for (uint_fast64_t i = action1.numberOfUsedNondeterminismVariables; i < action2.numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - action1.transitionsDd *= nondeterminismEncoding; - } - - // Add a new variable that resolves the nondeterminism between the two choices. - storm::dd::Add combinedTransitions = generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables], 1).ite(action2.transitionsDd, action1.transitionsDd); - - return ActionDecisionDiagram((action1.guardDd.toBdd() || action2.guardDd.toBdd()).template toAdd(), combinedTransitions, assignedGlobalVariables, numberOfUsedNondeterminismVariables + 1); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type."); - } - } - - template - typename DdPrismModelBuilder::ModuleDecisionDiagram DdPrismModelBuilder::createModuleDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, std::map const& synchronizingActionToOffsetMap) { - // Start by creating the action DD for the independent action. - ActionDecisionDiagram independentActionDd = createActionDecisionDiagram(generationInfo, module, 0, 0); - uint_fast64_t numberOfUsedNondeterminismVariables = independentActionDd.numberOfUsedNondeterminismVariables; - - // Create module DD for all synchronizing actions of the module. - std::map actionIndexToDdMap; - for (auto const& actionIndex : module.getSynchronizingActionIndices()) { - STORM_LOG_TRACE("Creating DD for action '" << actionIndex << "'."); - ActionDecisionDiagram tmp = createActionDecisionDiagram(generationInfo, module, actionIndex, synchronizingActionToOffsetMap.at(actionIndex)); - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, tmp.numberOfUsedNondeterminismVariables); - actionIndexToDdMap.emplace(actionIndex, tmp); - } - - return ModuleDecisionDiagram(independentActionDd, actionIndexToDdMap, generationInfo.moduleToIdentityMap.at(module.getName()), numberOfUsedNondeterminismVariables); - } - - template - storm::dd::Add DdPrismModelBuilder::getSynchronizationDecisionDiagram(GenerationInformation& generationInfo, uint_fast64_t actionIndex) { - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - if (actionIndex != 0) { - for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) { - if ((actionIndex - 1) == i) { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 1).template toAdd(); - } else { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd(); - } - } - } else { - for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd(); - } - } - return synchronization; - } - - template - storm::dd::Add DdPrismModelBuilder::createSystemFromModule(GenerationInformation& generationInfo, ModuleDecisionDiagram const& module) { - // If the model is an MDP, we need to encode the nondeterminism using additional variables. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - storm::dd::Add result = generationInfo.manager->template getAddZero(); - - // First, determine the highest number of nondeterminism variables that is used in any action and make - // all actions use the same amout of nondeterminism variables. - uint_fast64_t numberOfUsedNondeterminismVariables = module.numberOfUsedNondeterminismVariables; - - // Compute missing global variable identities in independent action. - std::set missingIdentities; - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - storm::dd::Add identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - // Add variables to independent action DD. - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - for (uint_fast64_t i = module.independentAction.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - result = identityEncoding * module.independentAction.transitionsDd * nondeterminismEncoding; - - // Add variables to synchronized action DDs. - std::map> synchronizingActionToDdMap; - for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) { - // Compute missing global variable identities in synchronizing actions. - missingIdentities = std::set(); - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first << "'."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - nondeterminismEncoding = generationInfo.manager->template getAddOne(); - for (uint_fast64_t i = synchronizingAction.second.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - synchronizingActionToDdMap.emplace(synchronizingAction.first, identityEncoding * synchronizingAction.second.transitionsDd * nondeterminismEncoding); - } - - // Add variables for synchronization. - result *= getSynchronizationDecisionDiagram(generationInfo); - - for (auto& synchronizingAction : synchronizingActionToDdMap) { - synchronizingAction.second *= getSynchronizationDecisionDiagram(generationInfo, synchronizingAction.first); - } - - // Now, we can simply add all synchronizing actions to the result. - for (auto const& synchronizingAction : synchronizingActionToDdMap) { - result += synchronizingAction.second; - } - - return result; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - // Simply add all actions, but make sure to include the missing global variable identities. - - // Compute missing global variable identities in independent action. - std::set missingIdentities; - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - storm::dd::Add identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - storm::dd::Add result = identityEncoding * module.independentAction.transitionsDd; - - for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) { - // Compute missing global variable identities in synchronizing actions. - missingIdentities = std::set(); - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first << "'."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - result += identityEncoding * synchronizingAction.second.transitionsDd; - } - return result; - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type."); - } - } - - template - typename DdPrismModelBuilder::SystemResult DdPrismModelBuilder::createSystemDecisionDiagram(GenerationInformation& generationInfo) { - ModuleComposer composer(generationInfo); - ModuleDecisionDiagram system = composer.compose(generationInfo.program.specifiesSystemComposition() ? generationInfo.program.getSystemCompositionConstruct().getSystemComposition() : *generationInfo.program.getDefaultSystemComposition()); - - storm::dd::Add result = createSystemFromModule(generationInfo, system); - - // Create an auxiliary DD that is used later during the construction of reward models. - STORM_LOG_TRACE("Counting: " << result.getNonZeroCount() << " // " << result.getNodeCount()); - storm::dd::Add stateActionDd = result.sumAbstract(generationInfo.columnMetaVariables); - - // For DTMCs, we normalize each row to 1 (to account for non-determinism). - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - result = result / stateActionDd; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - // For MDPs, we need to throw away the nondeterminism variables from the generation information that - // were never used. - for (uint_fast64_t index = system.numberOfUsedNondeterminismVariables; index < generationInfo.nondeterminismMetaVariables.size(); ++index) { - generationInfo.allNondeterminismVariables.erase(generationInfo.nondeterminismMetaVariables[index]); - } - generationInfo.nondeterminismMetaVariables.resize(system.numberOfUsedNondeterminismVariables); - } - - return SystemResult(result, system, stateActionDd); - } - - template - storm::models::symbolic::StandardRewardModel DdPrismModelBuilder::createRewardModelDecisionDiagrams(GenerationInformation& generationInfo, storm::prism::RewardModel const& rewardModel, ModuleDecisionDiagram const& globalModule, storm::dd::Add const& reachableStatesAdd, storm::dd::Add const& stateActionDd) { - - // Start by creating the state reward vector. - boost::optional> stateRewards; - if (rewardModel.hasStateRewards()) { - stateRewards = generationInfo.manager->template getAddZero(); - - for (auto const& stateReward : rewardModel.getStateRewards()) { - storm::dd::Add states = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getRewardValueExpression()); - - // Restrict the rewards to those states that satisfy the condition. - rewards = reachableStatesAdd * states * rewards; - - // Perform some sanity checks. - STORM_LOG_WARN_COND(rewards.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!rewards.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global state reward vector. - stateRewards.get() += rewards; - } - } - - // Next, build the state-action reward vector. - boost::optional> stateActionRewards; - if (rewardModel.hasStateActionRewards()) { - stateActionRewards = generationInfo.manager->template getAddZero(); - - for (auto const& stateActionReward : rewardModel.getStateActionRewards()) { - storm::dd::Add states = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getRewardValueExpression()); - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo, stateActionReward.getActionIndex()); - } - ActionDecisionDiagram const& actionDd = stateActionReward.isLabeled() ? globalModule.synchronizingActionToDecisionDiagramMap.at(stateActionReward.getActionIndex()) : globalModule.independentAction; - states *= actionDd.guardDd * reachableStatesAdd; - storm::dd::Add stateActionRewardDd = synchronization * states * rewards; - - // If we are building the state-action rewards for an MDP, we need to make sure that the encoding - // of the nondeterminism is present in the reward vector, so we ne need to multiply it with the - // legal state-actions. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - stateActionRewardDd *= stateActionDd; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - // For CTMCs, we need to multiply the entries with the exit rate of the corresponding action. - stateActionRewardDd *= actionDd.transitionsDd.sumAbstract(generationInfo.columnMetaVariables); - } - - // Perform some sanity checks. - STORM_LOG_WARN_COND(stateActionRewardDd.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!stateActionRewardDd.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global transition reward matrix. - stateActionRewards.get() += stateActionRewardDd; - } - - // Scale state-action rewards for DTMCs and CTMCs. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - stateActionRewards.get() /= stateActionDd; - } - } - - // Then build the transition reward matrix. - boost::optional> transitionRewards; - if (rewardModel.hasTransitionRewards()) { - transitionRewards = generationInfo.manager->template getAddZero(); - - for (auto const& transitionReward : rewardModel.getTransitionRewards()) { - storm::dd::Add sourceStates = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getSourceStatePredicateExpression()); - storm::dd::Add targetStates = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getTargetStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getRewardValueExpression()); - - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - - storm::dd::Add transitions; - if (transitionReward.isLabeled()) { - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo, transitionReward.getActionIndex()); - } - transitions = globalModule.synchronizingActionToDecisionDiagramMap.at(transitionReward.getActionIndex()).transitionsDd; - } else { - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo); - } - transitions = globalModule.independentAction.transitionsDd; - } - - storm::dd::Add transitionRewardDd = synchronization * sourceStates * targetStates * rewards; - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - // For DTMCs we need to keep the weighting for the scaling that follows. - transitionRewardDd = transitions * transitionRewardDd; - } else { - // For all other model types, we do not scale the rewards. - transitionRewardDd = transitions.notZero().template toAdd() * transitionRewardDd; - } - - // Perform some sanity checks. - STORM_LOG_WARN_COND(transitionRewardDd.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!transitionRewardDd.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global transition reward matrix. - transitionRewards.get() += transitionRewardDd; - } - - // Scale transition rewards for DTMCs. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - transitionRewards.get() /= stateActionDd; - } - } - - return storm::models::symbolic::StandardRewardModel(stateRewards, stateActionRewards, transitionRewards); - } - - template - std::shared_ptr> DdPrismModelBuilder::build(storm::prism::Program const& program, Options const& options) { - if (program.hasUndefinedConstants()) { - std::vector> undefinedConstants = program.getUndefinedConstants(); - std::stringstream stream; - bool printComma = false; - for (auto const& constant : undefinedConstants) { - if (printComma) { - stream << ", "; - } else { - printComma = true; - } - stream << constant.get().getName() << " (" << constant.get().getType() << ")"; - } - stream << "."; - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); - } - - STORM_LOG_TRACE("Building representation of program:" << std::endl << program << std::endl); - - // Start by initializing the structure used for storing all information needed during the model generation. - // In particular, this creates the meta variables used to encode the model. - GenerationInformation generationInfo(program); - - SystemResult system = createSystemDecisionDiagram(generationInfo); - storm::dd::Add transitionMatrix = system.allTransitionsDd; - - ModuleDecisionDiagram const& globalModule = system.globalModule; - storm::dd::Add stateActionDd = system.stateActionDd; - - // If we were asked to treat some states as terminal states, we cut away their transitions now. - storm::dd::Bdd terminalStatesBdd = generationInfo.manager->getBddZero(); - if (options.terminalStates || options.negatedTerminalStates) { - std::map constantsSubstitution = program.getConstantsSubstitution(); - - if (options.terminalStates) { - storm::expressions::Expression terminalExpression; - if (options.terminalStates.get().type() == typeid(storm::expressions::Expression)) { - terminalExpression = boost::get(options.terminalStates.get()); - } else { - std::string const& labelName = boost::get(options.terminalStates.get()); - if (program.hasLabel(labelName)) { - terminalExpression = program.getLabelExpression(labelName); - } else { - STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); - } - } - - if (terminalExpression.isInitialized()) { - // If the expression refers to constants of the model, we need to substitute them. - terminalExpression = terminalExpression.substitute(constantsSubstitution); - - STORM_LOG_TRACE("Making the states satisfying " << terminalExpression << " terminal."); - terminalStatesBdd = generationInfo.rowExpressionAdapter->translateExpression(terminalExpression).toBdd(); - } - } - if (options.negatedTerminalStates) { - storm::expressions::Expression negatedTerminalExpression; - if (options.negatedTerminalStates.get().type() == typeid(storm::expressions::Expression)) { - negatedTerminalExpression = boost::get(options.negatedTerminalStates.get()); - } else { - std::string const& labelName = boost::get(options.negatedTerminalStates.get()); - if (program.hasLabel(labelName)) { - negatedTerminalExpression = program.getLabelExpression(labelName); - } else { - STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); - } - } - - if (negatedTerminalExpression.isInitialized()) { - // If the expression refers to constants of the model, we need to substitute them. - negatedTerminalExpression = negatedTerminalExpression.substitute(constantsSubstitution); - - STORM_LOG_TRACE("Making the states *not* satisfying " << negatedTerminalExpression << " terminal."); - terminalStatesBdd |= !generationInfo.rowExpressionAdapter->translateExpression(negatedTerminalExpression).toBdd(); - } - } - - transitionMatrix *= (!terminalStatesBdd).template toAdd(); - } - - std::cout << "trans matrix has size " << transitionMatrix.getNodeCount() << std::endl; - - // Cut the transitions and rewards to the reachable fragment of the state space. - storm::dd::Bdd initialStates = createInitialStatesDecisionDiagram(generationInfo); - - storm::dd::Bdd transitionMatrixBdd = transitionMatrix.notZero(); - if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - transitionMatrixBdd = transitionMatrixBdd.existsAbstract(generationInfo.allNondeterminismVariables); - } - - storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionMatrixBdd, generationInfo.rowMetaVariables, generationInfo.columnMetaVariables); - storm::dd::Add reachableStatesAdd = reachableStates.template toAdd(); - transitionMatrix *= reachableStatesAdd; - stateActionDd *= reachableStatesAdd; - - // Detect deadlocks and 1) fix them if requested 2) throw an error otherwise. - storm::dd::Bdd statesWithTransition = transitionMatrixBdd.existsAbstract(generationInfo.columnMetaVariables); - storm::dd::Bdd deadlockStates = reachableStates && !statesWithTransition; - - // If there are deadlocks, either fix them or raise an error. - if (!deadlockStates.isZero()) { - // If we need to fix deadlocks, we do so now. - if (!storm::settings::getModule().isDontFixDeadlocksSet()) { - STORM_LOG_INFO("Fixing deadlocks in " << deadlockStates.getNonZeroCount() << " states. The first three of these states are: "); - - storm::dd::Add deadlockStatesAdd = deadlockStates.template toAdd(); - uint_fast64_t count = 0; - for (auto it = deadlockStatesAdd.begin(), ite = deadlockStatesAdd.end(); it != ite && count < 3; ++it, ++count) { - STORM_LOG_INFO((*it).first.toPrettyString(generationInfo.rowMetaVariables) << std::endl); - } - - if (program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC) { - storm::dd::Add identity = globalModule.identity; - - // Make sure that global variables do not change along the introduced self-loops. - for (auto const& var : generationInfo.allGlobalVariables) { - identity *= generationInfo.variableToIdentityMap.at(var); - } - - // For DTMCs, we can simply add the identity of the global module for all deadlock states. - transitionMatrix += deadlockStatesAdd * identity; - } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - // For MDPs, however, we need to select an action associated with the self-loop, if we do not - // want to attach a lot of self-loops to the deadlock states. - storm::dd::Add action = generationInfo.manager->template getAddOne(); - for (auto const& metaVariable : generationInfo.allNondeterminismVariables) { - action *= generationInfo.manager->template getIdentity(metaVariable); - } - // Make sure that global variables do not change along the introduced self-loops. - for (auto const& var : generationInfo.allGlobalVariables) { - action *= generationInfo.variableToIdentityMap.at(var); - } - transitionMatrix += deadlockStatesAdd * globalModule.identity * action; - } - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The model contains " << deadlockStates.getNonZeroCount() << " deadlock states. Please unset the option to not fix deadlocks, if you want to fix them automatically."); - } - } - - // Reduce the deadlock states by the states that we did simply not explore. - deadlockStates = deadlockStates && !terminalStatesBdd; - - // Now build the reward models. - std::vector> selectedRewardModels; - - // First, we make sure that all selected reward models actually exist. - for (auto const& rewardModelName : options.rewardModelsToBuild) { - STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); - } - - for (auto const& rewardModel : program.getRewardModels()) { - if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) { - std::cout << "build all? " << buildAllRewardModels << std::endl; - selectedRewardModels.push_back(rewardModel); - } - } - // If no reward model was selected until now and a referenced reward model appears to be unique, we build - // the only existing reward model (given that no explicit name was given for the referenced reward model). - if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { - selectedRewardModels.push_back(program.getRewardModel(0)); - } - - std::unordered_map> rewardModels; - for (auto const& rewardModel : selectedRewardModels) { - rewardModels.emplace(rewardModel.get().getName(), createRewardModelDecisionDiagrams(generationInfo, rewardModel.get(), globalModule, reachableStatesAdd, stateActionDd)); - } - - // Build the labels that can be accessed as a shortcut. - std::map labelToExpressionMapping; - for (auto const& label : program.getLabels()) { - labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression()); - } - - if (program.getModelType() == storm::prism::Program::ModelType::DTMC) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping, rewardModels)); - } else if (program.getModelType() == storm::prism::Program::ModelType::CTMC) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping, rewardModels)); - } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, generationInfo.allNondeterminismVariables, labelToExpressionMapping, rewardModels)); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Invalid model type."); - } - } - - template - storm::dd::Bdd DdPrismModelBuilder::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) { - storm::dd::Bdd initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialStatesExpression()).toBdd(); - - for (auto const& metaVariable : generationInfo.rowMetaVariables) { - initialStates &= generationInfo.manager->getRange(metaVariable); - } - - return initialStates; - } - - // Explicitly instantiate the symbolic model builder. - template class DdPrismModelBuilder; - template class DdPrismModelBuilder; - - } // namespace adapters -} // namespace storm - - From 2ba70e964c24e91f3b7834344f8b299eaf1f4c8b Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 18 May 2018 13:45:25 +0200 Subject: [PATCH 298/647] Added hasParameters() and supportsParameters() for symbolic models --- src/storm/models/sparse/Model.cpp | 4 ---- src/storm/models/symbolic/Model.cpp | 21 +++++++++++++++++++++ src/storm/models/symbolic/Model.h | 10 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/storm/models/sparse/Model.cpp b/src/storm/models/sparse/Model.cpp index 4bece4dcf..9ee91b5dd 100644 --- a/src/storm/models/sparse/Model.cpp +++ b/src/storm/models/sparse/Model.cpp @@ -423,11 +423,7 @@ namespace storm { template bool Model::supportsParameters() const { -#ifdef STORM_HAVE_CARL return std::is_same::value; -#else - return false; -#endif } template diff --git a/src/storm/models/symbolic/Model.cpp b/src/storm/models/symbolic/Model.cpp index ee90118cb..f7a9f367f 100644 --- a/src/storm/models/symbolic/Model.cpp +++ b/src/storm/models/symbolic/Model.cpp @@ -15,6 +15,7 @@ #include "storm/models/symbolic/StandardRewardModel.h" +#include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/utility/dd.h" @@ -362,6 +363,26 @@ namespace storm { bool Model::isSymbolicModel() const { return true; } + + template + bool Model::supportsParameters() const { + return std::is_same::value; + } + + template + bool Model::hasParameters() const { + if (!this->supportsParameters()) { + return false; + } + // Check for parameters + for (auto it = this->getTransitionMatrix().begin(false); it != this->getTransitionMatrix().end(); ++it) { + if (!storm::utility::isConstant((*it).second)) { + return true; + } + } + // Only constant values present + return false; + } template void Model::addParameters(std::set const& parameters) { diff --git a/src/storm/models/symbolic/Model.h b/src/storm/models/symbolic/Model.h index 1dca3dc6d..7b3500bd1 100644 --- a/src/storm/models/symbolic/Model.h +++ b/src/storm/models/symbolic/Model.h @@ -321,6 +321,16 @@ namespace storm { virtual bool isSymbolicModel() const override; + virtual bool supportsParameters() const override; + + /*! + * Checks whether the model has parameters. + * Performance warning: the worst-case complexity is linear in the number of transitions. + * + * @return True iff the model has parameters. + */ + virtual bool hasParameters() const override; + std::vector getLabels() const; void addParameters(std::set const& parameters); From 77179c02ac8fcfaa553093eeecc9ed369d1f809a Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 18 May 2018 15:01:29 +0200 Subject: [PATCH 299/647] added option to feed additional constraints to abstraction --- .../abstraction/AbstractionInformation.cpp | 30 ++++++++++++++++++- src/storm/abstraction/StateSetAbstractor.cpp | 4 +++ .../abstraction/GameBasedMdpModelChecker.cpp | 6 ++-- src/storm/parser/ExpressionCreator.cpp | 11 ++++--- src/storm/parser/ExpressionCreator.h | 6 +--- src/storm/parser/ExpressionParser.cpp | 6 +++- src/storm/parser/ExpressionParser.h | 4 ++- .../settings/modules/AbstractionSettings.cpp | 14 +++++++++ .../settings/modules/AbstractionSettings.h | 15 ++++++++++ src/storm/settings/modules/IOSettings.h | 4 +-- .../storage/SymbolicModelDescription.cpp | 24 +++++++++++++++ src/storm/storage/SymbolicModelDescription.h | 2 ++ 12 files changed, 110 insertions(+), 16 deletions(-) diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 5c5737f89..e9cb479a6 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -1,9 +1,16 @@ #include "storm/abstraction/AbstractionInformation.h" +#include + #include "storm/storage/BitVector.h" #include "storm/storage/dd/DdManager.h" +#include "storm/settings/modules/AbstractionSettings.h" +#include "storm/settings/SettingsManager.h" + +#include "storm/parser/ExpressionParser.h" + #include "storm/utility/macros.h" #include "storm/exceptions/InvalidOperationException.h" @@ -15,7 +22,28 @@ namespace storm { template AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), abstractedVariables(abstractedVariables), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()), allLocationIdentities(ddManager->getBddOne()), expressionToBddMap() { - // Intentionally left empty. + + // Obtain additional constraints from the settings. + auto const& settings = storm::settings::getModule(); + if (settings.isConstraintsSet()) { + std::string constraintsString = settings.getConstraintString(); + + std::vector constraintsAsStrings; + boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(",")); + + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + for (auto const& constraintString : constraintsAsStrings) { + storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString); + STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << "."); + constraints.emplace_back(constraint); + } + } } template diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index 86a3b8412..e115aa28d 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -16,6 +16,10 @@ namespace storm { template StateSetAbstractor::StateSetAbstractor(AbstractionInformation& abstractionInformation, std::vector const& statePredicates, std::shared_ptr const& smtSolverFactory) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), localExpressionInformation(abstractionInformation), relevantPredicatesAndVariables(), concretePredicateVariables(), forceRecomputation(true), cachedBdd(abstractionInformation.getDdManager().getBddOne()), constraint(abstractionInformation.getDdManager().getBddOne()) { + for (auto const& constraint : abstractionInformation.getConstraints()) { + smtSolver->add(constraint); + } + // Assert all state predicates. for (auto const& predicate : statePredicates) { smtSolver->add(predicate); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index e6eab03dc..7c626b093 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -58,7 +58,9 @@ namespace storm { template GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { - model.requireNoUndefinedConstants(); + + STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants. Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); + if (model.isPrismProgram()) { storm::prism::Program const& originalProgram = model.asPrismProgram(); STORM_LOG_THROW(originalProgram.getModelType() == storm::prism::Program::ModelType::DTMC || originalProgram.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::NotSupportedException, "Currently only DTMCs/MDPs are supported by the game-based model checker."); @@ -566,7 +568,7 @@ namespace storm { // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); - STORM_LOG_THROW(initialStates.getNonZeroCount() == 1 || checkTask.isBoundSet(), storm::exceptions::InvalidPropertyException, "Game-based abstraction refinement requires a bound on the formula for model with " << initialStates.getNonZeroCount() << " initial states."); +// STORM_LOG_THROW(initialStates.getNonZeroCount() == 1 || checkTask.isBoundSet(), storm::exceptions::InvalidPropertyException, "Game-based abstraction refinement requires a bound on the formula for model with " << initialStates.getNonZeroCount() << " initial states."); storm::dd::Bdd constraintStates = globalConstraintStates && game.getReachableStates(); storm::dd::Bdd targetStates = globalTargetStates && game.getReachableStates(); if (player1Direction == storm::OptimizationDirection::Minimize) { diff --git a/src/storm/parser/ExpressionCreator.cpp b/src/storm/parser/ExpressionCreator.cpp index b96dd5080..682342e29 100644 --- a/src/storm/parser/ExpressionCreator.cpp +++ b/src/storm/parser/ExpressionCreator.cpp @@ -16,6 +16,12 @@ namespace storm { // Intenetionally left empty. } + ExpressionCreator::~ExpressionCreator() { + if (deleteIdentifierMapping) { + delete this->identifiers; + } + } + storm::expressions::Expression ExpressionCreator::createIteExpression(storm::expressions::Expression const& e1, storm::expressions::Expression const& e2, storm::expressions::Expression const& e3, bool& pass) const { if (this->createExpressions) { try { @@ -241,7 +247,7 @@ namespace storm { void ExpressionCreator::setIdentifierMapping(std::unordered_map const& identifierMapping) { unsetIdentifierMapping(); - createExpressions =true; + createExpressions = true; identifiers = new qi::symbols(); for (auto const& identifierExpressionPair : identifierMapping) { identifiers->add(identifierExpressionPair.first, identifierExpressionPair.second); @@ -257,9 +263,6 @@ namespace storm { } this->identifiers = nullptr; } - - - } } diff --git a/src/storm/parser/ExpressionCreator.h b/src/storm/parser/ExpressionCreator.h index 20bcc5854..cdf36c1fc 100644 --- a/src/storm/parser/ExpressionCreator.h +++ b/src/storm/parser/ExpressionCreator.h @@ -19,11 +19,7 @@ namespace storm { public: ExpressionCreator(storm::expressions::ExpressionManager const& manager); - virtual ~ExpressionCreator() { - if (deleteIdentifierMapping) { - delete this->identifiers; - } - } + ~ExpressionCreator(); /*! * Sets an identifier mapping that is used to determine valid variables in the expression. The mapped-to diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm/parser/ExpressionParser.cpp index 5d824d82d..eec7e8349 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm/parser/ExpressionParser.cpp @@ -38,7 +38,7 @@ namespace storm { namespace parser { ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerModuloOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerModuloOperator_(), invalidIdentifiers_(invalidIdentifiers_) { - expressionCreator = new ExpressionCreator(manager); + expressionCreator = std::make_unique(manager); identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_') | qi::char_('.')) >> *(qi::alnum | qi::char_('_')))]]][qi::_pass = phoenix::bind(&ExpressionParser::isValidIdentifier, phoenix::ref(*this), qi::_1)]; identifier.name("identifier"); @@ -176,6 +176,10 @@ namespace storm { } } + ExpressionParser::~ExpressionParser() { + // Needed, because auto-generated destructor requires ExpressionCreator to be a complete type in the header. + } + void ExpressionParser::setIdentifierMapping(qi::symbols const* identifiers_) { expressionCreator->setIdentifierMapping(identifiers_); } diff --git a/src/storm/parser/ExpressionParser.h b/src/storm/parser/ExpressionParser.h index cb415c53e..d92de1e74 100644 --- a/src/storm/parser/ExpressionParser.h +++ b/src/storm/parser/ExpressionParser.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "storm/parser/SpiritParserDefinitions.h" #include "storm/parser/SpiritErrorHandler.h" @@ -46,6 +47,7 @@ namespace storm { * also parses boolean conjuncts that are erroneously consumed by the expression parser. */ ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_ = qi::symbols(), bool enableErrorHandling = true, bool allowBacktracking = false); + ~ExpressionParser(); ExpressionParser(ExpressionParser const& other) = default; ExpressionParser& operator=(ExpressionParser const& other) = default; @@ -207,7 +209,7 @@ namespace storm { prefixPowerModuloOperatorStruct prefixPowerModuloOperator_; - ExpressionCreator* expressionCreator; + std::unique_ptr expressionCreator; // The symbol table of invalid identifiers. diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 404298782..fccd65722 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -25,6 +25,7 @@ namespace storm { const std::string AbstractionSettings::solveModeOptionName = "solve"; const std::string AbstractionSettings::maximalAbstractionOptionName = "maxabs"; const std::string AbstractionSettings::rankRefinementPredicatesOptionName = "rankpred"; + const std::string AbstractionSettings::constraintsOptionName = "constraints"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -86,6 +87,11 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("off").build()) .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, constraintsOptionName, true, "Specifies additional constraints used by the abstraction.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").build()) + .build()); + } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -176,6 +182,14 @@ namespace storm { return this->getOption(rankRefinementPredicatesOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isConstraintsSet() const { + return this->getOption(constraintsOptionName).getHasOptionBeenSet(); + } + + std::string AbstractionSettings::getConstraintString() const { + return this->getOption(constraintsOptionName).getArgumentByName("constraints").getValueAsString(); + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 7fe212fbd..7cd950042 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -123,6 +123,20 @@ namespace storm { */ bool isRankRefinementPredicatesSet() const; + /*! + * Retrieves whether the constraints option was set. + * + * @return True if the constraints option was set. + */ + bool isConstraintsSet() const; + + /*! + * Retrieves the string that specifies additional constraints. + * + * @return The string that defines the constraints. + */ + std::string getConstraintString() const; + const static std::string moduleName; private: @@ -138,6 +152,7 @@ namespace storm { const static std::string solveModeOptionName; const static std::string maximalAbstractionOptionName; const static std::string rankRefinementPredicatesOptionName; + const static std::string constraintsOptionName; }; } diff --git a/src/storm/settings/modules/IOSettings.h b/src/storm/settings/modules/IOSettings.h index cc41176bf..7371cda76 100644 --- a/src/storm/settings/modules/IOSettings.h +++ b/src/storm/settings/modules/IOSettings.h @@ -214,9 +214,9 @@ namespace storm { std::string getChoiceLabelingFilename() const; /*! - * Retrieves whether the export-to-dot option was set. + * Retrieves whether the constants option was set. * - * @return True if the export-to-dot option was set. + * @return True if the constants option was set. */ bool isConstantsSet() const; diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index b08166125..d5387d73e 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -179,6 +179,30 @@ namespace storm { } } + bool SymbolicModelDescription::hasUndefinedConstants() const { + if (this->isPrismProgram()) { + return this->asPrismProgram().hasUndefinedConstants(); + } else { + return this->asJaniModel().hasUndefinedConstants(); + } + } + + std::vector SymbolicModelDescription::getUndefinedConstants() const { + std::vector result; + if (this->isPrismProgram()) { + std::vector> constants = this->asPrismProgram().getUndefinedConstants(); + for (auto const& constant : constants) { + result.emplace_back(constant.get().getExpressionVariable()); + } + } else { + std::vector> constants = this->asJaniModel().getUndefinedConstants(); + for (auto const& constant : constants) { + result.emplace_back(constant.get().getExpressionVariable()); + } + } + return result; + } + std::ostream& operator<<(std::ostream& out, SymbolicModelDescription const& model) { if (model.isPrismProgram()) { out << model.asPrismProgram(); diff --git a/src/storm/storage/SymbolicModelDescription.h b/src/storm/storage/SymbolicModelDescription.h index 137f1a7d4..c83f36358 100644 --- a/src/storm/storage/SymbolicModelDescription.h +++ b/src/storm/storage/SymbolicModelDescription.h @@ -47,6 +47,8 @@ namespace storm { std::map parseConstantDefinitions(std::string const& constantDefinitionString) const; void requireNoUndefinedConstants() const; + bool hasUndefinedConstants() const; + std::vector getUndefinedConstants() const; private: boost::optional> modelDescription; From f1c2cf985a1bb72166b4e1260b21cd7aaa781e73 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 18 May 2018 16:32:12 +0200 Subject: [PATCH 300/647] turned some debug output in game-based model checker to regular (verbose) output --- .../abstraction/GameBasedMdpModelChecker.cpp | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 7c626b093..c6fd3cf6b 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -57,7 +57,7 @@ namespace storm { using detail::PreviousExplicitResult; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants. Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); @@ -73,7 +73,7 @@ namespace storm { preprocessedModel = originalProgram; } auto flattenEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Flattened model in " << std::chrono::duration_cast(flattenEnd - flattenStart).count() << "ms."); + STORM_LOG_INFO("Flattened model in " << std::chrono::duration_cast(flattenEnd - flattenStart).count() << "ms."); STORM_LOG_TRACE("Game-based model checker got program " << preprocessedModel.asPrismProgram()); } else { @@ -564,7 +564,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -595,7 +595,7 @@ namespace storm { } auto iterationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); + STORM_LOG_INFO("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); } // If this point is reached, we have given up on abstraction. @@ -620,7 +620,7 @@ namespace storm { } previousQualitativeResult = qualitativeResult; auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); + STORM_LOG_INFO("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); // (2) compute the states for which we have to determine quantitative information. storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); @@ -633,14 +633,14 @@ namespace storm { // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. STORM_LOG_TRACE("No initial state is a 'maybe' state."); - STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); } else if (initialMaybeStates == initialStates && checkTask.isQualitativeSet()) { // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, // we can return the result here. @@ -674,7 +674,7 @@ namespace storm { } auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); @@ -694,7 +694,7 @@ namespace storm { // information about the game, but we could not yet answer the query. In this case, we need to refine. refiner.refine(game, transitionMatrixBdd, quantitativeResult); auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + STORM_LOG_INFO("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); } // Return null to indicate no result has been found yet. @@ -759,7 +759,7 @@ namespace storm { storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); auto translationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Translation to explicit representation completed in " << std::chrono::duration_cast(translationEnd - translationStart).count() << "ms."); + STORM_LOG_INFO("Translation to explicit representation completed in " << std::chrono::duration_cast(translationEnd - translationStart).count() << "ms."); // Prepare the two strategies. abstraction::ExplicitGameStrategyPair minStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); @@ -773,7 +773,7 @@ namespace storm { return result; } auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); + STORM_LOG_INFO("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); // (2) compute the states for which we have to determine quantitative information. storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()); @@ -786,14 +786,14 @@ namespace storm { // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. STORM_LOG_TRACE("No initial state is a 'maybe' state."); - STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); qualitativeRefinement = refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); } else if (initialStates.isSubsetOf(initialMaybeStates) && checkTask.isQualitativeSet()) { // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, // we can return the result here. @@ -822,7 +822,7 @@ namespace storm { return result; } auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.getMin().getRange(initialStates).first, quantitativeResult.getMax().getRange(initialStates).second, comparator); @@ -839,7 +839,7 @@ namespace storm { // information about the game, but we could not yet answer the query. In this case, we need to refine. refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + STORM_LOG_INFO("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); if (this->reuseQuantitativeResults) { PreviousExplicitResult nextPreviousResult; @@ -940,8 +940,8 @@ namespace storm { result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); - STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); - STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); return result; } @@ -1002,8 +1002,8 @@ namespace storm { result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); } - STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); - STORM_LOG_DEBUG("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); STORM_LOG_ASSERT(checkQualitativeStrategies(result, targetStates), "Qualitative strategies appear to be broken."); return result; From 08dd8f7b7caf4661996a3a33caa35afad540b808 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 18 May 2018 16:33:28 +0200 Subject: [PATCH 301/647] some fixes to make gcc happy --- .../abstraction/ExplicitGameStrategy.cpp | 3 ++ .../ExplicitQuantiativeResultMinMax.cpp | 48 ------------------- 2 files changed, 3 insertions(+), 48 deletions(-) delete mode 100644 src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp diff --git a/src/storm/abstraction/ExplicitGameStrategy.cpp b/src/storm/abstraction/ExplicitGameStrategy.cpp index 29748aa92..4445d697f 100644 --- a/src/storm/abstraction/ExplicitGameStrategy.cpp +++ b/src/storm/abstraction/ExplicitGameStrategy.cpp @@ -1,5 +1,8 @@ #include "storm/abstraction/ExplicitGameStrategy.h" +#include +#include + namespace storm { namespace abstraction { diff --git a/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp deleted file mode 100644 index 35237f4d5..000000000 --- a/src/storm/abstraction/ExplicitQuantiativeResultMinMax.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" - -namespace storm { - namespace abstraction { - - template - ExplicitQuantitativeResultMinMax::ExplicitQuantitativeResultMinMax(uint64_t numberOfStates) = default; - - template - ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMin() const { - return min; - } - - template - ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMin() { - return min; - } - - template - ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMax() const { - return max; - } - - template - ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMax() { - return max; - } - - template - ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) const { - if (dir == storm::OptimizationDirection::Minimize) { - return this->getMin(); - } else { - return this->getMax(); - } - } - - template - ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) { - if (dir == storm::OptimizationDirection::Minimize) { - return this->getMin(); - } else { - return this->getMax(); - } - } - - } -} From 7d8e9aa5d44604e6e6ec52c5b9317588f7b97eaf Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 19 May 2018 08:30:25 +0200 Subject: [PATCH 302/647] adding more output infos for game-based --- src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp | 2 +- src/storm/abstraction/prism/PrismMenuGameAbstractor.h | 2 +- src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index ffa590a57..be4e33d8e 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -275,7 +275,7 @@ namespace storm { automaton.notifyGuardsArePredicates(); } } - + // Explicitly instantiate the class. template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 5815c915a..a9ef79413 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -124,7 +124,7 @@ namespace storm { virtual void addTerminalStates(storm::expressions::Expression const& expression) override; virtual void notifyGuardsArePredicates() override; - + protected: using MenuGameAbstractor::exportToDot; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index c6fd3cf6b..2b545a54b 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -564,7 +564,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicates << (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); From f9d23873f1925fd88e55bd9c3fb0ee0a1016815a Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 20 May 2018 20:52:51 +0200 Subject: [PATCH 303/647] fixed minor bug in game-based abstraction --- .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 2b545a54b..eadaccead 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -641,10 +641,6 @@ namespace storm { qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); - } else if (initialMaybeStates == initialStates && checkTask.isQualitativeSet()) { - // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, - // we can return the result here. - return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); } // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. From 9e0d88e2122ba9c3d9b09a34a024745335f28d29 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 20 May 2018 21:52:44 +0200 Subject: [PATCH 304/647] overhauled output slightly --- src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index eadaccead..ce44a1db9 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -564,7 +564,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicates << (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); From 94a5a3da7c3638735fc3c334147ae852c0099919 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 22 May 2018 21:00:00 +0200 Subject: [PATCH 305/647] remove ffast-math --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5c8aa732..d4c789dd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") set(STORM_COMPILER_APPLECLANG ON) set(CLANG ON) set(STORM_COMPILER_ID "AppleClang") - set(CMAKE_MACOSX_RPATH ON) + set(CMAKE_MACOSX_RPATH ON) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(GCC ON) # using GCC @@ -223,16 +223,16 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG) if(FORCE_COLOR) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics") endif() - + if (LINUX) set(CLANG_STDLIB libstdc++) else() set(CLANG_STDLIB libc++) endif() - + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -stdlib=${CLANG_STDLIB} -ftemplate-depth=1024") - set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -fno-finite-math-only") - + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + if(LINUX) set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") @@ -242,20 +242,20 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG) endif() elseif (STORM_COMPILER_GCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays -ffast-math -fno-finite-math-only") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") endif () if (STORM_USE_LTO) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") - + # Fix for problems that occurred when using LTO on gcc. This should be removed when it # is not needed anymore as it makes the the already long link-step potentially longer. if (STORM_COMPILER_GCC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto-partition=none") endif() - + message(STATUS "Storm - Enabling link-time optimizations.") else() message(STATUS "Storm - Disabling link-time optimizations.") From 03707f0234f1d6b3f77ca080fbe0149afecccf83 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 22 May 2018 21:49:39 +0200 Subject: [PATCH 306/647] first step for fixing MEC decomposition: making SCC decomposition accept a bit vector of subsystem choices --- ...tronglyConnectedComponentDecomposition.cpp | 121 ++++++++++++------ .../StronglyConnectedComponentDecomposition.h | 24 +++- 2 files changed, 103 insertions(+), 42 deletions(-) diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index f6567985c..9eae9d05a 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -23,30 +23,35 @@ namespace storm { template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) { storm::storage::BitVector subsystem(model.getNumberOfStates(), block.begin(), block.end()); - performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } template template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) { storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end()); - performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, nullptr, nullptr, dropNaiveSccs, onlyBottomSccs); } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); + } + + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) { + performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs); } template @@ -72,7 +77,10 @@ namespace storm { } template - void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { + void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs) { + + STORM_LOG_ASSERT(!choices || subsystem, "Expecting subsystem if choices are given."); + uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); // Set up the environment of the algorithm. @@ -94,16 +102,30 @@ namespace storm { // Start the search for SCCs from every state in the block. uint_fast64_t currentIndex = 0; - for (auto state : subsystem) { - if (!hasPreorderNumber.get(state)) { - performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + if (subsystem) { + for (auto state : *subsystem) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + } + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + } } } // After we obtained the state-to-SCC mapping, we build the actual blocks. this->blocks.resize(sccCount); - for (auto state : subsystem) { - this->blocks[stateToSccMapping[state]].insert(state); + if (subsystem) { + for (auto state : *subsystem) { + this->blocks[stateToSccMapping[state]].insert(state); + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + this->blocks[stateToSccMapping[state]].insert(state); + } } // Now flag all trivial SCCs as such. @@ -132,13 +154,34 @@ namespace storm { // If requested, we need to drop all non-bottom SCCs. if (onlyBottomSccs) { - for (uint_fast64_t state = 0; state < numberOfStates; ++state) { - // If the block of the state is already known to be dropped, we don't need to check the transitions. - if (!blocksToDrop.get(stateToSccMapping[state])) { - for (typename storm::storage::SparseMatrix::const_iterator successorIt = transitionMatrix.getRowGroup(state).begin(), successorIte = transitionMatrix.getRowGroup(state).end(); successorIt != successorIte; ++successorIt) { - if (subsystem.get(successorIt->getColumn()) && stateToSccMapping[state] != stateToSccMapping[successorIt->getColumn()]) { - blocksToDrop.set(stateToSccMapping[state]); - break; + if (subsystem) { + for (uint64_t state : *subsystem) { + // If the block of the state is already known to be dropped, we don't need to check the transitions. + if (!blocksToDrop.get(stateToSccMapping[state])) { + for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) { + if (choices && !choices->get(row)) { + continue; + } + for (auto const& entry : transitionMatrix.getRow(row)) { + if (subsystem->get(entry.getColumn()) && stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) { + blocksToDrop.set(stateToSccMapping[state]); + break; + } + } + } + } + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + // If the block of the state is already known to be dropped, we don't need to check the transitions. + if (!blocksToDrop.get(stateToSccMapping[state])) { + for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) { + for (auto const& entry : transitionMatrix.getRow(row)) { + if (stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) { + blocksToDrop.set(stateToSccMapping[state]); + break; + } + } } } } @@ -163,15 +206,11 @@ namespace storm { template template void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::models::sparse::Model const& model, bool dropNaiveSccs, bool onlyBottomSccs) { - // Prepare a block that contains all states for a call to the other overload of this function. - storm::storage::BitVector fullSystem(model.getNumberOfStates(), true); - - // Call the overloaded function. - performSccDecomposition(model.getTransitionMatrix(), fullSystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), nullptr, nullptr, dropNaiveSccs, onlyBottomSccs); } template - void StronglyConnectedComponentDecomposition::performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount) { + void StronglyConnectedComponentDecomposition::performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount) { // Prepare the stack used for turning the recursive procedure into an iterative one. std::vector recursionStateStack; @@ -190,20 +229,26 @@ namespace storm { s.push_back(currentState); p.push_back(currentState); - for (auto const& successor : transitionMatrix.getRowGroup(currentState)) { - if (subsystem.get(successor.getColumn()) && successor.getValue() != storm::utility::zero()) { - if (currentState == successor.getColumn()) { - statesWithSelfLoop.set(currentState); - } - - if (!hasPreorderNumber.get(successor.getColumn())) { - // In this case, we must recursively visit the successor. We therefore push the state - // onto the recursion stack. - recursionStateStack.push_back(successor.getColumn()); - } else { - if (!stateHasScc.get(successor.getColumn())) { - while (preorderNumbers[p.back()] > preorderNumbers[successor.getColumn()]) { - p.pop_back(); + for (uint64_t row = transitionMatrix.getRowGroupIndices()[currentState], rowEnd = transitionMatrix.getRowGroupIndices()[currentState + 1]; row != rowEnd; ++row) { + if (choices && !choices->get(row)) { + continue; + } + + for (auto const& successor : transitionMatrix.getRow(row)) { + if ((!subsystem || subsystem->get(successor.getColumn())) && successor.getValue() != storm::utility::zero()) { + if (currentState == successor.getColumn()) { + statesWithSelfLoop.set(currentState); + } + + if (!hasPreorderNumber.get(successor.getColumn())) { + // In this case, we must recursively visit the successor. We therefore push the state + // onto the recursion stack. + recursionStateStack.push_back(successor.getColumn()); + } else { + if (!stateHasScc.get(successor.getColumn())) { + while (preorderNumbers[p.back()] > preorderNumbers[successor.getColumn()]) { + p.pop_back(); + } } } } diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.h b/src/storm/storage/StronglyConnectedComponentDecomposition.h index 04cebff92..5a9fa2cf4 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.h +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.h @@ -103,6 +103,20 @@ namespace storm { */ StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /* + * Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is + * given by a sparse matrix). + * + * @param transitionMatrix The transition matrix of the system to decompose. + * @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs. + * @param choices A bit vector indicating which choices of the states are contained in the subsystem. + * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state + * without a self-loop) are to be kept in the decomposition. + * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of + * leaving the SCC), are kept. + */ + StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /*! * Creates an SCC decomposition by copying the given SCC decomposition. * @@ -158,13 +172,14 @@ namespace storm { * the vector of blocks of the decomposition. * * @param transitionMatrix The transition matrix of the system to decompose. - * @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs. + * @param subsystem An optional bit vector indicating which subsystem to consider. + * @param choices An optional bit vector indicating which choices belong to the subsystem. * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state * without a self-loop) are to be kept in the decomposition. * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of * leaving the SCC), are kept. */ - void performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs); + void performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs); /*! * Uses the algorithm by Gabow/Cheriyan/Mehlhorn ("Path-based strongly connected component algorithm") to @@ -175,7 +190,8 @@ namespace storm { * @param startState The starting state for the search of Tarjan's algorithm. * @param statesWithSelfLoop A bit vector that is to be filled with all states that have a self-loop. This * is later needed for identification of the naive SCCs. - * @param subsystem The subsystem to search. + * @param subsystem An optional bit vector indicating which subsystem to consider. + * @param choices An optional bit vector indicating which choices belong to the subsystem. * @param currentIndex The next free index that can be assigned to states. * @param hasPreorderNumber A bit that is used to keep track of the states that already have a preorder number. * @param preorderNumbers A vector storing the preorder number for each state. @@ -187,7 +203,7 @@ namespace storm { * @param sccCount The number of SCCs that have been computed. As a side effect of this function, this count * is increased. */ - void performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount); + void performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount); }; } } From ca651ec61cc91cc1ebcacc8812879f01b8940009 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 23 May 2018 13:03:14 +0200 Subject: [PATCH 307/647] fixes github issue #24 related to MEC decomposition --- .../testfiles/mdp/prism-mec-example1.nm | 12 ++++++ .../testfiles/mdp/prism-mec-example2.nm | 13 ++++++ .../MaximalEndComponentDecomposition.cpp | 35 +++++++++------ ...tronglyConnectedComponentDecomposition.cpp | 5 +++ .../StronglyConnectedComponentDecomposition.h | 16 ++++++- .../MaximalEndComponentDecompositionTest.cpp | 43 +++++++++++++++++++ 6 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 resources/examples/testfiles/mdp/prism-mec-example1.nm create mode 100644 resources/examples/testfiles/mdp/prism-mec-example2.nm diff --git a/resources/examples/testfiles/mdp/prism-mec-example1.nm b/resources/examples/testfiles/mdp/prism-mec-example1.nm new file mode 100644 index 000000000..bb8ec7d17 --- /dev/null +++ b/resources/examples/testfiles/mdp/prism-mec-example1.nm @@ -0,0 +1,12 @@ +mdp + +module test + + x : [0..2]; + + [] x=0 -> true; + [] x=0 -> 0.5 : (x'=1) + 0.5: (x'=2); + [] x=1 -> (x'=0); + [] x=2 -> true; + +endmodule diff --git a/resources/examples/testfiles/mdp/prism-mec-example2.nm b/resources/examples/testfiles/mdp/prism-mec-example2.nm new file mode 100644 index 000000000..7ef54d4b2 --- /dev/null +++ b/resources/examples/testfiles/mdp/prism-mec-example2.nm @@ -0,0 +1,13 @@ +mdp + +module test + + x : [0..2]; + + [] x=0 -> true; + [] x=0 -> 0.5 : (x'=1) + 0.5: (x'=1); + [] x=0 -> (x'=2); + [] x=1 -> (x'=0); + [] x=2 -> true; + +endmodule diff --git a/src/storm/storage/MaximalEndComponentDecomposition.cpp b/src/storm/storage/MaximalEndComponentDecomposition.cpp index cd8b637e3..7cbf36fd7 100644 --- a/src/storm/storage/MaximalEndComponentDecomposition.cpp +++ b/src/storm/storage/MaximalEndComponentDecomposition.cpp @@ -80,7 +80,20 @@ namespace storm { endComponentStateSets.emplace_back(states.begin(), states.end(), true); } storm::storage::BitVector statesToCheck(numberOfStates); - + storm::storage::BitVector includedChoices; + if (choices) { + includedChoices = *choices; + } else if (states) { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount()); + for (auto state : *states) { + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + includedChoices.set(choice, true); + } + } + } else { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); + } + for (std::list::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) { StateBlock const& mec = *mecIterator; @@ -88,7 +101,7 @@ namespace storm { bool mecChanged = false; // Get an SCC decomposition of the current MEC candidate. - StronglyConnectedComponentDecomposition sccs(transitionMatrix, mec, true); + StronglyConnectedComponentDecomposition sccs(transitionMatrix, mec, includedChoices, true); // We need to do another iteration in case we have either more than once SCC or the SCC is smaller than // the MEC canditate itself. @@ -105,10 +118,16 @@ namespace storm { bool keepStateInMEC = false; for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + // If the choice is not part of our subsystem, skip it. if (choices && !choices->get(choice)) { continue; } + + // If the choice is not included any more, skip it. + if (!includedChoices.get(choice)) { + continue; + } bool choiceContainedInMEC = true; for (auto const& entry : transitionMatrix.getRow(choice)) { @@ -117,6 +136,7 @@ namespace storm { } if (!scc.containsState(entry.getColumn())) { + includedChoices.set(choice, false); choiceContainedInMEC = false; break; } @@ -125,7 +145,6 @@ namespace storm { // If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC. if (choiceContainedInMEC) { keepStateInMEC = true; - break; } } @@ -185,15 +204,7 @@ namespace storm { continue; } - bool choiceContained = true; - for (auto const& entry : transitionMatrix.getRow(choice)) { - if (!mecStateSet.containsState(entry.getColumn())) { - choiceContained = false; - break; - } - } - - if (choiceContained) { + if (includedChoices.get(choice)) { containedChoices.insert(choice); } } diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index 9eae9d05a..6ab3e31f6 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -38,6 +38,11 @@ namespace storm { performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) { + storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end()); + performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs); + } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, bool dropNaiveSccs, bool onlyBottomSccs) { diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.h b/src/storm/storage/StronglyConnectedComponentDecomposition.h index 5a9fa2cf4..7d244b914 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.h +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.h @@ -78,7 +78,21 @@ namespace storm { * leaving the SCC), are kept. */ StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs = false, bool onlyBottomSccs = false); - + + /* + * Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is + * given by a sparse matrix). + * + * @param transitionMatrix The transition matrix of the system to decompose. + * @param block The block to decompose into SCCs. + * @param choices A bit vector indicating which choices of the states are contained in the subsystem. + * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state + * without a self-loop) are to be kept in the decomposition. + * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of + * leaving the SCC), are kept. + */ + StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /* * Creates an SCC decomposition of the given system (whose transition relation is given by a sparse matrix). * diff --git a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp index a7c23edf3..6e9718e6b 100644 --- a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp +++ b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp @@ -3,7 +3,11 @@ #include "storm/parser/AutoParser.h" #include "storm/storage/MaximalEndComponentDecomposition.h" #include "storm/models/sparse/MarkovAutomaton.h" +#include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" +#include "storm/builder/ExplicitModelBuilder.h" +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/parser/PrismParser.h" TEST(MaximalEndComponentDecomposition, FullSystem1) { std::shared_ptr> abstractModel = storm::parser::AutoParser<>::parseModel(STORM_TEST_RESOURCES_DIR "/tra/tiny1.tra", STORM_TEST_RESOURCES_DIR "/lab/tiny1.lab", "", ""); @@ -133,3 +137,42 @@ TEST(MaximalEndComponentDecomposition, Subsystem) { ASSERT_TRUE(false); } } + +TEST(MaximalEndComponentDecomposition, Example1) { + std::string prismModelPath = STORM_TEST_RESOURCES_DIR "/mdp/prism-mec-example1.nm"; + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(prismModelPath); + storm::prism::Program program = modelDescription.preprocess().asPrismProgram(); + + std::shared_ptr> model = storm::builder::ExplicitModelBuilder(program).build(); + std::shared_ptr> mdp = model->as>(); + + storm::storage::MaximalEndComponentDecomposition mecDecomposition(*mdp); + + EXPECT_EQ(mecDecomposition.size(), 2); + + ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2}); + EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{3}); + + ASSERT_TRUE(mecDecomposition[1].getStateSet() == storm::storage::MaximalEndComponent::set_type{0}); + EXPECT_TRUE(mecDecomposition[1].getChoicesForState(0) == storm::storage::MaximalEndComponent::set_type{0}); +} + +TEST(MaximalEndComponentDecomposition, Example2) { + std::string prismModelPath = STORM_TEST_RESOURCES_DIR "/mdp/prism-mec-example2.nm"; + storm::storage::SymbolicModelDescription modelDescription = storm::parser::PrismParser::parse(prismModelPath); + storm::prism::Program program = modelDescription.preprocess().asPrismProgram(); + + std::shared_ptr> model = storm::builder::ExplicitModelBuilder(program).build(); + std::shared_ptr> mdp = model->as>(); + + storm::storage::MaximalEndComponentDecomposition mecDecomposition(*mdp); + + EXPECT_EQ(mecDecomposition.size(), 2); + + ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2}); + EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{4}); + + ASSERT_TRUE((mecDecomposition[1].getStateSet() == storm::storage::MaximalEndComponent::set_type{0, 1})); + EXPECT_TRUE((mecDecomposition[1].getChoicesForState(0) == storm::storage::MaximalEndComponent::set_type{0, 1})); + EXPECT_TRUE((mecDecomposition[1].getChoicesForState(1) == storm::storage::MaximalEndComponent::set_type{3})); +} From 62e493d978dca21c17b14117b8609e7150e6b98e Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 23 May 2018 15:27:26 +0200 Subject: [PATCH 308/647] fix computation of generator matrix, pointed out by jklein --- src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 7e50785d0..a64cf4781 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -722,7 +722,7 @@ namespace storm { for (uint_fast64_t row = 0; row < generatorMatrix.getRowCount(); ++row) { for (auto& entry : generatorMatrix.getRow(row)) { if (entry.getColumn() == row) { - entry.setValue(-exitRates[row]); + entry.setValue(exitRates[row] - entry.getValue()); } } } From e1bb35ca0fe56139e372b7ae47d7e84a42ad7e10 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 23 May 2018 15:29:37 +0200 Subject: [PATCH 309/647] fix for the generator matrix fix --- src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index a64cf4781..99bad8ce1 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -722,7 +722,7 @@ namespace storm { for (uint_fast64_t row = 0; row < generatorMatrix.getRowCount(); ++row) { for (auto& entry : generatorMatrix.getRow(row)) { if (entry.getColumn() == row) { - entry.setValue(exitRates[row] - entry.getValue()); + entry.setValue(-exitRates[row] + entry.getValue()); } } } From 1a46300f617779be3210723cf0a3ceb5ba011185 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 24 May 2018 12:55:41 +0200 Subject: [PATCH 310/647] adding relative precision to comparator and game-based abstraction --- .../abstraction/GameBasedMdpModelChecker.cpp | 2 +- src/storm/settings/modules/AbstractionSettings.cpp | 10 ++++++++++ src/storm/settings/modules/AbstractionSettings.h | 6 ++++++ src/storm/utility/ConstantsComparator.cpp | 10 +++++++--- src/storm/utility/ConstantsComparator.h | 5 ++++- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index ce44a1db9..a5f4be44a 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -57,7 +57,7 @@ namespace storm { using detail::PreviousExplicitResult; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2, storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants. Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index fccd65722..08f947a48 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string AbstractionSettings::addAllGuardsOptionName = "all-guards"; const std::string AbstractionSettings::useInterpolationOptionName = "interpolation"; const std::string AbstractionSettings::precisionOptionName = "precision"; + const std::string AbstractionSettings::relativeOptionName = "relative"; const std::string AbstractionSettings::pivotHeuristicOptionName = "pivot-heuristic"; const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; @@ -66,6 +67,11 @@ namespace storm { .build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, true, "The precision used for detecting convergence.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-03).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, relativeOptionName, true, "Sets whether to use a relative termination criterion.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); std::vector pivotHeuristic = {"nearest-max-dev", "most-prob-path", "max-weighted-dev"}; this->addOption(storm::settings::OptionBuilder(moduleName, pivotHeuristicOptionName, true, "Sets the pivot selection heuristic.") @@ -148,6 +154,10 @@ namespace storm { return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); } + bool AbstractionSettings::getRelativeTerminationCriterion() const { + return this->getOption(relativeOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + AbstractionSettings::PivotSelectionHeuristic AbstractionSettings::getPivotSelectionHeuristic() const { std::string heuristicName = this->getOption(pivotHeuristicOptionName).getArgumentByName("name").getValueAsString(); if (heuristicName == "nearest-max-dev") { diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 7cd950042..0959f2772 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -83,6 +83,11 @@ namespace storm { */ double getPrecision() const; + /*! + * Retrieves whether to use a relative termination criterion for detecting convergence. + */ + bool getRelativeTerminationCriterion() const; + /*! * Retrieves the selected heuristic to select pivot blocks. * @@ -146,6 +151,7 @@ namespace storm { const static std::string addAllGuardsOptionName; const static std::string useInterpolationOptionName; const static std::string precisionOptionName; + const static std::string relativeOptionName; const static std::string pivotHeuristicOptionName; const static std::string reuseResultsOptionName; const static std::string restrictToRelevantStatesOptionName; diff --git a/src/storm/utility/ConstantsComparator.cpp b/src/storm/utility/ConstantsComparator.cpp index 913c79f2d..a4ed2e024 100644 --- a/src/storm/utility/ConstantsComparator.cpp +++ b/src/storm/utility/ConstantsComparator.cpp @@ -72,11 +72,11 @@ namespace storm { return std::abs(value1 - value2) < precision; } - ConstantsComparator::ConstantsComparator() : precision(storm::settings::getModule().getPrecision()) { + ConstantsComparator::ConstantsComparator() : precision(storm::settings::getModule().getPrecision()), relative(false) { // Intentionally left empty. } - ConstantsComparator::ConstantsComparator(double precision) : precision(precision) { + ConstantsComparator::ConstantsComparator(double precision, bool relative) : precision(precision), relative(relative) { // Intentionally left empty. } @@ -93,7 +93,11 @@ namespace storm { } bool ConstantsComparator::isEqual(double const& value1, double const& value2) const { - return std::abs(value1 - value2) <= precision; + if (relative) { + return value1 == value2 || std::abs(value1 - value2)/std::abs(value1 + value2) <= precision; + } else { + return std::abs(value1 - value2) <= precision; + } } bool ConstantsComparator::isConstant(double const&) const { diff --git a/src/storm/utility/ConstantsComparator.h b/src/storm/utility/ConstantsComparator.h index 988d08538..9f32551f3 100644 --- a/src/storm/utility/ConstantsComparator.h +++ b/src/storm/utility/ConstantsComparator.h @@ -56,7 +56,7 @@ namespace storm { public: ConstantsComparator(); - ConstantsComparator(double precision); + ConstantsComparator(double precision, bool relative = false); bool isOne(double const& value) const; @@ -73,6 +73,9 @@ namespace storm { private: // The precision used for comparisons. double precision; + + // Whether to use relative comparison for equality. + bool relative; }; } } From 138c61c9e53555e23454185bd8eae03214f05fd9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 24 May 2018 14:09:18 +0200 Subject: [PATCH 311/647] some more output --- src/storm/abstraction/StateSetAbstractor.cpp | 1 + .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index e115aa28d..4e4a88ee1 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -52,6 +52,7 @@ namespace storm { } std::set newRelevantPredicateIndices = localExpressionInformation.getRelatedExpressions(concretePredicateVariables); + // Since the number of relevant predicates is monotonic, we can simply check for the size here. STORM_LOG_ASSERT(newRelevantPredicateIndices.size() >= relevantPredicatesAndVariables.size(), "Illegal size of relevant predicates."); if (newRelevantPredicateIndices.size() > relevantPredicatesAndVariables.size()) { diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index a5f4be44a..0ebb77f7d 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -564,7 +564,7 @@ namespace storm { auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states, " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -576,10 +576,10 @@ namespace storm { } // #ifdef LOCAL_DEBUG -// initialStates.template toAdd().exportToDot("init.dot"); -// targetStates.template toAdd().exportToDot("target.dot"); +// initialStates.template toAdd().exportToDot("init" + std::to_string(iterations) + ".dot"); +// targetStates.template toAdd().exportToDot("target" + std::to_string(iterations) + ".dot"); // abstractor->exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne()); -// game.getReachableStates().template toAdd().exportToDot("reach.dot"); +// game.getReachableStates().template toAdd().exportToDot("reach" + std::to_string(iterations) + ".dot"); // #endif std::unique_ptr result; From e9a815666f1c65640f29b835fb20a72409cf01d4 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 24 May 2018 14:10:09 +0200 Subject: [PATCH 312/647] printing new predicates in verbose mode --- src/storm/abstraction/MenuGameRefiner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 627466d4a..2cab7a520 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1449,9 +1449,9 @@ namespace storm { template void MenuGameRefiner::performRefinement(std::vector const& refinementCommands) const { for (auto const& command : refinementCommands) { - STORM_LOG_TRACE("Refining with " << command.getPredicates().size() << " predicates."); + STORM_LOG_INFO("Refining with " << command.getPredicates().size() << " predicates."); for (auto const& predicate : command.getPredicates()) { - STORM_LOG_TRACE(predicate); + STORM_LOG_INFO(predicate); } if (!command.getPredicates().empty()) { abstractor.get().refine(command); From 8503dfff87a9c9ae967a293d782fd3259e9adaa0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 24 May 2018 14:52:31 +0200 Subject: [PATCH 313/647] fixing issue related to unary minus in JANI --- src/storm/parser/JaniParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/parser/JaniParser.cpp b/src/storm/parser/JaniParser.cpp index 725ab0a9d..b92b67efb 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm/parser/JaniParser.cpp @@ -905,7 +905,7 @@ namespace storm { ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] + arguments[1]; - } else if (opstring == "-") { + } else if (opstring == "-" && expressionStructure.count("left") > 0) { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); From 07fe1a240e7416a3d0a1f2d35073f657e1291560 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 25 May 2018 10:52:55 +0200 Subject: [PATCH 314/647] fixing superfluous reverse --- src/storm/abstraction/MenuGameRefiner.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 2cab7a520..1d2fb60b3 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -595,7 +595,7 @@ namespace storm { auto pathIt = reversedPath.rbegin(); - // Decode initial state. The state valuation also includes + // Decode pivot state. The state valuation also includes // * the bottom state, so we need to reserve one more, and // * the location variables, // so we need to reserve an appropriate size. @@ -609,7 +609,7 @@ namespace storm { predicate = predicate.changeManager(expressionManager); } - // Add ranges of further constraints. + // Add further constraints (like ranges). for (auto const& pred : abstractionInformation.getConstraints()) { predicates.back().push_back(pred.changeManager(expressionManager)); } @@ -706,8 +706,6 @@ namespace storm { ++actionIt; } - std::reverse(predicates.begin(), predicates.end()); - return std::make_pair(predicates, stepVariableToCopiedVariableMap); } From cfb1bc36ce5eac2c0081c70854ab7755508f51d3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 25 May 2018 12:19:04 +0200 Subject: [PATCH 315/647] treating bounded JANI variables with single bound --- src/storm/abstraction/MenuGameRefiner.cpp | 33 +++++++++++++++--- src/storm/generator/VariableInformation.cpp | 1 + src/storm/parser/JaniParser.cpp | 21 +++++++----- .../storage/jani/BoundedIntegerVariable.cpp | 34 +++++++++++++++---- .../storage/jani/BoundedIntegerVariable.h | 10 ++++++ 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 1d2fb60b3..888b534b4 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -619,6 +619,7 @@ namespace storm { // Traverse the path and construct necessary formula parts. auto actionIt = reversedLabels.rbegin(); + uint64_t step = 0; for (; pathIt != reversedPath.rend(); ++pathIt) { // Add new predicate frame. @@ -698,12 +699,36 @@ namespace storm { } } - // Enforce ranges of all assigned variables. -// for (auto const& variablePair : newVariableMaps) { -// for (auto const& ) -// } + // Enforce constraints of all assigned variables. + for (auto const& constraint : abstractionInformation.getConstraints()) { + std::set usedVariables = constraint.getVariables(); + + bool containsAssignedVariables = false; + for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) { + if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) { + break; + } + + if (*usedIt == *assignedIt) { + containsAssignedVariables = true; + break; + } + + if (*usedIt < *assignedIt) { + ++usedIt; + } else { + ++assignedIt; + } + } + + if (containsAssignedVariables) { + auto transformedConstraint = constraint.changeManager(expressionManager).substitute(currentSubstitution); + predicates.back().emplace_back(transformedConstraint); + } + } ++actionIt; + ++step; } return std::make_pair(predicates, stepVariableToCopiedVariableMap); diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 7f7ce0708..948535f79 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -89,6 +89,7 @@ namespace storm { } for (auto const& variable : model.getGlobalVariables().getBoundedIntegerVariables()) { if (!variable.isTransient()) { + STORM_LOG_THROW(variable.hasLowerBound() && variable.hasUpperBound(), storm::exceptions::WrongFormatException, "Bounded integer variables with infinite range are not supported."); int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt(); int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt(); uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); diff --git a/src/storm/parser/JaniParser.cpp b/src/storm/parser/JaniParser.cpp index b92b67efb..441089965 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm/parser/JaniParser.cpp @@ -684,12 +684,15 @@ namespace storm { std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scopeDescription + ") "); if(kind == "bounded") { // First do the bounds, that makes the code a bit more streamlined - STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound must be given"); - storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable " + name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(lowerboundExpr.isInitialized()); - STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") upper-bound must be given"); - storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(upperboundExpr.isInitialized()); + STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") + variableStructure.at("type").count("upper-bound") > 0, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound or upper-bound must be given"); + storm::expressions::Expression lowerboundExpr; + if (variableStructure.at("type").count("lower-bound") > 0) { + lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable " + name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + } + storm::expressions::Expression upperboundExpr; + if (variableStructure.at("type").count("upper-bound") > 0) { + upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + } STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") base must be given"); if(initvalcount == 1) { if(variableStructure.at("initial-value").is_null()) { @@ -704,9 +707,9 @@ namespace storm { if(initVal) { STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); } - STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - if(!lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { + STORM_LOG_THROW(!lowerboundExpr.isInitialized() || lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); + STORM_LOG_THROW(!upperboundExpr.isInitialized() || upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); + if (lowerboundExpr.isInitialized() && upperboundExpr.isInitialized() && !lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ")"); } return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, lowerboundExpr, upperboundExpr); diff --git a/src/storm/storage/jani/BoundedIntegerVariable.cpp b/src/storm/storage/jani/BoundedIntegerVariable.cpp index 5b851b127..ad15749e8 100644 --- a/src/storm/storage/jani/BoundedIntegerVariable.cpp +++ b/src/storm/storage/jani/BoundedIntegerVariable.cpp @@ -29,6 +29,10 @@ namespace storm { this->lowerBound = expression; } + bool BoundedIntegerVariable::hasLowerBound() const { + return this->lowerBound.isInitialized(); + } + storm::expressions::Expression const& BoundedIntegerVariable::getUpperBound() const { return upperBound; } @@ -37,8 +41,23 @@ namespace storm { this->upperBound = expression; } + bool BoundedIntegerVariable::hasUpperBound() const { + return this->upperBound.isInitialized(); + } + storm::expressions::Expression BoundedIntegerVariable::getRangeExpression() const { - return this->getLowerBound() <= this->getExpressionVariable() && this->getExpressionVariable() <= this->getUpperBound(); + storm::expressions::Expression range; + if (this->hasLowerBound()) { + range = this->getLowerBound() <= this->getExpressionVariable(); + } + if (this->hasUpperBound()) { + if (range.isInitialized()) { + range = range && this->getExpressionVariable() <= this->getUpperBound(); + } else { + range = this->getExpressionVariable() <= this->getUpperBound(); + } + } + return range; } bool BoundedIntegerVariable::isBoundedIntegerVariable() const { @@ -47,17 +66,20 @@ namespace storm { void BoundedIntegerVariable::substitute(std::map const& substitution) { Variable::substitute(substitution); - this->setLowerBound(this->getLowerBound().substitute(substitution)); - this->setUpperBound(this->getUpperBound().substitute(substitution)); + if (this->hasLowerBound()) { + this->setLowerBound(this->getLowerBound().substitute(substitution)); + } + if (this->hasUpperBound()) { + this->setUpperBound(this->getUpperBound().substitute(substitution)); + } } std::shared_ptr makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional initValue, bool transient, boost::optional lowerBound, boost::optional upperBound) { - STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides"); if (initValue) { - return std::make_shared(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get()); + return std::make_shared(name, variable, initValue.get(), transient, lowerBound ? lowerBound.get() : storm::expressions::Expression(), upperBound ? upperBound.get() : storm::expressions::Expression()); } else { assert(!transient); - return std::make_shared(name, variable, lowerBound.get(), upperBound.get()); + return std::make_shared(name, variable, lowerBound ? lowerBound.get() : storm::expressions::Expression(), upperBound ? upperBound.get() : storm::expressions::Expression()); } } } diff --git a/src/storm/storage/jani/BoundedIntegerVariable.h b/src/storm/storage/jani/BoundedIntegerVariable.h index 1f201ba2e..221d9dceb 100644 --- a/src/storm/storage/jani/BoundedIntegerVariable.h +++ b/src/storm/storage/jani/BoundedIntegerVariable.h @@ -33,6 +33,11 @@ namespace storm { */ void setLowerBound(storm::expressions::Expression const& expression); + /*! + * Retrieves whether the variable has a lower bound. + */ + bool hasLowerBound() const; + /*! * Retrieves the expression defining the upper bound of the variable. */ @@ -43,6 +48,11 @@ namespace storm { */ void setUpperBound(storm::expressions::Expression const& expression); + /*! + * Retrieves whether the variable has an upper bound. + */ + bool hasUpperBound() const; + /*! * Retrieves an expression characterizing the legal range of the bounded integer variable. */ From 8c965485666d10c908200159957fc2da6a7945c3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 27 May 2018 22:54:54 +0200 Subject: [PATCH 316/647] more work on game-based abstraction --- .../abstraction/AbstractionInformation.cpp | 16 + .../abstraction/AbstractionInformation.h | 7 + src/storm/abstraction/MenuGameRefiner.cpp | 139 ++++++- src/storm/abstraction/MenuGameRefiner.h | 4 + .../abstraction/prism/CommandAbstractor.cpp | 380 ++++++++++-------- .../abstraction/GameBasedMdpModelChecker.cpp | 32 +- .../abstraction/GameBasedMdpModelChecker.h | 6 + .../settings/modules/AbstractionSettings.cpp | 12 +- .../settings/modules/AbstractionSettings.h | 6 + src/storm/storage/dd/Bdd.cpp | 23 ++ src/storm/storage/dd/Bdd.h | 5 + src/storm/storage/dd/cudd/InternalCuddBdd.cpp | 26 ++ src/storm/storage/dd/cudd/InternalCuddBdd.h | 10 + .../storage/dd/sylvan/InternalSylvanBdd.cpp | 27 ++ .../storage/dd/sylvan/InternalSylvanBdd.h | 9 + 15 files changed, 493 insertions(+), 209 deletions(-) diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index e9cb479a6..7fd9a9d16 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -510,6 +510,19 @@ namespace storm { return result; } + template + template + std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const { + std::vector> splitChoices = choices.split(player2Variables); + + std::vector>> result; + for (auto const& choice : splitChoices) { + result.emplace_back(this->decodeChoiceToUpdateSuccessorMapping(choice)); + } + + return result; + } + template std::tuple AbstractionInformation::decodeStatePlayer1ChoiceAndUpdate(storm::dd::Bdd const& stateChoiceAndUpdate) const { STORM_LOG_ASSERT(stateChoiceAndUpdate.getNonZeroCount() == 1, "Wrong number of non-zero entries."); @@ -601,5 +614,8 @@ namespace storm { template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; } } diff --git a/src/storm/abstraction/AbstractionInformation.h b/src/storm/abstraction/AbstractionInformation.h index 4256f2149..e47e7ab2b 100644 --- a/src/storm/abstraction/AbstractionInformation.h +++ b/src/storm/abstraction/AbstractionInformation.h @@ -456,6 +456,13 @@ namespace storm { template std::map> decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + /*! + * Decodes the choices in the form of BDD over the destination variables where the choices are distinguished + * by player 2 variables. + */ + template + std::vector>> decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + /*! * Decodes the given BDD (over source, player 1 and aux variables) into a bit vector indicating the truth * values of the predicates in the state and the choice/update indices. diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 888b534b4..84ac8e7af 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -73,6 +73,7 @@ namespace storm { splitAll = splitMode == AbstractionSettings::SplitMode::All; splitPredicates = splitMode == AbstractionSettings::SplitMode::NonGuard; rankPredicates = abstractionSettings.isRankRefinementPredicatesSet(); + addPredicatesEagerly = abstractionSettings.isUseEagerRefinementSet(); equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); if (storm::settings::getModule().isAddAllGuardsSet()) { @@ -253,7 +254,7 @@ namespace storm { storm::expressions::Expression newPredicate; bool fromGuard = false; - // Get abstraction informatin for easier access. + // Get abstraction information for easier access. AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); // Decode the index of the command chosen by player 1. @@ -308,13 +309,17 @@ namespace storm { } } } - ++orderedUpdateIndex; break; } } STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates."); + STORM_LOG_TRACE("Possible refinement predicates:"); + for (auto const& pred : possibleRefinementPredicates) { + STORM_LOG_TRACE(pred); + } + if (rankPredicates) { // Since we can choose any of the deviation predicates to perform the split, we go through the remaining // updates and build all deviation predicates. We can then check whether any of the possible refinement @@ -368,6 +373,88 @@ namespace storm { return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {newPredicate}); } + template + RefinementPredicates MenuGameRefiner::derivePredicatesFromChoice(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& choice, storm::dd::Bdd const& choiceSuccessors) const { + // Prepare result. + storm::expressions::Expression newPredicate; + bool fromGuard = false; + + // Get abstraction information for easier access. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + + // Decode the index of the command chosen by player 1. + storm::dd::Add player1ChoiceAsAdd = player1Choice.template toAdd(); + auto pl1It = player1ChoiceAsAdd.begin(); + uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount()); + + // Check whether there are bottom states in the game and whether the choice actually picks the bottom state + // as the successor. + bool buttomStateSuccessor = !((abstractionInformation.getBottomStateBdd(false, false) && choiceSuccessors)).isZero(); + + std::vector possibleRefinementPredicates; + + // If the choice picks the bottom state, the new predicate is based on the guard of the appropriate command + // (that is the player 1 choice). + if (buttomStateSuccessor) { + STORM_LOG_TRACE("One of the successors is a bottom state, taking a guard as a new predicate."); + possibleRefinementPredicates.emplace_back(abstractor.get().getGuard(player1Index)); + fromGuard = true; + STORM_LOG_DEBUG("Derived new predicate (based on guard): " << possibleRefinementPredicates.back()); + } else { + STORM_LOG_TRACE("No bottom state successor. Deriving a new predicate using weakest precondition."); + + // Decode the choice successors. + std::map> choiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(choiceSuccessors); + std::vector> sortedChoiceUpdateIndicesAndMasses; + for (auto const& e : choiceUpdateToSuccessorMapping) { + sortedChoiceUpdateIndicesAndMasses.emplace_back(e.first, e.second.second); + } + std::sort(sortedChoiceUpdateIndicesAndMasses.begin(), sortedChoiceUpdateIndicesAndMasses.end(), [] (std::pair const& a, std::pair const& b) { return a.second > b.second; }); + + // Compute all other (not taken) choices. + std::set variablesToAbstract = game.getRowVariables(); + variablesToAbstract.insert(game.getPlayer1Variables().begin(), game.getPlayer1Variables().end()); + + storm::dd::Bdd otherChoices = (pivotState && !choice && player1Choice && game.getExtendedTransitionMatrix().toBdd()).existsAbstract(variablesToAbstract); + STORM_LOG_ASSERT(!otherChoices.isZero(), "Expected other choices."); + + // Decode the other choices. + std::vector>> otherChoicesUpdateToSuccessorMappings = abstractionInformation.template decodeChoicesToUpdateSuccessorMapping(game.getPlayer2Variables(), otherChoices); + + for (auto const& otherChoice : otherChoicesUpdateToSuccessorMappings) { + for (uint64_t updateIndex = 0; updateIndex < sortedChoiceUpdateIndicesAndMasses.size(); ++updateIndex) { + storm::storage::BitVector const& choiceSuccessor = choiceUpdateToSuccessorMapping.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first; + storm::storage::BitVector const& otherChoiceSuccessor = otherChoice.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first; + + bool deviates = choiceSuccessor != otherChoiceSuccessor; + if (deviates) { + std::map variableUpdates = abstractor.get().getVariableUpdates(player1Index, sortedChoiceUpdateIndicesAndMasses[updateIndex].first); + + for (uint64_t predicateIndex = 0; predicateIndex < choiceSuccessor.size(); ++predicateIndex) { + if (choiceSuccessor[predicateIndex] != otherChoiceSuccessor[predicateIndex]) { + possibleRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify()); + if (!rankPredicates) { + break; + } + } + } + + break; + } + } + } + + STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates."); + + STORM_LOG_TRACE("Possible refinement predicates:"); + for (auto const& pred : possibleRefinementPredicates) { + STORM_LOG_TRACE(pred); + } + } + + return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {possibleRefinementPredicates}); + } + template PivotStateCandidatesResult computePivotStates(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) { @@ -413,31 +500,39 @@ namespace storm { bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero(); if (lowerChoicesDifferent) { - STORM_LOG_TRACE("Deriving predicate based on lower choice."); - predicates = derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); + STORM_LOG_TRACE("Deriving predicates based on lower choice."); + if (this->addPredicatesEagerly) { + predicates = derivePredicatesFromChoice(game, pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice && minPlayer2Strategy, lowerChoice1); + } else { + predicates = derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); + } } - if (predicates && (!player1ChoicesDifferent || predicates.get().getSource() == RefinementPredicates::Source::Guard)) { + if (predicates && !player1ChoicesDifferent) { return predicates.get(); - } else { - boost::optional additionalPredicates; - - storm::dd::Bdd upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; - storm::dd::Bdd upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); - storm::dd::Bdd upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - - bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero() && !upperChoice1.isZero() && !upperChoice2.isZero(); - if (upperChoicesDifferent) { - STORM_LOG_TRACE("Deriving predicate based on upper choice."); + } + + boost::optional additionalPredicates; + + storm::dd::Bdd upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; + storm::dd::Bdd upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); + storm::dd::Bdd upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); + + bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero() && !upperChoice1.isZero() && !upperChoice2.isZero(); + if (upperChoicesDifferent) { + STORM_LOG_TRACE("Deriving predicates based on upper choice."); + if (this->addPredicatesEagerly) { + additionalPredicates = derivePredicatesFromChoice(game, pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice && maxPlayer2Strategy, upperChoice1); + } else { additionalPredicates = derivePredicatesFromDifferingChoices((pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2); } - - if (additionalPredicates) { - if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) { - return additionalPredicates.get(); - } else { - predicates.get().addPredicates(additionalPredicates.get().getPredicates()); - } + } + + if (additionalPredicates) { + if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) { + return additionalPredicates.get(); + } else { + predicates.get().addPredicates(additionalPredicates.get().getPredicates()); } } diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index a3269ac91..403cd92c7 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -145,6 +145,7 @@ namespace storm { private: RefinementPredicates derivePredicatesFromDifferingChoices(storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& lowerChoice, storm::dd::Bdd const& upperChoice) const; + RefinementPredicates derivePredicatesFromChoice(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& choice, storm::dd::Bdd const& choiceSuccessors) const; RefinementPredicates derivePredicatesFromPivotState(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; /*! @@ -186,6 +187,9 @@ namespace storm { /// A flag indicating whether predicates are to be ranked. bool rankPredicates; + /// A flag indicating whether predicates are to be generated eagerly. + bool addPredicatesEagerly; + /// A flag indicating whether all guards have been used to refine the abstraction. bool addedAllGuardsFlag; diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index cfd1bed60..d7003a39f 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -179,7 +179,6 @@ namespace storm { } relevantBlockPartition[representativeBlock].insert(relevantBlockPartition[assignmentVariableBlock].begin(), relevantBlockPartition[assignmentVariableBlock].end()); relevantBlockPartition[assignmentVariableBlock].clear(); - } } } @@ -188,200 +187,235 @@ namespace storm { // Now remove all blocks that are empty and obtain the partition. std::vector> cleanedRelevantBlockPartition; - for (auto& element : relevantBlockPartition) { - if (!element.empty()) { - cleanedRelevantBlockPartition.emplace_back(std::move(element)); + for (auto& outerBlock : relevantBlockPartition) { + if (!outerBlock.empty()) { + cleanedRelevantBlockPartition.emplace_back(); + + for (auto const& innerBlock : outerBlock) { + if (!localExpressionInformation.getExpressionBlock(innerBlock).empty()) { + cleanedRelevantBlockPartition.back().insert(innerBlock); + } + } + + if (cleanedRelevantBlockPartition.back().empty()) { + cleanedRelevantBlockPartition.pop_back(); + } } } relevantBlockPartition = std::move(cleanedRelevantBlockPartition); - // if the decomposition has size 1, use the plain technique from before - if (relevantBlockPartition.size() == 1) { - STORM_LOG_TRACE("Relevant block partition size is one, falling back to regular computation."); - recomputeCachedBddWithoutDecomposition(); - } else { - std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); + STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); + for (auto const& block : relevantBlockPartition) { + STORM_LOG_TRACE("New block of size " << block.size() << ":"); - // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard - // are not contained within a single block of our decomposition. - bool enumerateAbstractGuard = true; - std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); - for (auto const& block : relevantBlockPartition) { - bool allContained = true; - for (auto const& guardBlock : guardBlocks) { - if (block.find(guardBlock) == block.end()) { - allContained = false; - break; - } + std::set blockPredicateIndices; + for (auto const& innerBlock : block) { + blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } + + for (auto const& predicateIndex : blockPredicateIndices) { + STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); + } + } + + std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); + + // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard + // are not contained within a single block of our decomposition. + bool enumerateAbstractGuard = true; + std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + for (auto const& block : relevantBlockPartition) { + bool allContained = true; + for (auto const& guardBlock : guardBlocks) { + if (block.find(guardBlock) == block.end()) { + allContained = false; + break; } - if (allContained) { - enumerateAbstractGuard = false; + } + if (allContained) { + enumerateAbstractGuard = false; + } + } + + uint64_t numberOfSolutions = 0; + uint64_t numberOfTotalSolutions = 0; + + // If we need to enumerate the guard, do it only once now. + if (enumerateAbstractGuard) { + std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); + std::vector guardDecisionVariables; + std::vector> guardVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { + guardDecisionVariables.push_back(element.first); + guardVariablesAndPredicates.push_back(element); } } + abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); + smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { + abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); + + // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating + // the other solutions. + + // Create a new backtracking point before adding the guard. + smtSolver->push(); + + // Create the guard constraint. + std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); + + // Then add it to the solver. + for (auto const& expression : result.first) { + smtSolver->add(expression); + } - uint64_t numberOfSolutions = 0; + // Finally associate the level variables with the predicates. + for (auto const& indexVariablePair : result.second) { + smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + } + } + + // then enumerate the solutions for each of the blocks of the decomposition + uint64_t usedNondeterminismVariables = 0; + uint64_t blockCounter = 0; + std::vector> blockBdds; + for (auto const& block : relevantBlockPartition) { + std::set relevantPredicates; + for (auto const& innerBlock : block) { + relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } - if (enumerateAbstractGuard) { - // otherwise, enumerate the abstract guard so we do this only once - std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); - std::vector guardDecisionVariables; - std::vector> guardVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { - guardDecisionVariables.push_back(element.first); - guardVariablesAndPredicates.push_back(element); - } - } - abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); - smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { - abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " for abstract guard."); - - // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating - // the other solutions. - - // Create a new backtracking point before adding the guard. - smtSolver->push(); - - // Create the guard constraint. - std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); - - // Then add it to the solver. - for (auto const& expression : result.first) { - smtSolver->add(expression); - } - - // Finally associate the level variables with the predicates. - for (auto const& indexVariablePair : result.second) { - smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); - } + if (relevantPredicates.empty()) { + STORM_LOG_TRACE("Block does not contain relevant predicates, skipping it."); + continue; } - // then enumerate the solutions for each of the blocks of the decomposition - uint64_t usedNondeterminismVariables = 0; - uint64_t blockCounter = 0; - std::vector> blockBdds; - for (auto const& block : relevantBlockPartition) { - std::set relevantPredicates; - for (auto const& innerBlock : block) { - relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); - } - - std::vector transitionDecisionVariables; - std::vector> sourceVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relevantPredicates.find(element.second) != relevantPredicates.end()) { - transitionDecisionVariables.push_back(element.first); - sourceVariablesAndPredicates.push_back(element); - } + std::vector transitionDecisionVariables; + std::vector> sourceVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relevantPredicates.find(element.second) != relevantPredicates.end()) { + transitionDecisionVariables.push_back(element.first); + sourceVariablesAndPredicates.push_back(element); } - - std::vector>> destinationVariablesAndPredicates; - for (uint64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { - destinationVariablesAndPredicates.emplace_back(); - for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { - uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); - std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); - if (block.find(assignmentVariableBlockIndex) != block.end()) { - for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { - if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { - destinationVariablesAndPredicates.back().push_back(element); - transitionDecisionVariables.push_back(element.first); - } + } + + std::vector>> destinationVariablesAndPredicates; + for (uint64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { + destinationVariablesAndPredicates.emplace_back(); + for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { + uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); + std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); + if (block.find(assignmentVariableBlockIndex) != block.end()) { + for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { + if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { + destinationVariablesAndPredicates.back().push_back(element); + transitionDecisionVariables.push_back(element.first); } } } } - - std::unordered_map, std::vector>> sourceToDistributionsMap; - numberOfSolutions = 0; - smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { - sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); - numberOfSolutions = 0; - - // Now we search for the maximal number of choices of player 2 to determine how many DD variables we - // need to encode the nondeterminism. - uint_fast64_t maximalNumberOfChoices = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); - } - - // We now compute how many variables we need to encode the choices. We add one to the maximal number of - // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + 1))); - - // Finally, build overall result. - storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); - - uint_fast64_t sourceStateIndex = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); - STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - // We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice. - uint_fast64_t distributionIndex = 1; - storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); - for (auto const& distribution : sourceDistributionsPair.second) { - allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); - ++distributionIndex; - STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); - } - resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; - STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); - } - usedNondeterminismVariables += numberOfVariablesNeeded; - - blockBdds.push_back(resultBdd); - ++blockCounter; } - if (enumerateAbstractGuard) { - smtSolver->pop(); - } + std::unordered_map, std::vector>> sourceToDistributionsMap; + numberOfSolutions = 0; + smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { + sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); + numberOfTotalSolutions += numberOfSolutions; - // multiply the results - storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& blockBdd : blockBdds) { - resultBdd &= blockBdd; + // Now we search for the maximal number of choices of player 2 to determine how many DD variables we + // need to encode the nondeterminism. + uint_fast64_t maximalNumberOfChoices = 0; + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); } - // if we did not explicitly enumerate the guard, we can construct it from the result BDD. - if (!enumerateAbstractGuard) { - std::set allVariables(getAbstractionInformation().getSuccessorVariables()); - auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); - allVariables.insert(player2Variables.begin(), player2Variables.end()); - auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); - allVariables.insert(auxVariables.begin(), auxVariables.end()); - - std::set variablesToAbstract; - std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); + // We now compute how many variables we need to encode the choices. We add one to the maximal number of + // choices to account for a possible transition to a bottom state. + uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))); + std::cout << "need " << numberOfVariablesNeeded << " variables for " << (maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)) << " choices" << std::endl; + + // Finally, build overall result. + storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); + + uint_fast64_t sourceStateIndex = 0; + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); + STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - abstractGuard = resultBdd.existsAbstract(variablesToAbstract); - } else { - // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. - resultBdd &= abstractGuard; + // We start with the distribution index of 1, because 0 is reserved for a potential bottom choice. + uint_fast64_t distributionIndex = blockCounter == 0 ? 1 : 0; + storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); + for (auto const& distribution : sourceDistributionsPair.second) { + allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); + ++distributionIndex; + STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); + } + resultBdd |= sourceDistributionsPair.first && allDistributions; + ++sourceStateIndex; + STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } + usedNondeterminismVariables += numberOfVariablesNeeded; - // multiply with missing identities - resultBdd &= computeMissingIdentities(); - - // cache and return result - resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); + blockBdds.push_back(resultBdd); + ++blockCounter; + } + + if (enumerateAbstractGuard) { + smtSolver->pop(); + } + + // multiply the results + storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); + uint64_t blockIndex = 0; + for (auto const& blockBdd : blockBdds) { + blockBdd.template toAdd().exportToDot("block" + std::to_string(command.get().getGlobalIndex()) + "_" + std::to_string(blockIndex) + ".dot"); + resultBdd &= blockBdd; + ++blockIndex; + } + + // If we did not explicitly enumerate the guard, we can construct it from the result BDD. + if (!enumerateAbstractGuard) { + std::set allVariables(getAbstractionInformation().getSuccessorVariables()); + auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); + allVariables.insert(player2Variables.begin(), player2Variables.end()); + auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); + allVariables.insert(auxVariables.begin(), auxVariables.end()); - // Cache the result. - cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + std::set variablesToAbstract; + std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); - auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); - forceRecomputation = false; + abstractGuard = resultBdd.existsAbstract(variablesToAbstract); + } else { + // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. + resultBdd &= abstractGuard; } + + resultBdd.template toAdd().exportToDot("decomp" + std::to_string(command.get().getGlobalIndex()) + ".dot"); + + auto identities = computeMissingIdentities(); + identities.template toAdd().exportToDot("idents" + std::to_string(command.get().getGlobalIndex()) + ".dot"); + + // multiply with missing identities + resultBdd &= computeMissingIdentities(); + + // cache and return result + resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); + + // Cache the result. + cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + + auto end = std::chrono::high_resolution_clock::now(); + + STORM_LOG_TRACE("Enumerated " << numberOfTotalSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); + forceRecomputation = false; } template @@ -433,6 +467,8 @@ namespace storm { STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } + resultBdd.template toAdd().exportToDot("nodecomp" + std::to_string(command.get().getGlobalIndex()) + ".dot"); + resultBdd &= computeMissingIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -460,12 +496,12 @@ namespace storm { auto const& leftHandSidePredicates = localExpressionInformation.getRelatedExpressions(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); - // Keep track of all assigned variables, so we can find the related predicates later. - assignedVariables.insert(assignedVariable); +// // Keep track of all assigned variables, so we can find the related predicates later. +// assignedVariables.insert(assignedVariable); } - auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); - result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); +// auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); +// result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); return result; } @@ -594,6 +630,7 @@ namespace storm { for (; sourceRelevantIt != sourceRelevantIte; ++sourceRelevantIt) { // If the predicates do not match, there is a predicate missing, so we need to add its identity. if (updateRelevantIt == updateRelevantIte || sourceRelevantIt->second != updateRelevantIt->second) { + std::cout << "adding update identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(sourceRelevantIt->second) << " to update " << updateIndex << std::endl; updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(sourceRelevantIt->second); } else { ++updateRelevantIt; @@ -614,6 +651,7 @@ namespace storm { for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { + std::cout << "adding global identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(predicateIndex) << std::endl; result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++relevantIt; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 0ebb77f7d..c79a423d3 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -530,9 +530,8 @@ namespace storm { // Derive the optimization direction for player 1 (assuming menu-game abstraction). storm::OptimizationDirection player1Direction = getPlayer1Direction(checkTask); - + // Create the abstractor. - std::shared_ptr> abstractor; if (preprocessedModel.isPrismProgram()) { abstractor = std::make_shared>(preprocessedModel.asPrismProgram(), smtSolverFactory); } else { @@ -543,7 +542,6 @@ namespace storm { } abstractor->addTerminalStates(targetStateExpression); abstractor->setTargetStates(targetStateExpression); - // Create a refiner that can be used to refine the abstraction when needed. storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); @@ -556,15 +554,15 @@ namespace storm { boost::optional> previousSymbolicQualitativeResult = boost::none; boost::optional> previousSymbolicMinQuantitativeResult = boost::none; boost::optional> previousExplicitResult = boost::none; - for (uint_fast64_t iterations = 0; iterations < maximalNumberOfAbstractions; ++iterations) { + for (iteration = 0; iteration < maximalNumberOfAbstractions; ++iteration) { auto iterationStart = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Starting iteration " << iterations << "."); + STORM_LOG_TRACE("Starting iteration " << iteration << "."); // (1) build the abstraction. auto abstractionStart = std::chrono::high_resolution_clock::now(); storm::abstraction::MenuGame game = abstractor->abstract(); auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -575,11 +573,13 @@ namespace storm { targetStates |= game.getBottomStates(); } + exit(-1); + // #ifdef LOCAL_DEBUG -// initialStates.template toAdd().exportToDot("init" + std::to_string(iterations) + ".dot"); -// targetStates.template toAdd().exportToDot("target" + std::to_string(iterations) + ".dot"); -// abstractor->exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne()); -// game.getReachableStates().template toAdd().exportToDot("reach" + std::to_string(iterations) + ".dot"); +// initialStates.template toAdd().exportToDot("init" + std::to_string(iteration) + ".dot"); +// targetStates.template toAdd().exportToDot("target" + std::to_string(iteration) + ".dot"); +// abstractor->exportToDot("game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// game.getReachableStates().template toAdd().exportToDot("reach" + std::to_string(iteration) + ".dot"); // #endif std::unique_ptr result; @@ -595,7 +595,7 @@ namespace storm { } auto iterationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); + STORM_LOG_INFO("Iteration " << iteration << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); } // If this point is reached, we have given up on abstraction. @@ -790,10 +790,6 @@ namespace storm { qualitativeRefinement = refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); - } else if (initialStates.isSubsetOf(initialMaybeStates) && checkTask.isQualitativeSet()) { - // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, - // we can return the result here. - return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); } ExplicitQuantitativeResultMinMax quantitativeResult; @@ -1001,6 +997,12 @@ namespace storm { STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); +// this->abstractor->exportToDot("lower_game" + std::to_string(iteration) + ".dot", result.prob1Max.getStates(), (result.prob0Min.getPlayer1Strategy() && result.prob0Min.getPlayer2Strategy()) || (result.prob1Min.getPlayer1Strategy() && result.prob1Min.getPlayer2Strategy())); +// this->abstractor->exportToDot("upper_game" + std::to_string(iteration) + ".dot", targetStates, (result.prob0Max.getPlayer1Strategy() && result.prob0Max.getPlayer2Strategy()) || (result.prob1Max.getPlayer1Strategy() && result.prob1Max.getPlayer2Strategy())); +// this->abstractor->exportToDot("lower_game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// this->abstractor->exportToDot("upper_game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// exit(-1); + STORM_LOG_ASSERT(checkQualitativeStrategies(result, targetStates), "Qualitative strategies appear to be broken."); return result; } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 0319e48c5..e93e91c69 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -142,6 +142,12 @@ namespace storm { /// The mode selected for solving the abstraction. storm::settings::modules::AbstractionSettings::SolveMode solveMode; + + /// The currently used abstractor. + std::shared_ptr> abstractor; + + /// The performed number of refinement iterations. + uint64_t iteration; }; } } diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 08f947a48..0bee562f4 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -27,6 +27,7 @@ namespace storm { const std::string AbstractionSettings::maximalAbstractionOptionName = "maxabs"; const std::string AbstractionSettings::rankRefinementPredicatesOptionName = "rankpred"; const std::string AbstractionSettings::constraintsOptionName = "constraints"; + const std::string AbstractionSettings::useEagerRefinementOptionName = "eagerref"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -94,6 +95,11 @@ namespace storm { .setDefaultValueString("off").build()) .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, useEagerRefinementOptionName, true, "Sets whether to refine eagerly.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, constraintsOptionName, true, "Specifies additional constraints used by the abstraction.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").build()) .build()); @@ -111,7 +117,7 @@ namespace storm { } bool AbstractionSettings::isUseDecompositionSet() const { - return this->getOption(useDecompositionOptionName).getHasOptionBeenSet(); + return this->getOption(useDecompositionOptionName).getArgumentByName("value").getValueAsString() == "on"; } AbstractionSettings::SplitMode AbstractionSettings::getSplitMode() const { @@ -200,6 +206,10 @@ namespace storm { return this->getOption(constraintsOptionName).getArgumentByName("constraints").getValueAsString(); } + bool AbstractionSettings::isUseEagerRefinementSet() const { + return this->getOption(useEagerRefinementOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 0959f2772..2ff536be6 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -142,6 +142,11 @@ namespace storm { */ std::string getConstraintString() const; + /*! + * Retrieves whether to refine eagerly. + */ + bool isUseEagerRefinementSet() const; + const static std::string moduleName; private: @@ -159,6 +164,7 @@ namespace storm { const static std::string maximalAbstractionOptionName; const static std::string rankRefinementPredicatesOptionName; const static std::string constraintsOptionName; + const static std::string useEagerRefinementOptionName; }; } diff --git a/src/storm/storage/dd/Bdd.cpp b/src/storm/storage/dd/Bdd.cpp index 5271a628a..62aa7ccb1 100644 --- a/src/storm/storage/dd/Bdd.cpp +++ b/src/storm/storage/dd/Bdd.cpp @@ -410,6 +410,29 @@ namespace storm { return Add(this->getDdManager(), internalBdd.template toAdd(), this->getContainedMetaVariables()); } + template + std::vector> Bdd::split(std::set const& variables) const { + std::set remainingMetaVariables; + std::set_difference(this->getContainedMetaVariables().begin(), this->getContainedMetaVariables().end(), variables.begin(), variables.end(), std::inserter(remainingMetaVariables, remainingMetaVariables.begin())); + + std::vector ddGroupVariableIndices; + for (auto const& variable : variables) { + DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); + for (auto const& ddVariable : metaVariable.getDdVariables()) { + ddGroupVariableIndices.push_back(ddVariable.getIndex()); + } + } + std::sort(ddGroupVariableIndices.begin(), ddGroupVariableIndices.end()); + + std::vector> internalBddGroups = this->internalBdd.splitIntoGroups(ddGroupVariableIndices); + std::vector> groups; + for (auto const& internalBdd : internalBddGroups) { + groups.emplace_back(Bdd(this->getDdManager(), internalBdd, remainingMetaVariables)); + } + + return groups; + } + template storm::storage::BitVector Bdd::toVector(storm::dd::Odd const& rowOdd) const { return internalBdd.toVector(rowOdd, this->getSortedVariableIndices()); diff --git a/src/storm/storage/dd/Bdd.h b/src/storm/storage/dd/Bdd.h index 9e36ba52b..acb7e9122 100644 --- a/src/storm/storage/dd/Bdd.h +++ b/src/storm/storage/dd/Bdd.h @@ -343,6 +343,11 @@ namespace storm { template Add toAdd() const; + /*! + * Splits the BDD along the given variables (must be at the top). + */ + std::vector> split(std::set const& variables) const; + /*! * Converts the BDD to a bit vector. The given offset-labeled DD is used to determine the correct row of * each entry. diff --git a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp index b69040372..41aee2517 100644 --- a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp @@ -412,6 +412,32 @@ namespace storm { } } + std::vector> InternalBdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { + std::vector> result; + splitIntoGroupsRec(Cudd_Regular(this->getCuddDdNode()), Cudd_IsComplement(this->getCuddDdNode()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + + void InternalBdd::splitIntoGroupsRec(DdNode* dd, bool negated, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + if (negated && dd == Cudd_ReadOne(ddManager->getCuddManager().getManager())) { + return; + } + + if (currentLevel == maxLevel) { + groups.push_back(InternalBdd(ddManager, cudd::BDD(ddManager->getCuddManager(), negated ? Cudd_Complement(dd) : dd))); + } else if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { + splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } else { + DdNode* elseNode = Cudd_E(dd); + DdNode* thenNode = Cudd_T(dd); + + splitIntoGroupsRec(elseNode, negated ^ Cudd_IsComplement(elseNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(thenNode, negated ^ Cudd_IsComplement(thenNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + void InternalBdd::filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const { uint_fast64_t currentIndex = 0; filterExplicitVectorRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues); diff --git a/src/storm/storage/dd/cudd/InternalCuddBdd.h b/src/storm/storage/dd/cudd/InternalCuddBdd.h index 93c54c0c8..2a8d8dd52 100644 --- a/src/storm/storage/dd/cudd/InternalCuddBdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddBdd.h @@ -385,6 +385,14 @@ namespace storm { */ void filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const; + /*! + * Splits the BDD into several BDDs that differ in the encoding of the given group variables (given via indices). + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of BDDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + friend struct std::hash>; /*! @@ -504,6 +512,8 @@ namespace storm { */ static storm::expressions::Variable toExpressionRec(DdNode const* dd, cudd::Cudd const& ddManager, storm::expressions::ExpressionManager& manager, std::vector& expressions, std::unordered_map& indexToVariableMap, std::unordered_map, storm::expressions::Variable>& countIndexToVariablePair, std::unordered_map& nodeToCounterMap, std::vector& nextCounterForIndex); + void splitIntoGroupsRec(DdNode* dd, bool negated, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + InternalDdManager const* ddManager; cudd::BDD cuddBdd; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp index 97252476a..2ca68d944 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp @@ -443,6 +443,33 @@ namespace storm { } } + std::vector> InternalBdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { + std::vector> result; + splitIntoGroupsRec(this->getSylvanBdd().GetBDD(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + + void InternalBdd::splitIntoGroupsRec(BDD dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + if (dd == sylvan_false) { + return; + } + + if (currentLevel == maxLevel) { + groups.push_back(InternalBdd(ddManager, sylvan::Bdd(dd))); + } else if (bdd_isterminal(dd) || ddGroupVariableIndices[currentLevel] < sylvan_var(dd)) { + splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + BDD thenDdNode = sylvan_high(dd); + BDD elseDdNode = sylvan_low(dd); + + splitIntoGroupsRec(elseDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(thenDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + std::pair, std::unordered_map> InternalBdd::toExpression(storm::expressions::ExpressionManager& manager) const { std::pair, std::unordered_map> result; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanBdd.h b/src/storm/storage/dd/sylvan/InternalSylvanBdd.h index a1160654c..e5c5a3df2 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanBdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanBdd.h @@ -374,6 +374,14 @@ namespace storm { */ void filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const; + /*! + * Splits the BDD into several BDDs that differ in the encoding of the given group variables (given via indices). + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of BDDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + friend struct std::hash>; /*! @@ -488,6 +496,7 @@ namespace storm { */ static storm::expressions::Variable toExpressionRec(BDD dd, storm::expressions::ExpressionManager& manager, std::vector& expressions, std::unordered_map& indexToVariableMap, std::unordered_map, storm::expressions::Variable>& countIndexToVariablePair, std::unordered_map& nodeToCounterMap, std::vector& nextCounterForIndex); + void splitIntoGroupsRec(BDD dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; // The internal manager responsible for this BDD. InternalDdManager const* ddManager; From 5c38a4ef896684ddfa9a5b27629958076234f7f5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 28 May 2018 15:42:59 +0200 Subject: [PATCH 317/647] implemented environment for multiobjective settings --- src/storm/environment/Environment.cpp | 23 +++- src/storm/environment/Environment.h | 13 ++- src/storm/environment/SubEnvironment.cpp | 12 ++- .../modelchecker/ModelCheckerEnvironment.cpp | 31 ++++++ .../modelchecker/ModelCheckerEnvironment.h | 28 +++++ .../MultiObjectiveModelCheckerEnvironment.cpp | 100 ++++++++++++++++++ .../MultiObjectiveModelCheckerEnvironment.h | 48 +++++++++ .../multiObjectiveModelChecking.cpp | 6 +- .../pcaa/SparsePcaaAchievabilityQuery.cpp | 7 +- .../pcaa/SparsePcaaParetoQuery.cpp | 24 ++--- .../pcaa/SparsePcaaQuantitativeQuery.cpp | 18 ++-- .../pcaa/SparsePcaaQuantitativeQuery.h | 2 +- .../multiobjective/pcaa/SparsePcaaQuery.cpp | 57 +++++----- .../multiobjective/pcaa/SparsePcaaQuery.h | 4 +- 14 files changed, 305 insertions(+), 68 deletions(-) create mode 100644 src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp create mode 100644 src/storm/environment/modelchecker/ModelCheckerEnvironment.h create mode 100644 src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp create mode 100644 src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h diff --git a/src/storm/environment/Environment.cpp b/src/storm/environment/Environment.cpp index 0836de3f7..6d5d3ca2b 100644 --- a/src/storm/environment/Environment.cpp +++ b/src/storm/environment/Environment.cpp @@ -1,6 +1,8 @@ #include "storm/environment/Environment.h" #include "storm/environment/SubEnvironment.h" #include "storm/environment/solver/SolverEnvironment.h" +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + namespace storm { @@ -12,11 +14,28 @@ namespace storm { // Intentionally left empty. } + Environment::Environment(Environment const& other) : internalEnv(other.internalEnv) { + // Intentionally left empty. + } + + Environment& Environment::operator=(Environment const& other) { + internalEnv = other.internalEnv; + return *this; + } + SolverEnvironment& Environment::solver() { - return solverEnvironment.get(); + return internalEnv.get().solverEnvironment.get(); } SolverEnvironment const& Environment::solver() const { - return solverEnvironment.get(); + return internalEnv.get().solverEnvironment.get(); + } + + ModelCheckerEnvironment& Environment::modelchecker() { + return internalEnv.get().modelcheckerEnvironment.get(); + } + + ModelCheckerEnvironment const& Environment::modelchecker() const { + return internalEnv.get().modelcheckerEnvironment.get(); } } \ No newline at end of file diff --git a/src/storm/environment/Environment.h b/src/storm/environment/Environment.h index 988ca34c6..30ac31803 100644 --- a/src/storm/environment/Environment.h +++ b/src/storm/environment/Environment.h @@ -6,19 +6,30 @@ namespace storm { // Forward declare sub-environments class SolverEnvironment; + class ModelCheckerEnvironment; + + // Avoid implementing ugly copy constructors for environment by using an internal environment. + struct InternalEnvironment { + SubEnvironment solverEnvironment; + SubEnvironment modelcheckerEnvironment; + }; class Environment { public: Environment(); virtual ~Environment(); + Environment(Environment const& other); + Environment& operator=(Environment const& other); SolverEnvironment& solver(); SolverEnvironment const& solver() const; + ModelCheckerEnvironment& modelchecker(); + ModelCheckerEnvironment const& modelchecker() const; private: - SubEnvironment solverEnvironment; + SubEnvironment internalEnv; }; } diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index f11b2b1bf..920a06049 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -1,4 +1,9 @@ -#include +#include + +#include "storm/environment/Environment.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" @@ -36,6 +41,11 @@ namespace storm { return *subEnv; } + template class SubEnvironment; + + template class SubEnvironment; + template class SubEnvironment; + template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; diff --git a/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp b/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp new file mode 100644 index 000000000..f0d917a28 --- /dev/null +++ b/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp @@ -0,0 +1,31 @@ +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" + + +namespace storm { + + ModelCheckerEnvironment::ModelCheckerEnvironment() { + // Intentionally left empty + } + + ModelCheckerEnvironment::~ModelCheckerEnvironment() { + // Intentionally left empty + } + + MultiObjectiveModelCheckerEnvironment& ModelCheckerEnvironment::multi() { + return multiObjectiveModelCheckerEnvironment.get(); + } + + MultiObjectiveModelCheckerEnvironment const& ModelCheckerEnvironment::multi() const { + return multiObjectiveModelCheckerEnvironment.get(); + } +} + + diff --git a/src/storm/environment/modelchecker/ModelCheckerEnvironment.h b/src/storm/environment/modelchecker/ModelCheckerEnvironment.h new file mode 100644 index 000000000..2ec1eebd8 --- /dev/null +++ b/src/storm/environment/modelchecker/ModelCheckerEnvironment.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "storm/environment/Environment.h" +#include "storm/environment/SubEnvironment.h" + +namespace storm { + + // Forward declare subenvironments + class MultiObjectiveModelCheckerEnvironment; + + class ModelCheckerEnvironment { + public: + + ModelCheckerEnvironment(); + ~ModelCheckerEnvironment(); + + MultiObjectiveModelCheckerEnvironment& multi(); + MultiObjectiveModelCheckerEnvironment const& multi() const; + + + private: + SubEnvironment multiObjectiveModelCheckerEnvironment; + }; +} + diff --git a/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp new file mode 100644 index 000000000..92b51fde8 --- /dev/null +++ b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp @@ -0,0 +1,100 @@ +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + + MultiObjectiveModelCheckerEnvironment::MultiObjectiveModelCheckerEnvironment() { + auto const& multiobjectiveSettings = storm::settings::getModule(); + method = multiobjectiveSettings.getMultiObjectiveMethod(); + if (multiobjectiveSettings.isExportPlotSet()) { + plotPathUnderApprox = multiobjectiveSettings.getExportPlotDirectory() + "underapproximation.csv"; + plotPathOverApprox = multiobjectiveSettings.getExportPlotDirectory() + "overapproximation.csv"; + plotPathParetoPoints = multiobjectiveSettings.getExportPlotDirectory() + "paretopoints.csv"; + } + + precision = storm::utility::convertNumber(multiobjectiveSettings.getPrecision()); + if (multiobjectiveSettings.isMaxStepsSet()) { + maxSteps = multiobjectiveSettings.getMaxSteps(); + } + } + + MultiObjectiveModelCheckerEnvironment::~MultiObjectiveModelCheckerEnvironment() { + // Intentionally left empty + } + + storm::modelchecker::multiobjective::MultiObjectiveMethod const& MultiObjectiveModelCheckerEnvironment::getMethod() const { + return this->method; + } + + void MultiObjectiveModelCheckerEnvironment::setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value) { + this->method = value; + } + + bool MultiObjectiveModelCheckerEnvironment::isExportPlotSet() const { + return this->plotPathUnderApprox.is_initialized() || this->plotPathOverApprox.is_initialized() || this->plotPathParetoPoints.is_initialized(); + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathUnderApproximation() const { + return plotPathUnderApprox; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathUnderApproximation(std::string const& path) { + plotPathUnderApprox = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathUnderApproximation() { + plotPathUnderApprox = boost::none; + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathOverApproximation() const { + return plotPathOverApprox; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathOverApproximation(std::string const& path) { + plotPathOverApprox = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathOverApproximation() { + plotPathOverApprox = boost::none; + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathParetoPoints() const { + return plotPathParetoPoints; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathParetoPoints(std::string const& path) { + plotPathParetoPoints = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathParetoPoints() { + plotPathParetoPoints = boost::none; + } + + storm::RationalNumber const& MultiObjectiveModelCheckerEnvironment::getPrecision() const { + return precision; + } + + void MultiObjectiveModelCheckerEnvironment::setPrecision(storm::RationalNumber const& value) { + precision = value; + } + + bool MultiObjectiveModelCheckerEnvironment::isMaxStepsSet() const { + return maxSteps.is_initialized(); + } + + uint64_t const& MultiObjectiveModelCheckerEnvironment::getMaxSteps() const { + return maxSteps.get(); + } + + void MultiObjectiveModelCheckerEnvironment::setMaxSteps(uint64_t const& value) { + maxSteps = value; + } + + void MultiObjectiveModelCheckerEnvironment::unsetMaxSteps() { + maxSteps = boost::none; + } +} \ No newline at end of file diff --git a/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h new file mode 100644 index 000000000..f1d4f0203 --- /dev/null +++ b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" +#include "storm/modelchecker/multiobjective/MultiObjectiveModelCheckingMethod.h" +#include "storm/adapters/RationalNumberAdapter.h" + +namespace storm { + + class MultiObjectiveModelCheckerEnvironment { + public: + + MultiObjectiveModelCheckerEnvironment(); + ~MultiObjectiveModelCheckerEnvironment(); + + storm::modelchecker::multiobjective::MultiObjectiveMethod const& getMethod() const; + void setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value); + + bool isExportPlotSet() const; + boost::optional getPlotPathUnderApproximation() const; + void setPlotPathUnderApproximation(std::string const& path); + void unsetPlotPathUnderApproximation(); + boost::optional getPlotPathOverApproximation() const; + void setPlotPathOverApproximation(std::string const& path); + void unsetPlotPathOverApproximation(); + boost::optional getPlotPathParetoPoints() const; + void setPlotPathParetoPoints(std::string const& path); + void unsetPlotPathParetoPoints(); + + storm::RationalNumber const& getPrecision() const; + void setPrecision(storm::RationalNumber const& value); + + uint64_t const& getMaxSteps() const; + bool isMaxStepsSet() const; + void setMaxSteps(uint64_t const& value); + void unsetMaxSteps(); + + + private: + storm::modelchecker::multiobjective::MultiObjectiveMethod method; + boost::optional plotPathUnderApprox, plotPathOverApprox, plotPathParetoPoints; + storm::RationalNumber precision; + boost::optional maxSteps; + + }; +} + diff --git a/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp b/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp index 10276ffa6..bb18e9385 100644 --- a/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp +++ b/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp @@ -1,7 +1,7 @@ #include "storm/modelchecker/multiobjective/multiObjectiveModelChecking.h" #include "storm/utility/macros.h" - +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -74,8 +74,8 @@ namespace storm { result = query->check(env); - if(storm::settings::getModule().isExportPlotSet()) { - query->exportPlotOfCurrentApproximation(storm::settings::getModule().getExportPlotDirectory()); + if (env.modelchecker().multi().isExportPlotSet()) { + query->exportPlotOfCurrentApproximation(env); } break; } diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp index 409bd9ba9..b8ac5fe2d 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp @@ -7,9 +7,8 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/GeneralSettings.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + #include "storm/exceptions/InvalidOperationException.h" @@ -57,7 +56,7 @@ namespace storm { template bool SparsePcaaAchievabilityQuery::checkAchievability(Environment const& env) { // repeatedly refine the over/ under approximation until the threshold point is either in the under approx. or not in the over approx. - while(!this->maxStepsPerformed()){ + while(!this->maxStepsPerformed(env)){ WeightVector separatingVector = this->findSeparatingVector(thresholds); this->updateWeightedPrecision(separatingVector); this->performRefinementStep(env, std::move(separatingVector)); diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp index fe7a7b367..93c04e527 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp @@ -7,10 +7,7 @@ #include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" -#include "storm/settings/modules/GeneralSettings.h" - +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" namespace storm { namespace modelchecker { @@ -19,20 +16,19 @@ namespace storm { template SparsePcaaParetoQuery::SparsePcaaParetoQuery(SparseMultiObjectivePreprocessorResult& preprocessorResult) : SparsePcaaQuery(preprocessorResult) { STORM_LOG_ASSERT(preprocessorResult.queryType==SparseMultiObjectivePreprocessorResult::QueryType::Pareto, "Invalid query Type"); + } + + template + std::unique_ptr SparsePcaaParetoQuery::check(Environment const& env) { // Set the precision of the weight vector checker - typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber(storm::settings::getModule().getPrecision()); + typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber(env.modelchecker().multi().getPrecision()); weightedPrecision /= storm::utility::sqrt(storm::utility::convertNumber(this->objectives.size())); // multiobjPrecision / sqrt(numObjectives) is the largest possible value for which termination is guaranteed. // Lets be a little bit more precise to reduce the number of required iterations. weightedPrecision *= storm::utility::convertNumber(0.9); this->weightVectorChecker->setWeightedPrecision(weightedPrecision); - - } - - template - std::unique_ptr SparsePcaaParetoQuery::check(Environment const& env) { - + // refine the approximation exploreSetOfAchievablePoints(env); @@ -55,13 +51,13 @@ namespace storm { void SparsePcaaParetoQuery::exploreSetOfAchievablePoints(Environment const& env) { //First consider the objectives individually - for(uint_fast64_t objIndex = 0; objIndexobjectives.size() && !this->maxStepsPerformed(); ++objIndex) { + for(uint_fast64_t objIndex = 0; objIndexobjectives.size() && !this->maxStepsPerformed(env); ++objIndex) { WeightVector direction(this->objectives.size(), storm::utility::zero()); direction[objIndex] = storm::utility::one(); this->performRefinementStep(env, std::move(direction)); } - while(!this->maxStepsPerformed()) { + while(!this->maxStepsPerformed(env)) { // Get the halfspace of the underApproximation with maximal distance to a vertex of the overApproximation std::vector> underApproxHalfspaces = this->underApproximation->getHalfspaces(); std::vector overApproxVertices = this->overApproximation->getVertices(); @@ -76,7 +72,7 @@ namespace storm { } } } - if(farestDistance < storm::utility::convertNumber(storm::settings::getModule().getPrecision())) { + if(farestDistance < storm::utility::convertNumber(env.modelchecker().multi().getPrecision())) { // Goal precision reached! return; } diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp index 538752ab2..4df353cdd 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp @@ -8,9 +8,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" -#include "storm/settings/modules/GeneralSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/exceptions/InvalidOperationException.h" @@ -99,7 +97,7 @@ namespace storm { // We don't care for the optimizing objective at this point this->diracWeightVectorsToBeChecked.set(indexOfOptimizingObjective, false); - while(!this->maxStepsPerformed()){ + while(!this->maxStepsPerformed(env)){ WeightVector separatingVector = this->findSeparatingVector(thresholds); this->updateWeightedPrecisionInAchievabilityPhase(separatingVector); this->performRefinementStep(env, std::move(separatingVector)); @@ -150,10 +148,10 @@ namespace storm { // the supremum over all strategies. Hence, one could combine a scheduler inducing the optimum value (but possibly violating strict // thresholds) and (with very low probability) a scheduler that satisfies all (possibly strict) thresholds. GeometryValueType result = storm::utility::zero(); - while(!this->maxStepsPerformed()) { + while(!this->maxStepsPerformed(env)) { if (this->refinementSteps.empty()) { // We did not make any refinement steps during the checkAchievability phase (e.g., because there is only one objective). - this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber(storm::settings::getModule().getPrecision())); + this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber(env.modelchecker().multi().getPrecision())); WeightVector separatingVector = directionOfOptimizingObjective; this->performRefinementStep(env, std::move(separatingVector)); } @@ -165,7 +163,7 @@ namespace storm { optimizationRes = this->overApproximation->intersection(thresholdsAsPolytope)->optimize(directionOfOptimizingObjective); if (optimizationRes.second) { GeometryValueType precisionOfResult = optimizationRes.first[indexOfOptimizingObjective] - result; - if (precisionOfResult < storm::utility::convertNumber(storm::settings::getModule().getPrecision())) { + if (precisionOfResult < storm::utility::convertNumber(env.modelchecker().multi().getPrecision())) { // Goal precision reached! return result; } else { @@ -176,7 +174,7 @@ namespace storm { thresholds[indexOfOptimizingObjective] = result + storm::utility::one(); } WeightVector separatingVector = this->findSeparatingVector(thresholds); - this->updateWeightedPrecisionInImprovingPhase(separatingVector); + this->updateWeightedPrecisionInImprovingPhase(env, separatingVector); this->performRefinementStep(env, std::move(separatingVector)); } STORM_LOG_ERROR("Could not reach the desired precision: Exceeded maximum number of refinement steps"); @@ -185,11 +183,11 @@ namespace storm { template - void SparsePcaaQuantitativeQuery::updateWeightedPrecisionInImprovingPhase(WeightVector const& weights) { + void SparsePcaaQuantitativeQuery::updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights) { STORM_LOG_THROW(!storm::utility::isZero(weights[this->indexOfOptimizingObjective]), exceptions::UnexpectedException, "The chosen weight-vector gives zero weight for the objective that is to be optimized."); // If weighs[indexOfOptimizingObjective] is low, the computation of the weightVectorChecker needs to be more precise. // Our heuristic ensures that if p is the new vertex of the under-approximation, then max{ eps | p' = p + (0..0 eps 0..0) is in the over-approximation } <= multiobjective_precision/0.9 - GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber(storm::settings::getModule().getPrecision()); + GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber(env.modelchecker().multi().getPrecision()); // Normalize by division with the Euclidean Norm of the weight-vector weightedPrecision /= storm::utility::sqrt(storm::utility::vector::dotProduct(weights, weights)); weightedPrecision *= storm::utility::convertNumber(0.9); diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h index 164a87f21..234e6f291 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h @@ -45,7 +45,7 @@ namespace storm { * Updates the precision of the weightVectorChecker w.r.t. the provided weights */ void updateWeightedPrecisionInAchievabilityPhase(WeightVector const& weights); - void updateWeightedPrecisionInImprovingPhase(WeightVector const& weights); + void updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights); /* * Given that the thresholds are achievable, this function further refines the approximations and returns the optimized value diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp index 2164665e0..ef7e50d80 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp @@ -5,8 +5,7 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/multiobjective/Objective.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/storage/geometry/Hyperrectangle.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" @@ -126,9 +125,9 @@ namespace storm { } template - bool SparsePcaaQuery::maxStepsPerformed() const { - return storm::settings::getModule().isMaxStepsSet() && - this->refinementSteps.size() >= storm::settings::getModule().getMaxSteps(); + bool SparsePcaaQuery::maxStepsPerformed(Environment const& env) const { + return env.modelchecker().multi().isMaxStepsSet() && + this->refinementSteps.size() >= env.modelchecker().multi().getMaxSteps(); } @@ -191,7 +190,7 @@ namespace storm { } template - void SparsePcaaQuery::exportPlotOfCurrentApproximation(std::string const& destinationDir) const { + void SparsePcaaQuery::exportPlotOfCurrentApproximation(Environment const& env) const { STORM_LOG_ERROR_COND(objectives.size()==2, "Exporting plot requested but this is only implemented for the two-dimensional case."); @@ -223,35 +222,33 @@ namespace storm { std::vector columnHeaders = {"x", "y"}; std::vector> pointsForPlotting; - underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(underApproxVertices.size()); - for(auto const& v : underApproxVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); - } - storm::utility::exportDataToCSVFile(destinationDir + "underapproximation.csv", pointsForPlotting, columnHeaders); - - pointsForPlotting.clear(); - overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(overApproxVertices.size()); - for(auto const& v : overApproxVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathUnderApproximation()) { + underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); + pointsForPlotting.reserve(underApproxVertices.size()); + for(auto const& v : underApproxVertices) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathUnderApproximation().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "overapproximation.csv", pointsForPlotting, columnHeaders); - pointsForPlotting.clear(); - pointsForPlotting.reserve(paretoPoints.size()); - for(auto const& v : paretoPoints) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathOverApproximation()) { + pointsForPlotting.clear(); + overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); + pointsForPlotting.reserve(overApproxVertices.size()); + for(auto const& v : overApproxVertices) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathOverApproximation().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "paretopoints.csv", pointsForPlotting, columnHeaders); - pointsForPlotting.clear(); - auto boundVertices = boundariesAsPolytope->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(4); - for(auto const& v : boundVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathParetoPoints()) { + pointsForPlotting.clear(); + pointsForPlotting.reserve(paretoPoints.size()); + for(auto const& v : paretoPoints) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathParetoPoints().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "boundaries.csv", pointsForPlotting, columnHeaders); } #ifdef STORM_HAVE_CARL diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h index d92f0ccee..630503a08 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h @@ -38,7 +38,7 @@ namespace storm { * Note that the approximations will be intersected with a (sufficiently large) hyperrectangle in order to ensure that the polytopes are bounded * This only works for 2 dimensional queries. */ - void exportPlotOfCurrentApproximation(std::string const& destinationDir) const; + void exportPlotOfCurrentApproximation(Environment const& env) const; protected: @@ -87,7 +87,7 @@ namespace storm { /* * Returns true iff the maximum number of refinement steps (as possibly specified in the settings) has been reached */ - bool maxStepsPerformed() const; + bool maxStepsPerformed(Environment const& env) const; /* * Transforms the given point (or polytope) to values w.r.t. the original model/formula (e.g. negates values for minimizing objectives). From 7ef779a8a6c5f8790911123d735661847eb7be5c Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 28 May 2018 16:38:59 +0200 Subject: [PATCH 318/647] fixing one bug in abstraction using decomposition, started tracking down more --- src/storm/abstraction/jani/EdgeAbstractor.cpp | 2 +- .../abstraction/prism/CommandAbstractor.cpp | 27 +++++++++++++++---- .../prism/PrismMenuGameAbstractor.cpp | 6 +++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index 2342a497f..c0592df3c 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -561,9 +561,9 @@ namespace storm { } else { updateBdd &= !this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } - updateBdd &= this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } + updateBdd &= this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); result |= updateBdd; } diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index d7003a39f..929285943 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -240,6 +240,8 @@ namespace storm { uint64_t numberOfSolutions = 0; uint64_t numberOfTotalSolutions = 0; + std::cout << localExpressionInformation << std::endl; + // If we need to enumerate the guard, do it only once now. if (enumerateAbstractGuard) { std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); @@ -258,8 +260,10 @@ namespace storm { return true; }); STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); + abstractGuard.template toAdd().exportToDot("abstractguard" + std::to_string(command.get().getGlobalIndex()) + ".dot"); + - // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating + // Now that we have the abstract guard, we can add it as an assertion to the solver before enumerating // the other solutions. // Create a new backtracking point before adding the guard. @@ -288,7 +292,7 @@ namespace storm { for (auto const& innerBlock : block) { relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); } - + if (relevantPredicates.empty()) { STORM_LOG_TRACE("Block does not contain relevant predicates, skipping it."); continue; @@ -297,7 +301,9 @@ namespace storm { std::vector transitionDecisionVariables; std::vector> sourceVariablesAndPredicates; for (auto const& element : relevantPredicatesAndVariables.first) { + std::cout << "1-querying " << abstractionInformation.get().getPredicateByIndex(element.second) << std::endl; if (relevantPredicates.find(element.second) != relevantPredicates.end()) { + std::cout << "1-is relevant!" << std::endl; transitionDecisionVariables.push_back(element.first); sourceVariablesAndPredicates.push_back(element); } @@ -308,10 +314,14 @@ namespace storm { destinationVariablesAndPredicates.emplace_back(); for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); - std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); + std::cout << "assignment variable " << assignment.getVariable().getName() << " block index: " << assignmentVariableBlockIndex << std::endl; + if (block.find(assignmentVariableBlockIndex) != block.end()) { + std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { + std::cout << "2-querying " << abstractionInformation.get().getPredicateByIndex(element.second) << std::endl; if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { + std::cout << "2-is relevant!" << std::endl; destinationVariablesAndPredicates.back().push_back(element); transitionDecisionVariables.push_back(element.first); } @@ -355,6 +365,7 @@ namespace storm { storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); for (auto const& distribution : sourceDistributionsPair.second) { allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); + distribution.template toAdd().exportToDot("dist" + std::to_string(distributionIndex) + ".dot"); ++distributionIndex; STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); } @@ -364,6 +375,9 @@ namespace storm { } usedNondeterminismVariables += numberOfVariablesNeeded; +// resultBdd.template toAdd().exportToDot("result.dot"); +// exit(-1); + blockBdds.push_back(resultBdd); ++blockCounter; } @@ -406,6 +420,8 @@ namespace storm { // multiply with missing identities resultBdd &= computeMissingIdentities(); + resultBdd.template toAdd().exportToDot("decomp_idents" + std::to_string(command.get().getGlobalIndex()) + ".dot"); + // cache and return result resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); @@ -595,9 +611,10 @@ namespace storm { } else { updateBdd &= !this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } - updateBdd &= this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } - + + updateBdd &= this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); + result |= updateBdd; } diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 529ecffad..d9cbdd46e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -180,6 +180,12 @@ namespace storm { } initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + transitionRelation.template toAdd().exportToDot("transrel.dot"); + (initialStates && transitionRelation).template toAdd().exportToDot("transrelinit.dot"); + (transitionRelation && abstractionInformation.encodePlayer1Choice(6, this->getAbstractionInformation().getPlayer1VariableCount())).template toAdd().exportToDot("trans6.dot"); + + initialStates.template toAdd().exportToDot("initial.dot"); relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { From e78057256074e67bf8af3f9aabab9939f7fbdbe9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 28 May 2018 21:38:17 +0200 Subject: [PATCH 319/647] changing command decomposition of game-based abstraction and further debugging --- src/storm/abstraction/MenuGameRefiner.cpp | 4 + .../abstraction/prism/CommandAbstractor.cpp | 108 ++++++------------ .../abstraction/prism/CommandAbstractor.h | 14 +-- .../prism/PrismMenuGameAbstractor.cpp | 11 +- .../abstraction/GameBasedMdpModelChecker.cpp | 2 - 5 files changed, 52 insertions(+), 87 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 84ac8e7af..a9db0f620 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -279,6 +279,10 @@ namespace storm { // Decode both choices to explicit mappings. std::map> lowerChoiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(lowerChoice); std::map> upperChoiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(upperChoice); + + lowerChoice.template toAdd().exportToDot("lower.dot"); + upperChoice.template toAdd().exportToDot("upper.dot"); + STORM_LOG_ASSERT(lowerChoiceUpdateToSuccessorMapping.size() == upperChoiceUpdateToSuccessorMapping.size(), "Mismatching sizes after decode (" << lowerChoiceUpdateToSuccessorMapping.size() << " vs. " << upperChoiceUpdateToSuccessorMapping.size() << ")."); // First, sort updates according to probability mass. diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 929285943..84fe80137 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -98,7 +98,7 @@ namespace storm { template void CommandAbstractor::recomputeCachedBddWithDecomposition() { - STORM_LOG_TRACE("Recomputing BDD for command " << command.get() << " using the decomposition."); + STORM_LOG_TRACE("Recomputing BDD for command with index " << command.get().getGlobalIndex() << " (" << command.get() << ") using the decomposition."); auto start = std::chrono::high_resolution_clock::now(); // compute a decomposition of the command @@ -205,18 +205,16 @@ namespace storm { relevantBlockPartition = std::move(cleanedRelevantBlockPartition); STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); - for (auto const& block : relevantBlockPartition) { - STORM_LOG_TRACE("New block of size " << block.size() << ":"); - - std::set blockPredicateIndices; - for (auto const& innerBlock : block) { - blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); - } - - for (auto const& predicateIndex : blockPredicateIndices) { - STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); - } - } +// for (auto const& block : relevantBlockPartition) { +// std::set blockPredicateIndices; +// for (auto const& innerBlock : block) { +// blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); +// } +// +// for (auto const& predicateIndex : blockPredicateIndices) { +// STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); +// } +// } std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); @@ -240,8 +238,6 @@ namespace storm { uint64_t numberOfSolutions = 0; uint64_t numberOfTotalSolutions = 0; - std::cout << localExpressionInformation << std::endl; - // If we need to enumerate the guard, do it only once now. if (enumerateAbstractGuard) { std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); @@ -260,8 +256,6 @@ namespace storm { return true; }); STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); - abstractGuard.template toAdd().exportToDot("abstractguard" + std::to_string(command.get().getGlobalIndex()) + ".dot"); - // Now that we have the abstract guard, we can add it as an assertion to the solver before enumerating // the other solutions. @@ -301,9 +295,7 @@ namespace storm { std::vector transitionDecisionVariables; std::vector> sourceVariablesAndPredicates; for (auto const& element : relevantPredicatesAndVariables.first) { - std::cout << "1-querying " << abstractionInformation.get().getPredicateByIndex(element.second) << std::endl; if (relevantPredicates.find(element.second) != relevantPredicates.end()) { - std::cout << "1-is relevant!" << std::endl; transitionDecisionVariables.push_back(element.first); sourceVariablesAndPredicates.push_back(element); } @@ -314,14 +306,11 @@ namespace storm { destinationVariablesAndPredicates.emplace_back(); for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); - std::cout << "assignment variable " << assignment.getVariable().getName() << " block index: " << assignmentVariableBlockIndex << std::endl; if (block.find(assignmentVariableBlockIndex) != block.end()) { std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { - std::cout << "2-querying " << abstractionInformation.get().getPredicateByIndex(element.second) << std::endl; if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { - std::cout << "2-is relevant!" << std::endl; destinationVariablesAndPredicates.back().push_back(element); transitionDecisionVariables.push_back(element.first); } @@ -350,7 +339,6 @@ namespace storm { // We now compute how many variables we need to encode the choices. We add one to the maximal number of // choices to account for a possible transition to a bottom state. uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))); - std::cout << "need " << numberOfVariablesNeeded << " variables for " << (maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)) << " choices" << std::endl; // Finally, build overall result. storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); @@ -365,7 +353,6 @@ namespace storm { storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); for (auto const& distribution : sourceDistributionsPair.second) { allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); - distribution.template toAdd().exportToDot("dist" + std::to_string(distributionIndex) + ".dot"); ++distributionIndex; STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); } @@ -375,9 +362,6 @@ namespace storm { } usedNondeterminismVariables += numberOfVariablesNeeded; -// resultBdd.template toAdd().exportToDot("result.dot"); -// exit(-1); - blockBdds.push_back(resultBdd); ++blockCounter; } @@ -390,7 +374,6 @@ namespace storm { storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); uint64_t blockIndex = 0; for (auto const& blockBdd : blockBdds) { - blockBdd.template toAdd().exportToDot("block" + std::to_string(command.get().getGlobalIndex()) + "_" + std::to_string(blockIndex) + ".dot"); resultBdd &= blockBdd; ++blockIndex; } @@ -412,16 +395,9 @@ namespace storm { resultBdd &= abstractGuard; } - resultBdd.template toAdd().exportToDot("decomp" + std::to_string(command.get().getGlobalIndex()) + ".dot"); - - auto identities = computeMissingIdentities(); - identities.template toAdd().exportToDot("idents" + std::to_string(command.get().getGlobalIndex()) + ".dot"); - // multiply with missing identities resultBdd &= computeMissingIdentities(); - resultBdd.template toAdd().exportToDot("decomp_idents" + std::to_string(command.get().getGlobalIndex()) + ".dot"); - // cache and return result resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); @@ -483,8 +459,6 @@ namespace storm { STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } - resultBdd.template toAdd().exportToDot("nodecomp" + std::to_string(command.get().getGlobalIndex()) + ".dot"); - resultBdd &= computeMissingIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -504,12 +478,12 @@ namespace storm { std::set assignedVariables; for (auto const& assignment : assignments) { // Also, variables appearing on the right-hand side of an assignment are relevant for source state. - auto const& rightHandSidePredicates = localExpressionInformation.getRelatedExpressions(assignment.getExpression().getVariables()); + auto const& rightHandSidePredicates = localExpressionInformation.getExpressionsUsingVariables(assignment.getExpression().getVariables()); result.first.insert(rightHandSidePredicates.begin(), rightHandSidePredicates.end()); // Variables that are being assigned are relevant for the successor state. storm::expressions::Variable const& assignedVariable = assignment.getVariable(); - auto const& leftHandSidePredicates = localExpressionInformation.getRelatedExpressions(assignedVariable); + auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); // // Keep track of all assigned variables, so we can find the related predicates later. @@ -624,9 +598,7 @@ namespace storm { template storm::dd::Bdd CommandAbstractor::computeMissingIdentities() const { - storm::dd::Bdd identities = computeMissingGlobalIdentities(); - identities &= computeMissingUpdateIdentities(); - return identities; + return computeMissingUpdateIdentities(); } template @@ -639,51 +611,45 @@ namespace storm { auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].end(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - auto sourceRelevantIt = relevantPredicatesAndVariables.first.begin(); - auto sourceRelevantIte = relevantPredicatesAndVariables.first.end(); - // Go through all relevant source predicates. This is guaranteed to be a superset of the set of - // relevant successor predicates for any update. - for (; sourceRelevantIt != sourceRelevantIte; ++sourceRelevantIt) { - // If the predicates do not match, there is a predicate missing, so we need to add its identity. - if (updateRelevantIt == updateRelevantIte || sourceRelevantIt->second != updateRelevantIt->second) { - std::cout << "adding update identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(sourceRelevantIt->second) << " to update " << updateIndex << std::endl; - updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(sourceRelevantIt->second); + for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { + if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { + updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++updateRelevantIt; } } - + result |= updateIdentity && this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } return result; } - template - storm::dd::Bdd CommandAbstractor::computeMissingGlobalIdentities() const { - storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - - auto relevantIt = relevantPredicatesAndVariables.first.begin(); - auto relevantIte = relevantPredicatesAndVariables.first.end(); - - for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { - if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { - std::cout << "adding global identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(predicateIndex) << std::endl; - result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); - } else { - ++relevantIt; - } - } - - return result; - } +// template +// storm::dd::Bdd CommandAbstractor::computeMissingGlobalIdentities() const { +// storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); +// +// auto relevantIt = relevantPredicatesAndVariables.first.begin(); +// auto relevantIte = relevantPredicatesAndVariables.first.end(); +// +// for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { +// if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { +// std::cout << "adding global identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(predicateIndex) << std::endl; +// result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); +// } else { +// ++relevantIt; +// } +// } +// +// return result; +// } template GameBddResult CommandAbstractor::abstract() { if (forceRecomputation) { this->recomputeCachedBdd(); } else { - cachedDd.bdd &= computeMissingGlobalIdentities(); + cachedDd.bdd &= computeMissingUpdateIdentities(); } STORM_LOG_TRACE("Command produces " << cachedDd.bdd.getNonZeroCount() << " transitions."); diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index cb6146e73..9b911c8f5 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -213,13 +213,13 @@ namespace storm { */ AbstractionInformation& getAbstractionInformation(); - /*! - * Computes the globally missing state identities. - * - * @return A BDD that represents the global state identities for predicates that are irrelevant for the - * source and successor states. - */ - storm::dd::Bdd computeMissingGlobalIdentities() const; +// /*! +// * Computes the globally missing state identities. +// * +// * @return A BDD that represents the global state identities for predicates that are irrelevant for the +// * source and successor states. +// */ +// storm::dd::Bdd computeMissingGlobalIdentities() const; // An SMT responsible for this abstract command. std::unique_ptr smtSolver; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index d9cbdd46e..661aeca57 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -172,20 +172,17 @@ namespace storm { } relevantStatesWatch.stop(); + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + // Do a reachability analysis on the raw transition relation. storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); if (program.get().hasInitialConstruct()) { - initialStates &= validBlockAbstractor.getValidBlocks(); + initialStates &= validBlocks; } initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - - transitionRelation.template toAdd().exportToDot("transrel.dot"); - (initialStates && transitionRelation).template toAdd().exportToDot("transrelinit.dot"); - (transitionRelation && abstractionInformation.encodePlayer1Choice(6, this->getAbstractionInformation().getPlayer1VariableCount())).template toAdd().exportToDot("trans6.dot"); - - initialStates.template toAdd().exportToDot("initial.dot"); + reachableStates &= validBlocks; relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index c79a423d3..588040ce9 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -573,8 +573,6 @@ namespace storm { targetStates |= game.getBottomStates(); } - exit(-1); - // #ifdef LOCAL_DEBUG // initialStates.template toAdd().exportToDot("init" + std::to_string(iteration) + ".dot"); // targetStates.template toAdd().exportToDot("target" + std::to_string(iteration) + ".dot"); From 769fd4332c90674aff95a0651caaa53f457e7e22 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 29 May 2018 15:17:30 +0200 Subject: [PATCH 320/647] further debugging of game-based abstraction --- src/storm/abstraction/MenuGameRefiner.cpp | 63 ++++++++++++++----- src/storm/abstraction/MenuGameRefiner.h | 10 ++- .../abstraction/prism/CommandAbstractor.cpp | 28 +++++---- .../abstraction/prism/CommandAbstractor.h | 5 +- .../abstraction/prism/ModuleAbstractor.cpp | 4 +- .../abstraction/prism/ModuleAbstractor.h | 2 +- .../prism/PrismMenuGameAbstractor.cpp | 23 ++++--- .../abstraction/GameBasedMdpModelChecker.cpp | 4 +- .../settings/modules/AbstractionSettings.cpp | 22 +++++++ .../settings/modules/AbstractionSettings.h | 17 +++++ 10 files changed, 134 insertions(+), 44 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index a9db0f620..e511c3e29 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -14,6 +14,8 @@ #include "storm/utility/solver.h" #include "storm/utility/shortestPaths.h" +#include "storm/parser/ExpressionParser.h" + #include "storm/solver/MathsatSmtSolver.h" #include "storm/models/symbolic/StandardRewardModel.h" @@ -76,7 +78,7 @@ namespace storm { addPredicatesEagerly = abstractionSettings.isUseEagerRefinementSet(); equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); - if (storm::settings::getModule().isAddAllGuardsSet()) { + if (abstractionSettings.isAddAllGuardsSet()) { std::vector guards; std::pair player1Choices = this->abstractor.get().getPlayer1ChoiceRange(); @@ -91,11 +93,34 @@ namespace storm { this->abstractor.get().notifyGuardsArePredicates(); addedAllGuardsFlag = true; } + + if (abstractionSettings.isInjectRefinementPredicatesSet()) { + std::string predicatesString = abstractionSettings.getInjectedRefinementPredicates(); + std::vector predicatesAsStrings; + boost::split(predicatesAsStrings, predicatesString, boost::is_any_of(";")); + + auto const& expressionManager = abstractor.getAbstractionInformation().getExpressionManager(); + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + for (auto const& predicateString : predicatesAsStrings) { + storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); + STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); + refinementPredicatesToInject.emplace_back(predicate); + } + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(refinementPredicatesToInject.begin(), refinementPredicatesToInject.end()); + } } template - void MenuGameRefiner::refine(std::vector const& predicates) const { - performRefinement(createGlobalRefinement(preprocessPredicates(predicates, RefinementPredicates::Source::Manual))); + void MenuGameRefiner::refine(std::vector const& predicates, bool allowInjection) const { + performRefinement(createGlobalRefinement(preprocessPredicates(predicates, RefinementPredicates::Source::Manual)), allowInjection); } template @@ -279,10 +304,6 @@ namespace storm { // Decode both choices to explicit mappings. std::map> lowerChoiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(lowerChoice); std::map> upperChoiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(upperChoice); - - lowerChoice.template toAdd().exportToDot("lower.dot"); - upperChoice.template toAdd().exportToDot("upper.dot"); - STORM_LOG_ASSERT(lowerChoiceUpdateToSuccessorMapping.size() == upperChoiceUpdateToSuccessorMapping.size(), "Mismatching sizes after decode (" << lowerChoiceUpdateToSuccessorMapping.size() << " vs. " << upperChoiceUpdateToSuccessorMapping.size() << ")."); // First, sort updates according to probability mass. @@ -536,7 +557,11 @@ namespace storm { if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) { return additionalPredicates.get(); } else { - predicates.get().addPredicates(additionalPredicates.get().getPredicates()); + if (!predicates) { + predicates = additionalPredicates; + } else { + predicates.get().addPredicates(additionalPredicates.get().getPredicates()); + } } } @@ -1569,14 +1594,20 @@ namespace storm { } template - void MenuGameRefiner::performRefinement(std::vector const& refinementCommands) const { - for (auto const& command : refinementCommands) { - STORM_LOG_INFO("Refining with " << command.getPredicates().size() << " predicates."); - for (auto const& predicate : command.getPredicates()) { - STORM_LOG_INFO(predicate); - } - if (!command.getPredicates().empty()) { - abstractor.get().refine(command); + void MenuGameRefiner::performRefinement(std::vector const& refinementCommands, bool allowInjection) const { + if (!refinementPredicatesToInject.empty() && allowInjection) { + STORM_LOG_INFO("Refining with (injected) predicate " << refinementPredicatesToInject.back() << "."); + abstractor.get().refine(RefinementCommand({refinementPredicatesToInject.back()})); + refinementPredicatesToInject.pop_back(); + } else { + for (auto const& command : refinementCommands) { + STORM_LOG_INFO("Refining with " << command.getPredicates().size() << " predicates."); + for (auto const& predicate : command.getPredicates()) { + STORM_LOG_INFO(predicate); + } + if (!command.getPredicates().empty()) { + abstractor.get().refine(command); + } } } diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 403cd92c7..276d178fb 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -107,8 +107,10 @@ namespace storm { * Refines the abstractor with the given predicates. * * @param predicates The predicates to use for refinement. + * @param allowInjection If true, the refiner is free to inject manually-specified refinement predicates + * instead of the provided ones. */ - void refine(std::vector const& predicates) const; + void refine(std::vector const& predicates, bool allowInjection = true) const; /*! * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. @@ -170,7 +172,7 @@ namespace storm { boost::optional derivePredicatesFromInterpolationKShortestPaths(storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ValueType minProbability, ValueType maxProbability, ExplicitGameStrategyPair const& maxStrategyPair) const; boost::optional derivePredicatesFromInterpolationReversedPath(storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector const& reversedPath, std::vector const& stateToOffset, std::vector const& player1Labels) const; - void performRefinement(std::vector const& refinementCommands) const; + void performRefinement(std::vector const& refinementCommands, bool allowInjection = true) const; /// The underlying abstractor to refine. std::reference_wrapper> abstractor; @@ -193,6 +195,10 @@ namespace storm { /// A flag indicating whether all guards have been used to refine the abstraction. bool addedAllGuardsFlag; + /// A vector of refinement predicates that are injected (starting with the *last* one in this list). If + // empty, the predicates are derived as usual. + mutable std::vector refinementPredicatesToInject; + /// The heuristic to use for pivot block selection. storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic; diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 84fe80137..ff9884720 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace prism { template - CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory) { + CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); @@ -205,16 +205,22 @@ namespace storm { relevantBlockPartition = std::move(cleanedRelevantBlockPartition); STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); -// for (auto const& block : relevantBlockPartition) { -// std::set blockPredicateIndices; -// for (auto const& innerBlock : block) { -// blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); -// } -// -// for (auto const& predicateIndex : blockPredicateIndices) { -// STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); -// } -// } + if (this->debug) { + uint64_t blockIndex = 0; + for (auto const& block : relevantBlockPartition) { + STORM_LOG_TRACE("Predicates of block " << blockIndex << ":"); + std::set blockPredicateIndices; + for (auto const& innerBlock : block) { + blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } + + for (auto const& predicateIndex : blockPredicateIndices) { + STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); + } + + ++blockIndex; + } + } std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index 9b911c8f5..e6d7c7238 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -56,7 +56,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); /*! * Refines the abstract command with the given predicates. @@ -268,6 +268,9 @@ namespace storm { // A state-set abstractor used to determine the bottom states if not all guards were added. StateSetAbstractor bottomStateAbstractor; + + // A flag that indicates whether or not debug mode is enabled. + bool debug; }; } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index 09e1932cb..d1574e23b 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -23,12 +23,12 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { + ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { // For each concrete command, we create an abstract counterpart. uint64_t counter = 0; for (auto const& command : module.getCommands()) { - commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition); + commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition, debug); ++counter; } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index d5d2e9dc7..9771347c6 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -38,7 +38,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag that governs whether to use the decomposition in the abstraction. */ - ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); ModuleAbstractor(ModuleAbstractor const&) = default; ModuleAbstractor& operator=(ModuleAbstractor const&) = default; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 661aeca57..7370645ac 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -65,9 +65,11 @@ namespace storm { abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 64, static_cast(std::ceil(std::log2(maximalUpdateCount)))); // For each module of the concrete program, we create an abstract counterpart. - bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); + auto const& settings = storm::settings::getModule(); + bool useDecomposition = settings.isUseDecompositionSet(); + bool debug = settings.isDebugSet(); for (auto const& module : program.getModules()) { - this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition); + this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition, debug); } // Retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later. @@ -154,10 +156,12 @@ namespace storm { // Construct a set of all unnecessary variables, so we can abstract from it. std::set variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount())); + std::set successorAndAuxVariables(abstractionInformation.getSuccessorVariables()); auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables); variablesToAbstract.insert(player2Variables.begin(), player2Variables.end()); auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + successorAndAuxVariables.insert(auxVariables.begin(), auxVariables.end()); storm::utility::Stopwatch relevantStatesWatch(true); storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); @@ -173,16 +177,17 @@ namespace storm { relevantStatesWatch.stop(); storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + + // Compute the choices with only valid successors so we can restrict the game to these. + + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); - storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); - if (program.get().hasInitialConstruct()) { - initialStates &= validBlocks; - } + storm::dd::Bdd extendedTransitionRelation = validBlocks && nonTerminalStates && game.bdd && choicesWithOnlyValidSuccessors; + storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); + storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates() && validBlocks; initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - reachableStates &= validBlocks; relevantStatesWatch.start(); if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { @@ -222,7 +227,7 @@ namespace storm { // Construct the transition matrix by cutting away the transitions of unreachable states. // Note that we also restrict the successor states of transitions, because there might be successors // that are not in the relevant we restrict to. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); + storm::dd::Add transitionMatrix = (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= commandUpdateProbabilitiesAdd; transitionMatrix += deadlockTransitions; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 588040ce9..35613d9fd 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -372,7 +372,7 @@ namespace storm { // Extend the values of the maybe states by the qualitative values. result.values += min ? qualitativeResult.prob1Min.getPlayer1States().template toAdd() : qualitativeResult.prob1Max.getPlayer1States().template toAdd(); } else { - STORM_LOG_TRACE("No maybe states."); + STORM_LOG_TRACE("No " << (player2Direction == storm::OptimizationDirection::Minimize ? "min" : "max") << " maybe states."); // Extend the values of the maybe states by the qualitative values. result.values += min ? qualitativeResult.prob1Min.getPlayer1States().template toAdd() : qualitativeResult.prob1Max.getPlayer1States().template toAdd(); @@ -545,7 +545,7 @@ namespace storm { // Create a refiner that can be used to refine the abstraction when needed. storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); - refiner.refine(initialPredicates); + refiner.refine(initialPredicates, false); storm::dd::Bdd globalConstraintStates = abstractor->getStates(constraintExpression); storm::dd::Bdd globalTargetStates = abstractor->getStates(targetStateExpression); diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 0bee562f4..0f73e2c4f 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -28,6 +28,8 @@ namespace storm { const std::string AbstractionSettings::rankRefinementPredicatesOptionName = "rankpred"; const std::string AbstractionSettings::constraintsOptionName = "constraints"; const std::string AbstractionSettings::useEagerRefinementOptionName = "eagerref"; + const std::string AbstractionSettings::debugOptionName = "debug"; + const std::string AbstractionSettings::injectRefinementPredicatesOption = "injectref"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -104,6 +106,14 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").build()) .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, injectRefinementPredicatesOption, true, "Specifies predicates used by the refinement instead of the derived predicates.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("predicates", "The (semicolon-separated) refinement predicates to use.").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, true, "Sets whether to enable debug mode.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -210,6 +220,18 @@ namespace storm { return this->getOption(useEagerRefinementOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isDebugSet() const { + return this->getOption(debugOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isInjectRefinementPredicatesSet() const { + return this->getOption(injectRefinementPredicatesOption).getHasOptionBeenSet(); + } + + std::string AbstractionSettings::getInjectedRefinementPredicates() const { + return this->getOption(injectRefinementPredicatesOption).getArgumentByName("predicates").getValueAsString(); + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 2ff536be6..f6627129f 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -147,6 +147,21 @@ namespace storm { */ bool isUseEagerRefinementSet() const; + /*! + * Retrieves whether the debug option was set. + */ + bool isDebugSet() const; + + /*! + * Retrieves whether the option to inject the refinement predicates is set. + */ + bool isInjectRefinementPredicatesSet() const; + + /*! + * Retrieves a string containing refinement predicates to inject (if there are any). + */ + std::string getInjectedRefinementPredicates() const; + const static std::string moduleName; private: @@ -165,6 +180,8 @@ namespace storm { const static std::string rankRefinementPredicatesOptionName; const static std::string constraintsOptionName; const static std::string useEagerRefinementOptionName; + const static std::string debugOptionName; + const static std::string injectRefinementPredicatesOption; }; } From ed56a77d7952fec45fc207b1dd1beed252cea3a6 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 29 May 2018 16:43:22 +0200 Subject: [PATCH 321/647] started on fixing strategies --- .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 35613d9fd..46dde3b65 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -925,6 +925,9 @@ namespace storm { ExplicitQualitativeGameResultMinMax result; + ExplicitQualitativeGameResult problematicStates = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize); + std::cout << "Found " << problematicStates.getStates().getNumberOfSetBits() << " problematic states" << std::endl; + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); From 1e4b81812cc40aedd022a2ce5a37afbb3af8dc07 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 29 May 2018 16:47:39 +0200 Subject: [PATCH 322/647] Environment does no longer require that unused setting modules still have to be registered. --- src/storm/environment/SubEnvironment.cpp | 19 ++++++++++++++++--- src/storm/environment/SubEnvironment.h | 4 ++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index 920a06049..5226fdca4 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -16,31 +16,44 @@ namespace storm { template - SubEnvironment::SubEnvironment() : subEnv(std::make_unique()) { + SubEnvironment::SubEnvironment() : subEnv(nullptr) { // Intentionally left empty } template - SubEnvironment::SubEnvironment(SubEnvironment const& other) : subEnv(new EnvironmentType(*other.subEnv)) { + SubEnvironment::SubEnvironment(SubEnvironment const& other) : subEnv(other.subEnv ? new EnvironmentType(*other.subEnv) : nullptr) { // Intentionally left empty } template SubEnvironment& SubEnvironment::operator=(SubEnvironment const& other) { - subEnv = std::make_unique(*other.subEnv); + if (other.subEnv) { + subEnv = std::make_unique(*other.subEnv); + } else { + subEnv.reset(); + } return *this; } template EnvironmentType const& SubEnvironment::get() const { + assertInitialized(); return *subEnv; } template EnvironmentType& SubEnvironment::get() { + assertInitialized(); return *subEnv; } + template + void SubEnvironment::assertInitialized() const { + if (!subEnv) { + subEnv = std::make_unique(); + } + } + template class SubEnvironment; template class SubEnvironment; diff --git a/src/storm/environment/SubEnvironment.h b/src/storm/environment/SubEnvironment.h index 2b6ecbf87..b1858936d 100644 --- a/src/storm/environment/SubEnvironment.h +++ b/src/storm/environment/SubEnvironment.h @@ -16,8 +16,8 @@ namespace storm { EnvironmentType& get(); private: - std::unique_ptr subEnv; + void assertInitialized() const; + mutable std::unique_ptr subEnv; }; } - From 99e561995208116cfa7c7f65216b8b14932a68dd Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 28 May 2018 17:33:05 +0200 Subject: [PATCH 323/647] Export storm targets --- CMakeLists.txt | 2 ++ src/storm-cli-utilities/CMakeLists.txt | 2 +- src/storm-dft-cli/CMakeLists.txt | 2 +- src/storm-dft/CMakeLists.txt | 2 +- src/storm-gspn-cli/CMakeLists.txt | 2 +- src/storm-gspn/CMakeLists.txt | 2 +- src/storm-pars-cli/CMakeLists.txt | 2 +- src/storm-pars/CMakeLists.txt | 2 +- src/storm-pgcl-cli/CMakeLists.txt | 2 +- src/storm-pgcl/CMakeLists.txt | 2 +- src/storm/CMakeLists.txt | 4 ++-- 11 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4c789dd7..43ddbd8e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -500,4 +500,6 @@ add_subdirectory(src) include(export) +install(EXPORT storm_Targets FILE stormTargets.cmake DESTINATION ${CMAKE_INSTALL_DIR}) + include(StormCPackConfig.cmake) diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index 64c2848c7..84819b72b 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -36,5 +36,5 @@ add_custom_target(copy_storm_cli_util_headers DEPENDS ${STORM_CLI_UTIL_OUTPUT_HE add_dependencies(storm-cli-utilities copy_storm_pars_headers) # installation -install(TARGETS storm-cli-utilities RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-cli-utilities EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-dft-cli/CMakeLists.txt b/src/storm-dft-cli/CMakeLists.txt index 4780eef4d..5886ac0a0 100644 --- a/src/storm-dft-cli/CMakeLists.txt +++ b/src/storm-dft-cli/CMakeLists.txt @@ -6,4 +6,4 @@ set_target_properties(storm-dft-cli PROPERTIES OUTPUT_NAME "storm-dft") add_dependencies(binaries storm-dft-cli) # installation -install(TARGETS storm-dft-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-dft-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-dft/CMakeLists.txt b/src/storm-dft/CMakeLists.txt index 9ec70aed2..f191e537f 100644 --- a/src/storm-dft/CMakeLists.txt +++ b/src/storm-dft/CMakeLists.txt @@ -36,5 +36,5 @@ add_custom_target(copy_storm_dft_headers DEPENDS ${STORM_DFT_OUTPUT_HEADERS} ${S add_dependencies(storm-dft copy_storm_dft_headers) # installation -install(TARGETS storm-dft RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-dft EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-gspn-cli/CMakeLists.txt b/src/storm-gspn-cli/CMakeLists.txt index 39d656a4c..f06ff4a53 100644 --- a/src/storm-gspn-cli/CMakeLists.txt +++ b/src/storm-gspn-cli/CMakeLists.txt @@ -5,4 +5,4 @@ set_target_properties(storm-gspn-cli PROPERTIES OUTPUT_NAME "storm-gspn") add_dependencies(binaries storm-gspn-cli) # installation -install(TARGETS storm-gspn-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-gspn-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-gspn/CMakeLists.txt b/src/storm-gspn/CMakeLists.txt index cf80ff6aa..9312af543 100644 --- a/src/storm-gspn/CMakeLists.txt +++ b/src/storm-gspn/CMakeLists.txt @@ -15,4 +15,4 @@ set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) target_link_libraries(storm-gspn storm ${STORM_GSPN_LINK_LIBRARIES}) # installation -install(TARGETS storm-gspn RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-gspn EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pars-cli/CMakeLists.txt b/src/storm-pars-cli/CMakeLists.txt index 9e2f6f315..955ee93c8 100644 --- a/src/storm-pars-cli/CMakeLists.txt +++ b/src/storm-pars-cli/CMakeLists.txt @@ -6,4 +6,4 @@ set_target_properties(storm-pars-cli PROPERTIES OUTPUT_NAME "storm-pars") add_dependencies(binaries storm-pars-cli) # installation -install(TARGETS storm-pars-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-pars-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pars/CMakeLists.txt b/src/storm-pars/CMakeLists.txt index 4e2ec1e0f..b91292be4 100644 --- a/src/storm-pars/CMakeLists.txt +++ b/src/storm-pars/CMakeLists.txt @@ -36,5 +36,5 @@ add_custom_target(copy_storm_pars_headers DEPENDS ${STORM_PARS_OUTPUT_HEADERS} $ add_dependencies(storm-pars copy_storm_pars_headers) # installation -install(TARGETS storm-pars RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-pars EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pgcl-cli/CMakeLists.txt b/src/storm-pgcl-cli/CMakeLists.txt index 4f2799d4d..506772fd9 100644 --- a/src/storm-pgcl-cli/CMakeLists.txt +++ b/src/storm-pgcl-cli/CMakeLists.txt @@ -5,4 +5,4 @@ set_target_properties(storm-pgcl-cli PROPERTIES OUTPUT_NAME "storm-pgcl") add_dependencies(binaries storm-pgcl-cli) # installation -install(TARGETS storm-pgcl-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-pgcl-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pgcl/CMakeLists.txt b/src/storm-pgcl/CMakeLists.txt index e20a99483..059bff395 100644 --- a/src/storm-pgcl/CMakeLists.txt +++ b/src/storm-pgcl/CMakeLists.txt @@ -13,4 +13,4 @@ add_library(storm-pgcl SHARED ${STORM_PGCL_SOURCES} ${STORM_PGCL_HEADERS}) target_link_libraries(storm-pgcl storm) # installation -install(TARGETS storm-pgcl RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-pgcl EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm/CMakeLists.txt b/src/storm/CMakeLists.txt index 0cf8d3183..6a8cda64e 100644 --- a/src/storm/CMakeLists.txt +++ b/src/storm/CMakeLists.txt @@ -72,7 +72,7 @@ add_dependencies(storm copy_resources_headers) add_dependencies(binaries storm-main) # installation -install(TARGETS storm RUNTIME DESTINATION bin LIBRARY DESTINATION lib) -install(TARGETS storm-main RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib) +install(TARGETS storm-main EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include/storm FILES_MATCHING PATTERN "*.h") From c5e356bc40956c22c2e2c3b41d2bd1a0e1a055d9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 29 May 2018 16:50:30 +0200 Subject: [PATCH 324/647] Proper installation of Storm --- CMakeLists.txt | 10 ++++++++++ resources/cmake/macros/export.cmake | 20 ++++++++++++++++++-- resources/cmake/stormConfigVersion.cmake.in | 11 +++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 resources/cmake/stormConfigVersion.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ddbd8e9..8ca3b9b7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,14 @@ set(BIN_INSTALL_DIR lib/ CACHE PATH "Installation directory for executables") set(DEF_INSTALL_CMAKE_DIR "lib/CMake/storm") set(CMAKE_INSTALL_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") +# Add CMake install prefix +foreach(p LIB BIN INCLUDE CMAKE) + set(var ${p}_INSTALL_DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() +endforeach() + message("CMAKE_INSTALL_DIR: ${CMAKE_INSTALL_DIR}") # If the STORM_DEVELOPER option was turned on, by default we target a debug version, otherwise a release version. @@ -500,6 +508,8 @@ add_subdirectory(src) include(export) +install(FILES ${CMAKE_BINARY_DIR}/stormConfig.install.cmake DESTINATION ${CMAKE_INSTALL_DIR} RENAME stormConfig.cmake) +install(FILES ${CMAKE_BINARY_DIR}/stormConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DIR}) install(EXPORT storm_Targets FILE stormTargets.cmake DESTINATION ${CMAKE_INSTALL_DIR}) include(StormCPackConfig.cmake) diff --git a/resources/cmake/macros/export.cmake b/resources/cmake/macros/export.cmake index eb2e8fa84..606bde62f 100644 --- a/resources/cmake/macros/export.cmake +++ b/resources/cmake/macros/export.cmake @@ -8,7 +8,7 @@ message(STATUS "Registered with cmake") export(PACKAGE storm) set(DEP_TARGETS "") -foreach(dt ${STORM_DEP_TARGETS}) +foreach(dt ${STORM_DEP_TARGETS}) export_target(DEP_TARGETS ${dt}) endforeach() @@ -19,10 +19,26 @@ endforeach() include(CMakePackageConfigHelpers) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/stormConfigVersion.cmake + VERSION 0.1.0 + COMPATIBILITY SameMajorVersion ) + +# For the build tree set(CONF_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/include/") configure_package_config_file( resources/cmake/stormConfig.cmake.in ${PROJECT_BINARY_DIR}/stormConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_DIR} - PATH_VARS INCLUDE_INSTALL_DIR #SYSCONFIG_INSTALL_DIR + PATH_VARS INCLUDE_INSTALL_DIR +) + + # For the install tree +file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_DIR}" "${INCLUDE_INSTALL_DIR}") +set(CONF_INCLUDE_DIRS "\${storm_CMAKE_DIR}/${REL_INCLUDE_DIR}/storm") + +configure_package_config_file( + resources/cmake/stormConfig.cmake.in + ${PROJECT_BINARY_DIR}/stormConfig.install.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DIR} + PATH_VARS INCLUDE_INSTALL_DIR ) diff --git a/resources/cmake/stormConfigVersion.cmake.in b/resources/cmake/stormConfigVersion.cmake.in new file mode 100644 index 000000000..d248393ad --- /dev/null +++ b/resources/cmake/stormConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@storm_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() From bcd3d68c61323de0246d80fb27711e2731088cb7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 30 May 2018 16:32:39 +0200 Subject: [PATCH 325/647] further debugging --- src/storm/abstraction/MenuGameRefiner.cpp | 20 +++- .../abstraction/GameBasedMdpModelChecker.cpp | 107 +++++++++++++++++- 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index e511c3e29..da11864b4 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1097,9 +1097,14 @@ namespace storm { ValueType pivotStateDeviation = storm::utility::zero(); auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); + storm::storage::BitVector visitedStates(initialStates.size()); while (!dijkstraQueue.empty()) { auto distanceStatePair = *dijkstraQueue.begin(); uint64_t currentState = distanceStatePair.second; + visitedStates.set(currentState); + std::cout << "current: " << currentState << std::endl; + std::cout << "visited: " << visitedStates << std::endl; + ValueType currentDistance = distanceStatePair.first; dijkstraQueue.erase(dijkstraQueue.begin()); @@ -1128,10 +1133,10 @@ namespace storm { if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } - } + } + // If it is indeed a pivot state, we can abort the search here. if (isPivotState) { - if (considerDeviation && foundPivotState) { ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState]; if (deviationOfCurrentState > pivotStateDeviation) { @@ -1154,10 +1159,13 @@ namespace storm { } } + // TODO: remember the strategy from which we came and only go on to explore that further? + // Otherwise, we explore all its relevant successors. if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t minPlayer2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); uint64_t minPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor); + STORM_LOG_ASSERT(!maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(minPlayer2Successor) || minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor) == minPlayer2Choice, "Did not expect deviation in player 2 strategy."); STORM_LOG_ASSERT(player2Grouping[minPlayer2Successor] <= minPlayer2Choice && minPlayer2Choice < player2Grouping[minPlayer2Successor + 1], "Illegal choice for player 2."); for (auto const& entry : transitionMatrix.getRow(minPlayer2Choice)) { @@ -1175,10 +1183,13 @@ namespace storm { dijkstraQueue.emplace(alternateDistance, player1Successor); } } + } else { + STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting min strategy for non-target states."); } if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t maxPlayer2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); uint64_t maxPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor); + STORM_LOG_ASSERT(!minStrategyPair.getPlayer2Strategy().hasDefinedChoice(maxPlayer2Successor) || minStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor) == maxPlayer2Choice, "Did not expect deviation in player 2 strategy."); STORM_LOG_ASSERT(player2Grouping[maxPlayer2Successor] <= maxPlayer2Choice && maxPlayer2Choice < player2Grouping[maxPlayer2Successor + 1], "Illegal choice for player 2."); for (auto const& entry : transitionMatrix.getRow(maxPlayer2Choice)) { @@ -1188,7 +1199,7 @@ namespace storm { } ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); - if (probabilityDistances ? alternateDistance > distances[player1Successor] : !probabilityDistances && alternateDistance < distances[player1Successor]) { + if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[maxPlayer2Successor]); @@ -1196,6 +1207,8 @@ namespace storm { dijkstraQueue.emplace(alternateDistance, player1Successor); } } + } else { + STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting max strategy for non-target states."); } } @@ -1205,6 +1218,7 @@ namespace storm { // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, // which can happen when trying to refine using the qualitative result only. + STORM_LOG_TRACE("Did not find pivot state in explicit Dijkstra search."); return boost::none; } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 46dde3b65..f7374dd20 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -2,6 +2,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/symbolic/Dtmc.h" @@ -33,6 +34,7 @@ #include "storm/solver/SymbolicGameSolver.h" #include "storm/solver/StandardGameSolver.h" +#include "storm/environment/Environment.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" @@ -414,8 +416,10 @@ namespace storm { // If there is a previous result, unpack the previous values with respect to the new ODD. if (previousResult) { - previousResult.get().odd.oldToNewIndex(odd, [&previousResult,&result,player2Min] (uint64_t oldOffset, uint64_t newOffset) { - result.getValues()[newOffset] = player2Min ? previousResult.get().values.getMin().getValues()[oldOffset] : previousResult.get().values.getMax().getValues()[oldOffset]; + previousResult.get().odd.oldToNewIndex(odd, [&previousResult,&result,player2Min,player1Prob1States] (uint64_t oldOffset, uint64_t newOffset) { + if (!player2Min && !player1Prob1States.get(newOffset)) { + result.getValues()[newOffset] = player2Min ? previousResult.get().values.getMin().getValues()[oldOffset] : previousResult.get().values.getMax().getValues()[oldOffset]; + } }); } @@ -494,7 +498,7 @@ namespace storm { // Set values according to quantitative result (qualitative result has already been taken care of). storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); - + // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. uint64_t previousPlayer1MaybeStates = 0; uint64_t previousPlayer2MaybeStates = 0; @@ -804,7 +808,7 @@ namespace storm { if (result) { return result; } - + // (8) Solve the max values and check whether we can give the answer already. quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); @@ -820,6 +824,100 @@ namespace storm { return result; } +// std::cout << "target states " << targetStates << std::endl; + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + std::cout << "state " << state << " has values [" << quantitativeResult.getMin().getValues()[state] << ", " << quantitativeResult.getMax().getValues()[state] << "]" << std::endl; + + STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); + + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + uint64_t lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (upper player 1 choice " << lowerPlayer1Choice << ")."); + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + std::cout << "[min] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice << std::endl; + } + } + } + } + + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + uint64_t upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); + uint64_t upperPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); + std::cout << "[max] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice << std::endl; + } + } + } + } + } + + ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the lower ones. + storm::storage::SparseMatrixBuilder dtmcMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + auto dtmcMatrix = dtmcMatrixBuilder.build(); + std::vector sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + std::cout << "state " << state << ": " << sanityValues[state] << " vs " << quantitativeResult.getMin().getValues()[state] << std::endl; + std::cout << "[min] state is prob0? " << qualitativeResult.getProb0Min().getStates().get(state) << ", prob1? " << qualitativeResult.getProb1Min().getStates().get(state) << std::endl; + STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]) < 1e-6, "Got weird min divergences!"); + } + ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the upper ones. + dtmcMatrixBuilder = storm::storage::SparseMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + dtmcMatrix = dtmcMatrixBuilder.build(); + sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + std::cout << "state " << state << ": " << sanityValues[state] << " vs " << quantitativeResult.getMax().getValues()[state] << std::endl; + std::cout << "[max] state is prob0? " << qualitativeResult.getProb0Max().getStates().get(state) << ", prob1? " << qualitativeResult.getProb1Max().getStates().get(state) << std::endl; + STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]) < 1e-6, "Got weird max divergences!"); + } + // Make sure that all strategies are still valid strategies. STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << maxStrategyPair.getNumberOfUndefinedPlayer1States() << "."); @@ -926,7 +1024,6 @@ namespace storm { ExplicitQualitativeGameResultMinMax result; ExplicitQualitativeGameResult problematicStates = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize); - std::cout << "Found " << problematicStates.getStates().getNumberOfSetBits() << " problematic states" << std::endl; result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); From 8f4f5c555e8694f1cde50304fba755654a52be23 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 31 May 2018 12:26:51 +0200 Subject: [PATCH 326/647] explicit Dijkstra search for pivot state now follows the strategies separately --- src/storm/abstraction/MenuGameRefiner.cpp | 179 ++++++----- src/storm/abstraction/MenuGameRefiner.h | 3 + .../abstraction/GameBasedMdpModelChecker.cpp | 304 ++++++++++-------- .../abstraction/GameBasedMdpModelChecker.h | 13 +- src/storm/utility/Stopwatch.cpp | 21 +- src/storm/utility/Stopwatch.h | 12 +- 6 files changed, 318 insertions(+), 214 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index da11864b4..a262d2ffe 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1059,65 +1059,136 @@ namespace storm { return true; } + template + struct ExplicitDijkstraQueueElement { + ExplicitDijkstraQueueElement(ValueType const& distance, uint64_t state, bool lower) : distance(distance), state(state), lower(lower) { + // Intentionally left empty. + } + + ValueType distance; + uint64_t state; + bool lower; + }; + + template + struct ExplicitDijkstraQueueElementLess { + bool operator()(ExplicitDijkstraQueueElement const& a, ExplicitDijkstraQueueElement const& b) const { + if (a.distance < b.distance) { + return true; + } else if (a.distance > b.distance) { + return false; + } else { + if (a.state < b.state) { + return true; + } else if (a.state > b.state) { + return false; + } else { + if (a.lower < b.lower) { + return true; + } else { + return false; + } + } + } + } + }; + + template + void performDijkstraStep(std::set, ExplicitDijkstraQueueElementLess>& dijkstraQueue, bool probabilityDistances, std::vector& distances, std::vector>& predecessors, bool generatePredecessors, bool lower, uint64_t currentState, ValueType const& currentDistance, bool isPivotState, ExplicitGameStrategyPair const& strategyPair, ExplicitGameStrategyPair const& otherStrategyPair, std::vector const& player1Labeling, std::vector const& player2Grouping, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& relevantStates) { + if (strategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = strategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t player2Choice = strategyPair.getPlayer2Strategy().getChoice(player2Successor); + STORM_LOG_ASSERT(isPivotState || !otherStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) || strategyPair.getPlayer2Strategy().getChoice(player2Successor) == player2Choice, "Did not expect deviation in player 2 strategy."); + STORM_LOG_ASSERT(player2Grouping[player2Successor] <= player2Choice && player2Choice < player2Grouping[player2Successor + 1], "Illegal choice for player 2."); + + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + uint64_t player1Successor = entry.getColumn(); + if (!relevantStates.get(player1Successor)) { + continue; + } + + ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); + if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { + distances[player1Successor] = alternateDistance; + if (generatePredecessors) { + predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[player2Successor]); + } + dijkstraQueue.emplace(alternateDistance, player1Successor, lower); + } + } + } else { + STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting min strategy for non-target states."); + } + } + template boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair, std::vector const* lowerValues = nullptr, std::vector const* upperValues = nullptr) { STORM_LOG_ASSERT(!lowerValues || upperValues, "Expected none or both value results."); STORM_LOG_ASSERT(!upperValues || lowerValues, "Expected none or both value results."); - // Perform Dijkstra search that stays within the relevant states and searches for a state in which the - // strategies for the (commonly chosen) player 1 action leads to a player 2 state in which the choices differ. - ExplicitPivotStateResult result; + // Perform Dijkstra search that stays within the relevant states and searches for a (pivot) state in which + // the strategies the lower or upper player 1 action leads to a player 2 state in which the choices differ. + // To guarantee that the pivot state is reachable by either of the strategies, we do a parallel Dijkstra + // search in both the lower and upper strategy. bool probabilityDistances = pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MostProbablePath; uint64_t numberOfStates = initialStates.size(); ValueType inftyDistance = probabilityDistances ? storm::utility::zero() : storm::utility::infinity(); ValueType zeroDistance = probabilityDistances ? storm::utility::one() : storm::utility::zero(); - std::vector distances(numberOfStates, inftyDistance); + + // Create storages for the lower and upper Dijkstra search. + std::vector lowerDistances(numberOfStates, inftyDistance); + std::vector> lowerPredecessors; + std::vector upperDistances(numberOfStates, inftyDistance); + std::vector> upperPredecessors; + if (generatePredecessors) { - result.predecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); + lowerPredecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); + upperPredecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); } - // Use set as priority queue with unique membership; default comparison on pair works fine if distance is - // the first entry. - std::set, std::greater>> dijkstraQueue; + // Use set as priority queue with unique membership. + std::set, ExplicitDijkstraQueueElementLess> dijkstraQueue; for (auto initialState : initialStates) { if (!relevantStates.get(initialState)) { continue; } - distances[initialState] = zeroDistance; - dijkstraQueue.emplace(zeroDistance, initialState); + lowerDistances[initialState] = zeroDistance; + upperDistances[initialState] = zeroDistance; + dijkstraQueue.emplace(zeroDistance, initialState, true); + dijkstraQueue.emplace(zeroDistance, initialState, false); } // For some heuristics, we need to potentially find more than just one pivot. bool considerDeviation = (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::NearestMaximalDeviation || pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) && lowerValues && upperValues; bool foundPivotState = false; + + ExplicitDijkstraQueueElement pivotState(inftyDistance, 0, true); ValueType pivotStateDeviation = storm::utility::zero(); auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); - storm::storage::BitVector visitedStates(initialStates.size()); while (!dijkstraQueue.empty()) { - auto distanceStatePair = *dijkstraQueue.begin(); - uint64_t currentState = distanceStatePair.second; - visitedStates.set(currentState); - std::cout << "current: " << currentState << std::endl; - std::cout << "visited: " << visitedStates << std::endl; - - ValueType currentDistance = distanceStatePair.first; + // Take out currently best state. + auto currentDijkstraElement = *dijkstraQueue.begin(); + ValueType currentDistance = currentDijkstraElement.distance; + uint64_t currentState = currentDijkstraElement.state; + bool currentLower = currentDijkstraElement.lower; dijkstraQueue.erase(dijkstraQueue.begin()); - if (foundPivotState && (probabilityDistances ? currentDistance < result.distance : currentDistance > result.distance)) { + if (foundPivotState && (probabilityDistances ? currentDistance < pivotState.distance : currentDistance > pivotState.distance)) { if (pivotSelectionHeuristic != storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { // For the nearest maximal deviation and most probable path heuristics, future pivot states are // not important any more, because their distance will be strictly larger, so we can return the // current pivot state. - return result; + + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); } else if (pivotStateDeviation >= currentDistance) { // If the heuristic is maximal weighted deviation and the weighted deviation for any future pivot // state is necessarily at most as high as the current one, we can abort the search. - return result; + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); } } @@ -1128,19 +1199,21 @@ namespace storm { if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } - } else if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + } + if (!isPivotState && maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { isPivotState = true; } } - // If it is indeed a pivot state, we can abort the search here. + // If it is indeed a pivot state, we can potentially abort the search here. if (isPivotState) { if (considerDeviation && foundPivotState) { ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState]; + if (deviationOfCurrentState > pivotStateDeviation) { - result.pivotState = currentState; + pivotState = currentDijkstraElement; pivotStateDeviation = deviationOfCurrentState; if (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { // Scale the deviation with the distance (probability) for this heuristic. @@ -1148,71 +1221,25 @@ namespace storm { } } } else if (!foundPivotState) { - result.pivotState = currentState; - result.distance = distances[currentState]; + pivotState = currentDijkstraElement; foundPivotState = true; } // If there is no need to look at other deviations, stop here. if (!considerDeviation) { - return result; + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); } } - // TODO: remember the strategy from which we came and only go on to explore that further? - - // Otherwise, we explore all its relevant successors. - if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t minPlayer2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); - uint64_t minPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor); - STORM_LOG_ASSERT(!maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(minPlayer2Successor) || minStrategyPair.getPlayer2Strategy().getChoice(minPlayer2Successor) == minPlayer2Choice, "Did not expect deviation in player 2 strategy."); - STORM_LOG_ASSERT(player2Grouping[minPlayer2Successor] <= minPlayer2Choice && minPlayer2Choice < player2Grouping[minPlayer2Successor + 1], "Illegal choice for player 2."); - - for (auto const& entry : transitionMatrix.getRow(minPlayer2Choice)) { - uint64_t player1Successor = entry.getColumn(); - if (!relevantStates.get(player1Successor)) { - continue; - } - - ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); - if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { - distances[player1Successor] = alternateDistance; - if (generatePredecessors) { - result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[minPlayer2Successor]); - } - dijkstraQueue.emplace(alternateDistance, player1Successor); - } - } - } else { - STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting min strategy for non-target states."); - } - if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t maxPlayer2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); - uint64_t maxPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor); - STORM_LOG_ASSERT(!minStrategyPair.getPlayer2Strategy().hasDefinedChoice(maxPlayer2Successor) || minStrategyPair.getPlayer2Strategy().getChoice(maxPlayer2Successor) == maxPlayer2Choice, "Did not expect deviation in player 2 strategy."); - STORM_LOG_ASSERT(player2Grouping[maxPlayer2Successor] <= maxPlayer2Choice && maxPlayer2Choice < player2Grouping[maxPlayer2Successor + 1], "Illegal choice for player 2."); - - for (auto const& entry : transitionMatrix.getRow(maxPlayer2Choice)) { - uint64_t player1Successor = entry.getColumn(); - if (!relevantStates.get(player1Successor)) { - continue; - } - - ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); - if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { - distances[player1Successor] = alternateDistance; - if (generatePredecessors) { - result.predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[maxPlayer2Successor]); - } - dijkstraQueue.emplace(alternateDistance, player1Successor); - } - } + if (currentLower) { + performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); } else { - STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting max strategy for non-target states."); + performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); } } if (foundPivotState) { + ExplicitPivotStateResult result; return result; } diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 276d178fb..60d632694 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -76,6 +76,9 @@ namespace storm { template struct ExplicitPivotStateResult { ExplicitPivotStateResult() = default; + ExplicitPivotStateResult(uint64_t pivotState, ValueType distance, std::vector>&& predecessors) : pivotState(pivotState), distance(distance), predecessors(std::move(predecessors)) { + // Intentionally left empty. + } uint64_t pivotState; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index f7374dd20..ca01fca3b 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -59,7 +59,7 @@ namespace storm { using detail::PreviousExplicitResult; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2, storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2, storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants. Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); @@ -529,6 +529,8 @@ namespace storm { // Optimization: do not compute both bounds if not necessary (e.g. if bound given and exceeded, etc.) + totalWatch.start(); + // Set up initial predicates. std::vector initialPredicates = getInitialPredicates(constraintExpression, targetStateExpression); @@ -563,10 +565,11 @@ namespace storm { STORM_LOG_TRACE("Starting iteration " << iteration << "."); // (1) build the abstraction. - auto abstractionStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch abstractionWatch(true); storm::abstraction::MenuGame game = abstractor->abstract(); - auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + abstractionWatch.stop(); + totalAbstractionWatch.add(abstractionWatch); + STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << abstractionWatch.getTimeInMilliseconds() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -592,7 +595,8 @@ namespace storm { } if (result) { - printStatistics(*abstractor, game); + totalWatch.stop(); + printStatistics(*abstractor, game, iteration); return result; } @@ -600,6 +604,8 @@ namespace storm { STORM_LOG_INFO("Iteration " << iteration << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); } + totalWatch.stop(); + // If this point is reached, we have given up on abstraction. STORM_LOG_WARN("Could not derive result, maximal number of abstractions exceeded."); return nullptr; @@ -614,15 +620,16 @@ namespace storm { storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). - auto qualitativeStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch qualitativeWatch(true); SymbolicQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); if (result) { return result; } previousQualitativeResult = qualitativeResult; - auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); + qualitativeWatch.stop(); + totalSolutionWatch.add(qualitativeWatch); + STORM_LOG_INFO("Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() << "ms."); // (2) compute the states for which we have to determine quantitative information. storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); @@ -639,10 +646,11 @@ namespace storm { // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. - auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch refinementWatch(true); qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); - auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); } // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. @@ -652,27 +660,31 @@ namespace storm { storm::dd::Add initialStatesAdd = initialStates.template toAdd(); - auto quantitativeStart = std::chrono::high_resolution_clock::now(); - SymbolicQuantitativeGameResultMinMax quantitativeResult; // (7) Solve the min values and check whether we can give the answer already. + storm::utility::Stopwatch quantitativeWatch(true); quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); + quantitativeWatch.stop(); previousMinQuantitativeResult = quantitativeResult.min; result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); if (result) { + totalSolutionWatch.add(quantitativeWatch); return result; } // (8) Solve the max values and check whether we can give the answer already. + quantitativeWatch.start(); quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); + quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); if (result) { + totalSolutionWatch.add(quantitativeWatch); return result; } - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + totalSolutionWatch.add(quantitativeWatch); + STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); @@ -686,25 +698,118 @@ namespace storm { STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); - auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); - // (10) If we arrived at this point, it means that we have all qualitative and quantitative // information about the game, but we could not yet answer the query. In this case, we need to refine. + storm::utility::Stopwatch refinementWatch(true); refiner.refine(game, transitionMatrixBdd, quantitativeResult); - auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); } // Return null to indicate no result has been found yet. return nullptr; } + template + void postProcessStrategies(abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool sanityCheck) { + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); + + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + uint64_t lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (upper player 1 choice " << lowerPlayer1Choice << ")."); + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + if (sanityCheck) { + STORM_LOG_TRACE("[min] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice); + } + } + } + } + } + + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + uint64_t upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); + uint64_t upperPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); + STORM_LOG_TRACE("[max] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice); + } + } + } + } + } + + if (sanityCheck) { + ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the lower ones. + storm::storage::SparseMatrixBuilder dtmcMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + auto dtmcMatrix = dtmcMatrixBuilder.build(); + std::vector sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]) < 1e-4, "Got weird min divergences!"); + } + ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the upper ones. + dtmcMatrixBuilder = storm::storage::SparseMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + dtmcMatrix = dtmcMatrixBuilder.build(); + sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]) < 1e-4, "Got weird max divergences!"); + } + } + } + template std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult) { STORM_LOG_TRACE("Using sparse solving."); // (0) Start by transforming the necessary symbolic elements to explicit ones. - auto translationStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch translationWatch(true); storm::dd::Odd odd = game.getReachableStates().createOdd(); std::vector> labelingVariableSets = {game.getPlayer1Variables(), game.getPlayer2Variables()}; @@ -756,22 +861,25 @@ namespace storm { storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); - auto translationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Translation to explicit representation completed in " << std::chrono::duration_cast(translationEnd - translationStart).count() << "ms."); + translationWatch.stop(); + totalTranslationWatch.add(translationWatch); + STORM_LOG_INFO("Translation to explicit representation completed in " << translationWatch.getTimeInMilliseconds() << "ms."); // Prepare the two strategies. abstraction::ExplicitGameStrategyPair minStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); abstraction::ExplicitGameStrategyPair maxStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). - auto qualitativeStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch qualitativeWatch(true); ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousResult, odd, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, minStrategyPair, maxStrategyPair); + qualitativeWatch.stop(); + totalSolutionWatch.add(qualitativeWatch); + STORM_LOG_INFO("Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() << "ms."); + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); if (result) { return result; } - auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); // (2) compute the states for which we have to determine quantitative information. storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()); @@ -788,10 +896,11 @@ namespace storm { // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. - auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch refinementWatch(true); qualitativeRefinement = refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); - auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); } ExplicitQuantitativeResultMinMax quantitativeResult; @@ -802,132 +911,45 @@ namespace storm { STORM_LOG_TRACE("Starting numerical solution step."); // (7) Solve the min values and check whether we can give the answer already. - auto quantitativeStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch quantitativeWatch(true); quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair, odd, nullptr, nullptr, this->reuseQuantitativeResults ? previousResult : boost::none)); + quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); if (result) { + totalSolutionWatch.add(quantitativeWatch); return result; } // (8) Solve the max values and check whether we can give the answer already. + quantitativeWatch.start(); quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair)); + quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); if (result) { + totalSolutionWatch.add(quantitativeWatch); return result; } - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.getMin().getRange(initialStates).first, quantitativeResult.getMax().getRange(initialStates).second, comparator); if (result) { return result; } - -// std::cout << "target states " << targetStates << std::endl; - - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - std::cout << "state " << state << " has values [" << quantitativeResult.getMin().getValues()[state] << ", " << quantitativeResult.getMax().getValues()[state] << "]" << std::endl; - - STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); - STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); - - if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - uint64_t lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); - - STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (upper player 1 choice " << lowerPlayer1Choice << ")."); - uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); - - if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { - uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); - - if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); - - if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { - minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); - std::cout << "[min] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice << std::endl; - } - } - } - } - - if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - uint64_t upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); - - STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); - uint64_t upperPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); - - if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { - uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); - - if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); - - if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { - minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); - std::cout << "[max] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice << std::endl; - } - } - } - } - } - - ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should - ///////// still be the lower ones. - storm::storage::SparseMatrixBuilder dtmcMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - if (targetStates.get(state)) { - dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); - } else { - uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)); - for (auto const& entry : transitionMatrix.getRow(player2Choice)) { - dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); - } - } - } - auto dtmcMatrix = dtmcMatrixBuilder.build(); - std::vector sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); - - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - std::cout << "state " << state << ": " << sanityValues[state] << " vs " << quantitativeResult.getMin().getValues()[state] << std::endl; - std::cout << "[min] state is prob0? " << qualitativeResult.getProb0Min().getStates().get(state) << ", prob1? " << qualitativeResult.getProb1Min().getStates().get(state) << std::endl; - STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]) < 1e-6, "Got weird min divergences!"); - } - ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should - ///////// still be the upper ones. - dtmcMatrixBuilder = storm::storage::SparseMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - if (targetStates.get(state)) { - dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); - } else { - uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); - for (auto const& entry : transitionMatrix.getRow(player2Choice)) { - dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); - } - } - } - dtmcMatrix = dtmcMatrixBuilder.build(); - sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - std::cout << "state " << state << ": " << sanityValues[state] << " vs " << quantitativeResult.getMax().getValues()[state] << std::endl; - std::cout << "[max] state is prob0? " << qualitativeResult.getProb0Max().getStates().get(state) << ", prob1? " << qualitativeResult.getProb1Max().getStates().get(state) << std::endl; - STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]) < 1e-6, "Got weird max divergences!"); - } + postProcessStrategies(minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, quantitativeResult, this->debug); // Make sure that all strategies are still valid strategies. STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << maxStrategyPair.getNumberOfUndefinedPlayer1States() << "."); - auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); // (10) If we arrived at this point, it means that we have all qualitative and quantitative // information about the game, but we could not yet answer the query. In this case, we need to refine. + storm::utility::Stopwatch refinementWatch(true); refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); - auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_INFO("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); if (this->reuseQuantitativeResults) { PreviousExplicitResult nextPreviousResult; @@ -1106,15 +1128,37 @@ namespace storm { } template - void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const { + void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements) const { if (storm::settings::getModule().isShowStatisticsSet()) { storm::abstraction::AbstractionInformation const& abstractionInformation = abstractor.getAbstractionInformation(); + std::streamsize originalPrecision = std::cout.precision(); + std::cout << std::fixed << std::setprecision(2); + std::cout << std::endl; std::cout << "Statistics:" << std::endl; - std::cout << " * player 1 states (final game): " << game.getReachableStates().getNonZeroCount() << std::endl; + std::cout << " * size of final game: " << game.getReachableStates().getNonZeroCount() << " player 1 states" << std::endl; std::cout << " * transitions (final game): " << game.getTransitionMatrix().getNonZeroCount() << std::endl; - std::cout << " * predicates used in abstraction: " << abstractionInformation.getNumberOfPredicates() << std::endl; + std::cout << " * refinements: " << refinements << std::endl; + std::cout << " * predicates used in abstraction: " << abstractionInformation.getNumberOfPredicates() << std::endl << std::endl; + + uint64_t totalAbstractionTimeMillis = totalAbstractionWatch.getTimeInMilliseconds(); + uint64_t totalTranslationTimeMillis = totalTranslationWatch.getTimeInMilliseconds(); + uint64_t totalSolutionTimeMillis = totalSolutionWatch.getTimeInMilliseconds(); + uint64_t totalRefinementTimeMillis = totalRefinementWatch.getTimeInMilliseconds(); + uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds(); + + std::cout << "Time breakdown:" << std::endl; + std::cout << " * abstraction: " << totalAbstractionTimeMillis << "ms (" << 100 * static_cast(totalAbstractionTimeMillis)/totalTimeMillis << "%)" << std::endl; + if (this->solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Sparse) { + std::cout << " * translation: " << totalTranslationTimeMillis << "ms (" << 100 * static_cast(totalTranslationTimeMillis)/totalTimeMillis << "%)" << std::endl; + } + std::cout << " * solution: " << totalSolutionTimeMillis << "ms (" << 100 * static_cast(totalSolutionTimeMillis)/totalTimeMillis << "%)" << std::endl; + std::cout << " * refinement: " << totalRefinementTimeMillis << "ms (" << 100 * static_cast(totalRefinementTimeMillis)/totalTimeMillis << "%)" << std::endl; + std::cout << " ---------------------------------------------" << std::endl; + std::cout << " * total: " << totalTimeMillis << "ms" << std::endl << std::endl; + + std::cout << std::defaultfloat << std::setprecision(originalPrecision); } } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index e93e91c69..cf6d059aa 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -21,6 +21,7 @@ #include "storm/utility/ConstantsComparator.h" #include "storm/utility/solver.h" #include "storm/utility/graph.h" +#include "storm/utility/Stopwatch.h" namespace storm { namespace abstraction { @@ -114,7 +115,7 @@ namespace storm { ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); - void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const; + void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements) const; /* * Retrieves the expression characterized by the formula. The formula needs to be propositional. @@ -148,6 +149,16 @@ namespace storm { /// The performed number of refinement iterations. uint64_t iteration; + + /// A flag that indicates whether debug mode is enabled. + bool debug; + + /// Data stored for statistics. + storm::utility::Stopwatch totalAbstractionWatch; + storm::utility::Stopwatch totalSolutionWatch; + storm::utility::Stopwatch totalRefinementWatch; + storm::utility::Stopwatch totalTranslationWatch; + storm::utility::Stopwatch totalWatch; }; } } diff --git a/src/storm/utility/Stopwatch.cpp b/src/storm/utility/Stopwatch.cpp index 0a08a4e19..8c6f008a4 100644 --- a/src/storm/utility/Stopwatch.cpp +++ b/src/storm/utility/Stopwatch.cpp @@ -3,7 +3,7 @@ namespace storm { namespace utility { - Stopwatch::Stopwatch(bool startNow) : accumulatedTime(std::chrono::nanoseconds::zero()), stopped(true), startOfCurrentMeasurement(std::chrono::nanoseconds::zero()) { + Stopwatch::Stopwatch(bool startNow) : accumulatedTime(std::chrono::nanoseconds::zero()), isStopped(true), startOfCurrentMeasurement(std::chrono::nanoseconds::zero()) { if (startNow) { start(); } @@ -25,21 +25,30 @@ namespace storm { accumulatedTime += timeNanoseconds; } + void Stopwatch::add(Stopwatch const& other) { + STORM_LOG_WARN_COND(other.stopped(), "Expected stopped watch."); + accumulatedTime += other.accumulatedTime; + } + void Stopwatch::stop() { - STORM_LOG_WARN_COND(!stopped, "Stopwatch is already paused."); - stopped = true; + STORM_LOG_WARN_COND(!isStopped, "Stopwatch is already paused."); + isStopped = true; accumulatedTime += std::chrono::high_resolution_clock::now() - startOfCurrentMeasurement; } void Stopwatch::start() { - STORM_LOG_WARN_COND(stopped, "Stopwatch is already running."); - stopped = false; + STORM_LOG_WARN_COND(isStopped, "Stopwatch is already running."); + isStopped = false; startOfCurrentMeasurement = std::chrono::high_resolution_clock::now(); } void Stopwatch::reset() { accumulatedTime = std::chrono::nanoseconds::zero(); - stopped = true; + isStopped = true; + } + + bool Stopwatch::stopped() const { + return isStopped; } std::ostream& operator<<(std::ostream& out, Stopwatch const& stopwatch) { diff --git a/src/storm/utility/Stopwatch.h b/src/storm/utility/Stopwatch.h index 4f81ea8a8..e3b41f4e9 100644 --- a/src/storm/utility/Stopwatch.h +++ b/src/storm/utility/Stopwatch.h @@ -46,6 +46,11 @@ namespace storm { */ void addToTime(std::chrono::nanoseconds timeNanoseconds); + /*! + * Adds the value of the (stopped) watch to the accumulated time of this watch. + */ + void add(Stopwatch const& other); + /*! * Stop stopwatch and add measured time to total time. */ @@ -60,6 +65,11 @@ namespace storm { * Reset the stopwatch. */ void reset(); + + /*! + * Retrieves whether the watch is stopped. + */ + bool stopped() const; friend std::ostream& operator<<(std::ostream& out, Stopwatch const& stopwatch); @@ -68,7 +78,7 @@ namespace storm { std::chrono::nanoseconds accumulatedTime; // A flag indicating if the stopwatch is stopped right now. - bool stopped; + bool isStopped; // The timepoint when the stopwatch was started the last time (if it's not stopped). std::chrono::high_resolution_clock::time_point startOfCurrentMeasurement; From e216d553200d4fe2dc53c5f6ba68b1bafb91e250 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 31 May 2018 16:47:45 +0200 Subject: [PATCH 327/647] extended strategy redirection, better statistics --- src/storm/abstraction/MenuGameRefiner.cpp | 24 +-- .../abstraction/prism/CommandAbstractor.cpp | 35 ++-- .../abstraction/GameBasedMdpModelChecker.cpp | 177 +++++++++++++++--- .../abstraction/GameBasedMdpModelChecker.h | 8 +- .../settings/modules/AbstractionSettings.cpp | 28 ++- .../settings/modules/AbstractionSettings.h | 16 +- 6 files changed, 221 insertions(+), 67 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index a262d2ffe..25c4242ba 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -870,14 +870,11 @@ namespace storm { auto assertionStart = std::chrono::high_resolution_clock::now(); storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); uint64_t stepCounter = 0; - auto traceIt = trace.rbegin(); - auto traceIte = trace.rend(); - for (; traceIt != traceIte; ++traceIt) { - auto const& step = *traceIt; - interpolatingSolver.push(); + for (auto const& traceElement : trace) { + // interpolatingSolver.push(); interpolatingSolver.setInterpolationGroup(stepCounter); - for (auto const& predicate : step) { + for (auto const& predicate : traceElement) { interpolatingSolver.add(predicate); } @@ -898,6 +895,7 @@ namespace storm { storm::expressions::Expression interpolant = interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager()); if (interpolant.isFalse()) { // If the interpolant is false, it means that the prefix has become unsatisfiable. + STORM_LOG_TRACE("Trace formula became unsatisfiable at position " << step << " of " << stepCounter << "."); break; } if (!interpolant.isTrue()) { @@ -1231,16 +1229,18 @@ namespace storm { } } - if (currentLower) { - performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); - } else { - performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); + // We only need to search further if the state has some value deviation. + if (!lowerValues || !upperValues || (*lowerValues)[currentState] < (*upperValues)[currentState]) { + if (currentLower) { + performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); + } else { + performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors, false, currentState, currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); + } } } if (foundPivotState) { - ExplicitPivotStateResult result; - return result; + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); } // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index ff9884720..4a22b976f 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -565,7 +565,8 @@ namespace storm { template storm::dd::Bdd CommandAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, std::vector> const& variablePredicates) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& variableIndexPair : variablePredicates) { + for (auto variableIndexPairIt = variablePredicates.rbegin(), variableIndexPairIte = variablePredicates.rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { @@ -585,7 +586,8 @@ namespace storm { storm::dd::Bdd updateBdd = this->getAbstractionInformation().getDdManager().getBddOne(); // Translate block variables for this update into a successor block. - for (auto const& variableIndexPair : variablePredicates[updateIndex]) { + for (auto variableIndexPairIt = variablePredicates[updateIndex].rbegin(), variableIndexPairIte = variablePredicates[updateIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { updateBdd &= this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } else { @@ -613,17 +615,21 @@ namespace storm { for (uint_fast64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { // Compute the identities that are missing for this update. - auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].begin(); - auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].end(); + auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].rbegin(); + auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].rend(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { + for (uint_fast64_t predicateIndex = this->getAbstractionInformation().getNumberOfPredicates() - 1;; --predicateIndex) { if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++updateRelevantIt; } + + if (predicateIndex == 0) { + break; + } } result |= updateIdentity && this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); @@ -631,25 +637,6 @@ namespace storm { return result; } -// template -// storm::dd::Bdd CommandAbstractor::computeMissingGlobalIdentities() const { -// storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); -// -// auto relevantIt = relevantPredicatesAndVariables.first.begin(); -// auto relevantIte = relevantPredicatesAndVariables.first.end(); -// -// for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { -// if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { -// std::cout << "adding global identity of predicate " << this->getAbstractionInformation().getPredicateByIndex(predicateIndex) << std::endl; -// result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); -// } else { -// ++relevantIt; -// } -// } -// -// return result; -// } - template GameBddResult CommandAbstractor::abstract() { if (forceRecomputation) { diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index ca01fca3b..f08785a6d 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -91,6 +91,8 @@ namespace storm { reuseQualitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Qualitative; reuseQuantitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Quantitative; maximalNumberOfAbstractions = abstractionSettings.getMaximalAbstractionCount(); + fixPlayer1Strategy = abstractionSettings.isFixPlayer1StrategySet(); + fixPlayer2Strategy = abstractionSettings.isFixPlayer2StrategySet(); } template @@ -560,6 +562,8 @@ namespace storm { boost::optional> previousSymbolicQualitativeResult = boost::none; boost::optional> previousSymbolicMinQuantitativeResult = boost::none; boost::optional> previousExplicitResult = boost::none; + uint64_t peakPlayer1States = 0; + uint64_t peakTransitions = 0; for (iteration = 0; iteration < maximalNumberOfAbstractions; ++iteration) { auto iterationStart = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Starting iteration " << iteration << "."); @@ -569,7 +573,12 @@ namespace storm { storm::abstraction::MenuGame game = abstractor->abstract(); abstractionWatch.stop(); totalAbstractionWatch.add(abstractionWatch); - STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << game.getNumberOfStates() << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << game.getNumberOfTransitions() << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << abstractionWatch.getTimeInMilliseconds() << "ms)."); + + uint64_t numberOfPlayer1States = game.getNumberOfStates(); + peakPlayer1States = std::max(peakPlayer1States, numberOfPlayer1States); + uint64_t numberOfTransitions = game.getNumberOfTransitions(); + peakTransitions = std::max(peakTransitions, numberOfTransitions); + STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << numberOfPlayer1States << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << numberOfTransitions << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << abstractionWatch.getTimeInMilliseconds() << "ms)."); // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); @@ -596,7 +605,7 @@ namespace storm { if (result) { totalWatch.stop(); - printStatistics(*abstractor, game, iteration); + printStatistics(*abstractor, game, iteration, peakPlayer1States, peakTransitions); return result; } @@ -712,54 +721,169 @@ namespace storm { } template - void postProcessStrategies(abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool sanityCheck) { + void postProcessStrategies(storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { + + if (!redirectPlayer1 && !redirectPlayer2) { + return; + } + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + bool isProb0Min = qualitativeResult.getProb0Min().getStates().get(state); + + bool hasMinPlayer1Choice = false; + uint64_t lowerPlayer1Choice = 0; + bool hasMaxPlayer1Choice = false; + uint64_t upperPlayer1Choice = 0; + + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + hasMinPlayer1Choice = true; + lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (lowerPlayer2Choice == upperPlayer2Choice) { + continue; + } + + bool redirect = true; + if (isProb0Min) { + for (auto const& entry : transitionMatrix.getRow(upperPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + redirect = false; + break; + } + } + } + + if (redirectPlayer2 && redirect) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } + } + } + + bool lowerChoiceUnderUpperIsProb0 = false; + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + + if (lowerPlayer1Choice != upperPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + hasMaxPlayer1Choice = true; + + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (lowerPlayer2Choice == upperPlayer2Choice) { + continue; + } + + lowerChoiceUnderUpperIsProb0 = true; + for (auto const& entry : transitionMatrix.getRow(lowerPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + lowerChoiceUnderUpperIsProb0 = false; + break; + } + } + + bool redirect = true; + if (lowerChoiceUnderUpperIsProb0) { + for (auto const& entry : transitionMatrix.getRow(upperPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + redirect = false; + break; + } + } + } + + if (redirectPlayer2 && redirect) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } + } + } + + if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { + if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { + if (!isProb0Min || lowerChoiceUnderUpperIsProb0) { + minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + } + } + } + } + } + + template + void postProcessStrategies(storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { + + if (!redirectPlayer1 && !redirectPlayer2) { + return; + } + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); + bool hasMinPlayer1Choice = false; + uint64_t lowerPlayer1Choice = 0; + ValueType lowerValueUnderMinChoicePlayer1 = storm::utility::zero(); + bool hasMaxPlayer1Choice = false; + uint64_t upperPlayer1Choice = 0; + ValueType lowerValueUnderMaxChoicePlayer1 = storm::utility::zero(); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - uint64_t lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + hasMinPlayer1Choice = true; + lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); - STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (upper player 1 choice " << lowerPlayer1Choice << ")."); + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (lower player 1 choice " << lowerPlayer1Choice << ")."); uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMinChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); - if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { + lowerValueUnderMinChoicePlayer1 = lowerValueUnderUpperChoicePlayer2; minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); - if (sanityCheck) { - STORM_LOG_TRACE("[min] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice); - } } } } } if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - uint64_t upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); - STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); - uint64_t upperPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); - - if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + if (upperPlayer1Choice != lowerPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + hasMaxPlayer1Choice = true; + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMaxChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderLowerChoice = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - ValueType lowerValueUnderUpperChoice = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); - if (lowerValueUnderUpperChoice <= lowerValueUnderLowerChoice) { + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); - STORM_LOG_TRACE("[max] redirecting choice of state " << state << ": " << lowerValueUnderLowerChoice << " vs. " << lowerValueUnderUpperChoice); } } } } + + if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { + if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { + if (lowerValueUnderMaxChoicePlayer1 <= lowerValueUnderMinChoicePlayer1) { + minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + } + } + } } if (sanityCheck) { @@ -894,6 +1018,9 @@ namespace storm { STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + // Post-process strategies for better refinements. + postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, qualitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. storm::utility::Stopwatch refinementWatch(true); @@ -937,7 +1064,8 @@ namespace storm { return result; } - postProcessStrategies(minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, quantitativeResult, this->debug); + // Post-process strategies for better refinements. + postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); // Make sure that all strategies are still valid strategies. STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); @@ -1128,7 +1256,7 @@ namespace storm { } template - void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements) const { + void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements, uint64_t peakPlayer1States, uint64_t peakTransitions) const { if (storm::settings::getModule().isShowStatisticsSet()) { storm::abstraction::AbstractionInformation const& abstractionInformation = abstractor.getAbstractionInformation(); @@ -1137,10 +1265,11 @@ namespace storm { std::cout << std::endl; std::cout << "Statistics:" << std::endl; - std::cout << " * size of final game: " << game.getReachableStates().getNonZeroCount() << " player 1 states" << std::endl; + std::cout << " * size of final game: " << game.getReachableStates().getNonZeroCount() << " player 1 states, " << game.getTransitionMatrix().getNonZeroCount() << " transitions" << std::endl; + std::cout << " * peak size of game: " << peakPlayer1States << " player 1 states, " << peakTransitions << " transitions" << std::endl; std::cout << " * transitions (final game): " << game.getTransitionMatrix().getNonZeroCount() << std::endl; std::cout << " * refinements: " << refinements << std::endl; - std::cout << " * predicates used in abstraction: " << abstractionInformation.getNumberOfPredicates() << std::endl << std::endl; + std::cout << " * predicates: " << abstractionInformation.getNumberOfPredicates() << std::endl << std::endl; uint64_t totalAbstractionTimeMillis = totalAbstractionWatch.getTimeInMilliseconds(); uint64_t totalTranslationTimeMillis = totalTranslationWatch.getTimeInMilliseconds(); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index cf6d059aa..353be113a 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -115,7 +115,7 @@ namespace storm { ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); - void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements) const; + void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements, uint64_t peakPlayer1States, uint64_t peakTransitions) const; /* * Retrieves the expression characterized by the formula. The formula needs to be propositional. @@ -150,6 +150,12 @@ namespace storm { /// The performed number of refinement iterations. uint64_t iteration; + /// A flag indicating whether to fix player 1 strategies. + bool fixPlayer1Strategy; + + /// A flag indicating whether to fix player 2 strategies. + bool fixPlayer2Strategy; + /// A flag that indicates whether debug mode is enabled. bool debug; diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 0f73e2c4f..8153b8e2c 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -29,7 +29,9 @@ namespace storm { const std::string AbstractionSettings::constraintsOptionName = "constraints"; const std::string AbstractionSettings::useEagerRefinementOptionName = "eagerref"; const std::string AbstractionSettings::debugOptionName = "debug"; - const std::string AbstractionSettings::injectRefinementPredicatesOption = "injectref"; + const std::string AbstractionSettings::injectRefinementPredicatesOptionName = "injectref"; + const std::string AbstractionSettings::fixPlayer1StrategyOptionName = "fixpl1strat"; + const std::string AbstractionSettings::fixPlayer2StrategyOptionName = "fixpl2strat"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -106,10 +108,20 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").build()) .build()); - this->addOption(storm::settings::OptionBuilder(moduleName, injectRefinementPredicatesOption, true, "Specifies predicates used by the refinement instead of the derived predicates.") + this->addOption(storm::settings::OptionBuilder(moduleName, injectRefinementPredicatesOptionName, true, "Specifies predicates used by the refinement instead of the derived predicates.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("predicates", "The (semicolon-separated) refinement predicates to use.").build()) .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, fixPlayer1StrategyOptionName, true, "Sets whether to fix player 1 strategies.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, fixPlayer2StrategyOptionName, true, "Sets whether to fix player 2 strategies.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, true, "Sets whether to enable debug mode.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("off").build()) @@ -225,11 +237,19 @@ namespace storm { } bool AbstractionSettings::isInjectRefinementPredicatesSet() const { - return this->getOption(injectRefinementPredicatesOption).getHasOptionBeenSet(); + return this->getOption(injectRefinementPredicatesOptionName).getHasOptionBeenSet(); } std::string AbstractionSettings::getInjectedRefinementPredicates() const { - return this->getOption(injectRefinementPredicatesOption).getArgumentByName("predicates").getValueAsString(); + return this->getOption(injectRefinementPredicatesOptionName).getArgumentByName("predicates").getValueAsString(); + } + + bool AbstractionSettings::isFixPlayer1StrategySet() const { + return this->getOption(fixPlayer1StrategyOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isFixPlayer2StrategySet() const { + return this->getOption(fixPlayer2StrategyOptionName).getArgumentByName("value").getValueAsString() == "on"; } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index f6627129f..95f1e3e36 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -161,7 +161,17 @@ namespace storm { * Retrieves a string containing refinement predicates to inject (if there are any). */ std::string getInjectedRefinementPredicates() const; - + + /*! + * Retrieves whether player 1 strategies are to be fixed. + */ + bool isFixPlayer1StrategySet() const; + + /*! + * Retrieves whether player 2 strategies are to be fixed. + */ + bool isFixPlayer2StrategySet() const; + const static std::string moduleName; private: @@ -181,7 +191,9 @@ namespace storm { const static std::string constraintsOptionName; const static std::string useEagerRefinementOptionName; const static std::string debugOptionName; - const static std::string injectRefinementPredicatesOption; + const static std::string injectRefinementPredicatesOptionName; + const static std::string fixPlayer1StrategyOptionName; + const static std::string fixPlayer2StrategyOptionName; }; } From 4a0134797cbda1add3154ac9c91ae77d71ca8d28 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 31 May 2018 17:08:40 +0200 Subject: [PATCH 328/647] option to add initial predicates --- src/storm/abstraction/MenuGameAbstractor.h | 2 +- src/storm/abstraction/MenuGameRefiner.cpp | 4 ++++ src/storm/abstraction/MenuGameRefiner.h | 2 +- .../abstraction/prism/PrismMenuGameAbstractor.cpp | 2 +- src/storm/settings/modules/AbstractionSettings.cpp | 12 +++++++++++- src/storm/settings/modules/AbstractionSettings.h | 8 ++++++++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index f55a7f236..1887d60ec 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -76,7 +76,7 @@ namespace storm { * computation. */ virtual void notifyGuardsArePredicates() = 0; - + protected: bool isRestrictToRelevantStatesSet() const; diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 25c4242ba..4ebfc24ce 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -93,6 +93,10 @@ namespace storm { this->abstractor.get().notifyGuardsArePredicates(); addedAllGuardsFlag = true; } + if (abstractionSettings.isAddAllInitialExpressionsSet()) { + storm::expressions::Expression initialExpression = this->abstractor.get().getInitialExpression(); + performRefinement(createGlobalRefinement(preprocessPredicates({initialExpression}, RefinementPredicates::Source::InitialExpression))); + } if (abstractionSettings.isInjectRefinementPredicatesSet()) { std::string predicatesString = abstractionSettings.getInjectedRefinementPredicates(); diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index 60d632694..c906fa9cd 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -40,7 +40,7 @@ namespace storm { class RefinementPredicates { public: enum class Source { - WeakestPrecondition, InitialGuard, Guard, Interpolation, Manual + WeakestPrecondition, InitialGuard, InitialExpression, Guard, Interpolation, Manual }; RefinementPredicates() = default; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 7370645ac..88d75b50f 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -276,7 +276,7 @@ namespace storm { module.notifyGuardsArePredicates(); } } - + // Explicitly instantiate the class. template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 8153b8e2c..ace89c635 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -17,6 +17,7 @@ namespace storm { const std::string AbstractionSettings::useDecompositionOptionName = "decomposition"; const std::string AbstractionSettings::splitModeOptionName = "split"; const std::string AbstractionSettings::addAllGuardsOptionName = "all-guards"; + const std::string AbstractionSettings::addInitialExpressionsOptionName = "all-inits"; const std::string AbstractionSettings::useInterpolationOptionName = "interpolation"; const std::string AbstractionSettings::precisionOptionName = "precision"; const std::string AbstractionSettings::relativeOptionName = "relative"; @@ -65,7 +66,12 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("on").build()) .build()); - + + this->addOption(storm::settings::OptionBuilder(moduleName, addInitialExpressionsOptionName, true, "Sets whether all initial expressions are added as initial predicates.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, useInterpolationOptionName, true, "Sets whether interpolation is to be used to eliminate spurious pivot blocks.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("on").build()) @@ -166,6 +172,10 @@ namespace storm { return this->getOption(addAllGuardsOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isAddAllInitialExpressionsSet() const { + return this->getOption(addInitialExpressionsOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + void AbstractionSettings::setAddAllGuards(bool value) { this->getOption(addAllGuardsOptionName).getArgumentByName("value").setFromStringValue(value ? "on" : "off"); } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 95f1e3e36..5e2e8fdbc 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -62,6 +62,13 @@ namespace storm { */ bool isAddAllGuardsSet() const; + /*! + * Retrieves whether the option to add all initial expressions was set. + * + * @return True iff the option was set. + */ + bool isAddAllInitialExpressionsSet() const; + /*! * Sets the option to add all guards to the specified value. * @@ -179,6 +186,7 @@ namespace storm { const static std::string useDecompositionOptionName; const static std::string splitModeOptionName; const static std::string addAllGuardsOptionName; + const static std::string addInitialExpressionsOptionName; const static std::string useInterpolationOptionName; const static std::string precisionOptionName; const static std::string relativeOptionName; From ba3ec0da275e98642b7be456df57c39ffe141b16 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 31 May 2018 20:39:15 +0200 Subject: [PATCH 329/647] lifted all new stuff to JANI menu game abstractor --- .../ExplicitQuantitativeResult.cpp | 5 + .../abstraction/ExplicitQuantitativeResult.h | 3 +- .../abstraction/jani/AutomatonAbstractor.cpp | 6 +- .../abstraction/jani/AutomatonAbstractor.h | 2 +- src/storm/abstraction/jani/EdgeAbstractor.cpp | 471 +++++++++--------- src/storm/abstraction/jani/EdgeAbstractor.h | 26 +- .../jani/JaniMenuGameAbstractor.cpp | 45 +- .../abstraction/jani/JaniMenuGameAbstractor.h | 2 +- .../abstraction/prism/CommandAbstractor.cpp | 23 +- .../abstraction/prism/CommandAbstractor.h | 8 - .../abstraction/prism/ModuleAbstractor.cpp | 10 +- .../prism/PrismMenuGameAbstractor.cpp | 12 +- .../abstraction/GameBasedMdpModelChecker.cpp | 44 +- .../abstraction/GameBasedMdpModelChecker.h | 10 +- 14 files changed, 318 insertions(+), 349 deletions(-) diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.cpp b/src/storm/abstraction/ExplicitQuantitativeResult.cpp index 4b996483d..b15db88bb 100644 --- a/src/storm/abstraction/ExplicitQuantitativeResult.cpp +++ b/src/storm/abstraction/ExplicitQuantitativeResult.cpp @@ -13,6 +13,11 @@ namespace storm { // Intentionally left empty. } + template + ExplicitQuantitativeResult::ExplicitQuantitativeResult(std::vector&& values) : values(std::move(values)) { + // Intentionally left empty. + } + template std::vector const& ExplicitQuantitativeResult::getValues() const { return values; diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.h b/src/storm/abstraction/ExplicitQuantitativeResult.h index 7604655d8..449feb09e 100644 --- a/src/storm/abstraction/ExplicitQuantitativeResult.h +++ b/src/storm/abstraction/ExplicitQuantitativeResult.h @@ -15,7 +15,8 @@ namespace storm { public: ExplicitQuantitativeResult() = default; ExplicitQuantitativeResult(uint64_t numberOfStates); - + ExplicitQuantitativeResult(std::vector&& values); + std::vector const& getValues() const; std::vector& getValues(); void setValue(uint64_t state, ValueType const& value); diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index b14b4db7b..3063c5b1b 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -1,8 +1,8 @@ #include "storm/abstraction/jani/AutomatonAbstractor.h" #include "storm/abstraction/BottomStateResult.h" -#include "storm/abstraction/GameBddResult.h" #include "storm/abstraction/AbstractionInformation.h" +#include "storm/abstraction/GameBddResult.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Add.h" @@ -24,12 +24,12 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { + AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { // For each concrete command, we create an abstract counterpart. uint64_t edgeId = 0; for (auto const& edge : automaton.getEdges()) { - edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition); + edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition, debug); ++edgeId; } diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index 9e800b756..3053de3c4 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -35,7 +35,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); AutomatonAbstractor(AutomatonAbstractor const&) = default; AutomatonAbstractor& operator=(AutomatonAbstractor const&) = default; diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index c0592df3c..f60d99ece 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace jani { template - EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory) { + EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(edge.getNumberOfDestinations()); @@ -179,7 +179,6 @@ namespace storm { } relevantBlockPartition[representativeBlock].insert(relevantBlockPartition[assignmentVariableBlock].begin(), relevantBlockPartition[assignmentVariableBlock].end()); relevantBlockPartition[assignmentVariableBlock].clear(); - } } } @@ -188,200 +187,231 @@ namespace storm { // Now remove all blocks that are empty and obtain the partition. std::vector> cleanedRelevantBlockPartition; - for (auto& element : relevantBlockPartition) { - if (!element.empty()) { - cleanedRelevantBlockPartition.emplace_back(std::move(element)); + for (auto& outerBlock : relevantBlockPartition) { + if (!outerBlock.empty()) { + cleanedRelevantBlockPartition.emplace_back(); + + for (auto const& innerBlock : outerBlock) { + if (!localExpressionInformation.getExpressionBlock(innerBlock).empty()) { + cleanedRelevantBlockPartition.back().insert(innerBlock); + } + } + + if (cleanedRelevantBlockPartition.back().empty()) { + cleanedRelevantBlockPartition.pop_back(); + } } } relevantBlockPartition = std::move(cleanedRelevantBlockPartition); - // if the decomposition has size 1, use the plain technique from before - if (relevantBlockPartition.size() == 1) { - STORM_LOG_TRACE("Relevant block partition size is one, falling back to regular computation."); - recomputeCachedBddWithoutDecomposition(); - } else { - std::set variablesContainedInGuard = edge.get().getGuard().getVariables(); - - // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard - // are not contained within a single block of our decomposition. - bool enumerateAbstractGuard = true; - std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); + if (this->debug) { + uint64_t blockIndex = 0; for (auto const& block : relevantBlockPartition) { - bool allContained = true; - for (auto const& guardBlock : guardBlocks) { - if (block.find(guardBlock) == block.end()) { - allContained = false; - break; - } - } - if (allContained) { - enumerateAbstractGuard = false; - } - } - - uint64_t numberOfSolutions = 0; - - if (enumerateAbstractGuard) { - // otherwise, enumerate the abstract guard so we do this only once - std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); - std::vector guardDecisionVariables; - std::vector> guardVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { - guardDecisionVariables.push_back(element.first); - guardVariablesAndPredicates.push_back(element); - } + STORM_LOG_TRACE("Predicates of block " << blockIndex << ":"); + std::set blockPredicateIndices; + for (auto const& innerBlock : block) { + blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); } - abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); - smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { - abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " for abstract guard."); - - // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating - // the other solutions. - - // Create a new backtracking point before adding the guard. - smtSolver->push(); - // Create the guard constraint. - std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); - - // Then add it to the solver. - for (auto const& expression : result.first) { - smtSolver->add(expression); + for (auto const& predicateIndex : blockPredicateIndices) { + STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); } - // Finally associate the level variables with the predicates. - for (auto const& indexVariablePair : result.second) { - smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + ++blockIndex; + } + } + + std::set variablesContainedInGuard = edge.get().getGuard().getVariables(); + + // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard + // are not contained within a single block of our decomposition. + bool enumerateAbstractGuard = true; + std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + for (auto const& block : relevantBlockPartition) { + bool allContained = true; + for (auto const& guardBlock : guardBlocks) { + if (block.find(guardBlock) == block.end()) { + allContained = false; + break; } } - - // then enumerate the solutions for each of the blocks of the decomposition - uint64_t usedNondeterminismVariables = 0; - uint64_t blockCounter = 0; - std::vector> blockBdds; - for (auto const& block : relevantBlockPartition) { - std::set relevantPredicates; - for (auto const& innerBlock : block) { - relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + if (allContained) { + enumerateAbstractGuard = false; + } + } + + uint64_t numberOfSolutions = 0; + uint64_t numberOfTotalSolutions = 0; + + // If we need to enumerate the guard, do it only once now. + if (enumerateAbstractGuard) { + std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); + std::vector guardDecisionVariables; + std::vector> guardVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { + guardDecisionVariables.push_back(element.first); + guardVariablesAndPredicates.push_back(element); } - - std::vector transitionDecisionVariables; - std::vector> sourceVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relevantPredicates.find(element.second) != relevantPredicates.end()) { - transitionDecisionVariables.push_back(element.first); - sourceVariablesAndPredicates.push_back(element); - } + } + abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); + smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { + abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); + + // Now that we have the abstract guard, we can add it as an assertion to the solver before enumerating + // the other solutions. + + // Create a new backtracking point before adding the guard. + smtSolver->push(); + + // Create the guard constraint. + std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); + + // Then add it to the solver. + for (auto const& expression : result.first) { + smtSolver->add(expression); + } + + // Finally associate the level variables with the predicates. + for (auto const& indexVariablePair : result.second) { + smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + } + } + + // Then enumerate the solutions for each of the blocks of the decomposition + uint64_t usedNondeterminismVariables = 0; + uint64_t blockCounter = 0; + std::vector> blockBdds; + for (auto const& block : relevantBlockPartition) { + std::set relevantPredicates; + for (auto const& innerBlock : block) { + relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } + + if (relevantPredicates.empty()) { + STORM_LOG_TRACE("Block does not contain relevant predicates, skipping it."); + continue; + } + + std::vector transitionDecisionVariables; + std::vector> sourceVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relevantPredicates.find(element.second) != relevantPredicates.end()) { + transitionDecisionVariables.push_back(element.first); + sourceVariablesAndPredicates.push_back(element); } - - std::vector>> destinationVariablesAndPredicates; - for (uint64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { - destinationVariablesAndPredicates.emplace_back(); - for (auto const& assignment : edge.get().getDestination(destinationIndex).getOrderedAssignments().getAllAssignments()) { - uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getExpressionVariable()); + } + + std::vector>> destinationVariablesAndPredicates; + for (uint64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { + destinationVariablesAndPredicates.emplace_back(); + for (auto const& assignment : edge.get().getDestination(destinationIndex).getOrderedAssignments().getAllAssignments()) { + uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable().getExpressionVariable()); + + if (block.find(assignmentVariableBlockIndex) != block.end()) { std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); - if (block.find(assignmentVariableBlockIndex) != block.end()) { - for (auto const& element : relevantPredicatesAndVariables.second[destinationIndex]) { - if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { - destinationVariablesAndPredicates.back().push_back(element); - transitionDecisionVariables.push_back(element.first); - } + for (auto const& element : relevantPredicatesAndVariables.second[destinationIndex]) { + if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { + destinationVariablesAndPredicates.back().push_back(element); + transitionDecisionVariables.push_back(element.first); } } } } - - std::unordered_map, std::vector>> sourceToDistributionsMap; - numberOfSolutions = 0; - smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { - sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); - numberOfSolutions = 0; - - // Now we search for the maximal number of choices of player 2 to determine how many DD variables we - // need to encode the nondeterminism. - uint_fast64_t maximalNumberOfChoices = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); - } - - // We now compute how many variables we need to encode the choices. We add one to the maximal number of - // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + 1))); - - // Finally, build overall result. - storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); - - uint_fast64_t sourceStateIndex = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); - STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - // We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice. - uint_fast64_t distributionIndex = 1; - storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); - for (auto const& distribution : sourceDistributionsPair.second) { - allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); - ++distributionIndex; - STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); - } - resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; - STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); - } - usedNondeterminismVariables += numberOfVariablesNeeded; - - blockBdds.push_back(resultBdd); - ++blockCounter; } - if (enumerateAbstractGuard) { - smtSolver->pop(); - } + std::unordered_map, std::vector>> sourceToDistributionsMap; + numberOfSolutions = 0; + smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { + sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); + numberOfTotalSolutions += numberOfSolutions; - // multiply the results - storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& blockBdd : blockBdds) { - resultBdd &= blockBdd; + // Now we search for the maximal number of choices of player 2 to determine how many DD variables we + // need to encode the nondeterminism. + uint_fast64_t maximalNumberOfChoices = 0; + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); } - // if we did not explicitly enumerate the guard, we can construct it from the result BDD. - if (!enumerateAbstractGuard) { - std::set allVariables(this->getAbstractionInformation().getSuccessorVariables()); - auto player2Variables = this->getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); - allVariables.insert(player2Variables.begin(), player2Variables.end()); - auto auxVariables = this->getAbstractionInformation().getAuxVariableSet(0, this->getAbstractionInformation().getAuxVariableCount()); - allVariables.insert(auxVariables.begin(), auxVariables.end()); - - std::set variablesToAbstract; - std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); + // We now compute how many variables we need to encode the choices. We add one to the maximal number of + // choices to account for a possible transition to a bottom state. + uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))); + + // Finally, build overall result. + storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); + + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); + STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - abstractGuard = resultBdd.existsAbstract(variablesToAbstract); - } else { - // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. - resultBdd &= abstractGuard; + // We start with the distribution index of 1, because 0 is reserved for a potential bottom choice. + uint_fast64_t distributionIndex = blockCounter == 0 ? 1 : 0; + storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); + for (auto const& distribution : sourceDistributionsPair.second) { + allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); + ++distributionIndex; + STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); + } + resultBdd |= sourceDistributionsPair.first && allDistributions; + STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } + usedNondeterminismVariables += numberOfVariablesNeeded; - // multiply with missing identities - resultBdd &= computeMissingIdentities(); - - // cache and return result - resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); + blockBdds.push_back(resultBdd); + ++blockCounter; + } + + if (enumerateAbstractGuard) { + smtSolver->pop(); + } + + // multiply the results + storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); + uint64_t blockIndex = 0; + for (auto const& blockBdd : blockBdds) { + resultBdd &= blockBdd; + ++blockIndex; + } + + // If we did not explicitly enumerate the guard, we can construct it from the result BDD. + if (!enumerateAbstractGuard) { + std::set allVariables(getAbstractionInformation().getSuccessorVariables()); + auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); + allVariables.insert(player2Variables.begin(), player2Variables.end()); + auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); + allVariables.insert(auxVariables.begin(), auxVariables.end()); - // Cache the result. - cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + std::set variablesToAbstract; + std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); - auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); - forceRecomputation = false; + abstractGuard = resultBdd.existsAbstract(variablesToAbstract); + } else { + // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. + resultBdd &= abstractGuard; } + + // multiply with missing identities + resultBdd &= computeMissingDestinationIdentities(); + + // cache and return result + resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); + + // Cache the result. + cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + + auto end = std::chrono::high_resolution_clock::now(); + + STORM_LOG_TRACE("Enumerated " << numberOfTotalSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); + forceRecomputation = false; } template @@ -414,7 +444,6 @@ namespace storm { if (!skipBottomStates) { abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); } - uint_fast64_t sourceStateIndex = 0; for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { if (!skipBottomStates) { abstractGuard |= sourceDistributionsPair.first; @@ -431,11 +460,10 @@ namespace storm { STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); } resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } - resultBdd &= computeMissingIdentities(); + resultBdd &= computeMissingDestinationIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -461,14 +489,8 @@ namespace storm { storm::expressions::Variable const& assignedVariable = assignment.getExpressionVariable(); auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); - - // Keep track of all assigned variables, so we can find the related predicates later. - assignedVariables.insert(assignedVariable); } - auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); - result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); - return result; } @@ -535,7 +557,8 @@ namespace storm { template storm::dd::Bdd EdgeAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, std::vector> const& variablePredicates) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& variableIndexPair : variablePredicates) { + for (auto variableIndexPairIt = variablePredicates.rbegin(), variableIndexPairIte = variablePredicates.rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { @@ -555,7 +578,8 @@ namespace storm { storm::dd::Bdd updateBdd = this->getAbstractionInformation().getDdManager().getBddOne(); // Translate block variables for this update into a successor block. - for (auto const& variableIndexPair : variablePredicates[destinationIndex]) { + for (auto variableIndexPairIt = variablePredicates[destinationIndex].rbegin(), variableIndexPairIte = variablePredicates[destinationIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { updateBdd &= this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } else { @@ -572,99 +596,75 @@ namespace storm { } template - storm::dd::Bdd EdgeAbstractor::computeMissingIdentities() const { - storm::dd::Bdd identities = computeMissingGlobalIdentities(); - identities &= computeMissingUpdateIdentities(); - return identities; - } - - template - storm::dd::Bdd EdgeAbstractor::computeMissingUpdateIdentities() const { + storm::dd::Bdd EdgeAbstractor::computeMissingDestinationIdentities() const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddZero(); - for (uint_fast64_t updateIndex = 0; updateIndex < edge.get().getNumberOfDestinations(); ++updateIndex) { + for (uint_fast64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { // Compute the identities that are missing for this update. - auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].begin(); - auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].end(); + auto updateRelevantIt = relevantPredicatesAndVariables.second[destinationIndex].rbegin(); + auto updateRelevantIte = relevantPredicatesAndVariables.second[destinationIndex].rend(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - auto sourceRelevantIt = relevantPredicatesAndVariables.first.begin(); - auto sourceRelevantIte = relevantPredicatesAndVariables.first.end(); - - // Go through all relevant source predicates. This is guaranteed to be a superset of the set of - // relevant successor predicates for any update. - for (; sourceRelevantIt != sourceRelevantIte; ++sourceRelevantIt) { - // If the predicates do not match, there is a predicate missing, so we need to add its identity. - if (updateRelevantIt == updateRelevantIte || sourceRelevantIt->second != updateRelevantIt->second) { - updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(sourceRelevantIt->second); + for (uint_fast64_t predicateIndex = this->getAbstractionInformation().getNumberOfPredicates() - 1;; --predicateIndex) { + if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { + updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++updateRelevantIt; } + + if (predicateIndex == 0) { + break; + } } - result |= updateIdentity && this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); + result |= updateIdentity && this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } return result; } - template - storm::dd::Bdd EdgeAbstractor::computeMissingGlobalIdentities() const { - storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - - auto relevantIt = relevantPredicatesAndVariables.first.begin(); - auto relevantIte = relevantPredicatesAndVariables.first.end(); - - for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { - if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { - result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); - } else { - ++relevantIt; - } - } - - return result; - } - template GameBddResult EdgeAbstractor::abstract() { if (forceRecomputation) { this->recomputeCachedBdd(); } else { - cachedDd.bdd &= computeMissingGlobalIdentities(); + cachedDd.bdd &= computeMissingDestinationIdentities(); } + STORM_LOG_TRACE("Edge produces " << cachedDd.bdd.getNonZeroCount() << " transitions."); + return cachedDd; } template BottomStateResult EdgeAbstractor::getBottomStateTransitions(storm::dd::Bdd const& reachableStates, uint_fast64_t numberOfPlayer2Variables, boost::optional> const& locationVariables) { - // Compute the reachable states that have this edge enabled. - storm::dd::Bdd reachableStatesWithEdge; - if (locationVariables) { - reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); - } else { - reachableStatesWithEdge = (reachableStates && abstractGuard).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); - } - - STORM_LOG_TRACE("Computing bottom state transitions of edge with guard " << edge.get().getGuard()); + STORM_LOG_TRACE("Computing bottom state transitions of edge with index " << edgeId << "."); BottomStateResult result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero()); - // If the guard of this edge is a predicate, there are not bottom states/transitions. + // If the guard of this command is a predicate, there are not bottom states/transitions. if (skipBottomStates) { STORM_LOG_TRACE("Skipping bottom state computation for this edge."); return result; } - // Use the state abstractor to compute the set of abstract states that has this edge enabled but still - // has a transition to a bottom state. + storm::dd::Bdd reachableStatesWithEdge = reachableStates && abstractGuard; + // needed? +// if (locationVariables) { +// reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); +// } else { +// reachableStatesWithEdge = (reachableStates && abstractGuard).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); +// } + + + // Use the state abstractor to compute the set of abstract states that has this command enabled but + // still has a transition to a bottom state. bottomStateAbstractor.constrain(reachableStatesWithEdge); if (locationVariables) { result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex()); } else { result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge; } - + // If the result is empty one time, we can skip the bottom state computation from now on. if (result.states.isZero()) { skipBottomStates = true; @@ -673,14 +673,11 @@ namespace storm { // Now equip all these states with an actual transition to a bottom state. result.transitions = result.states && this->getAbstractionInformation().getAllPredicateIdentities() && this->getAbstractionInformation().getBottomStateBdd(false, false); - // Mark the states as bottom states and add source location information. + // Mark the states as bottom states. result.states &= this->getAbstractionInformation().getBottomStateBdd(true, false); - // Add the edge encoding. - result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(0, 0,numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount()); - - // Add the location identity to the transitions. - result.transitions &= this->getAbstractionInformation().getAllLocationIdentities(); + // Add the command encoding and the next free player 2 encoding. + result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(0, 0, numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount()); return result; } diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index 7ba7445a5..3c8c1d21b 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -58,7 +58,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use an edge decomposition during abstraction. */ - EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); /*! * Refines the abstract edge with the given predicates. @@ -187,21 +187,14 @@ namespace storm { * Recomputes the cached BDD using the decomposition. */ void recomputeCachedBddWithDecomposition(); - - /*! - * Computes the missing state identities. - * - * @return A BDD that represents the all missing state identities. - */ - storm::dd::Bdd computeMissingIdentities() const; /*! - * Computes the missing state identities for the updates. + * Computes the missing state identities for the destinations. * * @return A BDD that represents the state identities for predicates that are irrelevant for the * successor states. */ - storm::dd::Bdd computeMissingUpdateIdentities() const; + storm::dd::Bdd computeMissingDestinationIdentities() const; /*! * Retrieves the abstraction information object. @@ -216,15 +209,7 @@ namespace storm { * @return The abstraction information object. */ AbstractionInformation& getAbstractionInformation(); - - /*! - * Computes the globally missing state identities. - * - * @return A BDD that represents the global state identities for predicates that are irrelevant for the - * source and successor states. - */ - storm::dd::Bdd computeMissingGlobalIdentities() const; - + // An SMT responsible for this abstract command. std::unique_ptr smtSolver; @@ -275,6 +260,9 @@ namespace storm { // A state-set abstractor used to determine the bottom states if not all guards were added. StateSetAbstractor bottomStateAbstractor; + + // A flag that indicates whether or not debug mode is enabled. + bool debug; }; } } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index be4e33d8e..886bcbdcc 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -51,26 +51,28 @@ namespace storm { validBlockAbstractor.constrain(range); } - uint_fast64_t totalNumberOfCommands = 0; - uint_fast64_t maximalUpdateCount = 0; + uint_fast64_t totalNumberOfEdges = 0; + uint_fast64_t maximalDestinationCount = 0; std::vector allGuards; for (auto const& automaton : model.getAutomata()) { for (auto const& edge : automaton.getEdges()) { - maximalUpdateCount = std::max(maximalUpdateCount, static_cast(edge.getNumberOfDestinations())); + maximalDestinationCount = std::max(maximalDestinationCount, static_cast(edge.getNumberOfDestinations())); } - totalNumberOfCommands += automaton.getNumberOfEdges(); + totalNumberOfEdges += automaton.getNumberOfEdges(); } // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible // choices. If for some reason this should not be enough, we could grow this vector dynamically, but // odds are that it's impossible to treat such models in any event. - abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 64, static_cast(std::ceil(std::log2(maximalUpdateCount)))); + abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfEdges))), 64, static_cast(std::ceil(std::log2(maximalDestinationCount)))); // For each module of the concrete program, we create an abstract counterpart. - bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); + auto const& settings = storm::settings::getModule(); + bool useDecomposition = settings.isUseDecompositionSet(); + bool debug = settings.isDebugSet(); for (auto const& automaton : model.getAutomata()) { - automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition); + automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition, debug); } // Retrieve global BDDs/ADDs so we can multiply them in the abstraction process. @@ -105,7 +107,7 @@ namespace storm { MenuGame JaniMenuGameAbstractor::abstract() { if (refinementPerformed) { currentGame = buildGame(); - refinementPerformed = true; + refinementPerformed = false; } return *currentGame; } @@ -153,7 +155,7 @@ namespace storm { template std::unique_ptr> JaniMenuGameAbstractor::buildGame() { - // As long as there is only one module, we only build its game representation. + // As long as there is only one automaton, we only build its game representation. GameBddResult game = automata.front().abstract(); // Add the locations to the transitions. @@ -161,10 +163,12 @@ namespace storm { // Construct a set of all unnecessary variables, so we can abstract from it. std::set variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount())); + std::set successorAndAuxVariables(abstractionInformation.getSuccessorVariables()); auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables); variablesToAbstract.insert(player2Variables.begin(), player2Variables.end()); auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + successorAndAuxVariables.insert(auxVariables.begin(), auxVariables.end()); storm::utility::Stopwatch relevantStatesWatch(true); storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); @@ -179,12 +183,15 @@ namespace storm { } relevantStatesWatch.stop(); + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + + // Compute the choices with only valid successors so we can restrict the game to these. + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = nonTerminalStates && game.bdd.existsAbstract(variablesToAbstract); - storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); - if (!model.get().hasTrivialInitialStatesExpression()) { - initialStates &= validBlockAbstractor.getValidBlocks(); - } + storm::dd::Bdd extendedTransitionRelation = validBlocks && nonTerminalStates && game.bdd && choicesWithOnlyValidSuccessors; + storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); + storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates() && validBlocks; initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); @@ -194,20 +201,19 @@ namespace storm { storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); // In the presence of target states, we keep only states that can reach the target states. - auto newReachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; - reachableStates = newReachableStates; + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. reachableStates |= (reachableStates && !targetStates).relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); - relevantStatesWatch.stop(); // Restrict transition relation to relevant fragment for computation of deadlock states. transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()); + relevantStatesWatch.stop(); STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); } - + // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states, // as the bottom states are not contained in the reachable states. storm::dd::Bdd deadlockStates = transitionRelation.existsAbstract(abstractionInformation.getSuccessorVariables()); @@ -227,8 +233,7 @@ namespace storm { // Construct the transition matrix by cutting away the transitions of unreachable states. // Note that we also restrict the successor states of transitions, because there might be successors // that are not in the set of relevant states we restrict to. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs())).template toAdd(); - + storm::dd::Add transitionMatrix = (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= edgeDecoratorAdd; transitionMatrix += deadlockTransitions; diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 916dbd7d6..80c625072 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -117,7 +117,7 @@ namespace storm { * @param highlightStates A BDD characterizing states that will be highlighted. * @param filter A filter that is applied to select which part of the game to export. */ - void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; virtual uint64_t getNumberOfPredicates() const override; diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 4a22b976f..39d95845b 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -283,7 +283,7 @@ namespace storm { } } - // then enumerate the solutions for each of the blocks of the decomposition + // Then enumerate the solutions for each of the blocks of the decomposition uint64_t usedNondeterminismVariables = 0; uint64_t blockCounter = 0; std::vector> blockBdds; @@ -349,7 +349,6 @@ namespace storm { // Finally, build overall result. storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); - uint_fast64_t sourceStateIndex = 0; for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); @@ -363,7 +362,6 @@ namespace storm { STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); } resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } usedNondeterminismVariables += numberOfVariablesNeeded; @@ -402,7 +400,7 @@ namespace storm { } // multiply with missing identities - resultBdd &= computeMissingIdentities(); + resultBdd &= computeMissingUpdateIdentities(); // cache and return result resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); @@ -465,7 +463,7 @@ namespace storm { STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } - resultBdd &= computeMissingIdentities(); + resultBdd &= computeMissingUpdateIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -491,14 +489,8 @@ namespace storm { storm::expressions::Variable const& assignedVariable = assignment.getVariable(); auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); - -// // Keep track of all assigned variables, so we can find the related predicates later. -// assignedVariables.insert(assignedVariable); } -// auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); -// result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); - return result; } @@ -507,7 +499,7 @@ namespace storm { std::pair, std::vector>> result; // To start with, all predicates related to the guard are relevant source predicates. - result.first = localExpressionInformation.getRelatedExpressions(command.get().getGuardExpression().getVariables()); + result.first = localExpressionInformation.getExpressionsUsingVariables(command.get().getGuardExpression().getVariables()); // Then, we add the predicates that become relevant, because of some update. for (auto const& update : command.get().getUpdates()) { @@ -596,7 +588,6 @@ namespace storm { } updateBdd &= this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); - result |= updateBdd; } @@ -604,11 +595,6 @@ namespace storm { return result; } - template - storm::dd::Bdd CommandAbstractor::computeMissingIdentities() const { - return computeMissingUpdateIdentities(); - } - template storm::dd::Bdd CommandAbstractor::computeMissingUpdateIdentities() const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddZero(); @@ -619,7 +605,6 @@ namespace storm { auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].rend(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - for (uint_fast64_t predicateIndex = this->getAbstractionInformation().getNumberOfPredicates() - 1;; --predicateIndex) { if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index e6d7c7238..9cc48b3b2 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -213,14 +213,6 @@ namespace storm { */ AbstractionInformation& getAbstractionInformation(); -// /*! -// * Computes the globally missing state identities. -// * -// * @return A BDD that represents the global state identities for predicates that are irrelevant for the -// * source and successor states. -// */ -// storm::dd::Bdd computeMissingGlobalIdentities() const; - // An SMT responsible for this abstract command. std::unique_ptr smtSolver; diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index d1574e23b..bafb43717 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -1,7 +1,7 @@ #include "storm/abstraction/prism/ModuleAbstractor.h" -#include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/BottomStateResult.h" +#include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/GameBddResult.h" #include "storm/storage/dd/DdManager.h" @@ -26,10 +26,8 @@ namespace storm { ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { // For each concrete command, we create an abstract counterpart. - uint64_t counter = 0; for (auto const& command : module.getCommands()) { commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition, debug); - ++counter; } } @@ -37,8 +35,7 @@ namespace storm { void ModuleAbstractor::refine(std::vector const& predicates) { for (uint_fast64_t index = 0; index < commands.size(); ++index) { STORM_LOG_TRACE("Refining command with index " << index << "."); - CommandAbstractor& command = commands[index]; - command.refine(predicates); + commands[index].refine(predicates); } } @@ -85,8 +82,7 @@ namespace storm { BottomStateResult ModuleAbstractor::getBottomStateTransitions(storm::dd::Bdd const& reachableStates, uint_fast64_t numberOfPlayer2Variables) { BottomStateResult result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero()); - for (uint64_t index = 0; index < commands.size(); ++index) { - auto& command = commands[index]; + for (auto& command : commands) { BottomStateResult commandBottomStateResult = command.getBottomStateTransitions(reachableStates, numberOfPlayer2Variables); result.states |= commandBottomStateResult.states; result.transitions |= commandBottomStateResult.transitions; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 88d75b50f..60ab41e92 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -33,8 +33,7 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, - std::shared_ptr const& smtSolverFactory) + PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory) : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager(), program.getAllExpressionVariables(), smtSolverFactory->create(program.getManager())), modules(), initialStateAbstractor(abstractionInformation, {program.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(false) { // For now, we assume that there is a single module. If the program has more than one module, it needs @@ -179,7 +178,6 @@ namespace storm { storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); // Compute the choices with only valid successors so we can restrict the game to these. - auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); // Do a reachability analysis on the raw transition relation. @@ -226,7 +224,7 @@ namespace storm { // Construct the transition matrix by cutting away the transitions of unreachable states. // Note that we also restrict the successor states of transitions, because there might be successors - // that are not in the relevant we restrict to. + // that are not in the set of relevant states we restrict to. storm::dd::Add transitionMatrix = (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= commandUpdateProbabilitiesAdd; transitionMatrix += deadlockTransitions; @@ -242,9 +240,7 @@ namespace storm { reachableStates |= bottomStateResult.states; } - std::set usedPlayer2Variables(abstractionInformation.getPlayer2Variables().begin(), abstractionInformation.getPlayer2Variables().begin() + game.numberOfPlayer2Variables); - - std::set allNondeterminismVariables = usedPlayer2Variables; + std::set allNondeterminismVariables = player2Variables; allNondeterminismVariables.insert(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()); std::set allSourceVariables(abstractionInformation.getSourceVariables()); @@ -252,7 +248,7 @@ namespace storm { std::set allSuccessorVariables(abstractionInformation.getSuccessorVariables()); allSuccessorVariables.insert(abstractionInformation.getBottomStateVariable(false)); - return std::make_unique>(abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(), transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(), std::set(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()), usedPlayer2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap()); + return std::make_unique>(abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(), transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(), std::set(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()), player2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap()); } template diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index f08785a6d..f06c91853 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -418,9 +418,10 @@ namespace storm { // If there is a previous result, unpack the previous values with respect to the new ODD. if (previousResult) { + STORM_LOG_ASSERT(player2Min, "Can only reuse previous values when minimizing."); previousResult.get().odd.oldToNewIndex(odd, [&previousResult,&result,player2Min,player1Prob1States] (uint64_t oldOffset, uint64_t newOffset) { - if (!player2Min && !player1Prob1States.get(newOffset)) { - result.getValues()[newOffset] = player2Min ? previousResult.get().values.getMin().getValues()[oldOffset] : previousResult.get().values.getMax().getValues()[oldOffset]; + if (!player1Prob1States.get(newOffset)) { + result.getValues()[newOffset] = player2Min ? previousResult.get().values.getValues()[oldOffset] : previousResult.get().values.getValues()[oldOffset]; } }); } @@ -1019,7 +1020,11 @@ namespace storm { STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); // Post-process strategies for better refinements. + storm::utility::Stopwatch strategyProcessingWatch(true); postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, qualitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + strategyProcessingWatch.stop(); + totalStrategyProcessingWatch.add(strategyProcessingWatch); + STORM_LOG_DEBUG("Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() << "ms."); // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. @@ -1040,6 +1045,11 @@ namespace storm { // (7) Solve the min values and check whether we can give the answer already. storm::utility::Stopwatch quantitativeWatch(true); quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair, odd, nullptr, nullptr, this->reuseQuantitativeResults ? previousResult : boost::none)); + + // Dispose of previous result as we now reused it. + if (previousResult) { + previousResult.get().clear(); + } quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); if (result) { @@ -1065,7 +1075,12 @@ namespace storm { } // Post-process strategies for better refinements. + storm::utility::Stopwatch strategyProcessingWatch(true); postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + strategyProcessingWatch.stop(); + totalStrategyProcessingWatch.add(strategyProcessingWatch); + STORM_LOG_DEBUG("Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() << "ms."); + // Make sure that all strategies are still valid strategies. STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); @@ -1081,28 +1096,9 @@ namespace storm { if (this->reuseQuantitativeResults) { PreviousExplicitResult nextPreviousResult; - nextPreviousResult.values = std::move(quantitativeResult); + nextPreviousResult.values = std::move(quantitativeResult.getMin()); nextPreviousResult.odd = odd; - - // We transform the offset choices for the states to their labels, so we can more easily identify - // them in the next iteration. - nextPreviousResult.minPlayer1Labels.resize(odd.getTotalOffset()); - nextPreviousResult.maxPlayer1Labels.resize(odd.getTotalOffset()); - for (uint64_t player1State = 0; player1State < odd.getTotalOffset(); ++player1State) { - if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(player1State)) { - nextPreviousResult.minPlayer1Labels[player1State] = player1Labeling[minStrategyPair.getPlayer1Strategy().getChoice(player1State)]; - } else { - nextPreviousResult.minPlayer1Labels[player1State] = std::numeric_limits::max(); - } - if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(player1State)) { - nextPreviousResult.maxPlayer1Labels[player1State] = player1Labeling[maxStrategyPair.getPlayer1Strategy().getChoice(player1State)]; - } else { - nextPreviousResult.minPlayer1Labels[player1State] = std::numeric_limits::max(); - } - } - previousResult = std::move(nextPreviousResult); - STORM_LOG_TRACE("Prepared next previous result to reuse values."); } } @@ -1273,6 +1269,7 @@ namespace storm { uint64_t totalAbstractionTimeMillis = totalAbstractionWatch.getTimeInMilliseconds(); uint64_t totalTranslationTimeMillis = totalTranslationWatch.getTimeInMilliseconds(); + uint64_t totalStrategyProcessingTimeMillis = totalStrategyProcessingWatch.getTimeInMilliseconds(); uint64_t totalSolutionTimeMillis = totalSolutionWatch.getTimeInMilliseconds(); uint64_t totalRefinementTimeMillis = totalRefinementWatch.getTimeInMilliseconds(); uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds(); @@ -1281,6 +1278,9 @@ namespace storm { std::cout << " * abstraction: " << totalAbstractionTimeMillis << "ms (" << 100 * static_cast(totalAbstractionTimeMillis)/totalTimeMillis << "%)" << std::endl; if (this->solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Sparse) { std::cout << " * translation: " << totalTranslationTimeMillis << "ms (" << 100 * static_cast(totalTranslationTimeMillis)/totalTimeMillis << "%)" << std::endl; + if (fixPlayer1Strategy || fixPlayer2Strategy) { + std::cout << " * strategy processing: " << totalStrategyProcessingTimeMillis << "ms (" << 100 * static_cast(totalStrategyProcessingTimeMillis)/totalTimeMillis << "%)" << std::endl; + } } std::cout << " * solution: " << totalSolutionTimeMillis << "ms (" << 100 * static_cast(totalSolutionTimeMillis)/totalTimeMillis << "%)" << std::endl; std::cout << " * refinement: " << totalRefinementTimeMillis << "ms (" << 100 * static_cast(totalRefinementTimeMillis)/totalTimeMillis << "%)" << std::endl; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 353be113a..d76eee4f2 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -62,10 +62,13 @@ namespace storm { namespace detail { template struct PreviousExplicitResult { - ExplicitQuantitativeResultMinMax values; - std::vector minPlayer1Labels; - std::vector maxPlayer1Labels; + ExplicitQuantitativeResult values; storm::dd::Odd odd; + + void clear() { + odd = storm::dd::Odd(); + values = ExplicitQuantitativeResult(); + } }; } @@ -164,6 +167,7 @@ namespace storm { storm::utility::Stopwatch totalSolutionWatch; storm::utility::Stopwatch totalRefinementWatch; storm::utility::Stopwatch totalTranslationWatch; + storm::utility::Stopwatch totalStrategyProcessingWatch; storm::utility::Stopwatch totalWatch; }; } From eaf01ab443aed1a6b9a3cecaa84bce2dab2c9859 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 31 May 2018 22:18:54 +0200 Subject: [PATCH 330/647] bugfix --- .../abstraction/ValidBlockAbstractor.cpp | 32 ++++++++++++++----- src/storm/abstraction/ValidBlockAbstractor.h | 2 +- .../abstraction/prism/CommandAbstractor.cpp | 2 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/storm/abstraction/ValidBlockAbstractor.cpp b/src/storm/abstraction/ValidBlockAbstractor.cpp index 16364b156..bf213964d 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.cpp +++ b/src/storm/abstraction/ValidBlockAbstractor.cpp @@ -5,6 +5,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/utility/solver.h" +#include "storm/utility/Stopwatch.h" namespace storm { namespace abstraction { @@ -68,25 +69,39 @@ namespace storm { template void ValidBlockAbstractor::recomputeValidBlocks() { storm::dd::Bdd newValidBlocks = abstractionInformation.get().getDdManager().getBddOne(); - + for (uint64_t blockIndex = 0; blockIndex < localExpressionInformation.getNumberOfBlocks(); ++blockIndex) { std::set const& predicateBlock = localExpressionInformation.getExpressionBlock(blockIndex); // If the size of the block changed, we need to add the appropriate variables and recompute the solution. if (relevantVariablesAndPredicates[blockIndex].size() < predicateBlock.size()) { - recomputeValidBlockForPredicateBlock(blockIndex); + recomputeValidBlocksForPredicateBlock(blockIndex); } - - newValidBlocks &= validBlocksForPredicateBlocks[blockIndex]; } - validBlocks = newValidBlocks; + // Now compute the conjunction of all blocks. + std::vector> blocks = validBlocksForPredicateBlocks; + std::vector> newBlocks; + while (blocks.size() > 1) { + storm::utility::Stopwatch conj(true); + for (uint64_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex) { + if (blockIndex < localExpressionInformation.getNumberOfBlocks() - 1) { + newBlocks.emplace_back(blocks[blockIndex] && blocks[blockIndex + 1]); + } else { + newBlocks.emplace_back(blocks[blockIndex]); + } + } + conj.stop(); + + std::swap(blocks, newBlocks); + } + + validBlocks = blocks.front(); } template - void ValidBlockAbstractor::recomputeValidBlockForPredicateBlock(uint64_t blockIndex) { + void ValidBlockAbstractor::recomputeValidBlocksForPredicateBlock(uint64_t blockIndex) { std::set const& predicateBlock = localExpressionInformation.getExpressionBlock(blockIndex); - std::vector> newVariables = this->getAbstractionInformation().declareNewVariables(relevantVariablesAndPredicates[blockIndex], predicateBlock); for (auto const& element : newVariables) { smtSolvers[blockIndex]->add(storm::expressions::iff(element.first, this->getAbstractionInformation().getPredicateByIndex(element.second))); @@ -121,7 +136,8 @@ namespace storm { template storm::dd::Bdd ValidBlockAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, uint64_t blockIndex) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& variableIndexPair : relevantVariablesAndPredicates[blockIndex]) { + for (auto variableIndexPairIt = relevantVariablesAndPredicates[blockIndex].rbegin(), variableIndexPairIte = relevantVariablesAndPredicates[blockIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { diff --git a/src/storm/abstraction/ValidBlockAbstractor.h b/src/storm/abstraction/ValidBlockAbstractor.h index 33f7fb590..145638def 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.h +++ b/src/storm/abstraction/ValidBlockAbstractor.h @@ -44,7 +44,7 @@ namespace storm { /*! * Recomputed the valid blocks for the given predicate block. */ - void recomputeValidBlockForPredicateBlock(uint64_t blockIndex); + void recomputeValidBlocksForPredicateBlock(uint64_t blockIndex); /*! * Retrieves the abstraction information object. diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 39d95845b..26a3d2c69 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -344,7 +344,7 @@ namespace storm { // We now compute how many variables we need to encode the choices. We add one to the maximal number of // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))); + uint_fast64_t numberOfVariablesNeeded = maximalNumberOfChoices > 1 ? static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))) : 0; // Finally, build overall result. storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); From fa14b993e476e7e77a6640e5a9d27cb4735e9785 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Jun 2018 08:37:12 +0200 Subject: [PATCH 331/647] fixing valid block abstractor --- .../abstraction/ValidBlockAbstractor.cpp | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/storm/abstraction/ValidBlockAbstractor.cpp b/src/storm/abstraction/ValidBlockAbstractor.cpp index bf213964d..dbc84dd13 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.cpp +++ b/src/storm/abstraction/ValidBlockAbstractor.cpp @@ -77,26 +77,11 @@ namespace storm { if (relevantVariablesAndPredicates[blockIndex].size() < predicateBlock.size()) { recomputeValidBlocksForPredicateBlock(blockIndex); } + + newValidBlocks &= validBlocksForPredicateBlocks[blockIndex]; } - // Now compute the conjunction of all blocks. - std::vector> blocks = validBlocksForPredicateBlocks; - std::vector> newBlocks; - while (blocks.size() > 1) { - storm::utility::Stopwatch conj(true); - for (uint64_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex) { - if (blockIndex < localExpressionInformation.getNumberOfBlocks() - 1) { - newBlocks.emplace_back(blocks[blockIndex] && blocks[blockIndex + 1]); - } else { - newBlocks.emplace_back(blocks[blockIndex]); - } - } - conj.stop(); - - std::swap(blocks, newBlocks); - } - - validBlocks = blocks.front(); + validBlocks = newValidBlocks; } template From 41b494edd39f0293595b555795dc4e73f109e00d Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Jun 2018 08:57:11 +0200 Subject: [PATCH 332/647] fixing bug due to too few variables being reserved --- src/storm/abstraction/jani/EdgeAbstractor.cpp | 4 ++-- src/storm/abstraction/prism/CommandAbstractor.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index f60d99ece..e37676c64 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -344,8 +344,8 @@ namespace storm { // We now compute how many variables we need to encode the choices. We add one to the maximal number of // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))); - + uint_fast64_t numberOfVariablesNeeded = (maximalNumberOfChoices > 1) ? (static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0))))) : (blockCounter == 0 ? 1 : 0); + // Finally, build overall result. storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 26a3d2c69..bc65bc453 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -344,7 +344,7 @@ namespace storm { // We now compute how many variables we need to encode the choices. We add one to the maximal number of // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = maximalNumberOfChoices > 1 ? static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0)))) : 0; + uint_fast64_t numberOfVariablesNeeded = (maximalNumberOfChoices > 1) ? (static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0))))) : (blockCounter == 0 ? 1 : 0); // Finally, build overall result. storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); From c6e28a3bc7a767e271e6579b7f0132902b546b7f Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Jun 2018 20:29:18 +0200 Subject: [PATCH 333/647] adding setup timer --- src/storm/abstraction/MenuGameRefiner.cpp | 2 -- .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 4 ++++ src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 4ebfc24ce..3ccae8ab4 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1568,7 +1568,6 @@ namespace storm { for (auto const& predicate : predicateClass.second) { bool addPredicate = true; for (auto const& atom : cleanedAtomsOfClass) { - ++checkCounter; if (predicate.areSame(atom)) { addPredicate = false; break; @@ -1601,7 +1600,6 @@ namespace storm { for (auto const& newAtom : predicateClass.second) { bool addAtom = true; for (auto const& oldPredicate : oldPredicateClassIt->second) { - ++checkCounter; if (newAtom.areSame(oldPredicate)) { addAtom = false; break; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index f06c91853..6d74d0897 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -535,6 +535,7 @@ namespace storm { totalWatch.start(); // Set up initial predicates. + setupWatch.start(); std::vector initialPredicates = getInitialPredicates(constraintExpression, targetStateExpression); // Derive the optimization direction for player 1 (assuming menu-game abstraction). @@ -558,6 +559,7 @@ namespace storm { storm::dd::Bdd globalConstraintStates = abstractor->getStates(constraintExpression); storm::dd::Bdd globalTargetStates = abstractor->getStates(targetStateExpression); + setupWatch.stop(); // Enter the main-loop of abstraction refinement. boost::optional> previousSymbolicQualitativeResult = boost::none; @@ -1272,9 +1274,11 @@ namespace storm { uint64_t totalStrategyProcessingTimeMillis = totalStrategyProcessingWatch.getTimeInMilliseconds(); uint64_t totalSolutionTimeMillis = totalSolutionWatch.getTimeInMilliseconds(); uint64_t totalRefinementTimeMillis = totalRefinementWatch.getTimeInMilliseconds(); + uint64_t setupTime = setupWatch.getTimeInMilliseconds(); uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds(); std::cout << "Time breakdown:" << std::endl; + std::cout << " * setup: " << setupTime << "ms (" << 100 * static_cast(totalSetupTime)/totalTimeMillis << "%)" << std::endl; std::cout << " * abstraction: " << totalAbstractionTimeMillis << "ms (" << 100 * static_cast(totalAbstractionTimeMillis)/totalTimeMillis << "%)" << std::endl; if (this->solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Sparse) { std::cout << " * translation: " << totalTranslationTimeMillis << "ms (" << 100 * static_cast(totalTranslationTimeMillis)/totalTimeMillis << "%)" << std::endl; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index d76eee4f2..0c585f993 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -168,6 +168,7 @@ namespace storm { storm::utility::Stopwatch totalRefinementWatch; storm::utility::Stopwatch totalTranslationWatch; storm::utility::Stopwatch totalStrategyProcessingWatch; + storm::utility::Stopwatch setupWatch; storm::utility::Stopwatch totalWatch; }; } From 2c82f6554c15186071b63baf83a6fc13b3748054 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Jun 2018 22:05:14 +0200 Subject: [PATCH 334/647] fixing statistics --- .../modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 6d74d0897..81d154d70 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -1265,7 +1265,6 @@ namespace storm { std::cout << "Statistics:" << std::endl; std::cout << " * size of final game: " << game.getReachableStates().getNonZeroCount() << " player 1 states, " << game.getTransitionMatrix().getNonZeroCount() << " transitions" << std::endl; std::cout << " * peak size of game: " << peakPlayer1States << " player 1 states, " << peakTransitions << " transitions" << std::endl; - std::cout << " * transitions (final game): " << game.getTransitionMatrix().getNonZeroCount() << std::endl; std::cout << " * refinements: " << refinements << std::endl; std::cout << " * predicates: " << abstractionInformation.getNumberOfPredicates() << std::endl << std::endl; @@ -1278,7 +1277,7 @@ namespace storm { uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds(); std::cout << "Time breakdown:" << std::endl; - std::cout << " * setup: " << setupTime << "ms (" << 100 * static_cast(totalSetupTime)/totalTimeMillis << "%)" << std::endl; + std::cout << " * setup: " << setupTime << "ms (" << 100 * static_cast(setupTime)/totalTimeMillis << "%)" << std::endl; std::cout << " * abstraction: " << totalAbstractionTimeMillis << "ms (" << 100 * static_cast(totalAbstractionTimeMillis)/totalTimeMillis << "%)" << std::endl; if (this->solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Sparse) { std::cout << " * translation: " << totalTranslationTimeMillis << "ms (" << 100 * static_cast(totalTranslationTimeMillis)/totalTimeMillis << "%)" << std::endl; From 1318bea87ab29f9fc9ad8ea3762288374f8fb6da Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 1 Jun 2018 23:03:34 +0200 Subject: [PATCH 335/647] adding support for manually injecting groups of refinement predicates --- src/storm/abstraction/MenuGameRefiner.cpp | 37 ++++++++++++++++------- src/storm/abstraction/MenuGameRefiner.h | 6 ++-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 3ccae8ab4..f829ff440 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -99,10 +99,6 @@ namespace storm { } if (abstractionSettings.isInjectRefinementPredicatesSet()) { - std::string predicatesString = abstractionSettings.getInjectedRefinementPredicates(); - std::vector predicatesAsStrings; - boost::split(predicatesAsStrings, predicatesString, boost::is_any_of(";")); - auto const& expressionManager = abstractor.getAbstractionInformation().getExpressionManager(); storm::parser::ExpressionParser expressionParser(expressionManager); std::unordered_map variableMapping; @@ -110,11 +106,25 @@ namespace storm { variableMapping[variableTypePair.first.getName()] = variableTypePair.first; } expressionParser.setIdentifierMapping(variableMapping); - - for (auto const& predicateString : predicatesAsStrings) { - storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); - STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); - refinementPredicatesToInject.emplace_back(predicate); + + std::string predicatesString = abstractionSettings.getInjectedRefinementPredicates(); + std::vector predicateGroupsAsStrings; + boost::split(predicateGroupsAsStrings, predicatesString, boost::is_any_of(";")); + + for (auto const& predicateGroupString : predicateGroupsAsStrings) { + std::vector predicatesAsStrings; + boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); + + refinementPredicatesToInject.emplace_back(); + for (auto const& predicateString : predicatesAsStrings) { + storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); + STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); + refinementPredicatesToInject.back().emplace_back(predicate); + } + STORM_LOG_THROW(!refinementPredicatesToInject.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(refinementPredicatesToInject.back().begin(), refinementPredicatesToInject.back().end()); } // Finally reverse the list, because we take the predicates from the back. @@ -1639,8 +1649,13 @@ namespace storm { template void MenuGameRefiner::performRefinement(std::vector const& refinementCommands, bool allowInjection) const { if (!refinementPredicatesToInject.empty() && allowInjection) { - STORM_LOG_INFO("Refining with (injected) predicate " << refinementPredicatesToInject.back() << "."); - abstractor.get().refine(RefinementCommand({refinementPredicatesToInject.back()})); + STORM_LOG_INFO("Refining with (injected) predicates."); + + for (auto const& predicate : refinementPredicatesToInject.back()) { + STORM_LOG_INFO(predicate); + } + + abstractor.get().refine(RefinementCommand(refinementPredicatesToInject.back())); refinementPredicatesToInject.pop_back(); } else { for (auto const& command : refinementCommands) { diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index c906fa9cd..cb6d48fd4 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -198,9 +198,9 @@ namespace storm { /// A flag indicating whether all guards have been used to refine the abstraction. bool addedAllGuardsFlag; - /// A vector of refinement predicates that are injected (starting with the *last* one in this list). If - // empty, the predicates are derived as usual. - mutable std::vector refinementPredicatesToInject; + /// A vector of vectors of refinement predicates that are injected (starting with the *last* one in this + /// list). If empty, the predicates are derived as usual. + mutable std::vector> refinementPredicatesToInject; /// The heuristic to use for pivot block selection. storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic; From 6f320090eb4fbe0572c03495a94d02abd70680da Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 5 Jun 2018 11:36:23 +0200 Subject: [PATCH 336/647] fixing bug where illegal choices were copied over --- .../abstraction/GameBasedMdpModelChecker.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 81d154d70..0d30b5075 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -427,7 +427,7 @@ namespace storm { } // Otherwise, we need to solve a (sub)game. - STORM_LOG_TRACE("Solving " << maybeStates.getNumberOfSetBits()<< " maybe states."); + STORM_LOG_TRACE("[" << player1Direction << ", " << player2Direction << "]: Solving " << maybeStates.getNumberOfSetBits()<< " maybe states."); // Create the game by selecting all maybe player 2 states (non-prob0/1) of all maybe player 1 states. std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); @@ -485,7 +485,12 @@ namespace storm { } // Copy over the player 2 action (modulo making it local) as all rows for the state are taken. - player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices()[player2State]; + if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { + player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() + [player2State]; + } else { + player2Scheduler[previousPlayer2States] = 0; + } ++previousPlayer2StatesForState; ++previousPlayer2States; @@ -897,6 +902,8 @@ namespace storm { if (targetStates.get(state)) { dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); } else { + STORM_LOG_ASSERT(minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected min player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)), "Expected max player 2 choice in state " << state << " with player 2 choice " << maxStrategyPair.getPlayer1Strategy().getChoice(state) << "."); uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)); for (auto const& entry : transitionMatrix.getRow(player2Choice)) { dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); @@ -916,6 +923,8 @@ namespace storm { if (targetStates.get(state)) { dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); } else { + STORM_LOG_ASSERT(maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected max player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)), "Expected max player 2 choice in state " << state << " with player 2 choice " << maxStrategyPair.getPlayer1Strategy().getChoice(state) << "."); uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); for (auto const& entry : transitionMatrix.getRow(player2Choice)) { dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); From 09876f68081aeda8c55671be4b58aae23b7a0e97 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 6 Jun 2018 16:46:01 +0200 Subject: [PATCH 337/647] lots of debug output --- .../abstraction/GameBasedMdpModelChecker.cpp | 109 ++++++++++++++++-- src/storm/storage/SparseMatrix.h | 2 +- src/storm/utility/vector.h | 7 +- 3 files changed, 106 insertions(+), 12 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 0d30b5075..802ee6949 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -38,6 +38,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/utility/prism.h" #include "storm/utility/macros.h" @@ -475,24 +476,40 @@ namespace storm { uint64_t maybeStatePosition = 0; previousPlayer2States = 0; for (auto state : maybeStates) { + if (state == 25305 || state == 67442 || state == 67440) { + std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; + } uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); - uint64_t previousPlayer2StatesForState = 0; + uint64_t previousPlayer2MaybeStatesForState = 0; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player2MaybeStates.get(player2State)) { + if (state == 25305 || state == 67442 || state == 67440) { + std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << std::endl; + } + if (player2State == chosenPlayer2State) { - player1Scheduler[maybeStatePosition] = previousPlayer2StatesForState; + player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState; + if (state == 25305 || state == 67442 || state == 67440) { + std::cout << "player 1 scheduler chooses " << previousPlayer2MaybeStatesForState << " which globally is " << player2State << std::endl; + } } - // Copy over the player 2 action (modulo making it local) as all rows for the state are taken. + // Copy over the player 2 action (modulo making it local) as all rows for the player 2 state are taken. if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() [player2State]; + if (state == 25305 || state == 67442 || state == 67440) { + std::cout << "copied over choice " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; + } } else { player2Scheduler[previousPlayer2States] = 0; + if (state == 25305 || state == 67442 || state == 67440) { + std::cout << "did not copy (undefined) choice for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; + } } - ++previousPlayer2StatesForState; + ++previousPlayer2MaybeStatesForState; ++previousPlayer2States; } } @@ -502,8 +519,14 @@ namespace storm { } // Solve actual game and track schedulers. + if (player1Scheduler.size() > 4713) { + std::cout << "before: player1Scheduler[4713] = " << player1Scheduler[4713] << std::endl; + } gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler); - + if (player1Scheduler.size() > 67440) { + std::cout << "after: player1Scheduler[4713] = " << player1Scheduler[4713] << std::endl; + } + // Set values according to quantitative result (qualitative result has already been taken care of). storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); @@ -511,16 +534,16 @@ namespace storm { uint64_t previousPlayer1MaybeStates = 0; uint64_t previousPlayer2MaybeStates = 0; for (auto state : maybeStates) { - uint64_t previousPlayer2StatesForState = 0; + uint64_t previousPlayer2MaybeStatesForState = 0; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { - if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2StatesForState) { + if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2MaybeStatesForState) { strategyPair.getPlayer1Strategy().setChoice(state, player2State); } if (player2MaybeStates.get(player2State)) { strategyPair.getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]); - ++previousPlayer2StatesForState; + ++previousPlayer2MaybeStatesForState; ++previousPlayer2MaybeStates; } } @@ -895,6 +918,8 @@ namespace storm { } if (sanityCheck) { + storm::utility::ConstantsComparator sanityComparator(1e-6, true); + ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should ///////// still be the lower ones. storm::storage::SparseMatrixBuilder dtmcMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); @@ -913,9 +938,21 @@ namespace storm { auto dtmcMatrix = dtmcMatrixBuilder.build(); std::vector sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + ValueType maxDiff = storm::utility::zero(); + uint64_t maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]) < 1e-4, "Got weird min divergences!"); + ValueType const& diff = std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]); + if (diff > maxDiff) { + maxState = state; + maxDiff = diff; + } } + STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "]"); + if (!sanityComparator.isZero(maxDiff)) { + exit(-1); + } + ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should ///////// still be the upper ones. dtmcMatrixBuilder = storm::storage::SparseMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); @@ -926,16 +963,68 @@ namespace storm { STORM_LOG_ASSERT(maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected max player 1 choice in state " << state << "."); STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)), "Expected max player 2 choice in state " << state << " with player 2 choice " << maxStrategyPair.getPlayer1Strategy().getChoice(state) << "."); uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + if (state == 25305) { + std::cout << "entry " << entry.getColumn() << " -> " << entry.getValue() << std::endl; + std::cout << "values [" << quantitativeResult.getMin().getValues()[entry.getColumn()] << ", " << quantitativeResult.getMax().getValues()[entry.getColumn()] << "]" << std::endl; + } } } } dtmcMatrix = dtmcMatrixBuilder.build(); sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + maxDiff = storm::utility::zero(); + maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - STORM_LOG_ASSERT(std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]) < 1e-4, "Got weird max divergences!"); + ValueType const& diff = std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]); + if (diff > maxDiff) { + maxState = state; + maxDiff = diff; + } + + if (dtmcMatrix.getRowCount() > 25305 && !targetStates.get(state)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + if (state == 25305) { + std::cout << "entry " << entry.getColumn() << " -> " << entry.getValue() << std::endl; + std::cout << "sanity value " << sanityValues[entry.getColumn()] << std::endl; + } + } + } + } + STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMax().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "]"); + if (!sanityComparator.isZero(maxDiff)) { + // Perform DFS from max diff state in upper system. + std::vector stack; + stack.push_back(maxState); + storm::storage::BitVector reachable(dtmcMatrix.getRowCount()); + + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + std::cout << "exploring player 1 state " << currentState << std::endl; + uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + std::cout << "going to player 2 state " << player2State << std::endl; + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + std::cout << "which takes choice " << player2Choice << " which locally is " << (player2Choice - transitionMatrix.getRowGroupIndices()[player2State]) << std::endl; + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + std::cout << entry.getColumn() << " -> " << entry.getValue() << std::endl; + auto successor = entry.getColumn(); + if (!reachable.get(successor)) { + if (!targetStates.get(successor)) { + reachable.set(successor); + stack.push_back(successor); + } + } + } + } + + exit(-1); } } } diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index c6b51b981..9f9abd952 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -693,7 +693,7 @@ namespace storm { * * @param useGroups If set to true, the constraint for the rows is interpreted as selecting whole row groups. * If it is not set, the row constraint is interpreted over the actual rows. Note that empty row groups will - * be dropped altogether. That is, if no row of a row group is selected *or* the row group is alread empty, + * be dropped altogether. That is, if no row of a row group is selected *or* the row group is already empty, * the submatrix will not have this row group. * @param constraint A bit vector indicating which rows to keep. * @param columnConstraint A bit vector indicating which columns to keep. diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index 56494dc03..8b7301e72 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -725,6 +725,10 @@ namespace storm { } if (choices && f(*targetIt, oldSelectedChoiceValue)) { + uint64_t distance = std::distance(target.begin(), targetIt); + if (distance == 1693 || distance == 4715 || distance == 4713) { + std::cout << "improving value at " << distance << ": moving from " << *choiceIt << " to " << selectedChoice << " because " << *targetIt << " is better than " << oldSelectedChoiceValue << std::endl; + } *choiceIt = selectedChoice; } } else { @@ -792,7 +796,8 @@ namespace storm { */ template void reduceVectorMinOrMax(storm::solver::OptimizationDirection dir, std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - if(dir == storm::solver::OptimizationDirection::Minimize) { + std::cout << "[" << dir << "]: reducing vector " << std::endl; + if (dir == storm::solver::OptimizationDirection::Minimize) { reduceVectorMin(source, target, rowGrouping, choices); } else { reduceVectorMax(source, target, rowGrouping, choices); From a2c990ea58707995aed1d331825302b46ef49df0 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 6 Jun 2018 16:50:44 +0200 Subject: [PATCH 338/647] Travis: changed mail address for notifications --- .travis.yml | 2 +- travis/generate_travis.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d6e942eec..1074ba368 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ notifications: on_failure: always on_success: change recipients: - secure: "Q9CW/PtyWkZwExDrfFFb9n1STGYsRfI6awv1bZHcGwfrDvhpXoMCuF8CwviIfilm7fFJJEoKizTtdRpY0HrOnY/8KY111xrtcFYosxdndv7xbESodIxQOUoIEFCO0mCNHwWYisoi3dAA7H3Yn661EsxluwHjzX5vY0xSbw0n229hlsFz092HwGLSU33zHl7eXpQk+BOFmBTRGlOq9obtDZ17zbHz1oXFZntHK/JDUIYP0b0uq8NvE2jM6CIVdcuSwmIkOhZJoO2L3Py3rBbPci+L2PSK4Smv2UjCPF8KusnOaFIyDB3LcNM9Jqq5ssJMrK/KaO6BiuYrOZXYWZ7KEg3Y/naC8HjOH1dzty+P7oW46sb9F03pTsufqD4R7wcK+9wROTztO6aJPDG/IPH7EWgrBTxqlOkVRwi2eYuQouZpZUW6EMClKbMHMIxCH2S8aOk/r1w2cNwmPEcunnP0nl413x/ByHr4fTPFykPj8pQxIsllYjpdWBRQfDOauKWGzk6LcrFW0qpWP+/aJ2vYu/IoZQMG5lMHbp6Y1Lg09pYm7Q983v3b7D+JvXhOXMyGq91HyPahA2wwKoG1GA4uoZ2I95/IFYNiKkelDd3WTBoFLNF9YFoEJNdCywm1fO2WY4WkyEFBuQcgDA+YpFMJJMxjTbivYk9jvHk2gji//2w=" + secure: "BoMQTBWnkh4ZLIHEaKu0tAKDohhVmOQ2pz/fjc+ScKG8mtvXqtpx0TiyePOUV1MuYNZiAP7x4mwABcoid55SwZ4+LPjd8uxXNfOji9B9GW5YqbqRvAeh7Es7dx48MyLYPIezjoryHH9R3Q2zZ9gmxgtw5eirjURcLNTXpKAwq/oOsKvh+vhOx4Qierw98wEXjMV7ipBzE4cfkgUbbX7oxGh1nsAsCew+rRmNLijfmE9tctYdH5W0wE+zC9ik+12Xyk3FwsDIABirPHfeCcEl+b9I0h1a2vZSZIA+sCDkIGKTiv9pCnsthn5LJc9pMLX7B/Wf6xLGMzpSiw3P1ZzjXpOE026WuyhTMVXqZYvbl7cJoNZiLCfTYg3MQVq5NHkq0h0jInIH7QlZYd0hZPOGONwdy17O1QmnX2Weq6G+Ps9siLVKFba37+y5PfRYkiUatJvDf2f7Jdxye6TWrUmlxQkAvs65ioyr8doad7IT1/yaGr/rBpXeQqZp6zNoMYr/cCRAYX6nOrnSszgiIWEc8QMMx+G31v77Uvd++9VG4MG9gbdpexpfYRNzKAxDarSaYEOuaWm2Z6R87bpNcjA+tW0hnBHBzRx0NFYYqXyW0tpVO9+035A9CHrLDLz77r4jJttcRvrP2rTbTBiwuhpmiufRyk3BuWlgzU3yaSuQV3M=" # # Configurations diff --git a/travis/generate_travis.py b/travis/generate_travis.py index ade78cbca..ac4e89417 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -61,7 +61,7 @@ if __name__ == "__main__": s += " on_failure: always\n" s += " on_success: change\n" s += " recipients:\n" - s += ' secure: "Q9CW/PtyWkZwExDrfFFb9n1STGYsRfI6awv1bZHcGwfrDvhpXoMCuF8CwviIfilm7fFJJEoKizTtdRpY0HrOnY/8KY111xrtcFYosxdndv7xbESodIxQOUoIEFCO0mCNHwWYisoi3dAA7H3Yn661EsxluwHjzX5vY0xSbw0n229hlsFz092HwGLSU33zHl7eXpQk+BOFmBTRGlOq9obtDZ17zbHz1oXFZntHK/JDUIYP0b0uq8NvE2jM6CIVdcuSwmIkOhZJoO2L3Py3rBbPci+L2PSK4Smv2UjCPF8KusnOaFIyDB3LcNM9Jqq5ssJMrK/KaO6BiuYrOZXYWZ7KEg3Y/naC8HjOH1dzty+P7oW46sb9F03pTsufqD4R7wcK+9wROTztO6aJPDG/IPH7EWgrBTxqlOkVRwi2eYuQouZpZUW6EMClKbMHMIxCH2S8aOk/r1w2cNwmPEcunnP0nl413x/ByHr4fTPFykPj8pQxIsllYjpdWBRQfDOauKWGzk6LcrFW0qpWP+/aJ2vYu/IoZQMG5lMHbp6Y1Lg09pYm7Q983v3b7D+JvXhOXMyGq91HyPahA2wwKoG1GA4uoZ2I95/IFYNiKkelDd3WTBoFLNF9YFoEJNdCywm1fO2WY4WkyEFBuQcgDA+YpFMJJMxjTbivYk9jvHk2gji//2w="\n' + s += ' secure: "BoMQTBWnkh4ZLIHEaKu0tAKDohhVmOQ2pz/fjc+ScKG8mtvXqtpx0TiyePOUV1MuYNZiAP7x4mwABcoid55SwZ4+LPjd8uxXNfOji9B9GW5YqbqRvAeh7Es7dx48MyLYPIezjoryHH9R3Q2zZ9gmxgtw5eirjURcLNTXpKAwq/oOsKvh+vhOx4Qierw98wEXjMV7ipBzE4cfkgUbbX7oxGh1nsAsCew+rRmNLijfmE9tctYdH5W0wE+zC9ik+12Xyk3FwsDIABirPHfeCcEl+b9I0h1a2vZSZIA+sCDkIGKTiv9pCnsthn5LJc9pMLX7B/Wf6xLGMzpSiw3P1ZzjXpOE026WuyhTMVXqZYvbl7cJoNZiLCfTYg3MQVq5NHkq0h0jInIH7QlZYd0hZPOGONwdy17O1QmnX2Weq6G+Ps9siLVKFba37+y5PfRYkiUatJvDf2f7Jdxye6TWrUmlxQkAvs65ioyr8doad7IT1/yaGr/rBpXeQqZp6zNoMYr/cCRAYX6nOrnSszgiIWEc8QMMx+G31v77Uvd++9VG4MG9gbdpexpfYRNzKAxDarSaYEOuaWm2Z6R87bpNcjA+tW0hnBHBzRx0NFYYqXyW0tpVO9+035A9CHrLDLz77r4jJttcRvrP2rTbTBiwuhpmiufRyk3BuWlgzU3yaSuQV3M="\n' s += "\n" s += "#\n" s += "# Configurations\n" From 9f72f67d9f0f3c55d73e7e8ab6075543570e37a9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 6 Jun 2018 22:44:23 +0200 Subject: [PATCH 339/647] adding precision to less/greater in vector reduction, adding export to json --- .../abstraction/GameBasedMdpModelChecker.cpp | 194 +++++++++++++++++- src/storm/utility/constants.h | 40 ++++ src/storm/utility/vector.h | 12 +- 3 files changed, 235 insertions(+), 11 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 802ee6949..eb253e625 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -843,7 +843,181 @@ namespace storm { } template - void postProcessStrategies(storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { + class ExplicitGameExporter { + public: + void exportToJson(std::string const& filename, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + + // Export game as json. + std::ofstream outfile(filename); + + // Export nodes. + outfile << "{\n\t\"nodes\": [" << std::endl; + exportNodes(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); + outfile << "\n\t]," << std::endl; + + // Export edges. + outfile << "\t\"edges\": [" << std::endl; + exportEdges(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); + outfile << "\n\t]\n}" << std::endl; + } + + private: + void exportEdge(std::ofstream& out, uint64_t id, uint64_t source, uint64_t target, std::string const& name, bool& first) { + if (!first) { + out << "," << std::endl; + } else { + first = false; + } + out << "\t\t{" << std::endl; + out << "\t\t\t\"data\": {" << std::endl; + out << "\t\t\t\t\"id\": \"" << id << "\"," << std::endl; + out << "\t\t\t\t\"name\": \"" << name << "\"," << std::endl; + out << "\t\t\t\t\"source\": \"" << source << "\"," << std::endl; + out << "\t\t\t\t\"target\": \"" << target << "\"" << std::endl; + out << "\t\t\t}" << std::endl; + out << "\t\t}"; + } + + void exportEdges(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + std::vector stack; + for (auto state : initialStates) { + stack.push_back(state); + } + storm::storage::BitVector reachablePlayer1(player1Groups.size() - 1); + + bool first = true; + uint64_t edgeId = 0; + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + // Follow lower. + if (minStrategyPair) { + if (minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2State = minStrategyPair->getPlayer1Strategy().getChoice(currentState); + exportEdge(out, edgeId++, currentState, player2State, "lo", first); + + uint64_t playerPState = minStrategyPair->getPlayer2Strategy().getChoice(player2State); + exportEdge(out, edgeId++, player2State, playerPState, "lo", first); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + + exportEdge(out, edgeId++, playerPState, player1Successor, std::to_string(entry.getValue()), first); + + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + } + } + } + + // Follow upper. + if (maxStrategyPair) { + if (maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2State = maxStrategyPair->getPlayer1Strategy().getChoice(currentState); + exportEdge(out, edgeId++, currentState, player2State, "hi", first); + + uint64_t playerPState = maxStrategyPair->getPlayer2Strategy().getChoice(player2State); + exportEdge(out, edgeId++, player2State, playerPState, "hi", first); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + + exportEdge(out, edgeId++, playerPState, player1Successor, std::to_string(entry.getValue()), first); + + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + } + } + } + } + } + + void exportNode(std::ofstream& out, uint64_t state, ExplicitQuantitativeResultMinMax const* quantitativeResult, bool& first, bool target = false) { + if (!first) { + out << "," << std::endl; + } else { + first = false; + } + out << "\t\t{" << std::endl; + out << "\t\t\t\"data\": {" << std::endl; + out << "\t\t\t\t\"id\": \"" << state << "\"," << std::endl; + out << "\t\t\t\t\"name\": \"" << state; + if (quantitativeResult) { + out << " [" << quantitativeResult->getMin().getValues()[state] << ", " << quantitativeResult->getMax().getValues()[state] << "]"; + if (target) { + out << ", T"; + } + } + out << "\"" << std::endl; + out << "\t\t\t}," << std::endl; + out << "\t\t\t\"group\": \"nodes\"," << std::endl; + out << "\t\t\t\"classes\": \"node\"" << std::endl; + out << "\t\t}"; + } + + void exportNodes(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + + std::vector stack; + for (auto state : initialStates) { + stack.push_back(state); + } + storm::storage::BitVector reachablePlayer1(player1Groups.size() - 1); + + bool first = true; + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + exportNode(out, currentState, &quantitativeResult, first, targetStates.get(currentState)); + + // Follow lower. + if (minStrategyPair) { + if (minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2State = minStrategyPair->getPlayer1Strategy().getChoice(currentState); + exportNode(out, player2State, nullptr, first); + + uint64_t playerPState = minStrategyPair->getPlayer2Strategy().getChoice(player2State); + exportNode(out, playerPState, nullptr, first); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + } + } + } + + // Follow upper. + if (maxStrategyPair) { + if (maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2State = maxStrategyPair->getPlayer1Strategy().getChoice(currentState); + exportNode(out, player2State, nullptr, first); + + uint64_t playerPState = maxStrategyPair->getPlayer2Strategy().getChoice(player2State); + exportNode(out, playerPState, nullptr, first); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + } + } + } + } + } + }; + + template + void postProcessStrategies(uint64_t iteration, storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { if (!redirectPlayer1 && !redirectPlayer2) { return; @@ -948,7 +1122,7 @@ namespace storm { } } STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); - STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "]"); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); if (!sanityComparator.isZero(maxDiff)) { exit(-1); } @@ -996,8 +1170,16 @@ namespace storm { } } STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); - STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMax().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "]"); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMax().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); if (!sanityComparator.isZero(maxDiff)) { + + ExplicitGameExporter exporter; + storm::storage::BitVector newInitialStates(player1Groups.size() - 1); + newInitialStates.set(maxState); + exporter.exportToJson("game" + std::to_string(iteration) + "_min.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, static_cast(nullptr)); + exporter.exportToJson("game" + std::to_string(iteration) + "_max.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, static_cast(nullptr), &maxStrategyPair); + + // Perform DFS from max diff state in upper system. std::vector stack; stack.push_back(maxState); @@ -1006,7 +1188,7 @@ namespace storm { while (!stack.empty()) { uint64_t currentState = stack.back(); stack.pop_back(); - + std::cout << "exploring player 1 state " << currentState << std::endl; uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); std::cout << "going to player 2 state " << player2State << std::endl; @@ -1019,6 +1201,8 @@ namespace storm { if (!targetStates.get(successor)) { reachable.set(successor); stack.push_back(successor); + } else { + std::cout << "found target state " << std::endl; } } } @@ -1176,7 +1360,7 @@ namespace storm { // Post-process strategies for better refinements. storm::utility::Stopwatch strategyProcessingWatch(true); - postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + postProcessStrategies(this->iteration, player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); strategyProcessingWatch.stop(); totalStrategyProcessingWatch.add(strategyProcessingWatch); STORM_LOG_DEBUG("Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() << "ms."); diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index c74592575..069303c04 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -30,6 +30,46 @@ namespace storm { namespace utility { + namespace detail { + template + struct ElementLess { + typedef std::less type; + }; + + struct DoubleLess { + bool operator()(double a, double b) const { + return b - a > 1e-17; + } + }; + + template<> + struct ElementLess { + typedef DoubleLess type; + }; + + template + struct ElementGreater { + typedef std::greater type; + }; + + struct DoubleGreater { + bool operator()(double a, double b) const { + return a - b > 1e-17; + } + }; + + template<> + struct ElementGreater { + typedef DoubleGreater type; + }; + } + + template + using ElementLess = typename detail::ElementLess::type; + + template + using ElementGreater = typename detail::ElementGreater::type; + template ValueType one(); diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index 8b7301e72..fa1c22cf4 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -727,7 +727,7 @@ namespace storm { if (choices && f(*targetIt, oldSelectedChoiceValue)) { uint64_t distance = std::distance(target.begin(), targetIt); if (distance == 1693 || distance == 4715 || distance == 4713) { - std::cout << "improving value at " << distance << ": moving from " << *choiceIt << " to " << selectedChoice << " because " << *targetIt << " is better than " << oldSelectedChoiceValue << std::endl; + std::cout << std::setprecision(50) << "improving value at " << distance << ": moving from " << *choiceIt << " to " << selectedChoice << " because " << *targetIt << " is better than " << oldSelectedChoiceValue << std::endl; } *choiceIt = selectedChoice; } @@ -744,7 +744,7 @@ namespace storm { tbb::parallel_for(tbb::blocked_range(0, target.size()), TbbReduceVectorFunctor(source, target, rowGrouping, choices, Filter())); } #endif - + /*! * Reduces the given source vector by selecting the smallest element out of each row group. * @@ -755,13 +755,13 @@ namespace storm { */ template void reduceVectorMin(std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - reduceVector>(source, target, rowGrouping, choices); + reduceVector>(source, target, rowGrouping, choices); } #ifdef STORM_HAVE_INTELTBB template void reduceVectorMinParallel(std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - reduceVector>(source, target, rowGrouping, choices); + reduceVector>(source, target, rowGrouping, choices); } #endif @@ -775,13 +775,13 @@ namespace storm { */ template void reduceVectorMax(std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - reduceVector>(source, target, rowGrouping, choices); + reduceVector>(source, target, rowGrouping, choices); } #ifdef STORM_HAVE_INTELTBB template void reduceVectorMaxParallel(std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - reduceVector>(source, target, rowGrouping, choices); + reduceVector>(source, target, rowGrouping, choices); } #endif From 14724b529f7a42025692dbf95becdf0e69950f3e Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 7 Jun 2018 16:45:15 +0200 Subject: [PATCH 340/647] further debugging --- .../ExplicitQualitativeGameResult.cpp | 1 - .../ExplicitQuantitativeResult.cpp | 3 + .../ExplicitQuantitativeResultMinMax.cpp | 3 + src/storm/abstraction/MenuGame.cpp | 3 +- src/storm/abstraction/MenuGameAbstractor.cpp | 2 +- src/storm/abstraction/MenuGameRefiner.cpp | 8 +- src/storm/abstraction/StateSetAbstractor.cpp | 2 +- .../SymbolicQuantitativeGameResult.cpp | 1 + .../SymbolicQuantitativeGameResultMinMax.cpp | 2 +- .../abstraction/jani/AutomatonAbstractor.cpp | 2 +- src/storm/abstraction/jani/EdgeAbstractor.cpp | 2 +- .../jani/JaniMenuGameAbstractor.cpp | 2 +- .../abstraction/prism/CommandAbstractor.cpp | 2 +- .../abstraction/prism/ModuleAbstractor.cpp | 2 +- .../prism/PrismMenuGameAbstractor.cpp | 2 +- .../abstraction/GameBasedMdpModelChecker.cpp | 332 ++++++++++-------- .../abstraction/GameBasedMdpModelChecker.h | 14 +- src/storm/solver/GmmxxMultiplier.cpp | 37 +- src/storm/solver/GmmxxMultiplier.h | 4 + src/storm/solver/Multiplier.cpp | 2 +- src/storm/solver/SymbolicGameSolver.cpp | 6 +- src/storm/solver/SymbolicGameSolver.h | 4 +- src/storm/storage/SparseMatrix.cpp | 68 ++-- src/storm/storage/SparseMatrix.h | 7 + src/storm/utility/ConstantsComparator.cpp | 46 +++ src/storm/utility/ConstantsComparator.h | 25 ++ src/storm/utility/shortestPaths.cpp | 1 + 27 files changed, 375 insertions(+), 208 deletions(-) diff --git a/src/storm/abstraction/ExplicitQualitativeGameResult.cpp b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp index 8ff41f18a..1a903249d 100644 --- a/src/storm/abstraction/ExplicitQualitativeGameResult.cpp +++ b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp @@ -7,7 +7,6 @@ namespace storm { // Intentionally left empty. } - storm::storage::BitVector const& ExplicitQualitativeGameResult::getStates() const { return this->getPlayer1States(); } diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.cpp b/src/storm/abstraction/ExplicitQuantitativeResult.cpp index b15db88bb..fc6cc14b0 100644 --- a/src/storm/abstraction/ExplicitQuantitativeResult.cpp +++ b/src/storm/abstraction/ExplicitQuantitativeResult.cpp @@ -2,6 +2,8 @@ #include "storm/storage/BitVector.h" +#include "storm/adapters/RationalNumberAdapter.h" + #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -55,5 +57,6 @@ namespace storm { } template class ExplicitQuantitativeResult; + template class ExplicitQuantitativeResult; } } diff --git a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp index fe8799a9f..34a3ed22d 100644 --- a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp +++ b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp @@ -1,5 +1,7 @@ #include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" +#include "storm/adapters/RationalNumberAdapter.h" + namespace storm { namespace abstraction { @@ -57,5 +59,6 @@ namespace storm { } template class ExplicitQuantitativeResultMinMax; + template class ExplicitQuantitativeResultMinMax; } } diff --git a/src/storm/abstraction/MenuGame.cpp b/src/storm/abstraction/MenuGame.cpp index 6252697bc..8258ddb51 100644 --- a/src/storm/abstraction/MenuGame.cpp +++ b/src/storm/abstraction/MenuGame.cpp @@ -82,8 +82,9 @@ namespace storm { template class MenuGame; template class MenuGame; + #ifdef STORM_HAVE_CARL - template class MenuGame; + template class MenuGame; #endif } } diff --git a/src/storm/abstraction/MenuGameAbstractor.cpp b/src/storm/abstraction/MenuGameAbstractor.cpp index c999b9316..2094568a2 100644 --- a/src/storm/abstraction/MenuGameAbstractor.cpp +++ b/src/storm/abstraction/MenuGameAbstractor.cpp @@ -176,7 +176,7 @@ namespace storm { template class MenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class MenuGameAbstractor; + template class MenuGameAbstractor; #endif } } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index f829ff440..987aaa367 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -1119,7 +1119,12 @@ namespace storm { continue; } - ValueType alternateDistance = probabilityDistances ? currentDistance * entry.getValue() : currentDistance + storm::utility::one(); + ValueType alternateDistance; + if (probabilityDistances) { + alternateDistance = currentDistance * entry.getValue(); + } else { + alternateDistance = currentDistance + storm::utility::one(); + } if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { distances[player1Successor] = alternateDistance; if (generatePredecessors) { @@ -1682,6 +1687,7 @@ namespace storm { template class MenuGameRefiner; template class MenuGameRefiner; + template class MenuGameRefiner; #ifdef STORM_HAVE_CARL // Currently, this instantiation does not work. diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index 4e4a88ee1..21b03a476 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -159,7 +159,7 @@ namespace storm { template class StateSetAbstractor; template class StateSetAbstractor; #ifdef STORM_HAVE_CARL - template class StateSetAbstractor; + template class StateSetAbstractor; #endif } } diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp index 9c91b1b97..839ba732e 100644 --- a/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp +++ b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp @@ -55,6 +55,7 @@ namespace storm { template class SymbolicQuantitativeGameResult; template class SymbolicQuantitativeGameResult; + template class SymbolicQuantitativeGameResult; } } diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp index 08be6fad6..9a58c2597 100644 --- a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp +++ b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp @@ -7,6 +7,6 @@ namespace storm { SymbolicQuantitativeGameResultMinMax::SymbolicQuantitativeGameResultMinMax(SymbolicQuantitativeGameResult const& min, SymbolicQuantitativeGameResult const& max) : min(min), max(max) { // Intentionally left empty. } - + } } diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index 3063c5b1b..21481f00c 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -151,7 +151,7 @@ namespace storm { template class AutomatonAbstractor; template class AutomatonAbstractor; #ifdef STORM_HAVE_CARL - template class AutomatonAbstractor; + template class AutomatonAbstractor; #endif } } diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index e37676c64..950221dcd 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -727,7 +727,7 @@ namespace storm { template class EdgeAbstractor; template class EdgeAbstractor; #ifdef STORM_HAVE_CARL - template class EdgeAbstractor; + template class EdgeAbstractor; #endif } } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 886bcbdcc..d233e3f5f 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -285,7 +285,7 @@ namespace storm { template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class JaniMenuGameAbstractor; + template class JaniMenuGameAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index bc65bc453..d73526454 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -703,7 +703,7 @@ namespace storm { template class CommandAbstractor; template class CommandAbstractor; #ifdef STORM_HAVE_CARL - template class CommandAbstractor; + template class CommandAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index bafb43717..ab031eeab 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -125,7 +125,7 @@ namespace storm { template class ModuleAbstractor; template class ModuleAbstractor; #ifdef STORM_HAVE_CARL - template class ModuleAbstractor; + template class ModuleAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 60ab41e92..d25a51712 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -277,7 +277,7 @@ namespace storm { template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class PrismMenuGameAbstractor; + template class PrismMenuGameAbstractor; #endif } } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index eb253e625..d1078b8c8 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -97,14 +97,14 @@ namespace storm { } template - bool GameBasedMdpModelChecker::canHandle(CheckTask const& checkTask) const { + bool GameBasedMdpModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); storm::logic::FragmentSpecification fragment = storm::logic::reachability(); return formula.isInFragment(fragment) && checkTask.isOnlyInitialStatesRelevantSet(); } template - std::unique_ptr GameBasedMdpModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { + std::unique_ptr GameBasedMdpModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); std::map labelToExpressionMapping; if (preprocessedModel.isPrismProgram()) { @@ -121,11 +121,11 @@ namespace storm { storm::expressions::Expression constraintExpression = pathFormula.getLeftSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); storm::expressions::Expression targetStateExpression = pathFormula.getRightSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); - return performGameBasedAbstractionRefinement(env, checkTask.substituteFormula(pathFormula), constraintExpression, targetStateExpression); + return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula(pathFormula), constraintExpression, targetStateExpression); } template - std::unique_ptr GameBasedMdpModelChecker::computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) { + std::unique_ptr GameBasedMdpModelChecker::computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::EventuallyFormula const& pathFormula = checkTask.getFormula(); std::map labelToExpressionMapping; if (preprocessedModel.isPrismProgram()) { @@ -142,11 +142,11 @@ namespace storm { storm::expressions::Expression constraintExpression = preprocessedModel.getManager().boolean(true); storm::expressions::Expression targetStateExpression = pathFormula.getSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); - return performGameBasedAbstractionRefinement(env, checkTask.substituteFormula(pathFormula), constraintExpression, targetStateExpression); + return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula(pathFormula), constraintExpression, targetStateExpression); } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& prob0, storm::dd::Bdd const& prob1) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& prob0, storm::dd::Bdd const& prob1) { std::unique_ptr result; if (checkTask.isBoundSet()) { @@ -185,7 +185,7 @@ namespace storm { } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, SymbolicQualitativeGameResultMinMax const& qualitativeResult) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, SymbolicQualitativeGameResultMinMax const& qualitativeResult) { // Check whether we can already give the answer based on the current information. std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); if (result) { @@ -199,7 +199,7 @@ namespace storm { } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& prob0, storm::storage::BitVector const& prob1) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& prob0, storm::storage::BitVector const& prob1) { std::unique_ptr result; if (checkTask.isBoundSet()) { @@ -238,7 +238,7 @@ namespace storm { } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::storage::BitVector const& initialStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::storage::BitVector const& initialStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult) { // Check whether we can already give the answer based on the current information. std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); if (result) { @@ -252,7 +252,7 @@ namespace storm { } template - std::unique_ptr checkForResultAfterQuantitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection const& player2Direction, std::pair const& initialValueRange) { + std::unique_ptr checkForResultAfterQuantitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection const& player2Direction, std::pair const& initialValueRange) { std::unique_ptr result; // If the minimum value exceeds an upper threshold or the maximum value is below a lower threshold, we can @@ -476,7 +476,7 @@ namespace storm { uint64_t maybeStatePosition = 0; previousPlayer2States = 0; for (auto state : maybeStates) { - if (state == 25305 || state == 67442 || state == 67440) { + if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; } uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); @@ -484,13 +484,13 @@ namespace storm { uint64_t previousPlayer2MaybeStatesForState = 0; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player2MaybeStates.get(player2State)) { - if (state == 25305 || state == 67442 || state == 67440) { - std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << std::endl; + if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << " ranging from row " << submatrix.getRowGroupIndices()[previousPlayer2States] << " to " << submatrix.getRowGroupIndices()[previousPlayer2States + 1] << std::endl; } if (player2State == chosenPlayer2State) { player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState; - if (state == 25305 || state == 67442 || state == 67440) { + if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { std::cout << "player 1 scheduler chooses " << previousPlayer2MaybeStatesForState << " which globally is " << player2State << std::endl; } } @@ -499,12 +499,12 @@ namespace storm { if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() [player2State]; - if (state == 25305 || state == 67442 || state == 67440) { + if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { std::cout << "copied over choice " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; } } else { player2Scheduler[previousPlayer2States] = 0; - if (state == 25305 || state == 67442 || state == 67440) { + if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { std::cout << "did not copy (undefined) choice for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; } } @@ -516,16 +516,11 @@ namespace storm { ++maybeStatePosition; } + STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); } // Solve actual game and track schedulers. - if (player1Scheduler.size() > 4713) { - std::cout << "before: player1Scheduler[4713] = " << player1Scheduler[4713] << std::endl; - } gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler); - if (player1Scheduler.size() > 67440) { - std::cout << "after: player1Scheduler[4713] = " << player1Scheduler[4713] << std::endl; - } // Set values according to quantitative result (qualitative result has already been taken care of). storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); @@ -555,7 +550,7 @@ namespace storm { } template - std::unique_ptr GameBasedMdpModelChecker::performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { + std::unique_ptr GameBasedMdpModelChecker::performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException, "The game-based abstraction refinement model checker can only compute the result for the initial states."); // Optimization: do not compute both bounds if not necessary (e.g. if bound given and exceeded, etc.) @@ -652,7 +647,7 @@ namespace storm { } template - std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { + std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { STORM_LOG_TRACE("Using dd-based solving."); @@ -845,24 +840,49 @@ namespace storm { template class ExplicitGameExporter { public: + ExplicitGameExporter() : showNonStrategyAlternatives(false) { + // Intentionally left empty. + } + void exportToJson(std::string const& filename, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { // Export game as json. std::ofstream outfile(filename); - - // Export nodes. - outfile << "{\n\t\"nodes\": [" << std::endl; - exportNodes(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); - outfile << "\n\t]," << std::endl; - - // Export edges. - outfile << "\t\"edges\": [" << std::endl; - exportEdges(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); - outfile << "\n\t]\n}" << std::endl; + exportGame(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); + } + + void setShowNonStrategyAlternatives(bool value) { + showNonStrategyAlternatives = value; } private: - void exportEdge(std::ofstream& out, uint64_t id, uint64_t source, uint64_t target, std::string const& name, bool& first) { + + struct NodeData { + NodeData(uint64_t id, uint64_t player, bool initial, bool target) : id(id), player(player), initial(initial), target(target) { + // Intentionally left empty. + } + + uint64_t id; + uint64_t player; // 0 = probabilistic player, 1 = player 1, 2 = player 2 + bool initial; + bool target; + }; + + struct EdgeData { + EdgeData(uint64_t id, uint64_t source, uint64_t target, ValueType probability, uint64_t label, bool min, bool max) : id(id), source(source), target(target), probability(probability), label(label), min(min), max(max) { + // Intentionally left empty. + } + + uint64_t id; + uint64_t source; + uint64_t target; + ValueType probability; + uint64_t label; + bool min; + bool max; + }; + + void exportEdge(std::ofstream& out, EdgeData const& data, bool& first) { if (!first) { out << "," << std::endl; } else { @@ -870,74 +890,30 @@ namespace storm { } out << "\t\t{" << std::endl; out << "\t\t\t\"data\": {" << std::endl; - out << "\t\t\t\t\"id\": \"" << id << "\"," << std::endl; - out << "\t\t\t\t\"name\": \"" << name << "\"," << std::endl; - out << "\t\t\t\t\"source\": \"" << source << "\"," << std::endl; - out << "\t\t\t\t\"target\": \"" << target << "\"" << std::endl; - out << "\t\t\t}" << std::endl; - out << "\t\t}"; - } - - void exportEdges(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { - std::vector stack; - for (auto state : initialStates) { - stack.push_back(state); + out << "\t\t\t\t\"id\": \"" << data.id << "\"," << std::endl; + if (data.probability != storm::utility::zero()) { + out << "\t\t\t\t\"name\": \"" << data.probability << "\"," << std::endl; + } else { + out << "\t\t\t\t\"name\": \"" << data.label << "\"," << std::endl; } - storm::storage::BitVector reachablePlayer1(player1Groups.size() - 1); - - bool first = true; - uint64_t edgeId = 0; - while (!stack.empty()) { - uint64_t currentState = stack.back(); - stack.pop_back(); - - // Follow lower. - if (minStrategyPair) { - if (minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t player2State = minStrategyPair->getPlayer1Strategy().getChoice(currentState); - exportEdge(out, edgeId++, currentState, player2State, "lo", first); - - uint64_t playerPState = minStrategyPair->getPlayer2Strategy().getChoice(player2State); - exportEdge(out, edgeId++, player2State, playerPState, "lo", first); - - for (auto const& entry : transitionMatrix.getRow(playerPState)) { - auto player1Successor = entry.getColumn(); - - exportEdge(out, edgeId++, playerPState, player1Successor, std::to_string(entry.getValue()), first); - - if (!reachablePlayer1.get(player1Successor)) { - reachablePlayer1.set(player1Successor); - stack.push_back(player1Successor); - } - } - } - } - - // Follow upper. - if (maxStrategyPair) { - if (maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t player2State = maxStrategyPair->getPlayer1Strategy().getChoice(currentState); - exportEdge(out, edgeId++, currentState, player2State, "hi", first); - - uint64_t playerPState = maxStrategyPair->getPlayer2Strategy().getChoice(player2State); - exportEdge(out, edgeId++, player2State, playerPState, "hi", first); - - for (auto const& entry : transitionMatrix.getRow(playerPState)) { - auto player1Successor = entry.getColumn(); - - exportEdge(out, edgeId++, playerPState, player1Successor, std::to_string(entry.getValue()), first); - - if (!reachablePlayer1.get(player1Successor)) { - reachablePlayer1.set(player1Successor); - stack.push_back(player1Successor); - } - } - } - } + out << "\t\t\t\t\"source\": \"" << data.source << "\"," << std::endl; + out << "\t\t\t\t\"target\": \"" << data.target << "\"" << std::endl; + out << "\t\t\t}," << std::endl; + out << "\t\t\t\"classes\": \""; + if (data.min && data.max) { + out << "minMaxEdge"; + } else if (data.min) { + out << "minEdge"; + } else if (data.max) { + out << "maxEdge"; + } else { + out << "edge"; } + out << "\"" << std::endl; + out << "\t\t}"; } - void exportNode(std::ofstream& out, uint64_t state, ExplicitQuantitativeResultMinMax const* quantitativeResult, bool& first, bool target = false) { + void exportNode(std::ofstream& out, NodeData const& data, ExplicitQuantitativeResultMinMax const* quantitativeResult, bool& first) { if (!first) { out << "," << std::endl; } else { @@ -945,75 +921,122 @@ namespace storm { } out << "\t\t{" << std::endl; out << "\t\t\t\"data\": {" << std::endl; - out << "\t\t\t\t\"id\": \"" << state << "\"," << std::endl; - out << "\t\t\t\t\"name\": \"" << state; - if (quantitativeResult) { - out << " [" << quantitativeResult->getMin().getValues()[state] << ", " << quantitativeResult->getMax().getValues()[state] << "]"; - if (target) { - out << ", T"; - } + out << "\t\t\t\t\"id\": \"" << data.id << "\"," << std::endl; + out << "\t\t\t\t\"name\": \"" << data.id; + if (quantitativeResult && data.player == 1) { + out << " [" << quantitativeResult->getMin().getValues()[data.id] << ", " << quantitativeResult->getMax().getValues()[data.id] << "]"; } out << "\"" << std::endl; out << "\t\t\t}," << std::endl; out << "\t\t\t\"group\": \"nodes\"," << std::endl; - out << "\t\t\t\"classes\": \"node\"" << std::endl; + out << "\t\t\t\"classes\": \""; + if (data.player == 1) { + if (data.initial) { + out << "initialNode"; + } else if (data.target) { + out << "targetNode"; + } else { + out << "node"; + } + } else if (data.player == 2) { + out << "pl2node"; + } else if (data.player == 0) { + out << "plpnode"; + } + out << "\"" << std::endl; out << "\t\t}"; } - void exportNodes(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + void exportGame(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + // To export the game as JSON, we build some data structures through a traversal and then emit them. + std::vector nodes; + std::vector edges; + std::vector stack; for (auto state : initialStates) { stack.push_back(state); } storm::storage::BitVector reachablePlayer1(player1Groups.size() - 1); - - bool first = true; + + uint64_t edgeId = 0; while (!stack.empty()) { uint64_t currentState = stack.back(); stack.pop_back(); + + nodes.emplace_back(currentState, 1, initialStates.get(currentState), targetStates.get(currentState)); - exportNode(out, currentState, &quantitativeResult, first, targetStates.get(currentState)); - - // Follow lower. - if (minStrategyPair) { - if (minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t player2State = minStrategyPair->getPlayer1Strategy().getChoice(currentState); - exportNode(out, player2State, nullptr, first); - - uint64_t playerPState = minStrategyPair->getPlayer2Strategy().getChoice(player2State); - exportNode(out, playerPState, nullptr, first); - - for (auto const& entry : transitionMatrix.getRow(playerPState)) { - auto player1Successor = entry.getColumn(); - if (!reachablePlayer1.get(player1Successor)) { - reachablePlayer1.set(player1Successor); - stack.push_back(player1Successor); - } - } + for (uint64_t player2State = player1Groups[currentState]; player2State < player1Groups[currentState + 1]; ++player2State) { + bool emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true; + bool min = false; + bool max = false; + + if (minStrategyPair && minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) && minStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) { + emit = true; + min = true; } - } - - // Follow upper. - if (maxStrategyPair) { - if (maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState)) { - uint64_t player2State = maxStrategyPair->getPlayer1Strategy().getChoice(currentState); - exportNode(out, player2State, nullptr, first); - - uint64_t playerPState = maxStrategyPair->getPlayer2Strategy().getChoice(player2State); - exportNode(out, playerPState, nullptr, first); - - for (auto const& entry : transitionMatrix.getRow(playerPState)) { - auto player1Successor = entry.getColumn(); - if (!reachablePlayer1.get(player1Successor)) { - reachablePlayer1.set(player1Successor); - stack.push_back(player1Successor); + if (maxStrategyPair && maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) && maxStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) { + emit = true; + max = true; + } + + if (emit) { + nodes.emplace_back(player2State, 2, false, false); + edges.emplace_back(edgeId++, currentState, player2State, storm::utility::zero(), player2State - player1Groups[currentState], min, max); + + for (uint64_t playerPState = player2Groups[player2State]; playerPState < player2Groups[player2State + 1]; ++playerPState) { + emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true; + min = false; + max = false; + + if (minStrategyPair && minStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) && minStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) { + emit = true; + min = true; + } + if (maxStrategyPair && maxStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) && maxStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) { + emit = true; + max = true; + } + + if (emit) { + nodes.emplace_back(playerPState, 0, false, false); + edges.emplace_back(edgeId++, player2State, playerPState, storm::utility::zero(), playerPState - player2Groups[player2State], min, max); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + + edges.emplace_back(edgeId++, playerPState, player1Successor, entry.getValue(), 0, false, false); + } } } } } } + + // Finally, export the data structures we built. + + // Export nodes. + out << "{\n\t\"nodes\": [" << std::endl; + bool first = true; + for (auto const& node : nodes) { + exportNode(out, node, &quantitativeResult, first); + } + out << "\n\t]," << std::endl; + + // Export edges. + first = true; + out << "\t\"edges\": [" << std::endl; + for (auto const& edge : edges) { + exportEdge(out, edge, first); + } + out << "\n\t]\n}" << std::endl; } + + bool showNonStrategyAlternatives; }; template @@ -1091,8 +1114,12 @@ namespace storm { } } +// ExplicitGameExporter exporter; +// exporter.exportToJson("game" + std::to_string(iteration) + ".json", player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, &maxStrategyPair); +// exit(-1); + if (sanityCheck) { - storm::utility::ConstantsComparator sanityComparator(1e-6, true); + storm::utility::ConstantsComparator sanityComparator( 1e-6, true); ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should ///////// still be the lower ones. @@ -1115,7 +1142,7 @@ namespace storm { ValueType maxDiff = storm::utility::zero(); uint64_t maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - ValueType const& diff = std::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]); + ValueType const& diff = storm::utility::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]); if (diff > maxDiff) { maxState = state; maxDiff = diff; @@ -1153,7 +1180,7 @@ namespace storm { maxDiff = storm::utility::zero(); maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - ValueType const& diff = std::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]); + ValueType const& diff = storm::utility::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]); if (diff > maxDiff) { maxState = state; maxDiff = diff; @@ -1189,9 +1216,9 @@ namespace storm { uint64_t currentState = stack.back(); stack.pop_back(); - std::cout << "exploring player 1 state " << currentState << std::endl; + std::cout << "exploring player 1 state " << currentState << " with " << (player1Groups[currentState + 1] - player1Groups[currentState]) << " player 2 successors from" << player1Groups[currentState] << " to " << player1Groups[currentState + 1] << std::endl; uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); - std::cout << "going to player 2 state " << player2State << std::endl; + std::cout << "going to player 2 state " << player2State << " with " << (player2Groups[player2State + 1] - player2Groups[player2State]) << " player 2 choices from " << player2Groups[player2State] << " to " << player2Groups[player2State + 1] << std::endl; uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); std::cout << "which takes choice " << player2Choice << " which locally is " << (player2Choice - transitionMatrix.getRowGroupIndices()[player2State]) << std::endl; for (auto const& entry : transitionMatrix.getRow(player2Choice)) { @@ -1214,7 +1241,7 @@ namespace storm { } template - std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult) { + std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult) { STORM_LOG_TRACE("Using sparse solving."); // (0) Start by transforming the necessary symbolic elements to explicit ones. @@ -1413,7 +1440,7 @@ namespace storm { } template - storm::OptimizationDirection GameBasedMdpModelChecker::getPlayer1Direction(CheckTask const& checkTask) { + storm::OptimizationDirection GameBasedMdpModelChecker::getPlayer1Direction(CheckTask const& checkTask) { if (preprocessedModel.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { return storm::OptimizationDirection::Maximize; } else if (checkTask.isOptimizationDirectionSet()) { @@ -1594,5 +1621,8 @@ namespace storm { template class GameBasedMdpModelChecker>; template class GameBasedMdpModelChecker>; template class GameBasedMdpModelChecker>; + + template class GameBasedMdpModelChecker>; + template class GameBasedMdpModelChecker>; } } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 0c585f993..c8af37073 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -87,18 +87,18 @@ namespace storm { explicit GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory = std::make_shared()); /// Overridden methods from super class. - virtual bool canHandle(CheckTask const& checkTask) const override; - virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; - virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) override; + virtual bool canHandle(CheckTask const& checkTask) const override; + virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) override; private: /*! * Performs the core part of the abstraction-refinement loop. */ - std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); + std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); - std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); - std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult); + std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); + std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult); /*! * Retrieves the initial predicates for the abstraction. @@ -108,7 +108,7 @@ namespace storm { /*! * Derives the optimization direction of player 1. */ - storm::OptimizationDirection getPlayer1Direction(CheckTask const& checkTask); + storm::OptimizationDirection getPlayer1Direction(CheckTask const& checkTask); /*! * Performs a qualitative check on the the given game to compute the (player 1) states that have probability diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index f145317da..bfed0bf25 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -116,10 +116,20 @@ namespace storm { gmm::mult(gmmMatrix, x, result); } } + + template + void GmmxxMultiplier::multAddReduceHelper(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + if (dir == storm::OptimizationDirection::Minimize) { + multAddReduceHelper>(rowGroupIndices, x, b, result, choices); + } else { + multAddReduceHelper>(rowGroupIndices, x, b, result, choices); + } + } template - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - bool min = dir == OptimizationDirection::Minimize; + template + void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + Compare compare; typedef std::vector VectorType; typedef gmm::csr_matrix MatrixType; @@ -170,7 +180,7 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if (min ? newValue < currentValue : newValue > currentValue) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *row_group_it; @@ -180,7 +190,7 @@ namespace storm { // Finally write value to target vector. *target_it = currentValue; - if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + if (choices && compare(currentValue, oldSelectedChoiceValue)) { *choice_it = selectedChoice; } } @@ -188,7 +198,8 @@ namespace storm { } template<> - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type."); } @@ -207,10 +218,10 @@ namespace storm { } #ifdef STORM_HAVE_INTELTBB - template + template class TbbMultAddReduceFunctor { public: - TbbMultAddReduceFunctor(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { + TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { // Intentionally left empty. } @@ -265,7 +276,7 @@ namespace storm { ValueType newValue = b ? *bIt : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); - if (min ? newValue < currentValue : newValue > currentValue) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *groupIt; @@ -276,14 +287,14 @@ namespace storm { // Finally write value to target vector. *resultIt = currentValue; - if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + if (choices && compare(currentValue, oldSelectedChoiceValue)) { *choiceIt = selectedChoice; } } } private: - storm::solver::OptimizationDirection dir; + Compare compare; std::vector const& rowGroupIndices; gmm::csr_matrix const& matrix; std::vector const& x; @@ -296,7 +307,11 @@ namespace storm { template void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor(dir, rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + if (dir == storm::OptimizationDirection::Minimize) { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + } else { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + } #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices); diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index fdebd557d..da70e2a05 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -27,6 +27,7 @@ namespace storm { virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; virtual void clearCache() const override; + private: void initialize() const; @@ -37,6 +38,9 @@ namespace storm { void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + template + void multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + mutable gmm::csr_matrix gmmMatrix; }; diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp index 38d81fee4..3347ef2dc 100644 --- a/src/storm/solver/Multiplier.cpp +++ b/src/storm/solver/Multiplier.cpp @@ -73,7 +73,7 @@ namespace storm { STORM_LOG_INFO_COND(!changed, "Selecting '" + toString(type) + "' as the multiplier type to match the selected equation solver. If you want to override this, please explicitly specify a different multiplier type."); } - switch (env.solver().multiplier().getType()) { + switch (type) { case MultiplierType::Gmmxx: return std::make_unique>(matrix); case MultiplierType::Native: diff --git a/src/storm/solver/SymbolicGameSolver.cpp b/src/storm/solver/SymbolicGameSolver.cpp index 7ed466650..957a5de78 100644 --- a/src/storm/solver/SymbolicGameSolver.cpp +++ b/src/storm/solver/SymbolicGameSolver.cpp @@ -156,9 +156,11 @@ namespace storm { template class SymbolicGameSolver; template class SymbolicGameSolver; - + template class SymbolicGameSolver; + template class SymbolicGameSolverFactory; template class SymbolicGameSolverFactory; - + template class SymbolicGameSolverFactory; + } } diff --git a/src/storm/solver/SymbolicGameSolver.h b/src/storm/solver/SymbolicGameSolver.h index 69446f3d1..6ca502ef9 100644 --- a/src/storm/solver/SymbolicGameSolver.h +++ b/src/storm/solver/SymbolicGameSolver.h @@ -73,10 +73,10 @@ namespace storm { storm::dd::Bdd allRows; // An ADD that can be used to compensate for the illegal choices of player 1. - storm::dd::Add illegalPlayer1Mask; + storm::dd::Add illegalPlayer1Mask; // An ADD that can be used to compensate for the illegal choices of player 2. - storm::dd::Add illegalPlayer2Mask; + storm::dd::Add illegalPlayer2Mask; // The row variables. std::set rowMetaVariables; diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index e27fae045..24d9e55f7 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -1588,7 +1588,17 @@ namespace storm { template void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - bool min = dir == OptimizationDirection::Minimize; + if (dir == OptimizationDirection::Minimize) { + multiplyAndReduceForward>(rowGroupIndices, vector, summand, result, choices); + } else { + multiplyAndReduceForward>(rowGroupIndices, vector, summand, result, choices); + } + } + + template + template + void SparseMatrix::multiplyAndReduceForward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + Compare compare; auto elementIt = this->begin(); auto rowGroupIt = rowGroupIndices.begin(); auto rowIt = rowIndications.begin(); @@ -1600,7 +1610,7 @@ namespace storm { if (choices) { choiceIt = choices->begin(); } - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; @@ -1608,14 +1618,14 @@ namespace storm { uint64_t currentRow = 0; for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++choiceIt, ++rowGroupIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { currentValue = *summandIt; ++summandIt; } - + for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } @@ -1640,7 +1650,7 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if (min ? newValue < currentValue : newValue > currentValue) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *rowGroupIt; @@ -1650,16 +1660,16 @@ namespace storm { ++summandIt; } } - + // Finally write value to target vector. *resultIt = currentValue; - if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + if (choices && compare(currentValue, oldSelectedChoiceValue)) { *choiceIt = selectedChoice; } } } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const { @@ -1669,7 +1679,17 @@ namespace storm { template void SparseMatrix::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - bool min = dir == OptimizationDirection::Minimize; + if (dir == storm::OptimizationDirection::Minimize) { + multiplyAndReduceBackward>(rowGroupIndices, vector, summand, result, choices); + } else { + multiplyAndReduceBackward>(rowGroupIndices, vector, summand, result, choices); + } + } + + template + template + void SparseMatrix::multiplyAndReduceBackward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + Compare compare; auto elementIt = this->end() - 1; auto rowGroupIt = rowGroupIndices.end() - 2; auto rowIt = rowIndications.end() - 2; @@ -1681,22 +1701,22 @@ namespace storm { if (choices) { choiceIt = choices->end() - 1; } - + // Variables for correctly tracking choices (only update if new choice is strictly better). ValueType oldSelectedChoiceValue; uint64_t selectedChoice; - + uint64_t currentRow = this->getRowCount() - 1; for (auto resultIt = result.end() - 1, resultIte = result.begin() - 1; resultIt != resultIte; --resultIt, --choiceIt, --rowGroupIt) { ValueType currentValue = storm::utility::zero(); - + // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { if (summand) { currentValue = *summandIt; --summandIt; } - + for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } @@ -1719,17 +1739,17 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if (min ? newValue < currentValue : newValue > currentValue) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *rowGroupIt; } } } - + // Finally write value to target vector. *resultIt = currentValue; - if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + if (choices && compare(currentValue, oldSelectedChoiceValue)) { *choiceIt = selectedChoice; } } @@ -1744,14 +1764,14 @@ namespace storm { #endif #ifdef STORM_HAVE_INTELTBB - template + template class TbbMultAddReduceFunctor { public: typedef typename storm::storage::SparseMatrix::index_type index_type; typedef typename storm::storage::SparseMatrix::value_type value_type; typedef typename storm::storage::SparseMatrix::const_iterator const_iterator; - TbbMultAddReduceFunctor(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand), choices(choices) { + TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand), choices(choices) { // Intentionally left empty. } @@ -1813,7 +1833,7 @@ namespace storm { oldSelectedChoiceValue = newValue; } - if (min ? newValue < currentValue : newValue > currentValue) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { selectedChoice = currentRow - *groupIt; @@ -1823,7 +1843,7 @@ namespace storm { // Finally write value to target vector. *resultIt = currentValue; - if (choices && (min ? currentValue < oldSelectedChoiceValue : currentValue > oldSelectedChoiceValue)) { + if (choices && compare(currentValue, oldSelectedValue)) { *choiceIt = selectedChoice; } } @@ -1831,7 +1851,7 @@ namespace storm { } private: - OptimizationDirection dir; + Compare compare; std::vector const& rowGroupIndices; std::vector> const& columnsAndEntries; std::vector const& rowIndications; @@ -1843,7 +1863,11 @@ namespace storm { template void SparseMatrix::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor(dir, rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + if (dir == storm::OptimizationDirection::Minimize) { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + } else { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + } } #ifdef STORM_HAVE_CARL diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index 9f9abd952..f742a7c49 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -859,9 +859,16 @@ namespace storm { void multiplyAndReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const; void multiplyAndReduceForward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceForward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const; + void multiplyAndReduceBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceBackward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; #ifdef STORM_HAVE_INTELTBB void multiplyAndReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceParallel(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; #endif /*! diff --git a/src/storm/utility/ConstantsComparator.cpp b/src/storm/utility/ConstantsComparator.cpp index a4ed2e024..6d8318047 100644 --- a/src/storm/utility/ConstantsComparator.cpp +++ b/src/storm/utility/ConstantsComparator.cpp @@ -108,6 +108,52 @@ namespace storm { return value1 < value2 - precision; } + ConstantsComparator::ConstantsComparator() : precision(storm::utility::zero()), relative(false) { + // Intentionally left empty. + } + + ConstantsComparator::ConstantsComparator(storm::RationalNumber precision, bool relative) : precision(precision), relative(false) { + // Intentionally left empty. + } + + bool ConstantsComparator::isOne(storm::RationalNumber const& value) const { + if (storm::utility::isZero(precision)) { + return storm::utility::isOne(value); + } + return storm::utility::abs(value - one()) <= precision; + } + + bool ConstantsComparator::isZero(storm::RationalNumber const& value) const { + if (storm::utility::isZero(precision)) { + return storm::utility::isOne(value); + } + return storm::utility::abs(value) <= precision; + } + + bool ConstantsComparator::isEqual(storm::RationalNumber const& value1, storm::RationalNumber const& value2) const { + if (storm::utility::isZero(precision)) { + return value1 == value2; + } + + if (relative) { + return value1 == value2 || storm::utility::abs(value1 - value2)/storm::utility::abs(value1 + value2) <= precision; + } else { + return storm::utility::abs(value1 - value2) <= precision; + } + } + + bool ConstantsComparator::isConstant(storm::RationalNumber const& value) const { + return true; + } + + bool ConstantsComparator::isInfinity(storm::RationalNumber const& value) const { + return false; + } + + bool ConstantsComparator::isLess(storm::RationalNumber const& value1, storm::RationalNumber const& value2) const { + return value1 < value2 - precision; + } + // Explicit instantiations. template class ConstantsComparator; template class ConstantsComparator; diff --git a/src/storm/utility/ConstantsComparator.h b/src/storm/utility/ConstantsComparator.h index 9f32551f3..99f7cd625 100644 --- a/src/storm/utility/ConstantsComparator.h +++ b/src/storm/utility/ConstantsComparator.h @@ -77,6 +77,31 @@ namespace storm { // Whether to use relative comparison for equality. bool relative; }; + + // For rational numbers we specialize this class and consider the comparison modulo some predefined precision. + template<> + class ConstantsComparator { + public: + ConstantsComparator(); + + ConstantsComparator(storm::RationalNumber precision, bool relative); + + bool isOne(storm::RationalNumber const& value) const; + + bool isZero(storm::RationalNumber const& value) const; + + bool isEqual(storm::RationalNumber const& value1, storm::RationalNumber const& value2) const; + + bool isConstant(storm::RationalNumber const& value) const; + + bool isInfinity(storm::RationalNumber const& value) const; + + bool isLess(storm::RationalNumber const& value1, storm::RationalNumber const& value2) const; + + private: + storm::RationalNumber precision; + bool relative; + }; } } diff --git a/src/storm/utility/shortestPaths.cpp b/src/storm/utility/shortestPaths.cpp index 8432ce1a5..b18e309d4 100644 --- a/src/storm/utility/shortestPaths.cpp +++ b/src/storm/utility/shortestPaths.cpp @@ -377,6 +377,7 @@ namespace storm { template class ShortestPathsGenerator; + template class ShortestPathsGenerator; // only prints the info stored in the Path struct; // does not traverse the actual path (see printKShortestPath for that) From 135c38777f88c452b9856a7a31615885a374bfd3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 7 Jun 2018 22:53:41 +0200 Subject: [PATCH 341/647] game-based abstraction working with rational numbers --- .../abstraction/AbstractionInformation.cpp | 6 ++-- src/storm/api/verification.h | 4 +-- .../abstraction/GameBasedMdpModelChecker.cpp | 29 ++++++++++++++----- src/storm/utility/ConstantsComparator.cpp | 8 ++--- src/storm/utility/constants.h | 4 +-- src/storm/utility/graph.cpp | 10 ++++++- 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 7fd9a9d16..4b61ed4d8 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -491,7 +491,7 @@ namespace storm { template template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const { - std::map> result; + std::map> result; storm::dd::Add lowerChoiceAsAdd = choice.template toAdd(); for (auto const& successorValuePair : lowerChoiceAsAdd) { @@ -614,8 +614,10 @@ namespace storm { template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; - + template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; } } diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 5d07f9f51..2bec11dcf 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -38,7 +38,7 @@ namespace storm { } template - typename std::enable_if::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task) { + typename std::enable_if::value || std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task) { STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::NotSupportedException, "Can only treat DTMCs/MDPs using the abstraction refinement engine."); std::unique_ptr result; @@ -60,7 +60,7 @@ namespace storm { } template - typename std::enable_if::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&) { + typename std::enable_if::value && !std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type."); } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index d1078b8c8..c8b758516 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -713,13 +713,19 @@ namespace storm { quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); + totalSolutionWatch.add(quantitativeWatch); if (result) { - totalSolutionWatch.add(quantitativeWatch); return result; } - - totalSolutionWatch.add(quantitativeWatch); - STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + + ValueType minVal = quantitativeResult.min.getInitialStatesRange().first; + ValueType maxVal = quantitativeResult.max.getInitialStatesRange().second; + if (std::is_same::value) { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + } else { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + } + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); @@ -1142,7 +1148,7 @@ namespace storm { ValueType maxDiff = storm::utility::zero(); uint64_t maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - ValueType const& diff = storm::utility::abs(sanityValues[state] - quantitativeResult.getMin().getValues()[state]); + ValueType diff = storm::utility::abs(ValueType(sanityValues[state] - quantitativeResult.getMin().getValues()[state])); if (diff > maxDiff) { maxState = state; maxDiff = diff; @@ -1180,7 +1186,7 @@ namespace storm { maxDiff = storm::utility::zero(); maxState = 0; for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - ValueType const& diff = storm::utility::abs(sanityValues[state] - quantitativeResult.getMax().getValues()[state]); + ValueType diff = storm::utility::abs(ValueType(sanityValues[state] - quantitativeResult.getMax().getValues()[state])); if (diff > maxDiff) { maxState = state; maxDiff = diff; @@ -1373,11 +1379,18 @@ namespace storm { quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair)); quantitativeWatch.stop(); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); + totalSolutionWatch.add(quantitativeWatch); if (result) { - totalSolutionWatch.add(quantitativeWatch); return result; } - STORM_LOG_INFO("Obtained quantitative bounds [" << quantitativeResult.getMin().getRange(initialStates).first << ", " << quantitativeResult.getMax().getRange(initialStates).second << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + + ValueType minVal = quantitativeResult.getMin().getRange(initialStates).first; + ValueType maxVal = quantitativeResult.getMax().getRange(initialStates).second; + if (std::is_same::value) { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + } else { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + } // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.getMin().getRange(initialStates).first, quantitativeResult.getMax().getRange(initialStates).second, comparator); diff --git a/src/storm/utility/ConstantsComparator.cpp b/src/storm/utility/ConstantsComparator.cpp index 6d8318047..2b7aad2d9 100644 --- a/src/storm/utility/ConstantsComparator.cpp +++ b/src/storm/utility/ConstantsComparator.cpp @@ -112,7 +112,7 @@ namespace storm { // Intentionally left empty. } - ConstantsComparator::ConstantsComparator(storm::RationalNumber precision, bool relative) : precision(precision), relative(false) { + ConstantsComparator::ConstantsComparator(storm::RationalNumber precision, bool relative) : precision(precision), relative(relative) { // Intentionally left empty. } @@ -120,7 +120,7 @@ namespace storm { if (storm::utility::isZero(precision)) { return storm::utility::isOne(value); } - return storm::utility::abs(value - one()) <= precision; + return storm::utility::abs(storm::RationalNumber(value - one())) <= precision; } bool ConstantsComparator::isZero(storm::RationalNumber const& value) const { @@ -136,9 +136,9 @@ namespace storm { } if (relative) { - return value1 == value2 || storm::utility::abs(value1 - value2)/storm::utility::abs(value1 + value2) <= precision; + return value1 == value2 || storm::utility::abs(storm::RationalNumber(value1 - value2))/storm::utility::abs(storm::RationalNumber(value1 + value2)) <= precision; } else { - return storm::utility::abs(value1 - value2) <= precision; + return storm::utility::abs(storm::RationalNumber(value1 - value2)) <= precision; } } diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 069303c04..9d83a0a49 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -38,7 +38,7 @@ namespace storm { struct DoubleLess { bool operator()(double a, double b) const { - return b - a > 1e-17; + return b - a > 1e-18; } }; @@ -54,7 +54,7 @@ namespace storm { struct DoubleGreater { bool operator()(double a, double b) const { - return a - b > 1e-17; + return a - b > 1e-18; } }; diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 4844abb83..36b377051 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -1736,6 +1736,10 @@ namespace storm { template std::pair performProb01Min(storm::models::sparse::NondeterministicModel const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates); + template ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair); + + template ExplicitGameProb01Result performProb1(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::ExplicitGameStrategyPair* strategyPair, boost::optional const& player1Candidates); + template std::vector getTopologicalSort(storm::storage::SparseMatrix const& matrix); // End of instantiations for storm::RationalNumber. @@ -1869,7 +1873,7 @@ namespace storm { template std::pair, storm::dd::Bdd> performProb01Min(storm::models::symbolic::NondeterministicModel const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates); template SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); - + template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); // Instantiations for Sylvan (rational number). @@ -1908,6 +1912,10 @@ namespace storm { template std::pair, storm::dd::Bdd> performProb01Min(storm::models::symbolic::NondeterministicModel const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates); + template SymbolicGameProb01Result performProb0(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy); + + template SymbolicGameProb01Result performProb1(storm::models::symbolic::StochasticTwoPlayerGame const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, storm::OptimizationDirection const& player1Strategy, storm::OptimizationDirection const& player2Strategy, bool producePlayer1Strategy, bool producePlayer2Strategy, boost::optional> const& player1Candidates); + // Instantiations for Sylvan (rational function). template storm::dd::Bdd performProbGreater0(storm::models::symbolic::Model const& model, storm::dd::Bdd const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, boost::optional const& stepBound = boost::optional()); From 9b80c65d72e8b964fcd8ba888f5a87869f4ca9f2 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 8 Jun 2018 16:38:38 +0200 Subject: [PATCH 342/647] more and more debugging --- .../abstraction/GameBasedMdpModelChecker.cpp | 87 +++++++++++++++++-- src/storm/storage/SparseMatrix.cpp | 12 +++ src/storm/utility/constants.h | 4 +- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index c8b758516..89920bf59 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -476,7 +476,7 @@ namespace storm { uint64_t maybeStatePosition = 0; previousPlayer2States = 0; for (auto state : maybeStates) { - if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + if (state == 2324 || state == 50377 || state == 50209) { std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; } uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); @@ -484,13 +484,13 @@ namespace storm { uint64_t previousPlayer2MaybeStatesForState = 0; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player2MaybeStates.get(player2State)) { - if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + if (state == 2324 || state == 50377 || state == 50209) { std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << " ranging from row " << submatrix.getRowGroupIndices()[previousPlayer2States] << " to " << submatrix.getRowGroupIndices()[previousPlayer2States + 1] << std::endl; } if (player2State == chosenPlayer2State) { player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState; - if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + if (state == 2324 || state == 50377 || state == 50209) { std::cout << "player 1 scheduler chooses " << previousPlayer2MaybeStatesForState << " which globally is " << player2State << std::endl; } } @@ -499,12 +499,12 @@ namespace storm { if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() [player2State]; - if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + if (state == 2324 || state == 50377 || state == 50209) { std::cout << "copied over choice " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; } } else { player2Scheduler[previousPlayer2States] = 0; - if (state == 1976 || state == 46452 || state == 114590 || state == 84730 || state == 84575 || state == 84562 || state == 31895 || state == 84574 || state == 84561 || state == 32933 || state == 86740 || state == 86734 || state == 31789 || state == 86740 || state == 84360 || state == 84358) { + if (state == 2324 || state == 50377 || state == 50209) { std::cout << "did not copy (undefined) choice for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; } } @@ -517,6 +517,37 @@ namespace storm { ++maybeStatePosition; } STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); + } else { + // If the starting strategy pair was provided, we need to extract the choices of the maybe states here. + uint64_t maybeStatePosition = 0; + previousPlayer2States = 0; + for (auto state : maybeStates) { + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; + } + + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "player 1 scheduler chooses " << player1Scheduler[maybeStatePosition] << " which globally is " << (player1Groups[state] + player1Scheduler[maybeStatePosition]) << std::endl; + } + + uint64_t previousPlayer2MaybeStatesForState = 0; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player2MaybeStates.get(player2State)) { + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << " ranging from row " << submatrix.getRowGroupIndices()[previousPlayer2States] << " to " << submatrix.getRowGroupIndices()[previousPlayer2States + 1] << std::endl; + } + + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "player 2 scheduler chooses " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << (transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2States]) << ")" << std::endl; + } + ++previousPlayer2MaybeStatesForState; + ++previousPlayer2States; + } + } + + ++maybeStatePosition; + } + STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); } // Solve actual game and track schedulers. @@ -530,18 +561,27 @@ namespace storm { uint64_t previousPlayer2MaybeStates = 0; for (auto state : maybeStates) { uint64_t previousPlayer2MaybeStatesForState = 0; + bool madePlayer1Choice = false; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2MaybeStatesForState) { + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "player 1 choosing " << player2State << " in " << state << std::endl; + } strategyPair.getPlayer1Strategy().setChoice(state, player2State); + madePlayer1Choice = true; } if (player2MaybeStates.get(player2State)) { + if (state == 2324 || state == 50377 || state == 50209) { + std::cout << "player 2 choosing " << (transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]) << " in " << player2State << " for player 1 state " << state << std::endl; + } strategyPair.getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]); ++previousPlayer2MaybeStatesForState; ++previousPlayer2MaybeStates; } } + STORM_LOG_ASSERT(madePlayer1Choice, "Player 1 state " << state << " did not make a choice, scheduler: " << player1Scheduler[previousPlayer1MaybeStates] << "."); ++previousPlayer1MaybeStates; } @@ -1157,6 +1197,41 @@ namespace storm { STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); if (!sanityComparator.isZero(maxDiff)) { + ExplicitGameExporter exporter; + storm::storage::BitVector newInitialStates(player1Groups.size() - 1); + newInitialStates.set(maxState); + exporter.exportToJson("game" + std::to_string(iteration) + "_min.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, static_cast(nullptr)); + exporter.exportToJson("game" + std::to_string(iteration) + "_max.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, static_cast(nullptr), &maxStrategyPair); + + + // Perform DFS from max diff state in upper system. + std::vector stack; + stack.push_back(maxState); + storm::storage::BitVector reachable(dtmcMatrix.getRowCount()); + + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + std::cout << "exploring player 1 state " << currentState << " with " << (player1Groups[currentState + 1] - player1Groups[currentState]) << " player 2 successors from" << player1Groups[currentState] << " to " << player1Groups[currentState + 1] << std::endl; + uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(currentState); + std::cout << "going to player 2 state " << player2State << " with " << (player2Groups[player2State + 1] - player2Groups[player2State]) << " player 2 choices from " << player2Groups[player2State] << " to " << player2Groups[player2State + 1] << std::endl; + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + std::cout << "which takes choice " << player2Choice << " which locally is " << (player2Choice - transitionMatrix.getRowGroupIndices()[player2State]) << std::endl; + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + std::cout << entry.getColumn() << " -> " << entry.getValue() << std::endl; + auto successor = entry.getColumn(); + if (!reachable.get(successor)) { + if (!targetStates.get(successor)) { + reachable.set(successor); + stack.push_back(successor); + } else { + std::cout << "found target state " << std::endl; + } + } + } + } + exit(-1); } @@ -1493,7 +1568,7 @@ namespace storm { ExplicitQualitativeGameResultMinMax result; - ExplicitQualitativeGameResult problematicStates = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize); +// ExplicitQualitativeGameResult problematicStates = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize); result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 24d9e55f7..6e8c2333b 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -1630,6 +1630,11 @@ namespace storm { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } + if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { + std::cout << "got initial value " << currentValue << " for state " << std::distance(result.begin(), resultIt) << " in row " << currentRow << std::endl; + } + + if (choices) { selectedChoice = 0; if (*choiceIt == 0) { @@ -1645,6 +1650,10 @@ namespace storm { for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } + + if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { + std::cout << "got value " << currentValue << " for state " << std::distance(result.begin(), resultIt) << " in row " << currentRow << std::endl; + } if (choices && currentRow == *choiceIt + *rowGroupIt) { oldSelectedChoiceValue = newValue; @@ -1664,6 +1673,9 @@ namespace storm { // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { + if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { + std::cout << "changing choice in " << std::distance(result.begin(), resultIt) << " from " << *choiceIt << " to " << selectedChoice << " because " << currentValue << " is better than " << oldSelectedChoiceValue << std::endl; + } *choiceIt = selectedChoice; } } diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 9d83a0a49..069303c04 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -38,7 +38,7 @@ namespace storm { struct DoubleLess { bool operator()(double a, double b) const { - return b - a > 1e-18; + return b - a > 1e-17; } }; @@ -54,7 +54,7 @@ namespace storm { struct DoubleGreater { bool operator()(double a, double b) const { - return a - b > 1e-18; + return a - b > 1e-17; } }; From 30a95ef9d6dafe7577119bdd650aa6a720bd3fc2 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Fri, 8 Jun 2018 11:28:38 +0200 Subject: [PATCH 343/647] Simplify check whether argument of --prop is a file/property Before, the argument to `--prop` was only treated as a file if (a) it exits and (b) contains a dot. We remove the requirement for a dot and always treat the argument as a file if it exists. --- src/storm/api/properties.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index f6a2d00e3..5b5d53bcb 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -24,10 +24,9 @@ namespace storm { } std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter) { - // If the given property looks like a file (containing a dot and there exists a file with that name), - // we try to parse it as a file, otherwise we assume it's a property. + // If the given property is a file, we parse it as a file, otherwise we assume it's a property. std::vector properties; - if (inputString.find(".") != std::string::npos && std::ifstream(inputString).good()) { + if (std::ifstream(inputString).good()) { properties = formulaParser.parseFromFile(inputString); } else { properties = formulaParser.parseFromString(inputString); From 04a1bbedfcf72dbab46f65368b079a2cf622dcd1 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Fri, 8 Jun 2018 12:34:43 +0200 Subject: [PATCH 344/647] properties.cpp: Log filename of properties file in --verbose mode --- src/storm/api/properties.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index 5b5d53bcb..71fab4d79 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -27,6 +27,7 @@ namespace storm { // If the given property is a file, we parse it as a file, otherwise we assume it's a property. std::vector properties; if (std::ifstream(inputString).good()) { + STORM_LOG_INFO("Loading properties from file: " << inputString << std::endl); properties = formulaParser.parseFromFile(inputString); } else { properties = formulaParser.parseFromString(inputString); From 2948611f3f61afccf8cf402e32d430e5b1609f9b Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Fri, 8 Jun 2018 16:54:20 +0200 Subject: [PATCH 345/647] cli.cpp: Quote arguments in "Command line arguments" status line It's nice to be able to copy-paste the arguments from a log file to a shell, so we'd like to have proper quoting. We thus use single quotes if an argument contains non-safe characters in the log output. --- src/storm-cli-utilities/cli.cpp | 27 ++++++++++++++++++++++++--- src/storm-cli-utilities/cli.h | 7 +++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/storm-cli-utilities/cli.cpp b/src/storm-cli-utilities/cli.cpp index dfc3065b8..4d44454c8 100644 --- a/src/storm-cli-utilities/cli.cpp +++ b/src/storm-cli-utilities/cli.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "storm-cli-utilities/model-handling.h" @@ -63,7 +64,27 @@ namespace storm { storm::utility::cleanUp(); return 0; } - + + std::string shellQuoteSingleIfNecessary(const std::string& arg) { + // quote empty argument + if (arg.empty()) { + return "''"; + } + + if (arg.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./=") != std::string::npos) { + // contains potentially unsafe character, needs quoting + if (arg.find('\'') != std::string::npos) { + // contains ', we have to replace all ' with '\'' + std::string escaped(arg); + boost::replace_all(escaped, "'", "'\\''"); + return "'" + escaped + "'"; + } else { + return "'" + arg + "'"; + } + } + + return arg; + } void printHeader(std::string const& name, const int argc, const char** argv) { STORM_PRINT(name << " " << storm::utility::StormVersion::shortVersionString() << std::endl << std::endl); @@ -71,7 +92,7 @@ namespace storm { // "Compute" the command line argument string with which storm was invoked. std::stringstream commandStream; for (int i = 1; i < argc; ++i) { - commandStream << argv[i] << " "; + commandStream << " " << shellQuoteSingleIfNecessary(argv[i]); } std::string command = commandStream.str(); @@ -79,7 +100,7 @@ namespace storm { if (!command.empty()) { std::time_t result = std::time(nullptr); STORM_PRINT("Date: " << std::ctime(&result)); - STORM_PRINT("Command line arguments: " << commandStream.str() << std::endl); + STORM_PRINT("Command line arguments:" << commandStream.str() << std::endl); STORM_PRINT("Current working directory: " << storm::utility::cli::getCurrentWorkingDirectory() << std::endl << std::endl); } } diff --git a/src/storm-cli-utilities/cli.h b/src/storm-cli-utilities/cli.h index e8d8601e9..66c51bad6 100644 --- a/src/storm-cli-utilities/cli.h +++ b/src/storm-cli-utilities/cli.h @@ -11,6 +11,13 @@ namespace storm { */ int64_t process(const int argc, const char** argv); + /*! + * For a command-line argument, returns a quoted version + * with single quotes if it contains unsafe characters. + * Otherwise, just returns the unquoted argument. + */ + std::string shellQuoteSingleIfNecessary(const std::string& arg); + void printHeader(std::string const& name, const int argc, const char** argv); void printVersion(std::string const& name); From b6d67e7995ae69cf14bd4f320ba4effe06a6b3b8 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Fri, 8 Jun 2018 16:59:03 +0200 Subject: [PATCH 346/647] properties.cpp: Output warning if we filter away all properties --- src/storm/api/properties.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index 71fab4d79..163679013 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -78,6 +78,11 @@ namespace storm { std::set const& propertyNameSet = propertyFilter.get(); std::vector result; std::set reducedPropertyNames; + + if (propertyNameSet.empty()) { + STORM_LOG_WARN("Filtering all properties."); + } + for (auto const& property : properties) { if (propertyNameSet.find(property.getName()) != propertyNameSet.end()) { result.push_back(property); From 48f56081575a6c8a41255b49e3c33ffd140a626a Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 9 Jun 2018 21:59:06 +0200 Subject: [PATCH 347/647] making policy iteration available for game-based abstraction (prototypical for now) --- .../abstraction/GameBasedMdpModelChecker.cpp | 256 ++++-------------- src/storm/solver/StandardGameSolver.cpp | 86 +++++- src/storm/solver/StandardGameSolver.h | 4 +- src/storm/storage/SparseMatrix.cpp | 12 - src/storm/utility/constants.cpp | 12 + src/storm/utility/constants.h | 7 +- src/storm/utility/vector.h | 5 - 7 files changed, 147 insertions(+), 235 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 89920bf59..43e1e795c 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -476,37 +476,21 @@ namespace storm { uint64_t maybeStatePosition = 0; previousPlayer2States = 0; for (auto state : maybeStates) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; - } uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); uint64_t previousPlayer2MaybeStatesForState = 0; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player2MaybeStates.get(player2State)) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << " ranging from row " << submatrix.getRowGroupIndices()[previousPlayer2States] << " to " << submatrix.getRowGroupIndices()[previousPlayer2States + 1] << std::endl; - } - if (player2State == chosenPlayer2State) { player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState; - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 1 scheduler chooses " << previousPlayer2MaybeStatesForState << " which globally is " << player2State << std::endl; - } } // Copy over the player 2 action (modulo making it local) as all rows for the player 2 state are taken. if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() [player2State]; - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "copied over choice " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; - } } else { player2Scheduler[previousPlayer2States] = 0; - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "did not copy (undefined) choice for player 2 (global index " << startingStrategyPair->getPlayer2Strategy().getChoice(player2State) << ")" << std::endl; - } } ++previousPlayer2MaybeStatesForState; @@ -517,37 +501,6 @@ namespace storm { ++maybeStatePosition; } STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); - } else { - // If the starting strategy pair was provided, we need to extract the choices of the maybe states here. - uint64_t maybeStatePosition = 0; - previousPlayer2States = 0; - for (auto state : maybeStates) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "dealing with problematic state " << state << " whose local offset is " << maybeStatePosition << std::endl; - } - - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 1 scheduler chooses " << player1Scheduler[maybeStatePosition] << " which globally is " << (player1Groups[state] + player1Scheduler[maybeStatePosition]) << std::endl; - } - - uint64_t previousPlayer2MaybeStatesForState = 0; - for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { - if (player2MaybeStates.get(player2State)) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 2 state " << player2State << " is a player 2 maybe state with local index " << previousPlayer2States << " ranging from row " << submatrix.getRowGroupIndices()[previousPlayer2States] << " to " << submatrix.getRowGroupIndices()[previousPlayer2States + 1] << std::endl; - } - - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 2 scheduler chooses " << player2Scheduler[previousPlayer2States] << " for player 2 (global index " << (transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2States]) << ")" << std::endl; - } - ++previousPlayer2MaybeStatesForState; - ++previousPlayer2States; - } - } - - ++maybeStatePosition; - } - STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); } // Solve actual game and track schedulers. @@ -564,24 +517,18 @@ namespace storm { bool madePlayer1Choice = false; for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2MaybeStatesForState) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 1 choosing " << player2State << " in " << state << std::endl; - } strategyPair.getPlayer1Strategy().setChoice(state, player2State); madePlayer1Choice = true; } if (player2MaybeStates.get(player2State)) { - if (state == 2324 || state == 50377 || state == 50209) { - std::cout << "player 2 choosing " << (transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]) << " in " << player2State << " for player 1 state " << state << std::endl; - } strategyPair.getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]); ++previousPlayer2MaybeStatesForState; ++previousPlayer2MaybeStates; } } - STORM_LOG_ASSERT(madePlayer1Choice, "Player 1 state " << state << " did not make a choice, scheduler: " << player1Scheduler[previousPlayer1MaybeStates] << "."); + STORM_LOG_ASSERT(madePlayer1Choice, "[" << player1Direction << "]: player 1 state " << state << " did not make a choice, scheduler: " << player1Scheduler[previousPlayer1MaybeStates] << "."); ++previousPlayer1MaybeStates; } @@ -1088,82 +1035,76 @@ namespace storm { template void postProcessStrategies(uint64_t iteration, storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { - if (!redirectPlayer1 && !redirectPlayer2) { - return; - } - - for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { - STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); - STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); - - bool hasMinPlayer1Choice = false; - uint64_t lowerPlayer1Choice = 0; - ValueType lowerValueUnderMinChoicePlayer1 = storm::utility::zero(); - bool hasMaxPlayer1Choice = false; - uint64_t upperPlayer1Choice = 0; - ValueType lowerValueUnderMaxChoicePlayer1 = storm::utility::zero(); - - if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - hasMinPlayer1Choice = true; - lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); - - STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (lower player 1 choice " << lowerPlayer1Choice << ")."); - uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + if (redirectPlayer1 || redirectPlayer2) { + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); - ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - lowerValueUnderMinChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + bool hasMinPlayer1Choice = false; + uint64_t lowerPlayer1Choice = 0; + ValueType lowerValueUnderMinChoicePlayer1 = storm::utility::zero(); + bool hasMaxPlayer1Choice = false; + uint64_t upperPlayer1Choice = 0; + ValueType lowerValueUnderMaxChoicePlayer1 = storm::utility::zero(); - if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { - uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + hasMinPlayer1Choice = true; + lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); - if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (lower player 1 choice " << lowerPlayer1Choice << ")."); + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMinChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); - if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { - lowerValueUnderMinChoicePlayer1 = lowerValueUnderUpperChoicePlayer2; - minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { + lowerValueUnderMinChoicePlayer1 = lowerValueUnderUpperChoicePlayer2; + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } } } } - } - - if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { - upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); - if (upperPlayer1Choice != lowerPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { - hasMaxPlayer1Choice = true; - - uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); - ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); - lowerValueUnderMaxChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; - - STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); - uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); - - if (lowerPlayer2Choice != upperPlayer2Choice) { - ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + if (upperPlayer1Choice != lowerPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + hasMaxPlayer1Choice = true; + + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMaxChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); - if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { - minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { + minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); + } } } } - } - - if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { - if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { - if (lowerValueUnderMaxChoicePlayer1 <= lowerValueUnderMinChoicePlayer1) { - minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + + if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { + if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { + if (lowerValueUnderMaxChoicePlayer1 <= lowerValueUnderMinChoicePlayer1) { + minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + } } } } } -// ExplicitGameExporter exporter; -// exporter.exportToJson("game" + std::to_string(iteration) + ".json", player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, &maxStrategyPair); -// exit(-1); - if (sanityCheck) { storm::utility::ConstantsComparator sanityComparator( 1e-6, true); @@ -1196,44 +1137,6 @@ namespace storm { } STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); - if (!sanityComparator.isZero(maxDiff)) { - ExplicitGameExporter exporter; - storm::storage::BitVector newInitialStates(player1Groups.size() - 1); - newInitialStates.set(maxState); - exporter.exportToJson("game" + std::to_string(iteration) + "_min.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, static_cast(nullptr)); - exporter.exportToJson("game" + std::to_string(iteration) + "_max.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, static_cast(nullptr), &maxStrategyPair); - - - // Perform DFS from max diff state in upper system. - std::vector stack; - stack.push_back(maxState); - storm::storage::BitVector reachable(dtmcMatrix.getRowCount()); - - while (!stack.empty()) { - uint64_t currentState = stack.back(); - stack.pop_back(); - - std::cout << "exploring player 1 state " << currentState << " with " << (player1Groups[currentState + 1] - player1Groups[currentState]) << " player 2 successors from" << player1Groups[currentState] << " to " << player1Groups[currentState + 1] << std::endl; - uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(currentState); - std::cout << "going to player 2 state " << player2State << " with " << (player2Groups[player2State + 1] - player2Groups[player2State]) << " player 2 choices from " << player2Groups[player2State] << " to " << player2Groups[player2State + 1] << std::endl; - uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); - std::cout << "which takes choice " << player2Choice << " which locally is " << (player2Choice - transitionMatrix.getRowGroupIndices()[player2State]) << std::endl; - for (auto const& entry : transitionMatrix.getRow(player2Choice)) { - std::cout << entry.getColumn() << " -> " << entry.getValue() << std::endl; - auto successor = entry.getColumn(); - if (!reachable.get(successor)) { - if (!targetStates.get(successor)) { - reachable.set(successor); - stack.push_back(successor); - } else { - std::cout << "found target state " << std::endl; - } - } - } - } - - exit(-1); - } ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should ///////// still be the upper ones. @@ -1248,10 +1151,6 @@ namespace storm { for (auto const& entry : transitionMatrix.getRow(player2Choice)) { dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); - if (state == 25305) { - std::cout << "entry " << entry.getColumn() << " -> " << entry.getValue() << std::endl; - std::cout << "values [" << quantitativeResult.getMin().getValues()[entry.getColumn()] << ", " << quantitativeResult.getMax().getValues()[entry.getColumn()] << "]" << std::endl; - } } } } @@ -1266,58 +1165,9 @@ namespace storm { maxState = state; maxDiff = diff; } - - if (dtmcMatrix.getRowCount() > 25305 && !targetStates.get(state)) { - uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); - for (auto const& entry : transitionMatrix.getRow(player2Choice)) { - if (state == 25305) { - std::cout << "entry " << entry.getColumn() << " -> " << entry.getValue() << std::endl; - std::cout << "sanity value " << sanityValues[entry.getColumn()] << std::endl; - } - } - } } STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMax().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); - if (!sanityComparator.isZero(maxDiff)) { - - ExplicitGameExporter exporter; - storm::storage::BitVector newInitialStates(player1Groups.size() - 1); - newInitialStates.set(maxState); - exporter.exportToJson("game" + std::to_string(iteration) + "_min.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, &minStrategyPair, static_cast(nullptr)); - exporter.exportToJson("game" + std::to_string(iteration) + "_max.json", player1Groups, player2Groups, transitionMatrix, newInitialStates, constraintStates, targetStates, quantitativeResult, static_cast(nullptr), &maxStrategyPair); - - - // Perform DFS from max diff state in upper system. - std::vector stack; - stack.push_back(maxState); - storm::storage::BitVector reachable(dtmcMatrix.getRowCount()); - - while (!stack.empty()) { - uint64_t currentState = stack.back(); - stack.pop_back(); - - std::cout << "exploring player 1 state " << currentState << " with " << (player1Groups[currentState + 1] - player1Groups[currentState]) << " player 2 successors from" << player1Groups[currentState] << " to " << player1Groups[currentState + 1] << std::endl; - uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); - std::cout << "going to player 2 state " << player2State << " with " << (player2Groups[player2State + 1] - player2Groups[player2State]) << " player 2 choices from " << player2Groups[player2State] << " to " << player2Groups[player2State + 1] << std::endl; - uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); - std::cout << "which takes choice " << player2Choice << " which locally is " << (player2Choice - transitionMatrix.getRowGroupIndices()[player2State]) << std::endl; - for (auto const& entry : transitionMatrix.getRow(player2Choice)) { - std::cout << entry.getColumn() << " -> " << entry.getValue() << std::endl; - auto successor = entry.getColumn(); - if (!reachable.get(successor)) { - if (!targetStates.get(successor)) { - reachable.set(successor); - stack.push_back(successor); - } else { - std::cout << "found target state " << std::endl; - } - } - } - } - - exit(-1); - } } } diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index c57ff38b8..8192ba25e 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -7,11 +7,13 @@ #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/utility/graph.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/NotImplementedException.h" + namespace storm { namespace solver { @@ -87,7 +89,7 @@ namespace storm { localPlayer2Choices = std::make_unique>(); player2Choices = localPlayer2Choices.get(); } - + if (this->hasSchedulerHints()) { *player1Choices = this->player1ChoicesHint.get(); } else if (this->player1RepresentedByMatrix()) { @@ -95,7 +97,6 @@ namespace storm { *player1Choices = std::vector(this->getPlayer1Matrix().getRowGroupCount(), 0); } else { // Player 1 represented by grouping of player 2 states. - *player1Choices = this->getPlayer1Grouping(); player1Choices->resize(player1Choices->size() - 1); } if (this->hasSchedulerHints()) { @@ -103,12 +104,12 @@ namespace storm { } else if (!(providedPlayer1Choices && providedPlayer2Choices)) { player2Choices->resize(this->player2Matrix.getRowGroupCount()); } - + if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(this->player2Matrix.getRowGroupCount()); } if (!auxiliaryP1RowGroupVector) { - auxiliaryP1RowGroupVector = std::make_unique>(this->player1Matrix->getRowGroupCount()); + auxiliaryP1RowGroupVector = std::make_unique>(this->player1RepresentedByMatrix() ? this->player1Matrix->getRowGroupCount() : this->player1Grouping->size() - 1); } std::vector& subB = *auxiliaryP1RowGroupVector; @@ -138,9 +139,29 @@ namespace storm { // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); + + storm::storage::BitVector targetStates; + storm::storage::BitVector zeroStates; + if (!this->hasUniqueSolution()) { + // If there is no unique solution, we need to compute the states with probability 0 and set their values explicitly. + targetStates = storm::utility::vector::filterGreaterZero(subB); + zeroStates = ~storm::utility::graph::performProbGreater0(submatrix.transpose(), storm::storage::BitVector(targetStates.size(), true), targetStates); + } if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { submatrix.convertToEquationSystem(); } + if (!this->hasUniqueSolution()) { + for (auto state : zeroStates) { + for (auto& element : submatrix.getRow(state)) { + if (element.getColumn() == state) { + element.setValue(storm::utility::one()); + } else { + element.setValue(storm::utility::zero()); + } + } + subB[state] = storm::utility::zero(); + } + } auto submatrixSolver = linearEquationSolverFactory->create(environmentOfSolver, std::move(submatrix)); if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); @@ -154,10 +175,8 @@ namespace storm { Status status = Status::InProgress; uint64_t iterations = 0; do { - // Solve the equation system for the 'DTMC'. - // FIXME: we need to remove the 0- and 1- states to make the solution unique. submatrixSolver->solveEquations(environmentOfSolver, x, subB); - + bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); // If the scheduler did not improve, we are done. @@ -166,7 +185,27 @@ namespace storm { } else { // Update the solver. getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); - submatrix.convertToEquationSystem(); + + if (!this->hasUniqueSolution()) { + // If there is no unique solution, we need to compute the states with probability 0 and set their values explicitly. + targetStates = storm::utility::vector::filterGreaterZero(subB); + zeroStates = ~storm::utility::graph::performProbGreater0(submatrix.transpose(), storm::storage::BitVector(targetStates.size(), true), targetStates); + } + if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { + submatrix.convertToEquationSystem(); + } + if (!this->hasUniqueSolution()) { + for (auto state : zeroStates) { + for (auto& element : submatrix.getRow(state)) { + if (element.getColumn() == state) { + element.setValue(storm::utility::one()); + } else { + element.setValue(storm::utility::zero()); + } + } + subB[state] = storm::utility::zero(); + } + } submatrixSolver->setMatrix(std::move(submatrix)); } @@ -360,6 +399,29 @@ namespace storm { template bool StandardGameSolver::extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { + if (player1Dir == storm::OptimizationDirection::Minimize) { + if (player2Dir == storm::OptimizationDirection::Minimize) { + return extractChoices, storm::utility::ElementLess>(x, b, player2ChoiceValues, player1Choices, player2Choices); + } else { + return extractChoices, storm::utility::ElementGreater>(x, b, player2ChoiceValues, player1Choices, player2Choices); + } + } else { + if (player2Dir == storm::OptimizationDirection::Minimize) { + return extractChoices, storm::utility::ElementLess>(x, b, player2ChoiceValues, player1Choices, player2Choices); + } else { + return extractChoices, storm::utility::ElementGreater>(x, b, player2ChoiceValues, player1Choices, player2Choices); + } + } + + return false; + } + + template + template + bool StandardGameSolver::extractChoices(std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { + + ComparePlayer1 comparePlayer1; + ComparePlayer2 comparePlayer2; // get the choices of player 2 and the corresponding values. bool schedulerImproved = false; @@ -387,7 +449,7 @@ namespace storm { } choiceValue += b[firstRowInGroup + p2Choice]; - if (valueImproved(player2Dir, *currentValueIt, choiceValue)) { + if (comparePlayer2(choiceValue, *currentValueIt)) { schedulerImproved = true; player2Choices[p2Group] = p2Choice; *currentValueIt = std::move(choiceValue); @@ -409,7 +471,7 @@ namespace storm { continue; } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; - if (valueImproved(player1Dir, currentValue, choiceValue)) { + if (comparePlayer1(choiceValue, currentValue)) { schedulerImproved = true; player1Choices[p1Group] = p1Choice; currentValue = choiceValue; @@ -429,7 +491,7 @@ namespace storm { } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + player2State]; - if (valueImproved(player1Dir, currentValue, choiceValue)) { + if (comparePlayer1(choiceValue, currentValue)) { schedulerImproved = true; player1Choices[player1State] = player2State; currentValue = choiceValue; @@ -461,7 +523,7 @@ namespace storm { // Player 1 is represented by the grouping of player 2 states (vector). selectedRows.reserve(this->player2Matrix.getRowGroupCount()); for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { - uint64_t player2State = player1Choices[player1State]; + uint64_t player2State = this->getPlayer1Grouping()[player1State] + player1Choices[player1State]; selectedRows.emplace_back(player2Matrix.getRowGroupIndices()[player2State] + player2Choices[player2State]); } } diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 1af23601f..8f950838b 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -39,7 +39,9 @@ namespace storm { // Extracts the choices of the different players for the given solution x. // Returns true iff the newly extracted choices yield "better" values then the given choices for one of the players. bool extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; - + template + bool extractChoices(std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; + bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; bool player1RepresentedByMatrix() const; diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 6e8c2333b..a2b23eac9 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -1630,11 +1630,6 @@ namespace storm { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { - std::cout << "got initial value " << currentValue << " for state " << std::distance(result.begin(), resultIt) << " in row " << currentRow << std::endl; - } - - if (choices) { selectedChoice = 0; if (*choiceIt == 0) { @@ -1651,10 +1646,6 @@ namespace storm { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { - std::cout << "got value " << currentValue << " for state " << std::distance(result.begin(), resultIt) << " in row " << currentRow << std::endl; - } - if (choices && currentRow == *choiceIt + *rowGroupIt) { oldSelectedChoiceValue = newValue; } @@ -1673,9 +1664,6 @@ namespace storm { // Finally write value to target vector. *resultIt = currentValue; if (choices && compare(currentValue, oldSelectedChoiceValue)) { - if (std::distance(result.begin(), resultIt) == 2240 || std::distance(result.begin(), resultIt) == 2241 || std::distance(result.begin(), resultIt) == 8262 || std::distance(result.begin(), resultIt) == 8263 || std::distance(result.begin(), resultIt) == 8266 || std::distance(result.begin(), resultIt) == 8267) { - std::cout << "changing choice in " << std::distance(result.begin(), resultIt) << " from " << *choiceIt << " to " << selectedChoice << " because " << currentValue << " is better than " << oldSelectedChoiceValue << std::endl; - } *choiceIt = selectedChoice; } } diff --git a/src/storm/utility/constants.cpp b/src/storm/utility/constants.cpp index 6c0d1c814..d5c48a89b 100644 --- a/src/storm/utility/constants.cpp +++ b/src/storm/utility/constants.cpp @@ -45,6 +45,16 @@ namespace storm { return a == zero(); } + template + bool isNan(ValueType const& value) { + return false; + } + + template<> + bool isNan(double const& value) { + return isnan(value); + } + bool isAlmostZero(double const& a) { return a < 1e-12 && a > -1e-12; } @@ -950,6 +960,7 @@ namespace storm { template bool isZero(NumberTraits::IntegerType const& value); template bool isConstant(storm::ClnRationalNumber const& value); template bool isInfinity(storm::ClnRationalNumber const& value); + template bool isNan(storm::ClnRationalNumber const& value); template storm::NumberTraits::IntegerType convertNumber(storm::NumberTraits::IntegerType const& number); template storm::ClnRationalNumber convertNumber(storm::ClnRationalNumber const& number); template storm::ClnRationalNumber simplify(storm::ClnRationalNumber value); @@ -974,6 +985,7 @@ namespace storm { template bool isZero(NumberTraits::IntegerType const& value); template bool isConstant(storm::GmpRationalNumber const& value); template bool isInfinity(storm::GmpRationalNumber const& value); + template bool isNan(storm::GmpRationalNumber const& value); template storm::NumberTraits::IntegerType convertNumber(storm::NumberTraits::IntegerType const& number); template storm::GmpRationalNumber convertNumber(storm::GmpRationalNumber const& number); template storm::GmpRationalNumber simplify(storm::GmpRationalNumber value); diff --git a/src/storm/utility/constants.h b/src/storm/utility/constants.h index 069303c04..80e1ef336 100644 --- a/src/storm/utility/constants.h +++ b/src/storm/utility/constants.h @@ -38,7 +38,7 @@ namespace storm { struct DoubleLess { bool operator()(double a, double b) const { - return b - a > 1e-17; + return (a == 0.0 && b > 0.0) || (b - a > 1e-17); } }; @@ -54,7 +54,7 @@ namespace storm { struct DoubleGreater { bool operator()(double a, double b) const { - return a - b > 1e-17; + return (b == 0.0 && a > 0.0) || (a - b > 1e-17); } }; @@ -84,6 +84,9 @@ namespace storm { template bool isZero(ValueType const& a); + + template + bool isNan(ValueType const& a); bool isAlmostZero(double const& a); diff --git a/src/storm/utility/vector.h b/src/storm/utility/vector.h index fa1c22cf4..6d3c1d281 100644 --- a/src/storm/utility/vector.h +++ b/src/storm/utility/vector.h @@ -725,10 +725,6 @@ namespace storm { } if (choices && f(*targetIt, oldSelectedChoiceValue)) { - uint64_t distance = std::distance(target.begin(), targetIt); - if (distance == 1693 || distance == 4715 || distance == 4713) { - std::cout << std::setprecision(50) << "improving value at " << distance << ": moving from " << *choiceIt << " to " << selectedChoice << " because " << *targetIt << " is better than " << oldSelectedChoiceValue << std::endl; - } *choiceIt = selectedChoice; } } else { @@ -796,7 +792,6 @@ namespace storm { */ template void reduceVectorMinOrMax(storm::solver::OptimizationDirection dir, std::vector const& source, std::vector& target, std::vector const& rowGrouping, std::vector* choices = nullptr) { - std::cout << "[" << dir << "]: reducing vector " << std::endl; if (dir == storm::solver::OptimizationDirection::Minimize) { reduceVectorMin(source, target, rowGrouping, choices); } else { From e29e6c7cd28f30222ac0edfbd7a977d731a1105c Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 10 Jun 2018 12:20:40 +0200 Subject: [PATCH 348/647] high level counterexamples extended with more options, and improved performance when minimizing over a subset --- .../SMTMinimalLabelSetGenerator.h | 122 ++++++++++++++---- 1 file changed, 96 insertions(+), 26 deletions(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 6b4c440c1..000d830ad 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -49,14 +49,20 @@ namespace storm { // The set of labels that matter in terms of minimality. boost::container::flat_set minimalityLabels; - + // A set of labels that is definitely known to be taken in the final solution. boost::container::flat_set knownLabels; + + boost::container::flat_set dontCareLabels; // A list of relevant choices for each relevant state. std::map> relevantChoicesForRelevantStates; }; - + + struct GeneratorStats { + + }; + struct VariableInformation { // The manager responsible for the constraints we are building. std::shared_ptr manager; @@ -154,10 +160,12 @@ namespace storm { std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(remainingLabels, remainingLabels.end())); relevancyInformation.relevantLabels = remainingLabels; } - + + relevancyInformation.dontCareLabels = dontCareLabels; std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), dontCareLabels.begin(), dontCareLabels.end(), std::inserter(relevancyInformation.minimalityLabels, relevancyInformation.minimalityLabels.begin())); STORM_LOG_DEBUG("Found " << relevancyInformation.relevantLabels.size() << " relevant and " << relevancyInformation.knownLabels.size() << " known labels."); + STORM_LOG_DEBUG("Found " << relevancyInformation.minimalityLabels.size() << " labels to minize over."); return relevancyInformation; } @@ -649,10 +657,11 @@ namespace storm { // Popping the disjunction of negated guards from the solver stack. localSolver->pop(); + STORM_LOG_ERROR_COND(backwardImplicationAdded, "Error in adding cuts for counterexample generation (backward implication misses a label set)."); } else { STORM_LOG_DEBUG("Selection is enabled in initial state."); } - STORM_LOG_ERROR_COND(backwardImplicationAdded, "Error in adding cuts for counterexample generation (backward implication misses a label set)."); + } } else if (symbolicModel.isJaniModel()) { STORM_LOG_WARN("Model uses assignment levels, did not assert backward implications."); @@ -1316,7 +1325,7 @@ namespace storm { * in order to satisfy the constraint system. * @return The smallest set of labels such that the constraint system of the solver is satisfiable. */ - static boost::container::flat_set findSmallestCommandSet(storm::solver::SmtSolver& solver, VariableInformation& variableInformation, uint_fast64_t& currentBound) { + static boost::optional> findSmallestCommandSet(storm::solver::SmtSolver& solver, VariableInformation& variableInformation, uint_fast64_t& currentBound) { // Check if we can find a solution with the current bound. storm::expressions::Expression assumption = !variableInformation.auxiliaryVariables.back(); @@ -1331,6 +1340,10 @@ namespace storm { solver.add(variableInformation.auxiliaryVariables.back()); variableInformation.auxiliaryVariables.push_back(assertLessOrEqualKRelaxed(solver, variableInformation, ++currentBound)); assumption = !variableInformation.auxiliaryVariables.back(); + if (currentBound > (1 << variableInformation.minimalityLabelVariables.size())) { + STORM_LOG_DEBUG("Constraint system fully explored: Bound exceeds maximum of " << (1 << variableInformation.minimalityLabelVariables.size())); + return boost::none; + } } // At this point we know that the constraint system was satisfiable, so compute the induced label @@ -1342,12 +1355,17 @@ namespace storm { std::vector formulae; boost::container::flat_set unknownLabels; - std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + std::set_intersection(labelSet.begin(), labelSet.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + + //std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); for (auto const& label : unknownLabels) { formulae.emplace_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } + boost::container::flat_set remainingLabels; - std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + //std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + std::set_difference(relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + for (auto const& label : remainingLabels) { formulae.emplace_back(variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } @@ -1355,6 +1373,22 @@ namespace storm { STORM_LOG_DEBUG("Ruling out single solution."); assertDisjunction(solver, formulae, *variableInformation.manager); } + + static void ruleOutBiggerSolutions(storm::solver::SmtSolver& solver, boost::container::flat_set const& labelSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { + std::vector formulae; + + boost::container::flat_set unknownLabels; + std::set_intersection(labelSet.begin(), labelSet.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + + //std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + for (auto const& label : unknownLabels) { + formulae.emplace_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + + + STORM_LOG_DEBUG("Ruling out set of solutions."); + assertDisjunction(solver, formulae, *variableInformation.manager); + } /*! * Analyzes the given sub-model that has a maximal reachability of zero (i.e. no psi states are reachable) and tries to construct assertions that aim to make at least one psi state reachable. @@ -1664,6 +1698,9 @@ namespace storm { bool encodeReachability; bool useDynamicConstraints; bool silent = false; + uint64_t continueAfterFirstCounterexampleUntil = 0; + uint64_t maximumCounterexamples = 1; + uint64_t multipleCounterexampleSizeCap = 100000000; }; /*! @@ -1677,8 +1714,9 @@ namespace storm { * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). * @param options A set of options for customization. */ - static boost::container::flat_set getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { + static std::vector> getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 + std::vector> result; // Set up all clocks used for time measurement. auto totalClock = std::chrono::high_resolution_clock::now(); auto timeOfLastMessage = std::chrono::high_resolution_clock::now(); @@ -1762,10 +1800,10 @@ namespace storm { // If there are no relevant labels, return directly. if (relevancyInformation.relevantLabels.empty()) { - return commandSet; + return {commandSet}; } else if (relevancyInformation.minimalityLabels.empty()) { commandSet.insert(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end()); - return commandSet; + return {commandSet}; } // Set up some variables for the iterations. @@ -1775,17 +1813,31 @@ namespace storm { uint_fast64_t currentBound = 0; maximalReachabilityProbability = 0; uint_fast64_t zeroProbabilityCount = 0; + uint64_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive u uint64_t progressDelay = storm::settings::getModule().getShowProgressDelay(); do { STORM_LOG_DEBUG("Computing minimal command set."); solverClock = std::chrono::high_resolution_clock::now(); - commandSet = findSmallestCommandSet(*solver, variableInformation, currentBound); + boost::optional> smallest = findSmallestCommandSet(*solver, variableInformation, currentBound); totalSolverTime += std::chrono::high_resolution_clock::now() - solverClock; - STORM_LOG_DEBUG("Computed minimal command set of size " << commandSet.size() + relevancyInformation.knownLabels.size() << " (" << commandSet.size() << " + " << relevancyInformation.knownLabels.size() << ") "); + if(smallest == boost::none) { + STORM_LOG_DEBUG("No further counterexamples."); + break; + } else { + commandSet = smallest.get(); + } + STORM_LOG_DEBUG("Computed minimal command with bound " << currentBound << " and set of size " << commandSet.size() + relevancyInformation.knownLabels.size() << " (" << commandSet.size() << " + " << relevancyInformation.knownLabels.size() << ") "); // Restrict the given model to the current set of labels and compute the reachability probability. modelCheckingClock = std::chrono::high_resolution_clock::now(); commandSet.insert(relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end()); + commandSet.insert(relevancyInformation.dontCareLabels.begin(), relevancyInformation.dontCareLabels.end()); + if (commandSet.size() > smallestCounterexampleSize + options.continueAfterFirstCounterexampleUntil || (result.size() > 1 && commandSet.size() > options.multipleCounterexampleSizeCap) ) { + STORM_LOG_DEBUG("No further counterexamples of similar size."); + break; + } + + auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet); std::shared_ptr> const& subModel = subChoiceOrigins.first; std::vector> const& subLabelSets = subChoiceOrigins.second; @@ -1818,7 +1870,17 @@ namespace storm { ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); } } else { - done = true; + STORM_LOG_DEBUG("Found a counterexample."); + result.push_back(commandSet); + if (options.maximumCounterexamples > result.size()) { + STORM_LOG_DEBUG("Exclude counterexample for future."); + ruleOutBiggerSolutions(*solver, commandSet, variableInformation, relevancyInformation); + + } else { + STORM_LOG_DEBUG("Stop searching for further counterexamples."); + done = true; + } + } totalAnalysisTime += (std::chrono::high_resolution_clock::now() - analysisClock); ++iterations; @@ -1828,10 +1890,10 @@ namespace storm { if (static_cast(durationSinceLastMessage) >= progressDelay || lastSize < commandSet.size()) { auto milliseconds = std::chrono::duration_cast(now - totalClock).count(); if (lastSize < commandSet.size()) { - std::cout << "Improved lower bound to " << commandSet.size() << " after " << milliseconds << "ms." << std::endl; + std::cout << "Improved lower bound to " << currentBound << " after " << milliseconds << "ms." << std::endl; lastSize = commandSet.size(); } else { - std::cout << "Lower bound on label set size is " << commandSet.size() << " after " << milliseconds << "ms (checked " << iterations << " models, " << zeroProbabilityCount << " could not reach the target set)." << std::endl; + std::cout << "Lower bound on label set size is " << currentBound << " after " << milliseconds << "ms (checked " << iterations << " models, " << zeroProbabilityCount << " could not reach the target set)." << std::endl; timeOfLastMessage = std::chrono::high_resolution_clock::now(); } } @@ -1863,7 +1925,7 @@ namespace storm { std::cout << " * number of models that could not reach a target state: " << zeroProbabilityCount << " (" << 100 * static_cast(zeroProbabilityCount)/iterations << "%)" << std::endl << std::endl; } - return commandSet; + return result; #else throw storm::exceptions::NotImplementedException() << "This functionality is unavailable since storm has been compiled without support for Z3."; #endif @@ -1953,7 +2015,7 @@ namespace storm { } - static boost::container::flat_set computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { + static std::vector> computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); if (!options.silent) { std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; @@ -2025,28 +2087,36 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, dontCareLabels, options); + auto labelSets = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); if (!options.silent) { - std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + for (auto const& labelSet : labelSets) { + std::cout << std::endl << "Computed minimal label set of size " << labelSet.size(); + + } + std::cout << std::endl << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + } // Extend the command set properly. - if (lowerBoundedFormula) { - extendLabelSetLowerBound(model, labelSet, phiStates, psiStates, options.silent); + for (auto& labelSet : labelSets) { + if (lowerBoundedFormula) { + extendLabelSetLowerBound(model, labelSet, phiStates, psiStates, options.silent); + } } - return labelSet; + return labelSets; } static std::shared_ptr computeCounterexample(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { #ifdef STORM_HAVE_Z3 - auto labelSet = computeCounterexampleLabelSet(env, symbolicModel, model, formula); - + auto labelSets = computeCounterexampleLabelSet(env, symbolicModel, model, formula); + + if (symbolicModel.isPrismProgram()) { - return std::make_shared(symbolicModel.asPrismProgram().restrictCommands(labelSet)); + return std::make_shared(symbolicModel.asPrismProgram().restrictCommands(labelSets[0])); } else { STORM_LOG_ASSERT(symbolicModel.isJaniModel(), "Unknown symbolic model description type."); - return std::make_shared(symbolicModel.asJaniModel().restrictEdges(labelSet)); + return std::make_shared(symbolicModel.asJaniModel().restrictEdges(labelSets[0])); } #else throw storm::exceptions::NotImplementedException() << "This functionality is unavailable since storm has been compiled without support for Z3."; From d1ab2600688c2e645971c13329114b7b74ad8c0b Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 10 Jun 2018 12:22:34 +0200 Subject: [PATCH 349/647] remove outdated parts in highlevel counterexamplse --- .../SMTMinimalLabelSetGenerator.h | 106 ------------------ 1 file changed, 106 deletions(-) diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h index 000d830ad..0313fe655 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1162,112 +1162,6 @@ namespace storm { return relaxingVariable; } - /*! - * Asserts that the input vector encodes a decimal smaller or equal to one. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param input The binary encoded input number. - */ - static void assertLessOrEqualOne(z3::context& context, z3::solver& solver, std::vector input) { - std::transform(input.begin(), input.end(), input.begin(), [](z3::expr e) -> z3::expr { return !e; }); - assertConjunction(context, solver, input); - } - - /*! - * Asserts that at most one of given literals may be true at any time. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param blockingVariables A vector of variables out of which only one may be true. - */ - static void assertAtMostOne(z3::context& context, z3::solver& solver, std::vector const& literals) { - std::vector counter = createCounterCircuit(context, literals); - assertLessOrEqualOne(context, solver, counter); - } - - /*! - * Performs one Fu-Malik-Maxsat step. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param variableInformation A structure with information about the variables for the labels. - * @return True iff the constraint system was satisfiable. - */ - static bool fuMalikMaxsatStep(z3::context& context, z3::solver& solver, std::vector& auxiliaryVariables, std::vector& softConstraints, uint_fast64_t& nextFreeVariableIndex) { - z3::expr_vector assumptions(context); - for (auto const& auxiliaryVariable : auxiliaryVariables) { - assumptions.push_back(!auxiliaryVariable); - } - - // Check whether the assumptions are satisfiable. - STORM_LOG_DEBUG("Invoking satisfiability checking."); - z3::check_result result = solver.check(assumptions); - STORM_LOG_DEBUG("Done invoking satisfiability checking."); - - if (result == z3::sat) { - return true; - } else { - STORM_LOG_DEBUG("Computing unsat core."); - z3::expr_vector unsatCore = solver.unsat_core(); - STORM_LOG_DEBUG("Computed unsat core."); - - std::vector blockingVariables; - blockingVariables.reserve(unsatCore.size()); - - // Create stringstream to build expression names. - std::stringstream variableName; - - for (uint_fast64_t softConstraintIndex = 0; softConstraintIndex < softConstraints.size(); ++softConstraintIndex) { - for (uint_fast64_t coreIndex = 0; coreIndex < unsatCore.size(); ++coreIndex) { - bool isContainedInCore = false; - if (softConstraints[softConstraintIndex] == unsatCore[coreIndex]) { - isContainedInCore = true; - } - - if (isContainedInCore) { - variableName.clear(); - variableName.str(""); - variableName << "b" << nextFreeVariableIndex; - blockingVariables.push_back(context.bool_const(variableName.str().c_str())); - - variableName.clear(); - variableName.str(""); - variableName << "a" << nextFreeVariableIndex; - ++nextFreeVariableIndex; - auxiliaryVariables[softConstraintIndex] = context.bool_const(variableName.str().c_str()); - - softConstraints[softConstraintIndex] = softConstraints[softConstraintIndex] || blockingVariables.back(); - - solver.add(softConstraints[softConstraintIndex] || auxiliaryVariables[softConstraintIndex]); - } - } - } - - assertAtMostOne(context, solver, blockingVariables); - } - - return false; - } - - /*! - * Rules out the given command set for the given solver. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param commandSet The command set to rule out as a solution. - * @param variableInformation A structure with information about the variables for the labels. - */ - static void ruleOutSolution(z3::context& context, z3::solver& solver, boost::container::flat_set const& commandSet, VariableInformation const& variableInformation) { - z3::expr blockSolutionExpression = context.bool_val(false); - for (auto labelIndexPair : variableInformation.labelToIndexMap) { - if (commandSet.find(labelIndexPair.first) != commandSet.end()) { - blockSolutionExpression = blockSolutionExpression || variableInformation.labelVariables[labelIndexPair.second]; - } - } - - solver.add(blockSolutionExpression); - } /*! * Determines the set of labels that was chosen by the given model. From b0047a5a96ec3ce6b741f9d3c40ed30d625b554f Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 10 Jun 2018 14:06:58 +0200 Subject: [PATCH 350/647] improving choices in game policy iteration depending on precision of underlying solver --- src/storm/solver/StandardGameSolver.cpp | 54 +++++++++---------------- src/storm/solver/StandardGameSolver.h | 6 +-- 2 files changed, 20 insertions(+), 40 deletions(-) diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 8192ba25e..cd0409170 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -177,7 +177,7 @@ namespace storm { do { submatrixSolver->solveEquations(environmentOfSolver, x, subB); - bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); + bool schedulerImproved = extractChoices(environmentOfSolver, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); // If the scheduler did not improve, we are done. if (!schedulerImproved) { @@ -230,11 +230,11 @@ namespace storm { } template - bool StandardGameSolver::valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const { + bool StandardGameSolver::valueImproved(OptimizationDirection dir, ValueType const& precision, ValueType const& value1, ValueType const& value2) const { if (dir == OptimizationDirection::Minimize) { - return value2 < value1; + return value2 < value1 - precision; } else { - return value2 > value1; + return value2 > value1 + precision; } } @@ -325,11 +325,11 @@ namespace storm { // If requested, we store the scheduler for retrieval. if (trackSchedulers && this->hasUniqueSolution()) { if (trackingSchedulersInProvidedStorage) { - extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); + extractChoices(env, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); } else { this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); - extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); + extractChoices(env, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); } } @@ -398,31 +398,11 @@ namespace storm { } template - bool StandardGameSolver::extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { - if (player1Dir == storm::OptimizationDirection::Minimize) { - if (player2Dir == storm::OptimizationDirection::Minimize) { - return extractChoices, storm::utility::ElementLess>(x, b, player2ChoiceValues, player1Choices, player2Choices); - } else { - return extractChoices, storm::utility::ElementGreater>(x, b, player2ChoiceValues, player1Choices, player2Choices); - } - } else { - if (player2Dir == storm::OptimizationDirection::Minimize) { - return extractChoices, storm::utility::ElementLess>(x, b, player2ChoiceValues, player1Choices, player2Choices); - } else { - return extractChoices, storm::utility::ElementGreater>(x, b, player2ChoiceValues, player1Choices, player2Choices); - } - } - - return false; - } - - template - template - bool StandardGameSolver::extractChoices(std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { - - ComparePlayer1 comparePlayer1; - ComparePlayer2 comparePlayer2; - + bool StandardGameSolver::extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { + + std::pair, boost::optional> precisionInfo = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + ValueType precision = storm::utility::convertNumber(precisionInfo.first.get()); + // get the choices of player 2 and the corresponding values. bool schedulerImproved = false; auto currentValueIt = player2ChoiceValues.begin(); @@ -448,8 +428,9 @@ namespace storm { choiceValue += entry.getValue() * x[entry.getColumn()]; } choiceValue += b[firstRowInGroup + p2Choice]; - - if (comparePlayer2(choiceValue, *currentValueIt)) { + + if (valueImproved(player2Dir, precision, *currentValueIt, choiceValue)) { +// std::cout << std::setprecision(30) << "improving player 2 choice at " << p2Group << " from " << player2Choices[p2Group] << " to " << p2Choice << " because " << choiceValue << " is better than " << *currentValueIt << std::endl; schedulerImproved = true; player2Choices[p2Group] = p2Choice; *currentValueIt = std::move(choiceValue); @@ -471,7 +452,7 @@ namespace storm { continue; } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; - if (comparePlayer1(choiceValue, currentValue)) { + if (valueImproved(player1Dir, precision, currentValue, choiceValue)) { schedulerImproved = true; player1Choices[p1Group] = p1Choice; currentValue = choiceValue; @@ -486,12 +467,13 @@ namespace storm { uint64_t numberOfPlayer2Successors = this->getPlayer1Grouping()[player1State + 1] - this->getPlayer1Grouping()[player1State]; for (uint64_t player2State = 0; player2State < numberOfPlayer2Successors; ++player2State) { // If the choice is the currently selected one, we can skip it. - if (currentChoice == player2State + this->getPlayer1Grouping()[player1State]) { + if (currentChoice == player2State) { continue; } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + player2State]; - if (comparePlayer1(choiceValue, currentValue)) { + if (valueImproved(player1Dir, precision, currentValue, choiceValue)) { +// std::cout << std::setprecision(30) << "improving player 2 choice at " << player1State << " from " << player1Choices[player1State] << " to " << player2State << " because " << choiceValue << " is better than " << currentValue << std::endl; schedulerImproved = true; player1Choices[player1State] = player2State; currentValue = choiceValue; diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 8f950838b..8fa380001 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -38,11 +38,9 @@ namespace storm { // Extracts the choices of the different players for the given solution x. // Returns true iff the newly extracted choices yield "better" values then the given choices for one of the players. - bool extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; - template - bool extractChoices(std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; + bool extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; - bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; + bool valueImproved(OptimizationDirection dir, ValueType const& precision, ValueType const& value1, ValueType const& value2) const; bool player1RepresentedByMatrix() const; storm::storage::SparseMatrix const& getPlayer1Matrix() const; From 6dfce6a405fdd52e3f24f422893a29a77a3043da Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 18:50:56 +0200 Subject: [PATCH 351/647] extended counterexamples towards expected rewards, and moved counterexamples to a seperate lib (still in main cli) to slightly accelarate building times --- src/CMakeLists.txt | 1 + src/storm-cli-utilities/CMakeLists.txt | 2 +- src/storm-cli-utilities/cli.cpp | 2 + src/storm-cli-utilities/model-handling.h | 2 + src/storm-counterexamples/CMakeLists.txt | 40 ++++++++ .../api/counterexamples.cpp | 2 +- .../api/counterexamples.h | 4 +- .../counterexamples/Counterexample.cpp | 2 +- .../counterexamples/Counterexample.h | 0 .../HighLevelCounterexample.cpp | 2 +- .../counterexamples/HighLevelCounterexample.h | 2 +- .../MILPMinimalLabelSetGenerator.h | 4 +- .../SMTMinimalLabelSetGenerator.h | 91 +++++++++++++------ .../CounterexampleGeneratorSettings.cpp | 2 +- .../modules/CounterexampleGeneratorSettings.h | 0 src/storm-pars/settings/ParsSettings.cpp | 2 - src/storm/api/storm.h | 1 - src/storm/settings/SettingsManager.cpp | 2 - .../utility/ModelInstantiatorTest.cpp | 1 + 19 files changed, 118 insertions(+), 44 deletions(-) create mode 100644 src/storm-counterexamples/CMakeLists.txt rename src/{storm => storm-counterexamples}/api/counterexamples.cpp (95%) rename src/{storm => storm-counterexamples}/api/counterexamples.h (80%) rename src/{storm => storm-counterexamples}/counterexamples/Counterexample.cpp (79%) rename src/{storm => storm-counterexamples}/counterexamples/Counterexample.h (100%) rename src/{storm => storm-counterexamples}/counterexamples/HighLevelCounterexample.cpp (92%) rename src/{storm => storm-counterexamples}/counterexamples/HighLevelCounterexample.h (93%) rename src/{storm => storm-counterexamples}/counterexamples/MILPMinimalLabelSetGenerator.h (99%) rename src/{storm => storm-counterexamples}/counterexamples/SMTMinimalLabelSetGenerator.h (95%) rename src/{storm => storm-counterexamples}/settings/modules/CounterexampleGeneratorSettings.cpp (98%) rename src/{storm => storm-counterexamples}/settings/modules/CounterexampleGeneratorSettings.h (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index acf819119..0f277386d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) add_custom_target(binaries) add_subdirectory(storm) +add_subdirectory(storm-counterexamples) add_subdirectory(storm-cli-utilities) add_subdirectory(storm-pgcl) add_subdirectory(storm-pgcl-cli) diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index 84819b72b..5e37b5db4 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) diff --git a/src/storm-cli-utilities/cli.cpp b/src/storm-cli-utilities/cli.cpp index 4d44454c8..e79971cbc 100644 --- a/src/storm-cli-utilities/cli.cpp +++ b/src/storm-cli-utilities/cli.cpp @@ -49,6 +49,8 @@ namespace storm { storm::cli::printHeader("Storm", argc, argv); storm::settings::initializeAll("Storm", "storm"); + storm::settings::addModule(); + storm::utility::Stopwatch totalTimer(true); if (!storm::cli::parseOptions(argc, argv)) { return -1; diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index d03cfe630..b57818c08 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -2,6 +2,8 @@ #include "storm/api/storm.h" +#include "storm-counterexamples/api/counterexamples.h" + #include "storm/utility/resources.h" #include "storm/utility/file.h" #include "storm/utility/storm-version.h" diff --git a/src/storm-counterexamples/CMakeLists.txt b/src/storm-counterexamples/CMakeLists.txt new file mode 100644 index 000000000..d01c4ceb7 --- /dev/null +++ b/src/storm-counterexamples/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*.h ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-counterexamples) + + + +file(GLOB_RECURSE STORM_CEX_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*/*.cpp) +file(GLOB_RECURSE STORM_CEX_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*/*.h) + + +# Create storm-dft. +add_library(storm-counterexamples SHARED ${STORM_CEX_SOURCES} ${STORM_CEX_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-counterexamples PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-counterexamples) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-counterexamples PUBLIC storm) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_DFT_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_CEX_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_cex_headers DEPENDS ${STORM_CEX_OUTPUT_HEADERS} ${STORM_CEX_HEADERS}) +add_dependencies(storm-counterexamples copy_storm_cex_headers) + +# installation +install(TARGETS storm-counterexamples EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm/api/counterexamples.cpp b/src/storm-counterexamples/api/counterexamples.cpp similarity index 95% rename from src/storm/api/counterexamples.cpp rename to src/storm-counterexamples/api/counterexamples.cpp index c57724ad5..5652beba6 100644 --- a/src/storm/api/counterexamples.cpp +++ b/src/storm-counterexamples/api/counterexamples.cpp @@ -1,4 +1,4 @@ -#include "storm/api/counterexamples.h" +#include "storm-counterexamples/api/counterexamples.h" #include "storm/environment/Environment.h" diff --git a/src/storm/api/counterexamples.h b/src/storm-counterexamples/api/counterexamples.h similarity index 80% rename from src/storm/api/counterexamples.h rename to src/storm-counterexamples/api/counterexamples.h index 672ddc4df..6a5984991 100644 --- a/src/storm/api/counterexamples.h +++ b/src/storm-counterexamples/api/counterexamples.h @@ -1,7 +1,7 @@ #pragma once -#include "storm/counterexamples/MILPMinimalLabelSetGenerator.h" -#include "storm/counterexamples/SMTMinimalLabelSetGenerator.h" +#include "storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h" +#include "storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h" namespace storm { namespace api { diff --git a/src/storm/counterexamples/Counterexample.cpp b/src/storm-counterexamples/counterexamples/Counterexample.cpp similarity index 79% rename from src/storm/counterexamples/Counterexample.cpp rename to src/storm-counterexamples/counterexamples/Counterexample.cpp index 4aba71b9c..9975f54ba 100644 --- a/src/storm/counterexamples/Counterexample.cpp +++ b/src/storm-counterexamples/counterexamples/Counterexample.cpp @@ -1,4 +1,4 @@ -#include "storm/counterexamples/Counterexample.h" +#include "storm-counterexamples/counterexamples/Counterexample.h" namespace storm { namespace counterexamples { diff --git a/src/storm/counterexamples/Counterexample.h b/src/storm-counterexamples/counterexamples/Counterexample.h similarity index 100% rename from src/storm/counterexamples/Counterexample.h rename to src/storm-counterexamples/counterexamples/Counterexample.h diff --git a/src/storm/counterexamples/HighLevelCounterexample.cpp b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp similarity index 92% rename from src/storm/counterexamples/HighLevelCounterexample.cpp rename to src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp index 707ed6d39..11279a220 100644 --- a/src/storm/counterexamples/HighLevelCounterexample.cpp +++ b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp @@ -1,4 +1,4 @@ -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" namespace storm { namespace counterexamples { diff --git a/src/storm/counterexamples/HighLevelCounterexample.h b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.h similarity index 93% rename from src/storm/counterexamples/HighLevelCounterexample.h rename to src/storm-counterexamples/counterexamples/HighLevelCounterexample.h index 92310a5ba..27fe981c0 100644 --- a/src/storm/counterexamples/HighLevelCounterexample.h +++ b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/counterexamples/Counterexample.h" +#include "Counterexample.h" #include "storm/storage/SymbolicModelDescription.h" diff --git a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h similarity index 99% rename from src/storm/counterexamples/MILPMinimalLabelSetGenerator.h rename to src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h index 861f86f83..52ed50778 100644 --- a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h @@ -17,7 +17,7 @@ #include "storm/solver/MinMaxLinearEquationSolver.h" -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" #include "storm/utility/graph.h" #include "storm/utility/counterexamples.h" @@ -29,7 +29,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" +#include "storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h" namespace storm { diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h similarity index 95% rename from src/storm/counterexamples/SMTMinimalLabelSetGenerator.h rename to src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 0313fe655..4de23e767 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -5,7 +5,7 @@ #include "storm/solver/Z3SmtSolver.h" -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" #include "storm/storage/prism/Program.h" #include "storm/storage/expressions/Expression.h" @@ -1510,7 +1510,7 @@ namespace storm { * Returns the sub-model obtained from removing all choices that do not originate from the specified filterLabelSet. * Also returns the Labelsets of the sub-model. */ - static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet) { + static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional absorbState = boost::none) { bool customRowGrouping = model.isOfType(storm::models::ModelType::Mdp); @@ -1544,7 +1544,8 @@ namespace storm { if (customRowGrouping) { transitionMatrixBuilder.newRowGroup(currentRow); } - transitionMatrixBuilder.addNextValue(currentRow, state, storm::utility::one()); + uint64_t targetState = absorbState == boost::none ? state : absorbState.get(); + transitionMatrixBuilder.addNextValue(currentRow, targetState, storm::utility::one()); // Insert an empty label set for this choice resultLabelSet.emplace_back(); ++currentRow; @@ -1561,17 +1562,25 @@ namespace storm { return std::make_pair(resultModel, std::move(resultLabelSet)); } - static T computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { + static T computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& rewardName) { T result = storm::utility::zero(); std::vector allStatesResult; STORM_LOG_DEBUG("Invoking model checker."); if (model.isOfType(storm::models::ModelType::Dtmc)) { - allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false); + if (rewardName == boost::none) { + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false); + } else { + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), model.getRewardModel(rewardName.get()), psiStates, false); + } } else { - storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; - allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, false).values); + if (rewardName == boost::none) { + storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; + allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(),model.getBackwardTransitions(), phiStates,psiStates, false, false).values); + } else { + STORM_LOG_THROW(rewardName != boost::none, storm::exceptions::NotSupportedException, "Reward property counterexample generation is currently only supported for DTMCs."); + } } for (auto state : model.getInitialStates()) { result = std::max(result, allStatesResult[state]); @@ -1604,11 +1613,12 @@ namespace storm { * @param model The sparse model in which to find the minimal command set. * @param phiStates A bit vector characterizing all phi states in the model. * @param psiStates A bit vector characterizing all psi states in the model. - * @param probabilityThreshold The threshold that is to be achieved or exceeded. + * @param propertyThreshold The threshold that is to be achieved or exceeded. + * @param rewardName The name of the reward structure to use, or boost::none if probabilities are considerd. * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). * @param options A set of options for customization. */ - static std::vector> getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { + static std::vector> getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double propertyThreshold, boost::optional const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 std::vector> result; // Set up all clocks used for time measurement. @@ -1650,10 +1660,10 @@ namespace storm { // (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set. double maximalReachabilityProbability = 0; if (options.checkThresholdFeasible) { - maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates); + maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates, rewardName); - STORM_LOG_THROW((strictBound && maximalReachabilityProbability >= probabilityThreshold) || (!strictBound && maximalReachabilityProbability > probabilityThreshold), storm::exceptions::InvalidArgumentException, "Given probability threshold " << probabilityThreshold << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability << "."); - std::cout << std::endl << "Maximal reachability in model is " << maximalReachabilityProbability << "." << std::endl << std::endl; + STORM_LOG_THROW((strictBound && maximalReachabilityProbability >= propertyThreshold) || (!strictBound && maximalReachabilityProbability > propertyThreshold), storm::exceptions::InvalidArgumentException, "Given probability threshold " << propertyThreshold << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability << "."); + std::cout << std::endl << "Maximal property value in model is " << maximalReachabilityProbability << "." << std::endl << std::endl; } // (2) Identify all states and commands that are relevant, because only these need to be considered later. @@ -1705,7 +1715,7 @@ namespace storm { uint_fast64_t lastSize = 0; uint_fast64_t iterations = 0; uint_fast64_t currentBound = 0; - maximalReachabilityProbability = 0; + double maximalPropertyValue = 0; uint_fast64_t zeroProbabilityCount = 0; uint64_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive u uint64_t progressDelay = storm::settings::getModule().getShowProgressDelay(); @@ -1732,18 +1742,18 @@ namespace storm { } - auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet); + auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, psiStates.getNextSetIndex(0)); std::shared_ptr> const& subModel = subChoiceOrigins.first; std::vector> const& subLabelSets = subChoiceOrigins.second; // Now determine the maximal reachability probability in the sub-model. - maximalReachabilityProbability = computeMaximalReachabilityProbability(env, *subModel, phiStates, psiStates); + maximalPropertyValue = computeMaximalReachabilityProbability(env, *subModel, phiStates, psiStates, rewardName); totalModelCheckingTime += std::chrono::high_resolution_clock::now() - modelCheckingClock; // Depending on whether the threshold was successfully achieved or not, we proceed by either analyzing the bad solution or stopping the iteration process. analysisClock = std::chrono::high_resolution_clock::now(); - if ((strictBound && maximalReachabilityProbability < probabilityThreshold) || (!strictBound && maximalReachabilityProbability <= probabilityThreshold)) { - if (maximalReachabilityProbability == storm::utility::zero()) { + if ((strictBound && maximalPropertyValue < propertyThreshold) || (!strictBound && maximalPropertyValue <= propertyThreshold)) { + if (maximalPropertyValue == storm::utility::zero()) { ++zeroProbabilityCount; } @@ -1759,6 +1769,10 @@ namespace storm { // the given threshold, we analyze the solution and try to guide the solver into the right direction. analyzeInsufficientProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); } + + if (relevancyInformation.dontCareLabels.size() > 0) { + ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); + } } else { // Do not guide solver, just rule out current solution. ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); @@ -1915,22 +1929,41 @@ namespace storm { std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; } - STORM_LOG_THROW(formula->isProbabilityOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); - storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); - STORM_LOG_THROW(probabilityOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); - STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); + storm::logic::ComparisonType comparisonType; + double threshold; + boost::optional rewardName = boost::none; + + STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); + if (formula->isProbabilityOperatorFormula()) { + storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); + STORM_LOG_THROW(probabilityOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); + STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); + + comparisonType = probabilityOperator.getComparisonType(); + threshold = probabilityOperator.getThresholdAs(); + } else { + assert(formula->isRewardOperatorFormula()); + storm::logic::RewardOperatorFormula const& rewardOperator = formula->asRewardOperatorFormula(); + STORM_LOG_THROW(rewardOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); + STORM_LOG_THROW( rewardOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'F phi' for counterexample generation."); + + comparisonType = rewardOperator.getComparisonType(); + threshold = rewardOperator.getThresholdAs(); + rewardName = rewardOperator.getRewardModelName(); - storm::logic::ComparisonType comparisonType = probabilityOperator.getComparisonType(); - bool strictBound = comparisonType == storm::logic::ComparisonType::Less; - double threshold = probabilityOperator.getThresholdAs(); + STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for probability formulas."); + } + bool strictBound = comparisonType == storm::logic::ComparisonType::Less; + storm::logic::Formula const& subformula = formula->asOperatorFormula().getSubformula(); + storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; storm::modelchecker::SparsePropositionalModelChecker> modelchecker(model); - if (probabilityOperator.getSubformula().isUntilFormula()) { + if (subformula.isUntilFormula()) { STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for eventually formulas."); - storm::logic::UntilFormula const& untilFormula = probabilityOperator.getSubformula().asUntilFormula(); + storm::logic::UntilFormula const& untilFormula = subformula.asUntilFormula(); std::unique_ptr leftResult = modelchecker.check(env, untilFormula.getLeftSubformula()); std::unique_ptr rightResult = modelchecker.check(env, untilFormula.getRightSubformula()); @@ -1940,8 +1973,8 @@ namespace storm { phiStates = leftQualitativeResult.getTruthValuesVector(); psiStates = rightQualitativeResult.getTruthValuesVector(); - } else if (probabilityOperator.getSubformula().isEventuallyFormula()) { - storm::logic::EventuallyFormula const& eventuallyFormula = probabilityOperator.getSubformula().asEventuallyFormula(); + } else if (subformula.isEventuallyFormula()) { + storm::logic::EventuallyFormula const& eventuallyFormula = subformula.asEventuallyFormula(); std::unique_ptr subResult = modelchecker.check(env, eventuallyFormula.getSubformula()); @@ -1981,7 +2014,7 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSets = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, dontCareLabels, options); + auto labelSets = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, rewardName, strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); if (!options.silent) { for (auto const& labelSet : labelSets) { diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp similarity index 98% rename from src/storm/settings/modules/CounterexampleGeneratorSettings.cpp rename to src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp index 0eaf656bb..9fe9d3d36 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp @@ -1,4 +1,4 @@ -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" +#include "CounterexampleGeneratorSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/exceptions/InvalidSettingsException.h" diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.h b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h similarity index 100% rename from src/storm/settings/modules/CounterexampleGeneratorSettings.h rename to src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index a0e9d8073..bf6065d62 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -1,4 +1,3 @@ -#include #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" @@ -38,7 +37,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/api/storm.h b/src/storm/api/storm.h index ffc4c75a6..d8f6aed82 100644 --- a/src/storm/api/storm.h +++ b/src/storm/api/storm.h @@ -6,5 +6,4 @@ #include "storm/api/bisimulation.h" #include "storm/api/transformation.h" #include "storm/api/verification.h" -#include "storm/api/counterexamples.h" #include "storm/api/export.h" diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index fc2b80b35..f18f76bb1 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -17,7 +17,6 @@ #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/modules/CuddSettings.h" #include "storm/settings/modules/BuildSettings.h" #include "storm/settings/modules/SylvanSettings.h" @@ -531,7 +530,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp index e66a912d5..1873a4436 100644 --- a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp +++ b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp @@ -16,6 +16,7 @@ #include "storm/models/sparse/Model.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" TEST(ModelInstantiatorTest, BrpProb) { carl::VariablePool::getInstance().clear(); From 3a704ae5327b01c298e44ffa318c7a636c9c7cb0 Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 18:51:25 +0200 Subject: [PATCH 352/647] fix storm-dft missing includes --- src/storm-dft-cli/storm-dft.cpp | 1 + src/storm-dft/modelchecker/dft/DFTModelChecker.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 9923330d0..ce31be5b8 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -5,6 +5,7 @@ #include "storm-dft/settings/modules/FaultTreeSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/ResourceSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/utility/initialize.h" #include "storm-cli-utilities/cli.h" diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 8d277d60d..24e39a0f5 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -1,9 +1,12 @@ #include "DFTModelChecker.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/builder/ParallelCompositionBuilder.h" #include "storm/utility/bitoperations.h" #include "storm/utility/DirectEncodingExporter.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm-dft/builder/ExplicitDFTModelBuilder.h" #include "storm-dft/storage/dft/DFTIsomorphism.h" From 79bb6734ed94b6e5897ada83e1349bfb6e8502ff Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 20:20:39 +0200 Subject: [PATCH 353/647] compile and link parsers in seperate binary --- src/CMakeLists.txt | 1 + src/storm-cli-utilities/CMakeLists.txt | 2 +- src/storm-cli-utilities/model-handling.h | 1 + src/storm-dft-cli/storm-dft.cpp | 2 + src/storm-dft/parser/DFTGalileoParser.h | 4 +- src/storm-dft/parser/DFTJsonParser.h | 2 +- src/storm-gspn-cli/storm-gspn.cpp | 2 +- .../builder/ExplicitGspnModelBuilder.cpp | 2 +- src/storm-parsers/CMakeLists.txt | 42 +++++++++++ .../api/model_descriptions.cpp | 6 +- .../api/model_descriptions.h | 0 src/storm-parsers/api/properties.cpp | 71 +++++++++++++++++++ src/storm-parsers/api/properties.h | 43 +++++++++++ src/storm-parsers/api/storm-parsers.h | 4 ++ .../AtomicPropositionLabelingParser.cpp | 4 +- .../parser/AtomicPropositionLabelingParser.h | 0 .../parser/AutoParser.cpp | 10 +-- .../parser/AutoParser.h | 0 .../parser/DeterministicModelParser.cpp | 8 +-- .../parser/DeterministicModelParser.h | 0 .../DeterministicSparseTransitionParser.cpp | 4 +- .../DeterministicSparseTransitionParser.h | 0 .../parser/DirectEncodingParser.cpp | 2 +- .../parser/DirectEncodingParser.h | 2 +- .../parser/ExpressionCreator.cpp | 0 .../parser/ExpressionCreator.h | 2 +- .../parser/ExpressionParser.cpp | 4 +- .../parser/ExpressionParser.h | 4 +- .../parser/FormulaParser.cpp | 4 +- .../parser/FormulaParser.h | 4 +- .../parser/FormulaParserGrammar.cpp | 0 .../parser/FormulaParserGrammar.h | 4 +- .../parser/ImcaMarkovAutomatonParser.cpp | 2 +- .../parser/ImcaMarkovAutomatonParser.h | 2 +- .../parser/JaniParser.cpp | 0 .../parser/JaniParser.h | 0 .../parser/KeyValueParser.cpp | 0 .../parser/KeyValueParser.h | 0 .../parser/MappedFile.cpp | 2 +- .../parser/MappedFile.h | 0 .../parser/MarkovAutomatonParser.cpp | 0 .../parser/MarkovAutomatonParser.h | 2 +- .../MarkovAutomatonSparseTransitionParser.cpp | 2 +- .../MarkovAutomatonSparseTransitionParser.h | 0 .../parser/NondeterministicModelParser.cpp | 8 +-- .../parser/NondeterministicModelParser.h | 0 ...NondeterministicSparseTransitionParser.cpp | 4 +- .../NondeterministicSparseTransitionParser.h | 0 .../parser/PrismParser.cpp | 4 +- .../parser/PrismParser.h | 4 +- .../parser/ReadValues.h | 0 .../parser/SparseChoiceLabelingParser.cpp | 4 +- .../parser/SparseChoiceLabelingParser.h | 0 .../parser/SparseItemLabelingParser.cpp | 4 +- .../parser/SparseItemLabelingParser.h | 2 +- .../parser/SparseStateRewardParser.cpp | 4 +- .../parser/SparseStateRewardParser.h | 0 .../parser/SpiritErrorHandler.h | 2 +- .../parser/SpiritParserDefinitions.h | 0 .../parser/ValueParser.cpp | 2 +- .../parser/ValueParser.h | 2 +- src/storm-pgcl/parser/PgclParser.h | 6 +- src/storm/CMakeLists.txt | 2 - src/storm/api/builder.h | 6 +- src/storm/api/properties.cpp | 51 ------------- src/storm/api/properties.h | 12 +--- src/storm/api/storm.h | 1 - src/test/storm-pars/CMakeLists.txt | 2 +- .../ParametricDtmcPrctlModelCheckerTest.cpp | 6 +- .../SparseDtmcParameterLiftingTest.cpp | 2 + .../SparseMdpParameterLiftingTest.cpp | 2 + ...licParametricDtmcPrctlModelCheckerTest.cpp | 4 +- .../utility/ModelInstantiatorTest.cpp | 1 + src/test/storm/CMakeLists.txt | 2 +- .../storm/abstraction/PrismMenuGameTest.cpp | 2 +- .../storm/builder/DdJaniModelBuilderTest.cpp | 2 +- .../storm/builder/DdPrismModelBuilderTest.cpp | 2 +- .../builder/ExplicitJaniModelBuilderTest.cpp | 2 +- .../ExplicitJitJaniModelBuilderTest.cpp | 2 +- .../builder/ExplicitPrismModelBuilderTest.cpp | 2 +- src/test/storm/logic/FragmentCheckerTest.cpp | 2 +- .../ConditionalDtmcPrctlModelCheckerTest.cpp | 4 +- .../modelchecker/CtmcCslModelCheckerTest.cpp | 7 +- .../DtmcPrctlModelCheckerTest.cpp | 7 +- .../ExplicitDtmcPrctlModelCheckerTest.cpp | 6 +- .../ExplicitMdpPrctlModelCheckerTest.cpp | 6 +- .../GameBasedDtmcModelCheckerTest.cpp | 4 +- .../GameBasedMdpModelCheckerTest.cpp | 4 +- .../LraDtmcPrctlModelCheckerTest.cpp | 4 +- .../LraMdpPrctlModelCheckerTest.cpp | 4 +- .../modelchecker/MdpPrctlModelCheckerTest.cpp | 3 +- ...ulerGenerationMdpPrctlModelCheckerTest.cpp | 6 +- .../SparseDtmcEliminationModelCheckerTest.cpp | 4 +- ...tmcMultiDimensionalRewardUnfoldingTest.cpp | 1 + .../SparseExplorationModelCheckerTest.cpp | 4 +- ...arseMaCbMultiObjectiveModelCheckerTest.cpp | 1 + ...seMaPcaaMultiObjectiveModelCheckerTest.cpp | 1 + ...rseMdpCbMultiObjectiveModelCheckerTest.cpp | 1 + ...MdpMultiDimensionalRewardUnfoldingTest.cpp | 1 + ...eMdpPcaaMultiObjectiveModelCheckerTest.cpp | 1 + src/test/storm/parser/AutoParserTest.cpp | 2 +- .../parser/DeterministicModelParserTest.cpp | 2 +- ...eterministicSparseTransitionParserTest.cpp | 2 +- .../storm/parser/DirectEncodingParserTest.cpp | 2 +- src/test/storm/parser/FormulaParserTest.cpp | 2 +- src/test/storm/parser/MappedFileTest.cpp | 2 +- .../parser/MarkovAutomatonParserTest.cpp | 2 +- ...kovAutomatonSparseTransitionParserTest.cpp | 4 +- .../NondeterministicModelParserTest.cpp | 2 +- ...eterministicSparseTransitionParserTest.cpp | 2 +- src/test/storm/parser/PrismParserTest.cpp | 2 +- .../parser/SparseItemLabelingParserTest.cpp | 2 +- .../parser/SparseStateRewardParserTest.cpp | 2 +- .../MilpPermissiveSchedulerTest.cpp | 4 +- .../SmtPermissiveSchedulerTest.cpp | 4 +- ...sticModelBisimulationDecompositionTest.cpp | 4 +- src/test/storm/storage/JaniModelTest.cpp | 2 +- .../MaximalEndComponentDecompositionTest.cpp | 4 +- ...sticModelBisimulationDecompositionTest.cpp | 4 +- src/test/storm/storage/PrismProgramTest.cpp | 2 +- ...glyConnectedComponentDecompositionTest.cpp | 2 +- .../SymbolicBisimulationDecompositionTest.cpp | 6 +- src/test/storm/utility/GraphTest.cpp | 2 +- src/test/storm/utility/KSPTest.cpp | 2 +- 124 files changed, 322 insertions(+), 206 deletions(-) create mode 100644 src/storm-parsers/CMakeLists.txt rename src/{storm => storm-parsers}/api/model_descriptions.cpp (88%) rename src/{storm => storm-parsers}/api/model_descriptions.h (100%) create mode 100644 src/storm-parsers/api/properties.cpp create mode 100644 src/storm-parsers/api/properties.h create mode 100644 src/storm-parsers/api/storm-parsers.h rename src/{storm => storm-parsers}/parser/AtomicPropositionLabelingParser.cpp (98%) rename src/{storm => storm-parsers}/parser/AtomicPropositionLabelingParser.h (100%) rename src/{storm => storm-parsers}/parser/AutoParser.cpp (95%) rename src/{storm => storm-parsers}/parser/AutoParser.h (100%) rename src/{storm => storm-parsers}/parser/DeterministicModelParser.cpp (95%) rename src/{storm => storm-parsers}/parser/DeterministicModelParser.h (100%) rename src/{storm => storm-parsers}/parser/DeterministicSparseTransitionParser.cpp (99%) rename src/{storm => storm-parsers}/parser/DeterministicSparseTransitionParser.h (100%) rename src/{storm => storm-parsers}/parser/DirectEncodingParser.cpp (99%) rename src/{storm => storm-parsers}/parser/DirectEncodingParser.h (97%) rename src/{storm => storm-parsers}/parser/ExpressionCreator.cpp (100%) rename src/{storm => storm-parsers}/parser/ExpressionCreator.h (98%) rename src/{storm => storm-parsers}/parser/ExpressionParser.cpp (99%) rename src/{storm => storm-parsers}/parser/ExpressionParser.h (99%) rename src/{storm => storm-parsers}/parser/FormulaParser.cpp (98%) rename src/{storm => storm-parsers}/parser/FormulaParser.h (96%) rename src/{storm => storm-parsers}/parser/FormulaParserGrammar.cpp (100%) rename src/{storm => storm-parsers}/parser/FormulaParserGrammar.h (99%) rename src/{storm => storm-parsers}/parser/ImcaMarkovAutomatonParser.cpp (99%) rename src/{storm => storm-parsers}/parser/ImcaMarkovAutomatonParser.h (98%) rename src/{storm => storm-parsers}/parser/JaniParser.cpp (100%) rename src/{storm => storm-parsers}/parser/JaniParser.h (100%) rename src/{storm => storm-parsers}/parser/KeyValueParser.cpp (100%) rename src/{storm => storm-parsers}/parser/KeyValueParser.h (100%) rename src/{storm => storm-parsers}/parser/MappedFile.cpp (98%) rename src/{storm => storm-parsers}/parser/MappedFile.h (100%) rename src/{storm => storm-parsers}/parser/MarkovAutomatonParser.cpp (100%) rename src/{storm => storm-parsers}/parser/MarkovAutomatonParser.h (96%) rename src/{storm => storm-parsers}/parser/MarkovAutomatonSparseTransitionParser.cpp (99%) rename src/{storm => storm-parsers}/parser/MarkovAutomatonSparseTransitionParser.h (100%) rename src/{storm => storm-parsers}/parser/NondeterministicModelParser.cpp (93%) rename src/{storm => storm-parsers}/parser/NondeterministicModelParser.h (100%) rename src/{storm => storm-parsers}/parser/NondeterministicSparseTransitionParser.cpp (99%) rename src/{storm => storm-parsers}/parser/NondeterministicSparseTransitionParser.h (100%) rename src/{storm => storm-parsers}/parser/PrismParser.cpp (99%) rename src/{storm => storm-parsers}/parser/PrismParser.h (99%) rename src/{storm => storm-parsers}/parser/ReadValues.h (100%) rename src/{storm => storm-parsers}/parser/SparseChoiceLabelingParser.cpp (97%) rename src/{storm => storm-parsers}/parser/SparseChoiceLabelingParser.h (100%) rename src/{storm => storm-parsers}/parser/SparseItemLabelingParser.cpp (99%) rename src/{storm => storm-parsers}/parser/SparseItemLabelingParser.h (98%) rename src/{storm => storm-parsers}/parser/SparseStateRewardParser.cpp (96%) rename src/{storm => storm-parsers}/parser/SparseStateRewardParser.h (100%) rename src/{storm => storm-parsers}/parser/SpiritErrorHandler.h (95%) rename src/{storm => storm-parsers}/parser/SpiritParserDefinitions.h (100%) rename src/{storm => storm-parsers}/parser/ValueParser.cpp (96%) rename src/{storm => storm-parsers}/parser/ValueParser.h (97%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f277386d..7239a9676 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_custom_target(binaries) add_subdirectory(storm) add_subdirectory(storm-counterexamples) +add_subdirectory(storm-parsers) add_subdirectory(storm-cli-utilities) add_subdirectory(storm-pgcl) add_subdirectory(storm-pgcl-cli) diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index 5e37b5db4..de4c0fde1 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index b57818c08..41faf8732 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -3,6 +3,7 @@ #include "storm/api/storm.h" #include "storm-counterexamples/api/counterexamples.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/utility/resources.h" #include "storm/utility/file.h" diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index ce31be5b8..395985f7e 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -7,6 +7,8 @@ #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/GeneralSettings.h" + +#include "storm-parsers/api/storm-parsers.h" #include "storm/utility/initialize.h" #include "storm-cli-utilities/cli.h" diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index c56540edd..f956d8cb9 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -3,12 +3,12 @@ #include #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" #include "storm-dft/builder/DFTBuilder.h" -#include "storm/parser/ValueParser.h" +#include "storm-parsers/parser/ValueParser.h" namespace storm { diff --git a/src/storm-dft/parser/DFTJsonParser.h b/src/storm-dft/parser/DFTJsonParser.h index 5517d85e1..3b6812a76 100644 --- a/src/storm-dft/parser/DFTJsonParser.h +++ b/src/storm-dft/parser/DFTJsonParser.h @@ -3,7 +3,7 @@ #include #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 602b353a0..99d60b0d7 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -14,7 +14,7 @@ #include "api/storm.h" #include "storm-cli-utilities/cli.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/jani/Model.h" diff --git a/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp b/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp index 1960a623a..23ba78594 100644 --- a/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp +++ b/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp @@ -5,7 +5,7 @@ //#include "storm/utility/macros.h" //#include "storm/exceptions/NotImplementedException.h" //#include "storm/storage/expressions/ExpressionManager.h" -//#include "storm/parser/FormulaParser.h" +//#include "storm-parsers/parser/FormulaParser.h" //#include "storm/storage/expressions/ExpressionEvaluator.h" // //namespace storm { diff --git a/src/storm-parsers/CMakeLists.txt b/src/storm-parsers/CMakeLists.txt new file mode 100644 index 000000000..d459345e4 --- /dev/null +++ b/src/storm-parsers/CMakeLists.txt @@ -0,0 +1,42 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-parsers/*.h ${PROJECT_SOURCE_DIR}/src/storm-parsers/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-parsers) + + + +file(GLOB_RECURSE STORM_PARSER_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-parsers/*/*.cpp) +file(GLOB_RECURSE STORM_PARSER_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-parsers/*/*.h) + + +# Disable Debug compiler flags for PrismParser to lessen memory consumption during compilation +SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/storm-parsers/parser/PrismParser.cpp PROPERTIES COMPILE_FLAGS -g0) +# Create storm-dft. +add_library(storm-parsers SHARED ${STORM_PARSER_SOURCES} ${STORM_PARSER_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-parsers PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-parsers) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-parsers PUBLIC storm) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_PARSER_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_PARSER_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_parser_headers DEPENDS ${STORM_PARSER_OUTPUT_HEADERS} ${STORM_PARSER_HEADERS}) +add_dependencies(storm-parsers copy_storm_parser_headers) + +# installation +install(TARGETS storm-parsers EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm/api/model_descriptions.cpp b/src/storm-parsers/api/model_descriptions.cpp similarity index 88% rename from src/storm/api/model_descriptions.cpp rename to src/storm-parsers/api/model_descriptions.cpp index 76ce24116..a440dffef 100644 --- a/src/storm/api/model_descriptions.cpp +++ b/src/storm-parsers/api/model_descriptions.cpp @@ -1,7 +1,7 @@ -#include "storm/api/model_descriptions.h" +#include "model_descriptions.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/JaniParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/JaniParser.h" #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" diff --git a/src/storm/api/model_descriptions.h b/src/storm-parsers/api/model_descriptions.h similarity index 100% rename from src/storm/api/model_descriptions.h rename to src/storm-parsers/api/model_descriptions.h diff --git a/src/storm-parsers/api/properties.cpp b/src/storm-parsers/api/properties.cpp new file mode 100644 index 000000000..d5349544d --- /dev/null +++ b/src/storm-parsers/api/properties.cpp @@ -0,0 +1,71 @@ + + +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/api/properties.h" + + +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/prism/Program.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +#include "storm/logic/Formula.h" + +#include "storm/utility/cli.h" + + +namespace storm { + namespace api { + + boost::optional > parsePropertyFilter(std::string const &propertyFilter) { + if (propertyFilter == "all") { + return boost::none; + } + std::vector propertyNames = storm::utility::cli::parseCommaSeparatedStrings(propertyFilter); + std::set propertyNameSet(propertyNames.begin(), propertyNames.end()); + return propertyNameSet; + } + + std::vector parseProperties(storm::parser::FormulaParser &formulaParser, std::string const &inputString, boost::optional > const &propertyFilter) { + // If the given property is a file, we parse it as a file, otherwise we assume it's a property. + std::vector properties; + if (std::ifstream(inputString).good()) { + STORM_LOG_INFO("Loading properties from file: " << inputString << std::endl); + properties = formulaParser.parseFromFile(inputString); + } else { + properties = formulaParser.parseFromString(inputString); + } + + return filterProperties(properties, propertyFilter); + } + + std::vector parseProperties(std::string const &inputString, boost::optional > const &propertyFilter) { + auto exprManager = std::make_shared(); + storm::parser::FormulaParser formulaParser(exprManager); + return parseProperties(formulaParser, inputString, propertyFilter); + } + + std::vector parsePropertiesForJaniModel(std::string const &inputString, storm::jani::Model const &model, boost::optional > const &propertyFilter) { + storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); + auto formulas = parseProperties(formulaParser, inputString, propertyFilter); + return substituteConstantsInProperties(formulas, model.getConstantsSubstitution()); + } + + std::vector parsePropertiesForPrismProgram(std::string const &inputString, storm::prism::Program const &program, boost::optional > const &propertyFilter) { + storm::parser::FormulaParser formulaParser(program); + auto formulas = parseProperties(formulaParser, inputString, propertyFilter); + return substituteConstantsInProperties(formulas, program.getConstantsSubstitution()); + } + + std::vector parsePropertiesForSymbolicModelDescription(std::string const &inputString, storm::storage::SymbolicModelDescription const &modelDescription, boost::optional > const &propertyFilter) { + std::vector result; + if (modelDescription.isPrismProgram()) { + result = storm::api::parsePropertiesForPrismProgram(inputString, modelDescription.asPrismProgram(), propertyFilter); + } else { + STORM_LOG_ASSERT(modelDescription.isJaniModel(), "Unknown model description type."); + result = storm::api::parsePropertiesForJaniModel(inputString, modelDescription.asJaniModel(), propertyFilter); + } + return result; + } + } +} \ No newline at end of file diff --git a/src/storm-parsers/api/properties.h b/src/storm-parsers/api/properties.h new file mode 100644 index 000000000..81d37d965 --- /dev/null +++ b/src/storm-parsers/api/properties.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace storm { + namespace parser { + class FormulaParser; + } + namespace jani { + class Property; + class Model; + } + namespace expressions { + class Variable; + class Expression; + } + namespace prism { + class Program; + } + namespace storage { + class SymbolicModelDescription; + } + namespace logic { + class Formula; + } + + namespace api { + boost::optional> parsePropertyFilter(std::string const& propertyFilter); + + // Parsing properties. + std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter = boost::none); + std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter = boost::none); + + } +} diff --git a/src/storm-parsers/api/storm-parsers.h b/src/storm-parsers/api/storm-parsers.h new file mode 100644 index 000000000..b88188976 --- /dev/null +++ b/src/storm-parsers/api/storm-parsers.h @@ -0,0 +1,4 @@ +#pragma once + +#include "storm-parsers/api/model_descriptions.h" +#include "storm-parsers/api/properties.h" \ No newline at end of file diff --git a/src/storm/parser/AtomicPropositionLabelingParser.cpp b/src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp similarity index 98% rename from src/storm/parser/AtomicPropositionLabelingParser.cpp rename to src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp index 4d55b4fe8..a8afc93d7 100644 --- a/src/storm/parser/AtomicPropositionLabelingParser.cpp +++ b/src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp @@ -5,14 +5,14 @@ * Author: Gereon Kremer */ -#include "storm/parser/AtomicPropositionLabelingParser.h" +#include "storm-parsers/parser/AtomicPropositionLabelingParser.h" #include #include #include #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/storm/parser/AtomicPropositionLabelingParser.h b/src/storm-parsers/parser/AtomicPropositionLabelingParser.h similarity index 100% rename from src/storm/parser/AtomicPropositionLabelingParser.h rename to src/storm-parsers/parser/AtomicPropositionLabelingParser.h diff --git a/src/storm/parser/AutoParser.cpp b/src/storm-parsers/parser/AutoParser.cpp similarity index 95% rename from src/storm/parser/AutoParser.cpp rename to src/storm-parsers/parser/AutoParser.cpp index 896c4215e..9e96af5e6 100644 --- a/src/storm/parser/AutoParser.cpp +++ b/src/storm-parsers/parser/AutoParser.cpp @@ -1,12 +1,12 @@ -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" -#include "storm/parser/DeterministicModelParser.h" -#include "storm/parser/NondeterministicModelParser.h" -#include "storm/parser/MarkovAutomatonParser.h" +#include "storm-parsers/parser/DeterministicModelParser.h" +#include "storm-parsers/parser/NondeterministicModelParser.h" +#include "storm-parsers/parser/MarkovAutomatonParser.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/AutoParser.h b/src/storm-parsers/parser/AutoParser.h similarity index 100% rename from src/storm/parser/AutoParser.h rename to src/storm-parsers/parser/AutoParser.h diff --git a/src/storm/parser/DeterministicModelParser.cpp b/src/storm-parsers/parser/DeterministicModelParser.cpp similarity index 95% rename from src/storm/parser/DeterministicModelParser.cpp rename to src/storm-parsers/parser/DeterministicModelParser.cpp index cfe5a16df..6b81c0630 100644 --- a/src/storm/parser/DeterministicModelParser.cpp +++ b/src/storm-parsers/parser/DeterministicModelParser.cpp @@ -1,13 +1,13 @@ -#include "storm/parser/DeterministicModelParser.h" +#include "storm-parsers/parser/DeterministicModelParser.h" #include #include #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/DeterministicSparseTransitionParser.h" -#include "storm/parser/SparseItemLabelingParser.h" -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/DeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/parser/DeterministicModelParser.h b/src/storm-parsers/parser/DeterministicModelParser.h similarity index 100% rename from src/storm/parser/DeterministicModelParser.h rename to src/storm-parsers/parser/DeterministicModelParser.h diff --git a/src/storm/parser/DeterministicSparseTransitionParser.cpp b/src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/DeterministicSparseTransitionParser.cpp rename to src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp index 540371f74..229cc3c2e 100644 --- a/src/storm/parser/DeterministicSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/DeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/DeterministicSparseTransitionParser.h" #include #include @@ -9,7 +9,7 @@ #include "storm/utility/constants.h" #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" diff --git a/src/storm/parser/DeterministicSparseTransitionParser.h b/src/storm-parsers/parser/DeterministicSparseTransitionParser.h similarity index 100% rename from src/storm/parser/DeterministicSparseTransitionParser.h rename to src/storm-parsers/parser/DeterministicSparseTransitionParser.h diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm-parsers/parser/DirectEncodingParser.cpp similarity index 99% rename from src/storm/parser/DirectEncodingParser.cpp rename to src/storm-parsers/parser/DirectEncodingParser.cpp index 93d8a60f2..da4cd5228 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm-parsers/parser/DirectEncodingParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/DirectEncodingParser.h" +#include "storm-parsers/parser/DirectEncodingParser.h" #include #include diff --git a/src/storm/parser/DirectEncodingParser.h b/src/storm-parsers/parser/DirectEncodingParser.h similarity index 97% rename from src/storm/parser/DirectEncodingParser.h rename to src/storm-parsers/parser/DirectEncodingParser.h index 456445e1c..f025b8dfc 100644 --- a/src/storm/parser/DirectEncodingParser.h +++ b/src/storm-parsers/parser/DirectEncodingParser.h @@ -1,7 +1,7 @@ #ifndef STORM_PARSER_DIRECTENCODINGPARSER_H_ #define STORM_PARSER_DIRECTENCODINGPARSER_H_ -#include "storm/parser/ValueParser.h" +#include "storm-parsers/parser/ValueParser.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/storage/sparse/ModelComponents.h" diff --git a/src/storm/parser/ExpressionCreator.cpp b/src/storm-parsers/parser/ExpressionCreator.cpp similarity index 100% rename from src/storm/parser/ExpressionCreator.cpp rename to src/storm-parsers/parser/ExpressionCreator.cpp diff --git a/src/storm/parser/ExpressionCreator.h b/src/storm-parsers/parser/ExpressionCreator.h similarity index 98% rename from src/storm/parser/ExpressionCreator.h rename to src/storm-parsers/parser/ExpressionCreator.h index 20bcc5854..814dc964a 100644 --- a/src/storm/parser/ExpressionCreator.h +++ b/src/storm-parsers/parser/ExpressionCreator.h @@ -1,7 +1,7 @@ #pragma once #include // Very ugly, but currently we would like to have the symbol table here. -#include "storm/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" #include #include "storm/adapters/RationalNumberAdapter.h" diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm-parsers/parser/ExpressionParser.cpp similarity index 99% rename from src/storm/parser/ExpressionParser.cpp rename to src/storm-parsers/parser/ExpressionParser.cpp index 64e185b54..d1d6dcaf0 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm-parsers/parser/ExpressionParser.cpp @@ -1,10 +1,10 @@ -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/utility/constants.h" -#include "storm/parser/ExpressionCreator.h" +#include "storm-parsers/parser/ExpressionCreator.h" #include "storm/storage/expressions/Expression.h" diff --git a/src/storm/parser/ExpressionParser.h b/src/storm-parsers/parser/ExpressionParser.h similarity index 99% rename from src/storm/parser/ExpressionParser.h rename to src/storm-parsers/parser/ExpressionParser.h index cb415c53e..4fa075adc 100644 --- a/src/storm/parser/ExpressionParser.h +++ b/src/storm-parsers/parser/ExpressionParser.h @@ -2,8 +2,8 @@ #include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/expressions/OperatorType.h" #include "storm/adapters/RationalNumberAdapter.h" diff --git a/src/storm/parser/FormulaParser.cpp b/src/storm-parsers/parser/FormulaParser.cpp similarity index 98% rename from src/storm/parser/FormulaParser.cpp rename to src/storm-parsers/parser/FormulaParser.cpp index d8b9c2df2..0f44d469b 100644 --- a/src/storm/parser/FormulaParser.cpp +++ b/src/storm-parsers/parser/FormulaParser.cpp @@ -1,8 +1,8 @@ -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/prism/Program.h" diff --git a/src/storm/parser/FormulaParser.h b/src/storm-parsers/parser/FormulaParser.h similarity index 96% rename from src/storm/parser/FormulaParser.h rename to src/storm-parsers/parser/FormulaParser.h index d9c06fa92..49c78a720 100644 --- a/src/storm/parser/FormulaParser.h +++ b/src/storm-parsers/parser/FormulaParser.h @@ -3,8 +3,8 @@ #include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/jani/Property.h" #include "storm/storage/expressions/Expression.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp similarity index 100% rename from src/storm/parser/FormulaParserGrammar.cpp rename to src/storm-parsers/parser/FormulaParserGrammar.cpp diff --git a/src/storm/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h similarity index 99% rename from src/storm/parser/FormulaParserGrammar.h rename to src/storm-parsers/parser/FormulaParserGrammar.h index dd9a3a06f..c9d5ae020 100644 --- a/src/storm/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -3,11 +3,11 @@ #include #include -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/storage/jani/Property.h" #include "storm/logic/Formulas.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/modelchecker/results/FilterType.h" diff --git a/src/storm/parser/ImcaMarkovAutomatonParser.cpp b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp similarity index 99% rename from src/storm/parser/ImcaMarkovAutomatonParser.cpp rename to src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp index f55d09219..0cbf917f1 100644 --- a/src/storm/parser/ImcaMarkovAutomatonParser.cpp +++ b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/ImcaMarkovAutomatonParser.h" +#include "storm-parsers/parser/ImcaMarkovAutomatonParser.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BuildSettings.h" diff --git a/src/storm/parser/ImcaMarkovAutomatonParser.h b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.h similarity index 98% rename from src/storm/parser/ImcaMarkovAutomatonParser.h rename to src/storm-parsers/parser/ImcaMarkovAutomatonParser.h index f2820242e..b5c7beded 100644 --- a/src/storm/parser/ImcaMarkovAutomatonParser.h +++ b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.h @@ -7,7 +7,7 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/generator/StateBehavior.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" namespace storm { namespace parser { diff --git a/src/storm/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp similarity index 100% rename from src/storm/parser/JaniParser.cpp rename to src/storm-parsers/parser/JaniParser.cpp diff --git a/src/storm/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h similarity index 100% rename from src/storm/parser/JaniParser.h rename to src/storm-parsers/parser/JaniParser.h diff --git a/src/storm/parser/KeyValueParser.cpp b/src/storm-parsers/parser/KeyValueParser.cpp similarity index 100% rename from src/storm/parser/KeyValueParser.cpp rename to src/storm-parsers/parser/KeyValueParser.cpp diff --git a/src/storm/parser/KeyValueParser.h b/src/storm-parsers/parser/KeyValueParser.h similarity index 100% rename from src/storm/parser/KeyValueParser.h rename to src/storm-parsers/parser/KeyValueParser.h diff --git a/src/storm/parser/MappedFile.cpp b/src/storm-parsers/parser/MappedFile.cpp similarity index 98% rename from src/storm/parser/MappedFile.cpp rename to src/storm-parsers/parser/MappedFile.cpp index 5b9f02714..d28e8e927 100644 --- a/src/storm/parser/MappedFile.cpp +++ b/src/storm-parsers/parser/MappedFile.cpp @@ -5,7 +5,7 @@ * Author: Manuel Sascha Weiand */ -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include #include diff --git a/src/storm/parser/MappedFile.h b/src/storm-parsers/parser/MappedFile.h similarity index 100% rename from src/storm/parser/MappedFile.h rename to src/storm-parsers/parser/MappedFile.h diff --git a/src/storm/parser/MarkovAutomatonParser.cpp b/src/storm-parsers/parser/MarkovAutomatonParser.cpp similarity index 100% rename from src/storm/parser/MarkovAutomatonParser.cpp rename to src/storm-parsers/parser/MarkovAutomatonParser.cpp diff --git a/src/storm/parser/MarkovAutomatonParser.h b/src/storm-parsers/parser/MarkovAutomatonParser.h similarity index 96% rename from src/storm/parser/MarkovAutomatonParser.h rename to src/storm-parsers/parser/MarkovAutomatonParser.h index 763ece141..1f2087674 100644 --- a/src/storm/parser/MarkovAutomatonParser.h +++ b/src/storm-parsers/parser/MarkovAutomatonParser.h @@ -2,7 +2,7 @@ #define STORM_PARSER_MARKOVAUTOMATONPARSER_H_ #include "storm/models/sparse/MarkovAutomaton.h" -#include "storm/parser/MarkovAutomatonSparseTransitionParser.h" +#include "storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h" namespace storm { namespace parser { diff --git a/src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp rename to src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp index 25b62a2e2..9acd151b0 100644 --- a/src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp @@ -4,7 +4,7 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/FileIoException.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/cstring.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/MarkovAutomatonSparseTransitionParser.h b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h similarity index 100% rename from src/storm/parser/MarkovAutomatonSparseTransitionParser.h rename to src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h diff --git a/src/storm/parser/NondeterministicModelParser.cpp b/src/storm-parsers/parser/NondeterministicModelParser.cpp similarity index 93% rename from src/storm/parser/NondeterministicModelParser.cpp rename to src/storm-parsers/parser/NondeterministicModelParser.cpp index c107803eb..b26626fb0 100644 --- a/src/storm/parser/NondeterministicModelParser.cpp +++ b/src/storm-parsers/parser/NondeterministicModelParser.cpp @@ -1,13 +1,13 @@ -#include "storm/parser/NondeterministicModelParser.h" +#include "storm-parsers/parser/NondeterministicModelParser.h" #include #include #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/NondeterministicSparseTransitionParser.h" -#include "storm/parser/SparseItemLabelingParser.h" -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/NondeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/NondeterministicModelParser.h b/src/storm-parsers/parser/NondeterministicModelParser.h similarity index 100% rename from src/storm/parser/NondeterministicModelParser.h rename to src/storm-parsers/parser/NondeterministicModelParser.h diff --git a/src/storm/parser/NondeterministicSparseTransitionParser.cpp b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/NondeterministicSparseTransitionParser.cpp rename to src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp index cb941aec5..56b00070c 100644 --- a/src/storm/parser/NondeterministicSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp @@ -1,8 +1,8 @@ -#include "storm/parser/NondeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/NondeterministicSparseTransitionParser.h" #include -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/storm/parser/NondeterministicSparseTransitionParser.h b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.h similarity index 100% rename from src/storm/parser/NondeterministicSparseTransitionParser.h rename to src/storm-parsers/parser/NondeterministicSparseTransitionParser.h diff --git a/src/storm/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp similarity index 99% rename from src/storm/parser/PrismParser.cpp rename to src/storm-parsers/parser/PrismParser.cpp index ca59981cb..5d76736f7 100644 --- a/src/storm/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/prism/Compositions.h" @@ -11,7 +11,7 @@ #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" namespace storm { namespace parser { diff --git a/src/storm/parser/PrismParser.h b/src/storm-parsers/parser/PrismParser.h similarity index 99% rename from src/storm/parser/PrismParser.h rename to src/storm-parsers/parser/PrismParser.h index fe7f0bc83..38a112e9d 100644 --- a/src/storm/parser/PrismParser.h +++ b/src/storm-parsers/parser/PrismParser.h @@ -6,8 +6,8 @@ #include #include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/prism/Program.h" #include "storm/storage/expressions/Expression.h" diff --git a/src/storm/parser/ReadValues.h b/src/storm-parsers/parser/ReadValues.h similarity index 100% rename from src/storm/parser/ReadValues.h rename to src/storm-parsers/parser/ReadValues.h diff --git a/src/storm/parser/SparseChoiceLabelingParser.cpp b/src/storm-parsers/parser/SparseChoiceLabelingParser.cpp similarity index 97% rename from src/storm/parser/SparseChoiceLabelingParser.cpp rename to src/storm-parsers/parser/SparseChoiceLabelingParser.cpp index b51e8b97c..452045319 100644 --- a/src/storm/parser/SparseChoiceLabelingParser.cpp +++ b/src/storm-parsers/parser/SparseChoiceLabelingParser.cpp @@ -1,10 +1,10 @@ -#include "storm/parser/SparseChoiceLabelingParser.h" +#include "storm-parsers/parser/SparseChoiceLabelingParser.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" #include "storm/exceptions/FileIoException.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/cstring.h" namespace storm { diff --git a/src/storm/parser/SparseChoiceLabelingParser.h b/src/storm-parsers/parser/SparseChoiceLabelingParser.h similarity index 100% rename from src/storm/parser/SparseChoiceLabelingParser.h rename to src/storm-parsers/parser/SparseChoiceLabelingParser.h diff --git a/src/storm/parser/SparseItemLabelingParser.cpp b/src/storm-parsers/parser/SparseItemLabelingParser.cpp similarity index 99% rename from src/storm/parser/SparseItemLabelingParser.cpp rename to src/storm-parsers/parser/SparseItemLabelingParser.cpp index 2e98e4673..9e5e7b154 100644 --- a/src/storm/parser/SparseItemLabelingParser.cpp +++ b/src/storm-parsers/parser/SparseItemLabelingParser.cpp @@ -1,11 +1,11 @@ -#include "storm/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" #include #include #include #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/SparseItemLabelingParser.h b/src/storm-parsers/parser/SparseItemLabelingParser.h similarity index 98% rename from src/storm/parser/SparseItemLabelingParser.h rename to src/storm-parsers/parser/SparseItemLabelingParser.h index 4b901ab82..97c30cc25 100644 --- a/src/storm/parser/SparseItemLabelingParser.h +++ b/src/storm-parsers/parser/SparseItemLabelingParser.h @@ -4,7 +4,7 @@ #include #include -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/models/sparse/StateLabeling.h" #include "storm/models/sparse/ChoiceLabeling.h" diff --git a/src/storm/parser/SparseStateRewardParser.cpp b/src/storm-parsers/parser/SparseStateRewardParser.cpp similarity index 96% rename from src/storm/parser/SparseStateRewardParser.cpp rename to src/storm-parsers/parser/SparseStateRewardParser.cpp index f42b4cbe8..acb67e9fb 100644 --- a/src/storm/parser/SparseStateRewardParser.cpp +++ b/src/storm-parsers/parser/SparseStateRewardParser.cpp @@ -1,11 +1,11 @@ #include -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" #include "storm/exceptions/FileIoException.h" #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/SparseStateRewardParser.h b/src/storm-parsers/parser/SparseStateRewardParser.h similarity index 100% rename from src/storm/parser/SparseStateRewardParser.h rename to src/storm-parsers/parser/SparseStateRewardParser.h diff --git a/src/storm/parser/SpiritErrorHandler.h b/src/storm-parsers/parser/SpiritErrorHandler.h similarity index 95% rename from src/storm/parser/SpiritErrorHandler.h rename to src/storm-parsers/parser/SpiritErrorHandler.h index 34280e422..ab64008bc 100644 --- a/src/storm/parser/SpiritErrorHandler.h +++ b/src/storm-parsers/parser/SpiritErrorHandler.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/SpiritParserDefinitions.h b/src/storm-parsers/parser/SpiritParserDefinitions.h similarity index 100% rename from src/storm/parser/SpiritParserDefinitions.h rename to src/storm-parsers/parser/SpiritParserDefinitions.h diff --git a/src/storm/parser/ValueParser.cpp b/src/storm-parsers/parser/ValueParser.cpp similarity index 96% rename from src/storm/parser/ValueParser.cpp rename to src/storm-parsers/parser/ValueParser.cpp index 17495b0d9..61cd5c0ac 100644 --- a/src/storm/parser/ValueParser.cpp +++ b/src/storm-parsers/parser/ValueParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/ValueParser.h" +#include "storm-parsers/parser/ValueParser.h" #include "storm/exceptions/NotSupportedException.h" diff --git a/src/storm/parser/ValueParser.h b/src/storm-parsers/parser/ValueParser.h similarity index 97% rename from src/storm/parser/ValueParser.h rename to src/storm-parsers/parser/ValueParser.h index db948b75e..626857a3e 100644 --- a/src/storm/parser/ValueParser.h +++ b/src/storm-parsers/parser/ValueParser.h @@ -2,7 +2,7 @@ #define STORM_PARSER_VALUEPARSER_H_ #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm-pgcl/parser/PgclParser.h b/src/storm-pgcl/parser/PgclParser.h index dfd75a810..0e31094b9 100755 --- a/src/storm-pgcl/parser/PgclParser.h +++ b/src/storm-pgcl/parser/PgclParser.h @@ -5,9 +5,9 @@ #include #include // Includes files for building and parsing the PGCL program -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/Expression.h" #include "storm-pgcl/storage/pgcl/PgclProgram.h" diff --git a/src/storm/CMakeLists.txt b/src/storm/CMakeLists.txt index 6a8cda64e..dcd1bb9f9 100644 --- a/src/storm/CMakeLists.txt +++ b/src/storm/CMakeLists.txt @@ -28,8 +28,6 @@ if (ADDITIONAL_LINK_DIRS) link_directories(${ADDITIONAL_LINK_DIRS}) endif(ADDITIONAL_LINK_DIRS) -# Disable Debug compiler flags for PrismParser to lessen memory consumption during compilation -SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/storm/parser/PrismParser.cpp PROPERTIES COMPILE_FLAGS -g0) ############################################################################### ## diff --git a/src/storm/api/builder.h b/src/storm/api/builder.h index 715e6e1ac..8aa2e2e17 100644 --- a/src/storm/api/builder.h +++ b/src/storm/api/builder.h @@ -1,8 +1,8 @@ #pragma once -#include "storm/parser/AutoParser.h" -#include "storm/parser/DirectEncodingParser.h" -#include "storm/parser/ImcaMarkovAutomatonParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/DirectEncodingParser.h" +#include "storm-parsers/parser/ImcaMarkovAutomatonParser.h" #include "storm/storage/SymbolicModelDescription.h" diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index 163679013..e5010d8b9 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -1,6 +1,5 @@ #include "storm/api/properties.h" -#include "storm/parser/FormulaParser.h" #include "storm/storage/SymbolicModelDescription.h" #include "storm/storage/prism/Program.h" @@ -13,57 +12,7 @@ namespace storm { namespace api { - - boost::optional> parsePropertyFilter(std::string const& propertyFilter) { - if (propertyFilter == "all") { - return boost::none; - } - std::vector propertyNames = storm::utility::cli::parseCommaSeparatedStrings(propertyFilter); - std::set propertyNameSet(propertyNames.begin(), propertyNames.end()); - return propertyNameSet; - } - std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter) { - // If the given property is a file, we parse it as a file, otherwise we assume it's a property. - std::vector properties; - if (std::ifstream(inputString).good()) { - STORM_LOG_INFO("Loading properties from file: " << inputString << std::endl); - properties = formulaParser.parseFromFile(inputString); - } else { - properties = formulaParser.parseFromString(inputString); - } - - return filterProperties(properties, propertyFilter); - } - - std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter) { - auto exprManager = std::make_shared(); - storm::parser::FormulaParser formulaParser(exprManager); - return parseProperties(formulaParser, inputString, propertyFilter); - } - - std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter) { - storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); - auto formulas = parseProperties(formulaParser, inputString, propertyFilter); - return substituteConstantsInProperties(formulas, model.getConstantsSubstitution()); - } - - std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter) { - storm::parser::FormulaParser formulaParser(program); - auto formulas = parseProperties(formulaParser, inputString, propertyFilter); - return substituteConstantsInProperties(formulas, program.getConstantsSubstitution()); - } - - std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter) { - std::vector result; - if (modelDescription.isPrismProgram()) { - result = storm::api::parsePropertiesForPrismProgram(inputString, modelDescription.asPrismProgram(), propertyFilter); - } else { - STORM_LOG_ASSERT(modelDescription.isJaniModel(), "Unknown model description type."); - result = storm::api::parsePropertiesForJaniModel(inputString, modelDescription.asJaniModel(), propertyFilter); - } - return result; - } std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution) { std::vector preprocessedProperties; diff --git a/src/storm/api/properties.h b/src/storm/api/properties.h index c52073105..c0c878f48 100644 --- a/src/storm/api/properties.h +++ b/src/storm/api/properties.h @@ -8,9 +8,7 @@ #include namespace storm { - namespace parser { - class FormulaParser; - } + namespace jani { class Property; class Model; @@ -30,14 +28,6 @@ namespace storm { } namespace api { - boost::optional> parsePropertyFilter(std::string const& propertyFilter); - - // Parsing properties. - std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter = boost::none); - std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter = boost::none); // Process properties. std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution); diff --git a/src/storm/api/storm.h b/src/storm/api/storm.h index d8f6aed82..0048bc315 100644 --- a/src/storm/api/storm.h +++ b/src/storm/api/storm.h @@ -1,6 +1,5 @@ #pragma once -#include "storm/api/model_descriptions.h" #include "storm/api/properties.h" #include "storm/api/builder.h" #include "storm/api/bisimulation.h" diff --git a/src/test/storm-pars/CMakeLists.txt b/src/test/storm-pars/CMakeLists.txt index 0f2793553..28c5a391d 100644 --- a/src/test/storm-pars/CMakeLists.txt +++ b/src/test/storm-pars/CMakeLists.txt @@ -13,7 +13,7 @@ foreach (testsuite modelchecker utility) file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) add_executable (test-pars-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) - target_link_libraries(test-pars-${testsuite} storm-pars) + target_link_libraries(test-pars-${testsuite} storm-pars storm-parsers) target_link_libraries(test-pars-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) add_dependencies(test-pars-${testsuite} test-resources) diff --git a/src/test/storm-pars/modelchecker/ParametricDtmcPrctlModelCheckerTest.cpp b/src/test/storm-pars/modelchecker/ParametricDtmcPrctlModelCheckerTest.cpp index cf30285c5..91e08d2cf 100644 --- a/src/test/storm-pars/modelchecker/ParametricDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm-pars/modelchecker/ParametricDtmcPrctlModelCheckerTest.cpp @@ -2,13 +2,13 @@ #include "storm-config.h" #include "test/storm_gtest.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/parser/AutoParser.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/api/builder.h" diff --git a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp index dd6d59cf8..94bedf559 100644 --- a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp +++ b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp @@ -8,6 +8,8 @@ #include "storm-pars/api/storm-pars.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" + #include "storm/environment/solver/MinMaxSolverEnvironment.h" namespace { diff --git a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp index 3d3c97caa..48e71fd0b 100644 --- a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp +++ b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp @@ -8,6 +8,8 @@ #include "storm-pars/api/storm-pars.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" + #include "storm/environment/solver/MinMaxSolverEnvironment.h" namespace { diff --git a/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp b/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp index de5e6f849..f23a23e4a 100644 --- a/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm-pars/modelchecker/SymbolicParametricDtmcPrctlModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/utility/solver.h" #include "storm/storage/SymbolicModelDescription.h" @@ -9,7 +9,7 @@ #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQuantitativeCheckResult.h" #include "storm/solver/SymbolicEliminationLinearEquationSolver.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/DdPrismModelBuilder.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/symbolic/Dtmc.h" diff --git a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp index 1873a4436..fa7bb16eb 100644 --- a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp +++ b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp @@ -13,6 +13,7 @@ #include "storm-pars/utility/ModelInstantiator.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" diff --git a/src/test/storm/CMakeLists.txt b/src/test/storm/CMakeLists.txt index 0ae2fc509..c745943b4 100644 --- a/src/test/storm/CMakeLists.txt +++ b/src/test/storm/CMakeLists.txt @@ -13,7 +13,7 @@ foreach (testsuite abstraction adapter builder logic modelchecker parser permiss file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) add_executable (test-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) - target_link_libraries(test-${testsuite} storm) + target_link_libraries(test-${testsuite} storm storm-parsers) target_link_libraries(test-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) add_dependencies(test-${testsuite} test-resources) diff --git a/src/test/storm/abstraction/PrismMenuGameTest.cpp b/src/test/storm/abstraction/PrismMenuGameTest.cpp index a200c1d68..96c484d99 100644 --- a/src/test/storm/abstraction/PrismMenuGameTest.cpp +++ b/src/test/storm/abstraction/PrismMenuGameTest.cpp @@ -3,7 +3,7 @@ #ifdef STORM_HAVE_MSAT -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/abstraction/MenuGameRefiner.h" #include "storm/abstraction/prism/PrismMenuGameAbstractor.h" diff --git a/src/test/storm/builder/DdJaniModelBuilderTest.cpp b/src/test/storm/builder/DdJaniModelBuilderTest.cpp index fa657a96f..1515b83e3 100644 --- a/src/test/storm/builder/DdJaniModelBuilderTest.cpp +++ b/src/test/storm/builder/DdJaniModelBuilderTest.cpp @@ -10,7 +10,7 @@ #include "storm/storage/jani/Compositions.h" #include "storm/models/symbolic/StandardRewardModel.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/DdJaniModelBuilder.h" #include "storm/settings/SettingMemento.h" diff --git a/src/test/storm/builder/DdPrismModelBuilderTest.cpp b/src/test/storm/builder/DdPrismModelBuilderTest.cpp index 1ff4a79fe..a56aa1e12 100644 --- a/src/test/storm/builder/DdPrismModelBuilderTest.cpp +++ b/src/test/storm/builder/DdPrismModelBuilderTest.cpp @@ -8,7 +8,7 @@ #include "storm/models/symbolic/Ctmc.h" #include "storm/models/symbolic/Mdp.h" #include "storm/models/symbolic/StandardRewardModel.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/DdPrismModelBuilder.h" TEST(DdPrismModelBuilderTest_Sylvan, Dtmc) { diff --git a/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp index 4f21c3a64..95b690e96 100644 --- a/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp +++ b/src/test/storm/builder/ExplicitJaniModelBuilderTest.cpp @@ -3,7 +3,7 @@ #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/settings/SettingMemento.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/ExplicitModelBuilder.h" #include "storm/generator/JaniNextStateGenerator.h" #include "storm/storage/jani/Model.h" diff --git a/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp b/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp index 334735b02..c5c0eec05 100644 --- a/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp +++ b/src/test/storm/builder/ExplicitJitJaniModelBuilderTest.cpp @@ -3,7 +3,7 @@ #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/settings/SettingMemento.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/jit/ExplicitJitJaniModelBuilder.h" #include "storm/storage/jani/Model.h" diff --git a/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp b/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp index 8e5929618..65e1dff1d 100644 --- a/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp +++ b/src/test/storm/builder/ExplicitPrismModelBuilderTest.cpp @@ -2,7 +2,7 @@ #include "storm-config.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/MarkovAutomaton.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/ExplicitModelBuilder.h" diff --git a/src/test/storm/logic/FragmentCheckerTest.cpp b/src/test/storm/logic/FragmentCheckerTest.cpp index c846f7f68..5adf50028 100644 --- a/src/test/storm/logic/FragmentCheckerTest.cpp +++ b/src/test/storm/logic/FragmentCheckerTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/FragmentChecker.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/storage/expressions/ExpressionManager.h" diff --git a/src/test/storm/modelchecker/ConditionalDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/ConditionalDtmcPrctlModelCheckerTest.cpp index c0972c474..fd124f456 100644 --- a/src/test/storm/modelchecker/ConditionalDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/ConditionalDtmcPrctlModelCheckerTest.cpp @@ -2,12 +2,12 @@ #include "test/storm_gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/api/builder.h" #include "storm/storage/expressions/ExpressionManager.h" diff --git a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp index f2a790b9b..1b83be1c6 100644 --- a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp @@ -3,9 +3,10 @@ #include "storm-config.h" #include "storm/api/builder.h" -#include "storm/api/model_descriptions.h" +#include "storm-parsers/api/model_descriptions.h" #include "storm/api/properties.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/api/properties.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -18,7 +19,7 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/QualitativeCheckResult.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/environment/solver/NativeSolverEnvironment.h" diff --git a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp index ad6654ff4..f7f3b72a1 100644 --- a/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/DtmcPrctlModelCheckerTest.cpp @@ -3,9 +3,10 @@ #include "storm-config.h" #include "storm/api/builder.h" -#include "storm/api/model_descriptions.h" +#include "storm-parsers/api/model_descriptions.h" #include "storm/api/properties.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/api/properties.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -19,7 +20,7 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "storm/modelchecker/results/QualitativeCheckResult.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/environment/solver/NativeSolverEnvironment.h" diff --git a/src/test/storm/modelchecker/ExplicitDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/ExplicitDtmcPrctlModelCheckerTest.cpp index 06b90270b..025bc8c45 100644 --- a/src/test/storm/modelchecker/ExplicitDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/ExplicitDtmcPrctlModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" @@ -9,8 +9,8 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingMemento.h" -#include "storm/parser/AutoParser.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/ExplicitModelBuilder.h" #include "storm/storage/expressions/ExpressionManager.h" diff --git a/src/test/storm/modelchecker/ExplicitMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/ExplicitMdpPrctlModelCheckerTest.cpp index 91db98302..b295c397b 100644 --- a/src/test/storm/modelchecker/ExplicitMdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/ExplicitMdpPrctlModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -10,8 +10,8 @@ #include "storm/environment/solver/MinMaxSolverEnvironment.h" -#include "storm/parser/AutoParser.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/ExplicitModelBuilder.h" TEST(ExplicitMdpPrctlModelCheckerTest, Dice) { diff --git a/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp index 2a4f64c4d..3511aabec 100644 --- a/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/GameBasedDtmcModelCheckerTest.cpp @@ -1,13 +1,13 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/utility/solver.h" #include "storm/modelchecker/abstraction/GameBasedMdpModelChecker.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/DdPrismModelBuilder.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/symbolic/Dtmc.h" diff --git a/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp b/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp index 960cc56bc..225bf81b4 100644 --- a/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/GameBasedMdpModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/sparse/Model.h" @@ -13,6 +13,8 @@ #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" + #if defined STORM_HAVE_MSAT TEST(GameBasedMdpModelCheckerTest, Dice_Cudd) { #else diff --git a/src/test/storm/modelchecker/LraDtmcPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/LraDtmcPrctlModelCheckerTest.cpp index 59c589cb1..c964628b9 100644 --- a/src/test/storm/modelchecker/LraDtmcPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/LraDtmcPrctlModelCheckerTest.cpp @@ -2,7 +2,7 @@ #include "storm-config.h" #include "test/storm_gtest.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/settings/SettingMemento.h" #include "storm/logic/Formulas.h" #include "storm/solver/NativeLinearEquationSolver.h" @@ -17,7 +17,7 @@ #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/builder/ExplicitModelBuilder.h" namespace { diff --git a/src/test/storm/modelchecker/LraMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/LraMdpPrctlModelCheckerTest.cpp index ed3abb16b..b05ebfb76 100644 --- a/src/test/storm/modelchecker/LraMdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/LraMdpPrctlModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -12,7 +12,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" TEST(LraMdpPrctlModelCheckerTest, LRA_SingleMec) { storm::storage::SparseMatrixBuilder matrixBuilder; diff --git a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp index e0741fa30..feb90d438 100644 --- a/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp @@ -4,8 +4,9 @@ #include "test/storm_gtest.h" #include "storm/api/builder.h" -#include "storm/api/model_descriptions.h" +#include "storm-parsers/api/model_descriptions.h" #include "storm/api/properties.h" +#include "storm-parsers/api/properties.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/symbolic/Mdp.h" diff --git a/src/test/storm/modelchecker/SchedulerGenerationMdpPrctlModelCheckerTest.cpp b/src/test/storm/modelchecker/SchedulerGenerationMdpPrctlModelCheckerTest.cpp index 751a28ed2..6f82d6a47 100644 --- a/src/test/storm/modelchecker/SchedulerGenerationMdpPrctlModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SchedulerGenerationMdpPrctlModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -12,8 +12,8 @@ #include "storm/environment/solver/MinMaxSolverEnvironment.h" -#include "storm/parser/AutoParser.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/builder/ExplicitModelBuilder.h" namespace { diff --git a/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp index 00c8b88e5..ed182bf2c 100644 --- a/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseDtmcEliminationModelCheckerTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/reachability/SparseDtmcEliminationModelChecker.h" @@ -10,7 +10,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingMemento.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" TEST(SparseDtmcEliminationModelCheckerTest, Die) { std::shared_ptr> abstractModel = storm::parser::AutoParser<>::parseModel(STORM_TEST_RESOURCES_DIR "/tra/die.tra", STORM_TEST_RESOURCES_DIR "/lab/die.lab", "", STORM_TEST_RESOURCES_DIR "/rew/die.coin_flips.trans.rew"); diff --git a/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp b/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp index 36ca41ff0..3a20c997b 100644 --- a/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp +++ b/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp @@ -7,6 +7,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/utility/constants.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" TEST(SparseDtmcMultiDimensionalRewardUnfoldingTest, cost_bounded_die) { diff --git a/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp index a1645e2a0..dc7d7a55a 100644 --- a/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseExplorationModelCheckerTest.cpp @@ -4,8 +4,8 @@ #include "storm/logic/Formulas.h" #include "storm/modelchecker/exploration/SparseExplorationModelChecker.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/ExplorationSettings.h" diff --git a/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp index e5843b4e1..4970fff9d 100644 --- a/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp @@ -9,6 +9,7 @@ #include "storm/settings/modules/MultiObjectiveSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" diff --git a/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp index d2c116358..58c8e7494 100644 --- a/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp @@ -14,6 +14,7 @@ #include "storm/settings/modules/MultiObjectiveSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" diff --git a/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp index 7b2479ec3..f353092af 100644 --- a/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp @@ -7,6 +7,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" diff --git a/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp b/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp index 3f73da77e..4880564b0 100644 --- a/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp @@ -10,6 +10,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/utility/constants.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" diff --git a/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp index 947cbde55..8e4cb084c 100644 --- a/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp @@ -10,6 +10,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" TEST(SparseMdpPcaaMultiObjectiveModelCheckerTest, consensus) { diff --git a/src/test/storm/parser/AutoParserTest.cpp b/src/test/storm/parser/AutoParserTest.cpp index 0ddd14894..96aa9cc60 100644 --- a/src/test/storm/parser/AutoParserTest.cpp +++ b/src/test/storm/parser/AutoParserTest.cpp @@ -2,7 +2,7 @@ #include "storm-config.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/test/storm/parser/DeterministicModelParserTest.cpp b/src/test/storm/parser/DeterministicModelParserTest.cpp index b2f7ac9c2..bd5b0bf69 100644 --- a/src/test/storm/parser/DeterministicModelParserTest.cpp +++ b/src/test/storm/parser/DeterministicModelParserTest.cpp @@ -2,7 +2,7 @@ #include "storm-config.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/DeterministicModelParser.h" +#include "storm-parsers/parser/DeterministicModelParser.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Ctmc.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp index bd8e9e2f2..737d8ff04 100644 --- a/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp +++ b/src/test/storm/parser/DeterministicSparseTransitionParserTest.cpp @@ -8,7 +8,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/DeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/DeterministicSparseTransitionParser.h" #include "storm/storage/SparseMatrix.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" diff --git a/src/test/storm/parser/DirectEncodingParserTest.cpp b/src/test/storm/parser/DirectEncodingParserTest.cpp index 93bd34e04..c5716195b 100644 --- a/src/test/storm/parser/DirectEncodingParserTest.cpp +++ b/src/test/storm/parser/DirectEncodingParserTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/DirectEncodingParser.h" +#include "storm-parsers/parser/DirectEncodingParser.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/MarkovAutomaton.h" diff --git a/src/test/storm/parser/FormulaParserTest.cpp b/src/test/storm/parser/FormulaParserTest.cpp index 6269a082c..fd1206947 100644 --- a/src/test/storm/parser/FormulaParserTest.cpp +++ b/src/test/storm/parser/FormulaParserTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/FragmentSpecification.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/storage/expressions/ExpressionManager.h" diff --git a/src/test/storm/parser/MappedFileTest.cpp b/src/test/storm/parser/MappedFileTest.cpp index f33ee3aa2..362cbc899 100644 --- a/src/test/storm/parser/MappedFileTest.cpp +++ b/src/test/storm/parser/MappedFileTest.cpp @@ -9,7 +9,7 @@ #include "storm-config.h" #include -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/cstring.h" #include "storm/utility/file.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/test/storm/parser/MarkovAutomatonParserTest.cpp b/src/test/storm/parser/MarkovAutomatonParserTest.cpp index c31787087..3eb2dc3f7 100644 --- a/src/test/storm/parser/MarkovAutomatonParserTest.cpp +++ b/src/test/storm/parser/MarkovAutomatonParserTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/MarkovAutomatonParser.h" +#include "storm-parsers/parser/MarkovAutomatonParser.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/OutOfRangeException.h" diff --git a/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp b/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp index 461b28a95..f29a5689d 100644 --- a/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp +++ b/src/test/storm/parser/MarkovAutomatonSparseTransitionParserTest.cpp @@ -12,9 +12,9 @@ #include -#include "storm/parser/MarkovAutomatonSparseTransitionParser.h" +#include "storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h" #include "storm/utility/cstring.h" -#include "storm/parser/MarkovAutomatonParser.h" +#include "storm-parsers/parser/MarkovAutomatonParser.h" #include "storm/settings/SettingMemento.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/test/storm/parser/NondeterministicModelParserTest.cpp b/src/test/storm/parser/NondeterministicModelParserTest.cpp index b700c56f4..8ed57b2b7 100644 --- a/src/test/storm/parser/NondeterministicModelParserTest.cpp +++ b/src/test/storm/parser/NondeterministicModelParserTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/NondeterministicModelParser.h" +#include "storm-parsers/parser/NondeterministicModelParser.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp b/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp index 77344834a..9c740144f 100644 --- a/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp +++ b/src/test/storm/parser/NondeterministicSparseTransitionParserTest.cpp @@ -8,7 +8,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/NondeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/NondeterministicSparseTransitionParser.h" #include "storm/storage/SparseMatrix.h" #include "storm/settings/SettingMemento.h" diff --git a/src/test/storm/parser/PrismParserTest.cpp b/src/test/storm/parser/PrismParserTest.cpp index c86d90f63..4fe5735f5 100644 --- a/src/test/storm/parser/PrismParserTest.cpp +++ b/src/test/storm/parser/PrismParserTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" TEST(PrismParser, StandardModelTest) { storm::prism::Program result; diff --git a/src/test/storm/parser/SparseItemLabelingParserTest.cpp b/src/test/storm/parser/SparseItemLabelingParserTest.cpp index 695b6837b..2f5cf3c0b 100644 --- a/src/test/storm/parser/SparseItemLabelingParserTest.cpp +++ b/src/test/storm/parser/SparseItemLabelingParserTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" #include "storm/models/sparse/StateLabeling.h" -#include "storm/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" diff --git a/src/test/storm/parser/SparseStateRewardParserTest.cpp b/src/test/storm/parser/SparseStateRewardParserTest.cpp index d92203210..53524b3cd 100644 --- a/src/test/storm/parser/SparseStateRewardParserTest.cpp +++ b/src/test/storm/parser/SparseStateRewardParserTest.cpp @@ -10,7 +10,7 @@ #include -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" diff --git a/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp index 20707d33e..a6b0a34fd 100644 --- a/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp +++ b/src/test/storm/permissiveschedulers/MilpPermissiveSchedulerTest.cpp @@ -1,8 +1,8 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/logic/Formulas.h" #include "storm/permissivesched/PermissiveSchedulers.h" diff --git a/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp b/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp index b19f82618..1b873a935 100644 --- a/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp +++ b/src/test/storm/permissiveschedulers/SmtPermissiveSchedulerTest.cpp @@ -1,8 +1,8 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/logic/Formulas.h" #include "storm/permissivesched/PermissiveSchedulers.h" #include "storm/builder/ExplicitModelBuilder.h" diff --git a/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp index 3ebeca7a5..3341b1fe7 100644 --- a/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp +++ b/src/test/storm/storage/DeterministicModelBisimulationDecompositionTest.cpp @@ -1,7 +1,7 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/AutoParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/StandardRewardModel.h" diff --git a/src/test/storm/storage/JaniModelTest.cpp b/src/test/storm/storage/JaniModelTest.cpp index 7c7f393b3..c7a6b5c11 100644 --- a/src/test/storm/storage/JaniModelTest.cpp +++ b/src/test/storm/storage/JaniModelTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/utility/solver.h" diff --git a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp index 6e9718e6b..b30b5259b 100644 --- a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp +++ b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp @@ -1,13 +1,13 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/storage/MaximalEndComponentDecomposition.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/builder/ExplicitModelBuilder.h" #include "storm/storage/SymbolicModelDescription.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" TEST(MaximalEndComponentDecomposition, FullSystem1) { std::shared_ptr> abstractModel = storm::parser::AutoParser<>::parseModel(STORM_TEST_RESOURCES_DIR "/tra/tiny1.tra", STORM_TEST_RESOURCES_DIR "/lab/tiny1.lab", "", ""); diff --git a/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp b/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp index 596938852..d77fa8d64 100644 --- a/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp +++ b/src/test/storm/storage/NondeterministicModelBisimulationDecompositionTest.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/builder/ExplicitModelBuilder.h" diff --git a/src/test/storm/storage/PrismProgramTest.cpp b/src/test/storm/storage/PrismProgramTest.cpp index 8525f03e2..e860fa997 100644 --- a/src/test/storm/storage/PrismProgramTest.cpp +++ b/src/test/storm/storage/PrismProgramTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/utility/solver.h" diff --git a/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp b/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp index e447d2ec0..821b721a7 100644 --- a/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp +++ b/src/test/storm/storage/StronglyConnectedComponentDecompositionTest.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/storage/SparseMatrix.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" #include "storm/models/sparse/StandardRewardModel.h" diff --git a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp index d339bd027..64d2906d1 100644 --- a/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp +++ b/src/test/storm/storage/SymbolicBisimulationDecompositionTest.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" #include "storm-config.h" -#include "storm/parser/PrismParser.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/builder/DdPrismModelBuilder.h" @@ -19,7 +19,7 @@ #include "storm/solver/SymbolicMinMaxLinearEquationSolver.h" #include "storm/logic/Formulas.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" diff --git a/src/test/storm/utility/GraphTest.cpp b/src/test/storm/utility/GraphTest.cpp index ac646d99a..3098297c0 100644 --- a/src/test/storm/utility/GraphTest.cpp +++ b/src/test/storm/utility/GraphTest.cpp @@ -2,7 +2,7 @@ #include "storm-config.h" #include "storm/storage/SymbolicModelDescription.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/models/symbolic/Dtmc.h" #include "storm/models/symbolic/Mdp.h" #include "storm/models/symbolic/StandardRewardModel.h" diff --git a/src/test/storm/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp index 5ac954314..dfe14e817 100644 --- a/src/test/storm/utility/KSPTest.cpp +++ b/src/test/storm/utility/KSPTest.cpp @@ -3,7 +3,7 @@ #include "storm/builder/ExplicitModelBuilder.h" #include "storm/models/sparse/Dtmc.h" -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/SymbolicModelDescription.h" #include "storm/utility/graph.h" #include "storm/utility/shortestPaths.h" From 39698d6ecbe5d33c026259643f9b3566fc60c9c1 Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 21:01:14 +0200 Subject: [PATCH 354/647] fix install of storm-counterexamples --- src/storm-counterexamples/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-counterexamples/CMakeLists.txt b/src/storm-counterexamples/CMakeLists.txt index d01c4ceb7..2052930c6 100644 --- a/src/storm-counterexamples/CMakeLists.txt +++ b/src/storm-counterexamples/CMakeLists.txt @@ -20,7 +20,7 @@ set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) target_link_libraries(storm-counterexamples PUBLIC storm) # Install storm headers to include directory. -foreach(HEADER ${STORM_DFT_HEADERS}) +foreach(HEADER ${STORM_CEX_HEADERS}) string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) From 53238f43f753aa2a6a6786dd49215b9f39abc98c Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 21:01:38 +0200 Subject: [PATCH 355/647] fixed some missing includes due to updated API --- src/storm-gspn-cli/storm-gspn.cpp | 3 +++ src/test/storm-dft/CMakeLists.txt | 2 +- src/test/storm-dft/api/DftModelCheckerTest.cpp | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 99d60b0d7..46da4fea5 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -12,6 +12,8 @@ #include "storm/utility/initialize.h" #include "api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" #include "storm-cli-utilities/cli.h" #include "storm-parsers/parser/FormulaParser.h" @@ -27,6 +29,7 @@ #include "storm/exceptions/FileIoException.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm-gspn/settings/modules/GSPNSettings.h" #include "storm-gspn/settings/modules/GSPNExportSettings.h" diff --git a/src/test/storm-dft/CMakeLists.txt b/src/test/storm-dft/CMakeLists.txt index d461c2f9d..a0e96ee36 100644 --- a/src/test/storm-dft/CMakeLists.txt +++ b/src/test/storm-dft/CMakeLists.txt @@ -13,7 +13,7 @@ foreach (testsuite api) file(GLOB_RECURSE TEST_${testsuite}_FILES ${STORM_TESTS_BASE_PATH}/${testsuite}/*.h ${STORM_TESTS_BASE_PATH}/${testsuite}/*.cpp) add_executable (test-dft-${testsuite} ${TEST_${testsuite}_FILES} ${STORM_TESTS_BASE_PATH}/storm-test.cpp) - target_link_libraries(test-dft-${testsuite} storm-dft) + target_link_libraries(test-dft-${testsuite} storm-dft storm-parsers) target_link_libraries(test-dft-${testsuite} ${STORM_TEST_LINK_LIBRARIES}) add_dependencies(test-dft-${testsuite} test-resources) diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index 5db58d60d..b4e9534f9 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -2,6 +2,7 @@ #include "storm-config.h" #include "storm-dft/api/storm-dft.h" +#include "storm-parsers/api/storm-parsers.h" namespace { From 2aff2e9382e801f3ded6d41e2693d52feba147ca Mon Sep 17 00:00:00 2001 From: dehnert Date: Sun, 10 Jun 2018 22:00:22 +0200 Subject: [PATCH 356/647] adding some more timing output --- .../abstraction/GameBasedMdpModelChecker.cpp | 22 +++++++++++++------ .../solver/GmmxxLinearEquationSolver.cpp | 2 +- src/storm/utility/Stopwatch.cpp | 12 ++++++++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 43e1e795c..8e41c96eb 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -62,7 +62,15 @@ namespace storm { template GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2, storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { - STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants. Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); + if (model.hasUndefinedConstants()) { + auto undefinedConstants = model.getUndefinedConstants(); + std::vector undefinedConstantNames; + for (auto undefinedConstant : undefinedConstants) { + undefinedConstantNames.emplace_back(undefinedConstant.getName()); + } + + STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants (" << boost::algorithm::join(undefinedConstantNames, ",") << "). Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); + } if (model.isPrismProgram()) { storm::prism::Program const& originalProgram = model.asPrismProgram(); @@ -664,7 +672,7 @@ namespace storm { // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. STORM_LOG_TRACE("No initial state is a 'maybe' state."); - STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << "). Refining abstraction based on qualitative check."); // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. @@ -708,9 +716,9 @@ namespace storm { ValueType minVal = quantitativeResult.min.getInitialStatesRange().first; ValueType maxVal = quantitativeResult.max.getInitialStatesRange().second; if (std::is_same::value) { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } else { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } @@ -1259,7 +1267,7 @@ namespace storm { // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. STORM_LOG_TRACE("No initial state is a 'maybe' state."); - STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << "). Refining abstraction based on qualitative check."); // Post-process strategies for better refinements. storm::utility::Stopwatch strategyProcessingWatch(true); @@ -1312,9 +1320,9 @@ namespace storm { ValueType minVal = quantitativeResult.getMin().getRange(initialStates).first; ValueType maxVal = quantitativeResult.getMax().getRange(initialStates).second; if (std::is_same::value) { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } else { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index 83d5b6ef6..e20a47280 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -106,7 +106,7 @@ namespace storm { STORM_LOG_INFO("Iterative solver converged after " << iter.get_iteration() << " iterations."); return true; } else { - STORM_LOG_WARN("Iterative solver did not converge."); + STORM_LOG_WARN("Iterative solver did not converge after " << iter.get_iteration() << " iterations."); return false; } } diff --git a/src/storm/utility/Stopwatch.cpp b/src/storm/utility/Stopwatch.cpp index 8c6f008a4..f694df496 100644 --- a/src/storm/utility/Stopwatch.cpp +++ b/src/storm/utility/Stopwatch.cpp @@ -10,11 +10,19 @@ namespace storm { } Stopwatch::SecondType Stopwatch::getTimeInSeconds() const { - return std::chrono::duration_cast(accumulatedTime).count(); + auto time = accumulatedTime; + if (!this->stopped()) { + time += std::chrono::high_resolution_clock::now() - startOfCurrentMeasurement; + } + return std::chrono::duration_cast(time).count(); } Stopwatch::MilisecondType Stopwatch::getTimeInMilliseconds() const { - return std::chrono::duration_cast(accumulatedTime).count(); + auto time = accumulatedTime; + if (!this->stopped()) { + time += std::chrono::high_resolution_clock::now() - startOfCurrentMeasurement; + } + return std::chrono::duration_cast(time).count(); } Stopwatch::NanosecondType Stopwatch::getTimeInNanoseconds() const { From 84783520304a97e7bacabdea5af89c753dfac559 Mon Sep 17 00:00:00 2001 From: sjunges Date: Sun, 10 Jun 2018 23:00:12 +0200 Subject: [PATCH 357/647] dynamic constraints and minimality labels --- .../counterexamples/SMTMinimalLabelSetGenerator.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 4de23e767..a3dfbd066 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1387,7 +1387,10 @@ namespace storm { std::vector formulae; boost::container::flat_set unknownReachableLabels; std::set_difference(reachableLabels.begin(), reachableLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownReachableLabels, unknownReachableLabels.end())); - for (auto label : unknownReachableLabels) { + boost::container::flat_set unknownReachableMinimalityLabels; + std::set_intersection(unknownReachableLabels.begin(), unknownReachableLabels.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownReachableMinimalityLabels, unknownReachableMinimalityLabels.end())); + + for (auto label : unknownReachableMinimalityLabels) { formulae.push_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } for (auto const& cutLabelSet : cutLabels) { @@ -1488,7 +1491,10 @@ namespace storm { std::vector formulae; boost::container::flat_set unknownReachableLabels; std::set_difference(reachableLabels.begin(), reachableLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownReachableLabels, unknownReachableLabels.end())); - for (auto label : unknownReachableLabels) { + boost::container::flat_set unknownReachableMinimalityLabels; + std::set_intersection(unknownReachableLabels.begin(), unknownReachableLabels.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownReachableMinimalityLabels, unknownReachableMinimalityLabels.end())); + + for (auto label : unknownReachableMinimalityLabels) { formulae.push_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } for (auto const& cutLabelSet : cutLabels) { From 386f0b2e47f414695634bb721497b9be9e9a7fed Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 12 Jun 2018 12:08:41 +0200 Subject: [PATCH 358/647] fixing bug in scheduler improvement step of policy iteration for games --- .../abstraction/GameBasedMdpModelChecker.cpp | 1 - src/storm/solver/StandardGameSolver.cpp | 60 +++++++++++-------- src/storm/solver/StandardGameSolver.h | 6 +- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 8e41c96eb..de741b0e3 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -549,7 +549,6 @@ namespace storm { STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException, "The game-based abstraction refinement model checker can only compute the result for the initial states."); // Optimization: do not compute both bounds if not necessary (e.g. if bound given and exceeded, etc.) - totalWatch.start(); // Set up initial predicates. diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index cd0409170..8857d947d 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -7,6 +7,10 @@ #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/GeneralSettings.h" + +#include "storm/utility/ConstantsComparator.h" #include "storm/utility/graph.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" @@ -18,23 +22,31 @@ namespace storm { namespace solver { template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(nullptr), player1Matrix(&player1Matrix), player2Matrix(player2Matrix) { - // Intentionally left empty. + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(nullptr), player1Matrix(&player1Matrix), player2Matrix(player2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(std::make_unique>(std::move(player1Matrix))), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(nullptr), player1Matrix(localPlayer1Matrix.get()), player2Matrix(*localPlayer2Matrix) { - // Intentionally left empty. + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(std::make_unique>(std::move(player1Matrix))), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(nullptr), player1Matrix(localPlayer1Matrix.get()), player2Matrix(*localPlayer2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template - StandardGameSolver::StandardGameSolver(std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(&player1Grouping), player1Matrix(nullptr), player2Matrix(player2Matrix) { - + StandardGameSolver::StandardGameSolver(std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(&player1Grouping), player1Matrix(nullptr), player2Matrix(player2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template - StandardGameSolver::StandardGameSolver(std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(std::make_unique>(std::move(player1Grouping))), localPlayer1Matrix(nullptr), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(localPlayer1Grouping.get()), player1Matrix(nullptr), player2Matrix(*localPlayer2Matrix) { - // Intentionally left empty. + StandardGameSolver::StandardGameSolver(std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(std::make_unique>(std::move(player1Grouping))), localPlayer1Matrix(nullptr), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(localPlayer1Grouping.get()), player1Matrix(nullptr), player2Matrix(*localPlayer2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template @@ -177,6 +189,7 @@ namespace storm { do { submatrixSolver->solveEquations(environmentOfSolver, x, subB); + // Check whether we can improve local choices. bool schedulerImproved = extractChoices(environmentOfSolver, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); // If the scheduler did not improve, we are done. @@ -230,11 +243,11 @@ namespace storm { } template - bool StandardGameSolver::valueImproved(OptimizationDirection dir, ValueType const& precision, ValueType const& value1, ValueType const& value2) const { + bool StandardGameSolver::valueImproved(OptimizationDirection dir, storm::utility::ConstantsComparator const& comparator, ValueType const& value1, ValueType const& value2) const { if (dir == OptimizationDirection::Minimize) { - return value2 < value1 - precision; + return comparator.isLess(value2, value1); } else { - return value2 > value1 + precision; + return comparator.isLess(value1, value2); } } @@ -399,18 +412,17 @@ namespace storm { template bool StandardGameSolver::extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { - - std::pair, boost::optional> precisionInfo = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); - ValueType precision = storm::utility::convertNumber(precisionInfo.first.get()); - + + storm::utility::ConstantsComparator comparator(linearEquationSolverIsExact ? storm::utility::zero() : storm::utility::convertNumber(env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()).first.get()), false); + // get the choices of player 2 and the corresponding values. bool schedulerImproved = false; auto currentValueIt = player2ChoiceValues.begin(); - for (uint_fast64_t p2Group = 0; p2Group < this->player2Matrix.getRowGroupCount(); ++p2Group) { + for (uint_fast64_t p2Group = 0; p2Group < this->player2Matrix.getRowGroupCount(); ++p2Group, ++currentValueIt) { uint_fast64_t firstRowInGroup = this->player2Matrix.getRowGroupIndices()[p2Group]; uint_fast64_t rowGroupSize = this->player2Matrix.getRowGroupIndices()[p2Group + 1] - firstRowInGroup; - // We need to check whether the scheduler improved. Therefore, we first have to evaluate the current choice + // We need to check whether the scheduler improved. Therefore, we first have to evaluate the current choice. uint_fast64_t currentP2Choice = player2Choices[p2Group]; *currentValueIt = storm::utility::zero(); for (auto const& entry : this->player2Matrix.getRow(firstRowInGroup + currentP2Choice)) { @@ -418,7 +430,7 @@ namespace storm { } *currentValueIt += b[firstRowInGroup + currentP2Choice]; - // now check the other choices + // Now check other choices improve the value. for (uint_fast64_t p2Choice = 0; p2Choice < rowGroupSize; ++p2Choice) { if (p2Choice == currentP2Choice) { continue; @@ -428,9 +440,8 @@ namespace storm { choiceValue += entry.getValue() * x[entry.getColumn()]; } choiceValue += b[firstRowInGroup + p2Choice]; - - if (valueImproved(player2Dir, precision, *currentValueIt, choiceValue)) { -// std::cout << std::setprecision(30) << "improving player 2 choice at " << p2Group << " from " << player2Choices[p2Group] << " to " << p2Choice << " because " << choiceValue << " is better than " << *currentValueIt << std::endl; + + if (valueImproved(player2Dir, comparator, *currentValueIt, choiceValue)) { schedulerImproved = true; player2Choices[p2Group] = p2Choice; *currentValueIt = std::move(choiceValue); @@ -452,7 +463,7 @@ namespace storm { continue; } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; - if (valueImproved(player1Dir, precision, currentValue, choiceValue)) { + if (valueImproved(player1Dir, comparator, currentValue, choiceValue)) { schedulerImproved = true; player1Choices[p1Group] = p1Choice; currentValue = choiceValue; @@ -463,7 +474,7 @@ namespace storm { // Player 1 represented by grouping of player 2 states (vector). for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { uint64_t currentChoice = player1Choices[player1State]; - ValueType currentValue = player2ChoiceValues[currentChoice]; + ValueType currentValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + currentChoice]; uint64_t numberOfPlayer2Successors = this->getPlayer1Grouping()[player1State + 1] - this->getPlayer1Grouping()[player1State]; for (uint64_t player2State = 0; player2State < numberOfPlayer2Successors; ++player2State) { // If the choice is the currently selected one, we can skip it. @@ -472,8 +483,7 @@ namespace storm { } ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + player2State]; - if (valueImproved(player1Dir, precision, currentValue, choiceValue)) { -// std::cout << std::setprecision(30) << "improving player 2 choice at " << player1State << " from " << player1Choices[player1State] << " to " << player2State << " because " << choiceValue << " is better than " << currentValue << std::endl; + if (valueImproved(player1Dir, comparator, currentValue, choiceValue)) { schedulerImproved = true; player1Choices[player1State] = player2State; currentValue = choiceValue; diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 8fa380001..7c7519231 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -40,7 +40,7 @@ namespace storm { // Returns true iff the newly extracted choices yield "better" values then the given choices for one of the players. bool extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; - bool valueImproved(OptimizationDirection dir, ValueType const& precision, ValueType const& value1, ValueType const& value2) const; + bool valueImproved(OptimizationDirection dir, storm::utility::ConstantsComparator const& comparator, ValueType const& value1, ValueType const& value2) const; bool player1RepresentedByMatrix() const; storm::storage::SparseMatrix const& getPlayer1Matrix() const; @@ -75,6 +75,10 @@ namespace storm { std::vector const* player1Grouping; storm::storage::SparseMatrix const* player1Matrix; storm::storage::SparseMatrix const& player2Matrix; + + /// A flag indicating whether the linear equation solver is exact. This influences how choices are updated + /// in policy iteration. + bool linearEquationSolverIsExact; }; } } From 9e398ffaab09fec2bb4593d27982c4644371fdb4 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 12 Jun 2018 15:07:42 +0200 Subject: [PATCH 359/647] Minor improvements for some CMake output --- CMakeLists.txt | 14 +++++++------- resources/3rdparty/CMakeLists.txt | 14 +++++++------- resources/3rdparty/carl/CMakeLists.txt | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ca3b9b7e..ee6c1117c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ foreach(p LIB BIN INCLUDE CMAKE) endif() endforeach() -message("CMAKE_INSTALL_DIR: ${CMAKE_INSTALL_DIR}") +message(STATUS "Storm - CMake install dir: ${CMAKE_INSTALL_DIR}") # If the STORM_DEVELOPER option was turned on, by default we target a debug version, otherwise a release version. if (STORM_DEVELOPER) @@ -153,15 +153,15 @@ elseif (WIN32) set(STATIC_EXT ".lib") set(LIB_PREFIX "") endif() -message(STATUS "Assuming extension for shared libraries: ${DYNAMIC_EXT}") -message(STATUS "Assuming extension for static libraries: ${STATIC_EXT}") +message(STATUS "Storm - Assuming extension for shared libraries: ${DYNAMIC_EXT}") +message(STATUS "Storm - Assuming extension for static libraries: ${STATIC_EXT}") if(BUILD_SHARED_LIBS) set(LIB_EXT ${DYNAMIC_EXT}) - message(STATUS "Build dynamic libraries.") + message(STATUS "Storm - Build dynamic libraries.") else() set(LIB_EXT ${STATIC_EXT}) - message(STATUS "Build static libraries.") + message(STATUS "Storm - Build static libraries.") endif() ############################################################# @@ -443,7 +443,7 @@ if (STORM_GIT_VERSION_STRING MATCHES "NOTFOUND") set(STORM_VERSION_SOURCE "VersionSource::Static") set(STORM_VERSION_COMMITS_AHEAD "boost::none") include(version.cmake) - message(WARNING "Storm - git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") + message(WARNING "Storm - Git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") endif() # check whether there is a label ('alpha', 'pre', etc.) @@ -473,7 +473,7 @@ endif() set(STORM_VERSION "${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_DEV_PATCH}") set(STORM_VERSION_STRING "${STORM_VERSION}${STORM_VERSION_LABEL_STRING}${STORM_VERSION_DEV_STRING}") -message(STATUS "Storm - version is ${STORM_VERSION_STRING} (version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}${STORM_VERSION_LABEL_STRING} + ${STORM_VERSION_COMMITS_AHEAD} commits), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).") +message(STATUS "Storm - Version is ${STORM_VERSION_STRING} (version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}${STORM_VERSION_LABEL_STRING} + ${STORM_VERSION_COMMITS_AHEAD} commits), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).") # Configure a header file to pass some of the CMake settings to the source code diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index 5957f3b51..caaa2a0f1 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -239,16 +239,16 @@ if(carl_FOUND AND NOT STORM_FORCE_SHIPPED_CARL) else() set(STORM_SHIPPED_CARL ON) # The first external project will be built at *configure stage* - message("START CARL CONFIG PROCESS") - file(MAKE_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download) + message(STATUS "Carl - Start of config process") + file(MAKE_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download) execute_process( COMMAND ${CMAKE_COMMAND} ${STORM_3RDPARTY_SOURCE_DIR}/carl "-DSTORM_3RDPARTY_BINARY_DIR=${STORM_3RDPARTY_BINARY_DIR}" "-DBoost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}" "-DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS}" WORKING_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download OUTPUT_VARIABLE carlconfig_out RESULT_VARIABLE carlconfig_result) - + if(NOT carlconfig_result) - message("${carlconfig_out}") + message(STATUS "${carlconfig_out}") endif() execute_process( COMMAND ${CMAKE_COMMAND} --build . --target carl-config @@ -257,10 +257,10 @@ else() RESULT_VARIABLE carlconfig_result ) if(NOT carlconfig_result) - message("${carlconfig_out}") + message(STATUS "${carlconfig_out}") endif() - message("END CARL CONFIG PROCESS") - + message(STATUS "Carl - End of config process") + message(STATUS "Storm - Using shipped version of carl.") ExternalProject_Add( carl diff --git a/resources/3rdparty/carl/CMakeLists.txt b/resources/3rdparty/carl/CMakeLists.txt index 4b819682d..3bb50d1b1 100644 --- a/resources/3rdparty/carl/CMakeLists.txt +++ b/resources/3rdparty/carl/CMakeLists.txt @@ -4,7 +4,7 @@ include(ExternalProject) option(STORM_3RDPARTY_BINARY_DIR "3rd party bin dir") -message(STORM_3RDPARTY_BINARY_DIR: ${STORM_3RDPARTY_BINARY_DIR}) +message(STATUS "Carl - Storm 3rdparty binary dir: ${STORM_3RDPARTY_BINARY_DIR}") ExternalProject_Add(carl-config GIT_REPOSITORY https://github.com/smtrat/carl @@ -22,4 +22,4 @@ ExternalProject_Add(carl-config add_custom_target(build-carl) add_dependencies(build-carl carl-config) -message("done") +message(STATUS "Carl - Finished configuration.") From afb0be124565e466ed9f5788e88fa34de82cb410 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 12 Jun 2018 15:08:14 +0200 Subject: [PATCH 360/647] Fixed missing dependencies to storm-parsers --- src/storm-dft/CMakeLists.txt | 2 +- src/storm-parsers/CMakeLists.txt | 2 +- src/storm-pgcl/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm-dft/CMakeLists.txt b/src/storm-dft/CMakeLists.txt index f191e537f..48a046238 100644 --- a/src/storm-dft/CMakeLists.txt +++ b/src/storm-dft/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-dft PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-dft) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-dft PUBLIC storm storm-gspn ${STORM_DFT_LINK_LIBRARIES}) +target_link_libraries(storm-dft PUBLIC storm storm-gspn storm-parsers ${STORM_DFT_LINK_LIBRARIES}) # Install storm headers to include directory. foreach(HEADER ${STORM_DFT_HEADERS}) diff --git a/src/storm-parsers/CMakeLists.txt b/src/storm-parsers/CMakeLists.txt index d459345e4..24d9532b5 100644 --- a/src/storm-parsers/CMakeLists.txt +++ b/src/storm-parsers/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB_RECURSE STORM_PARSER_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-parsers/* # Disable Debug compiler flags for PrismParser to lessen memory consumption during compilation SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/storm-parsers/parser/PrismParser.cpp PROPERTIES COMPILE_FLAGS -g0) -# Create storm-dft. +# Create storm-parsers. add_library(storm-parsers SHARED ${STORM_PARSER_SOURCES} ${STORM_PARSER_HEADERS}) # Remove define symbol for shared libstorm. diff --git a/src/storm-pgcl/CMakeLists.txt b/src/storm-pgcl/CMakeLists.txt index 059bff395..7b86f73c3 100644 --- a/src/storm-pgcl/CMakeLists.txt +++ b/src/storm-pgcl/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB_RECURSE STORM_PGCL_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-pgcl/*/*.h) # Create storm-pgcl. add_library(storm-pgcl SHARED ${STORM_PGCL_SOURCES} ${STORM_PGCL_HEADERS}) -target_link_libraries(storm-pgcl storm) +target_link_libraries(storm-pgcl storm storm-parsers) # installation install(TARGETS storm-pgcl EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) From a6e6d5993f9b3c80db73a25661f3dfce067d158c Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 13 Jun 2018 16:37:45 +0200 Subject: [PATCH 361/647] Travis: set unlimited clone depth to allow versioning with git describe --- .travis.yml | 5 ++++- travis/generate_travis.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1074ba368..8a5dd952d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,9 @@ sudo: required dist: trusty language: cpp +git: + depth: false + # Enable caching cache: timeout: 1000 @@ -25,7 +28,7 @@ notifications: on_failure: always on_success: change recipients: - secure: "BoMQTBWnkh4ZLIHEaKu0tAKDohhVmOQ2pz/fjc+ScKG8mtvXqtpx0TiyePOUV1MuYNZiAP7x4mwABcoid55SwZ4+LPjd8uxXNfOji9B9GW5YqbqRvAeh7Es7dx48MyLYPIezjoryHH9R3Q2zZ9gmxgtw5eirjURcLNTXpKAwq/oOsKvh+vhOx4Qierw98wEXjMV7ipBzE4cfkgUbbX7oxGh1nsAsCew+rRmNLijfmE9tctYdH5W0wE+zC9ik+12Xyk3FwsDIABirPHfeCcEl+b9I0h1a2vZSZIA+sCDkIGKTiv9pCnsthn5LJc9pMLX7B/Wf6xLGMzpSiw3P1ZzjXpOE026WuyhTMVXqZYvbl7cJoNZiLCfTYg3MQVq5NHkq0h0jInIH7QlZYd0hZPOGONwdy17O1QmnX2Weq6G+Ps9siLVKFba37+y5PfRYkiUatJvDf2f7Jdxye6TWrUmlxQkAvs65ioyr8doad7IT1/yaGr/rBpXeQqZp6zNoMYr/cCRAYX6nOrnSszgiIWEc8QMMx+G31v77Uvd++9VG4MG9gbdpexpfYRNzKAxDarSaYEOuaWm2Z6R87bpNcjA+tW0hnBHBzRx0NFYYqXyW0tpVO9+035A9CHrLDLz77r4jJttcRvrP2rTbTBiwuhpmiufRyk3BuWlgzU3yaSuQV3M=" + - secure: "VWnsiQkt1xjgRo1hfNiNQqvLSr0fshFmLV7jJlUixhCr094mgD0U2bNKdUfebm28Byg9UyDYPbOFDC0sx7KydKiL1q7FKKXkyZH0k04wUu8XiNw+fYkDpmPnQs7G2n8oJ/GFJnr1Wp/1KI3qX5LX3xot4cJfx1I5iFC2O+p+ng6v/oSX+pewlMv4i7KL16ftHHHMo80N694v3g4B2NByn4GU2/bjVQcqlBp/TiVaUa5Nqu9DxZi/n9CJqGEaRHOblWyMO3EyTZsn45BNSWeQ3DtnMwZ73rlIr9CaEgCeuArc6RGghUAVqRI5ao+N5apekIaILwTgL6AJn+Lw/+NRPa8xclgd0rKqUQJMJCDZKjKz2lmIs3bxfELOizxJ3FJQ5R95FAxeAZ6rb/j40YqVVTw2IMBDnEE0J5ZmpUYNUtPti/Adf6GD9Fb2y8sLo0XDJzkI8OxYhfgjSy5KYmRj8O5MXcP2MAE8LQauNO3MaFnL9VMVOTZePJrPozQUgM021uyahf960+QNI06Uqlmg+PwWkSdllQlxHHplOgW7zClFhtSUpnJxcsUBzgg4kVg80gXUwAQkaDi7A9Wh2bs+TvMlmHzBwg+2SaAfWDgjeJIeOaipDkF1uSGzC+EHAiiKYMLd4Aahoi8SuelJUucoyJyLAq00WdUFQIh/izVhM4Y=" # # Configurations diff --git a/travis/generate_travis.py b/travis/generate_travis.py index ac4e89417..49723a13c 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -44,6 +44,9 @@ if __name__ == "__main__": s += "dist: trusty\n" s += "language: cpp\n" s += "\n" + s += "git:\n" + s += " depth: false\n" + s += "\n" s += "# Enable caching\n" s += "cache:\n" s += " timeout: 1000\n" @@ -61,7 +64,7 @@ if __name__ == "__main__": s += " on_failure: always\n" s += " on_success: change\n" s += " recipients:\n" - s += ' secure: "BoMQTBWnkh4ZLIHEaKu0tAKDohhVmOQ2pz/fjc+ScKG8mtvXqtpx0TiyePOUV1MuYNZiAP7x4mwABcoid55SwZ4+LPjd8uxXNfOji9B9GW5YqbqRvAeh7Es7dx48MyLYPIezjoryHH9R3Q2zZ9gmxgtw5eirjURcLNTXpKAwq/oOsKvh+vhOx4Qierw98wEXjMV7ipBzE4cfkgUbbX7oxGh1nsAsCew+rRmNLijfmE9tctYdH5W0wE+zC9ik+12Xyk3FwsDIABirPHfeCcEl+b9I0h1a2vZSZIA+sCDkIGKTiv9pCnsthn5LJc9pMLX7B/Wf6xLGMzpSiw3P1ZzjXpOE026WuyhTMVXqZYvbl7cJoNZiLCfTYg3MQVq5NHkq0h0jInIH7QlZYd0hZPOGONwdy17O1QmnX2Weq6G+Ps9siLVKFba37+y5PfRYkiUatJvDf2f7Jdxye6TWrUmlxQkAvs65ioyr8doad7IT1/yaGr/rBpXeQqZp6zNoMYr/cCRAYX6nOrnSszgiIWEc8QMMx+G31v77Uvd++9VG4MG9gbdpexpfYRNzKAxDarSaYEOuaWm2Z6R87bpNcjA+tW0hnBHBzRx0NFYYqXyW0tpVO9+035A9CHrLDLz77r4jJttcRvrP2rTbTBiwuhpmiufRyk3BuWlgzU3yaSuQV3M="\n' + s += ' - secure: "VWnsiQkt1xjgRo1hfNiNQqvLSr0fshFmLV7jJlUixhCr094mgD0U2bNKdUfebm28Byg9UyDYPbOFDC0sx7KydKiL1q7FKKXkyZH0k04wUu8XiNw+fYkDpmPnQs7G2n8oJ/GFJnr1Wp/1KI3qX5LX3xot4cJfx1I5iFC2O+p+ng6v/oSX+pewlMv4i7KL16ftHHHMo80N694v3g4B2NByn4GU2/bjVQcqlBp/TiVaUa5Nqu9DxZi/n9CJqGEaRHOblWyMO3EyTZsn45BNSWeQ3DtnMwZ73rlIr9CaEgCeuArc6RGghUAVqRI5ao+N5apekIaILwTgL6AJn+Lw/+NRPa8xclgd0rKqUQJMJCDZKjKz2lmIs3bxfELOizxJ3FJQ5R95FAxeAZ6rb/j40YqVVTw2IMBDnEE0J5ZmpUYNUtPti/Adf6GD9Fb2y8sLo0XDJzkI8OxYhfgjSy5KYmRj8O5MXcP2MAE8LQauNO3MaFnL9VMVOTZePJrPozQUgM021uyahf960+QNI06Uqlmg+PwWkSdllQlxHHplOgW7zClFhtSUpnJxcsUBzgg4kVg80gXUwAQkaDi7A9Wh2bs+TvMlmHzBwg+2SaAfWDgjeJIeOaipDkF1uSGzC+EHAiiKYMLd4Aahoi8SuelJUucoyJyLAq00WdUFQIh/izVhM4Y="\n' s += "\n" s += "#\n" s += "# Configurations\n" From 4f4d1f4423d29917719b3beb0b2d9ea3cff6ffb8 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 14 Jun 2018 14:19:13 +0200 Subject: [PATCH 362/647] do not scale precision --- src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index de741b0e3..e7b87abe6 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -60,7 +60,7 @@ namespace storm { using detail::PreviousExplicitResult; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision() * 2, storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision(), storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { if (model.hasUndefinedConstants()) { auto undefinedConstants = model.getUndefinedConstants(); From 4134630fa64d054145ed456fc1fa5639ede50ff7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 20 Jun 2018 15:40:05 +0200 Subject: [PATCH 363/647] adding gap output --- .../abstraction/GameBasedMdpModelChecker.cpp | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index e7b87abe6..d1cb9190b 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -711,15 +711,19 @@ namespace storm { if (result) { return result; } - + ValueType minVal = quantitativeResult.min.getInitialStatesRange().first; ValueType maxVal = quantitativeResult.max.getInitialStatesRange().second; + ValueType difference = maxVal - minVal; if (std::is_same::value) { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + std::stringstream differenceStream; + differenceStream.setf(std::ios::fixed, std::ios::floatfield); + differenceStream.precision(15); + differenceStream << difference; + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (difference " << differenceStream.str() << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } else { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "], difference " << difference << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } - // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); @@ -1318,10 +1322,15 @@ namespace storm { ValueType minVal = quantitativeResult.getMin().getRange(initialStates).first; ValueType maxVal = quantitativeResult.getMax().getRange(initialStates).second; + ValueType difference = maxVal - minVal; if (std::is_same::value) { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + std::stringstream differenceStream; + differenceStream.setf(std::ios::fixed, std::ios::floatfield); + differenceStream.precision(15); + differenceStream << difference; + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (difference " << differenceStream.str() << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } else { - STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "]) on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "], difference " << difference << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); } // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. From cdfa32846463872bfa51a87c86c09bd14e297879 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 22 Jun 2018 10:57:52 +0200 Subject: [PATCH 364/647] first attempt at adapting to Z3 interface change --- resources/3rdparty/CMakeLists.txt | 9 +++++++++ src/storm/adapters/Z3ExpressionAdapter.cpp | 19 ++++++++++++++----- .../DynamicStatePriorityQueue.h | 2 +- .../MaximalEndComponentDecompositionTest.cpp | 4 ++-- src/test/storm/utility/KSPTest.cpp | 4 ++-- storm-config.h.in | 7 +++++++ 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index caaa2a0f1..18a68a23f 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -168,6 +168,15 @@ else() message (WARNING "Storm - Z3 not found. Building of Prism/JANI models will not be supported.") endif(Z3_FOUND) +# split Z3 version into its components +string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) +list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) +list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) +list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) +if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") + set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) +endif() + ############################################################# ## ## glpk diff --git a/src/storm/adapters/Z3ExpressionAdapter.cpp b/src/storm/adapters/Z3ExpressionAdapter.cpp index c7e27756d..fec9068b0 100644 --- a/src/storm/adapters/Z3ExpressionAdapter.cpp +++ b/src/storm/adapters/Z3ExpressionAdapter.cpp @@ -12,6 +12,15 @@ namespace storm { namespace adapters { #ifdef STORM_HAVE_Z3 + +#ifdef STORM_Z3_API_USES_STANDARD_INTEGERS + typedef int64_t Z3_SIGNED_INTEGER; + typedef int64_t Z3_UNSIGNED_INTEGER; +#else + typedef long long Z3_SIGNED_INTEGER; + typedef unsigned long long Z3_UNSIGNED_INTEGER; +#endif + Z3ExpressionAdapter::Z3ExpressionAdapter(storm::expressions::ExpressionManager& manager, z3::context& context) : manager(manager), context(context), additionalAssertions(), variableToExpressionMapping() { // Intentionally left empty. } @@ -133,17 +142,17 @@ namespace storm { case Z3_OP_ANUM: // Arithmetic numeral. if (expr.is_int() && expr.is_const()) { - long long value; + Z3_SIGNED_INTEGER value; if (Z3_get_numeral_int64(expr.ctx(), expr, &value)) { return manager.integer(value); } else { STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Expression is constant integer and value does not fit into 64-bit integer."); } } else if (expr.is_real() && expr.is_const()) { - long long num; - long long den; + Z3_SIGNED_INTEGER num; + Z3_SIGNED_INTEGER den; if (Z3_get_numeral_rational_int64(expr.ctx(), expr, &num, &den)) { - return manager.rational(storm::utility::convertNumber((int_fast64_t) num) / storm::utility::convertNumber((int_fast64_t) den)); + return manager.rational(storm::utility::convertNumber(static_cast(num)) / storm::utility::convertNumber(static_cast(den))); } else { return manager.rational(storm::utility::convertNumber(std::string(Z3_get_numeral_string(expr.ctx(), expr)))); } @@ -304,7 +313,7 @@ namespace storm { return cacheIt->second; } - z3::expr result = context.int_val(static_cast(expression.getValue())); + z3::expr result = context.int_val(static_cast(expression.getValue())); expressionCache.emplace(&expression, result); return result; diff --git a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h index 0ac38769d..4065ee265 100644 --- a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h +++ b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h @@ -17,7 +17,7 @@ namespace storm { namespace stateelimination { struct PriorityComparator { - bool operator()(std::pair const& first, std::pair const& second) { + bool operator()(std::pair const& first, std::pair const& second) const { return (first.second < second.second) || (first.second == second.second && first.first < second.first) ; } }; diff --git a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp index b30b5259b..ced1cd6b0 100644 --- a/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp +++ b/src/test/storm/storage/MaximalEndComponentDecompositionTest.cpp @@ -148,7 +148,7 @@ TEST(MaximalEndComponentDecomposition, Example1) { storm::storage::MaximalEndComponentDecomposition mecDecomposition(*mdp); - EXPECT_EQ(mecDecomposition.size(), 2); + EXPECT_EQ(2ull, mecDecomposition.size()); ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2}); EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{3}); @@ -167,7 +167,7 @@ TEST(MaximalEndComponentDecomposition, Example2) { storm::storage::MaximalEndComponentDecomposition mecDecomposition(*mdp); - EXPECT_EQ(mecDecomposition.size(), 2); + EXPECT_EQ(2ull, mecDecomposition.size()); ASSERT_TRUE(mecDecomposition[0].getStateSet() == storm::storage::MaximalEndComponent::set_type{2}); EXPECT_TRUE(mecDecomposition[0].getChoicesForState(2) == storm::storage::MaximalEndComponent::set_type{4}); diff --git a/src/test/storm/utility/KSPTest.cpp b/src/test/storm/utility/KSPTest.cpp index dfe14e817..d584a7660 100644 --- a/src/test/storm/utility/KSPTest.cpp +++ b/src/test/storm/utility/KSPTest.cpp @@ -81,7 +81,7 @@ TEST(KSPTest, kspStateSet) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); auto bv = spg.getStates(7); - EXPECT_EQ(50, bv.getNumberOfSetBits()); + EXPECT_EQ(50ull, bv.getNumberOfSetBits()); // The result may sadly depend on the compiler/system, so checking a particular outcome is not feasible. // storm::storage::BitVector referenceBV(model->getNumberOfStates(), false); @@ -97,7 +97,7 @@ TEST(KSPTest, kspPathAsList) { storm::utility::ksp::ShortestPathsGenerator spg(*model, testState); auto list = spg.getPathAsList(7); - EXPECT_EQ(50, list.size()); + EXPECT_EQ(50ull, list.size()); // TODO: use path that actually has a loop or something to make this more interesting // auto reference = storm::utility::ksp::OrderedStateList{296, 288, 281, 272, 266, 260, 253, 245, 238, 230, 224, 218, 211, 203, 196, 188, 182, 176, 169, 161, 154, 146, 140, 134, 127, 119, 112, 104, 98, 92, 85, 77, 70, 81, 74, 65, 58, 52, 45, 37, 30, 22, 17, 12, 9, 6, 4, 2, 1, 0}; diff --git a/storm-config.h.in b/storm-config.h.in index b0290b751..55d2247d3 100644 --- a/storm-config.h.in +++ b/storm-config.h.in @@ -41,6 +41,13 @@ // Whether the optimization feature of Z3 is available and to be used (define/undef) #cmakedefine STORM_HAVE_Z3_OPTIMIZE +// Version of Z3 used by Storm. +#define STORM_Z3_VERSION_MAJOR @STORM_Z3_VERSION_MAJOR@ +#define STORM_Z3_VERSION_MINOR @STORM_Z3_VERSION_MINOR@ +#define STORM_Z3_VERSION_PATCH @STORM_Z3_VERSION_PATCH@ +#define STORM_Z3_VERSION @Z3_VERSION@ +#cmakedefine STORM_Z3_API_USES_STANDARD_INTEGERS + // Whether MathSAT is available and to be used (define/undef) #cmakedefine STORM_HAVE_MSAT From dfc0141894c34a1b8c4014adee82677f0595bad5 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 22 Jun 2018 13:25:21 +0200 Subject: [PATCH 365/647] minor fix to Z3 API modification --- src/storm/adapters/Z3ExpressionAdapter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/storm/adapters/Z3ExpressionAdapter.cpp b/src/storm/adapters/Z3ExpressionAdapter.cpp index fec9068b0..8a7f55bf5 100644 --- a/src/storm/adapters/Z3ExpressionAdapter.cpp +++ b/src/storm/adapters/Z3ExpressionAdapter.cpp @@ -1,5 +1,7 @@ #include "storm/adapters/Z3ExpressionAdapter.h" +#include + #include "storm/storage/expressions/Expressions.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/utility/macros.h" @@ -15,7 +17,7 @@ namespace storm { #ifdef STORM_Z3_API_USES_STANDARD_INTEGERS typedef int64_t Z3_SIGNED_INTEGER; - typedef int64_t Z3_UNSIGNED_INTEGER; + typedef uint64_t Z3_UNSIGNED_INTEGER; #else typedef long long Z3_SIGNED_INTEGER; typedef unsigned long long Z3_UNSIGNED_INTEGER; From 87e34d7b324686ae80143a4915aa128c327aec8d Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 22 Jun 2018 15:05:36 +0200 Subject: [PATCH 366/647] Added Support for Total Reward Formulas for DTMCs in the Sparse Engine --- src/storm/logic/FragmentSpecification.cpp | 2 ++ src/storm/modelchecker/AbstractModelChecker.cpp | 7 +++++++ src/storm/modelchecker/AbstractModelChecker.h | 1 + .../modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp | 6 ++++++ .../modelchecker/prctl/SparseDtmcPrctlModelChecker.h | 1 + .../prctl/helper/SparseDtmcPrctlHelper.cpp | 10 ++++++++++ .../modelchecker/prctl/helper/SparseDtmcPrctlHelper.h | 2 ++ src/storm/models/sparse/NondeterministicModel.cpp | 2 +- src/storm/models/sparse/NondeterministicModel.h | 2 +- 9 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index cdcfc6ecd..ad7678d79 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -59,6 +59,7 @@ namespace storm { prctl.setCumulativeRewardFormulasAllowed(true); prctl.setInstantaneousFormulasAllowed(true); prctl.setReachabilityRewardFormulasAllowed(true); + prctl.setTotalRewardFormulasAllowed(true); prctl.setLongRunAverageOperatorsAllowed(true); prctl.setStepBoundedCumulativeRewardFormulasAllowed(true); prctl.setTimeBoundedCumulativeRewardFormulasAllowed(true); @@ -81,6 +82,7 @@ namespace storm { csrl.setCumulativeRewardFormulasAllowed(true); csrl.setInstantaneousFormulasAllowed(true); csrl.setReachabilityRewardFormulasAllowed(true); + csrl.setTotalRewardFormulasAllowed(true); csrl.setLongRunAverageOperatorsAllowed(true); csrl.setTimeBoundedCumulativeRewardFormulasAllowed(true); diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index 2712b6d4a..e6c4f282f 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -105,6 +105,8 @@ namespace storm { return this->computeInstantaneousRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula())); } else if (rewardFormula.isReachabilityRewardFormula()) { return this->computeReachabilityRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula())); + } else if (rewardFormula.isTotalRewardFormula()) { + return this->computeTotalRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asTotalRewardFormula())); } else if (rewardFormula.isLongRunAverageRewardFormula()) { return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); } else if (rewardFormula.isConditionalRewardFormula()) { @@ -132,6 +134,11 @@ namespace storm { std::unique_ptr AbstractModelChecker::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); } + + template + std::unique_ptr AbstractModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + } template std::unique_ptr AbstractModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { diff --git a/src/storm/modelchecker/AbstractModelChecker.h b/src/storm/modelchecker/AbstractModelChecker.h index 0d391f1d9..3251ea1fa 100644 --- a/src/storm/modelchecker/AbstractModelChecker.h +++ b/src/storm/modelchecker/AbstractModelChecker.h @@ -63,6 +63,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); // The methods to compute the long-run average probabilities and timing measures. diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 4a746bf07..240657e81 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -123,6 +123,12 @@ namespace storm { std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } + + template + std::unique_ptr SparseDtmcPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet(), checkTask.getHint()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } template std::unique_ptr SparseDtmcPrctlModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index ebc7d39a3..6500da487 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -30,6 +30,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 03d3fb1a0..2745569ad 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -383,6 +383,16 @@ namespace storm { return result; } + template + std::vector SparseDtmcPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ModelCheckerHint const& hint) { + // Identify the states from which only states with zero reward are reachable. + // We can then compute reachability rewards assuming these states as target set. + storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix); + storm::storage::BitVector rew0States = storm::utility::graph::performProbGreater0(backwardTransitions, statesWithoutReward, ~statesWithoutReward); + rew0States.complement(); + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0States, qualitative, hint); + } + template std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index a4e2882bc..49fe21deb 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -42,6 +42,8 @@ namespace storm { static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount); + static std::vector computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); diff --git a/src/storm/models/sparse/NondeterministicModel.cpp b/src/storm/models/sparse/NondeterministicModel.cpp index 263f67c16..08331c6f5 100644 --- a/src/storm/models/sparse/NondeterministicModel.cpp +++ b/src/storm/models/sparse/NondeterministicModel.cpp @@ -45,7 +45,7 @@ namespace storm { } template - std::shared_ptr> NondeterministicModel::applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates) { + std::shared_ptr> NondeterministicModel::applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates) const { storm::storage::SparseModelMemoryProduct memoryProduct(*this, scheduler); if (!dropUnreachableStates) { memoryProduct.setBuildFullProduct(); diff --git a/src/storm/models/sparse/NondeterministicModel.h b/src/storm/models/sparse/NondeterministicModel.h index ac8603e7f..5280ba962 100644 --- a/src/storm/models/sparse/NondeterministicModel.h +++ b/src/storm/models/sparse/NondeterministicModel.h @@ -57,7 +57,7 @@ namespace storm { * @param scheduler the considered scheduler. * @param dropUnreachableStates if set, the resulting model only considers the states that are reachable from an initial state */ - std::shared_ptr> applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates = true); + std::shared_ptr> applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates = true) const; virtual void printModelInformationToStream(std::ostream& out) const override; From c2dd57cda57319a548c2ee1de3f50cc718a205fc Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 22 Jun 2018 17:28:01 +0200 Subject: [PATCH 367/647] total rewards for mdps --- .../prctl/helper/SparseMdpPrctlHelper.cpp | 75 +++++++++++++++++++ .../prctl/helper/SparseMdpPrctlHelper.h | 3 + .../transformer/EndComponentEliminator.h | 34 +++++---- 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 8c13c73c4..e2ce02120 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -35,6 +35,8 @@ #include "storm/utility/ProgressMeasurement.h" #include "storm/utility/export.h" +#include "storm/transformer/EndComponentEliminator.h" + #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/exceptions/InvalidStateException.h" @@ -839,6 +841,79 @@ namespace storm { return result; } + template + template + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { + + // Reduce to reachability rewards + if (goal.minimize) { + STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented"); + // Identify the states from which no reward can be collected under some scheduler + storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix); + storm::storage::BitVector statesWithZeroRewardChoice(transitionMatrix.getRowGroupCount(), false); + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + if (choicesWithoutReward.getNextSetIndex(transitionMatrix.getRowGroupIndices()[state])< transitionMatrix.getRowGroupIndices()[state + 1]) { + statesWithZeroRewardChoice.set(state); + } + } + storm::storage::BitVector rew0EStates = storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, statesWithZeroRewardChoice, ~statesWithZeroRewardChoice, false, 0, choicesWithoutReward); + rew0EStates.complement(); + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0EStates, qualitative, false, hint); + } else { + // Identify the states from which only states with zero reward are reachable. + storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix); + storm::storage::BitVector rew0AStates = storm::utility::graph::performProbGreater0E(backwardTransitions, statesWithoutReward, ~statesWithoutReward); + rew0AStates.complement(); + + // There might be end components that consists only of states/choices with zero rewards. The reachability reward semantics would assign such + // end components reward infinity. To avoid this, we potentially need to eliminate such end components + storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true); + if (storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, rew0AStates).full()) { + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0AStates, qualitative, produceScheduler, hint); + } else { + // The transformation of schedulers for the ec-eliminated system back to the original one is not implemented. + STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented"); + storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix); + auto ecElimResult = storm::transformer::EndComponentEliminator::transform(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), choicesWithoutReward, rew0AStates, true); + storm::storage::BitVector newRew0AStates(ecElimResult.matrix.getRowGroupCount(), false); + for (auto const& oldRew0AState : rew0AStates) { + newRew0AStates.set(ecElimResult.oldToNewStateMapping[oldRew0AState]); + } + + return computeReachabilityRewardsHelper(env, std::move(goal), ecElimResult.matrix, ecElimResult.matrix.transpose(true), + [&] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { + std::vector result; + std::vector oldChoiceRewards = rewardModel.getTotalRewardVector(rowCount, transitionMatrix); + result.reserve(rowCount); + for (uint64_t newState : maybeStates) { + for (uint64_t newChoice = transitionMatrix.getRowGroupIndices()[newState]; newChoice < transitionMatrix.getRowGroupIndices()[newState + 1]; ++newChoice) { + uint64_t oldChoice = ecElimResult.newToOldRowMapping[newChoice]; + result.push_back(oldChoiceRewards[oldChoice]); + } + } + STORM_LOG_ASSERT(result.size() == rowCount, "Unexpected size of reward vector."); + return result; + }, newRew0AStates, qualitative, false, + [&] () { + storm::storage::BitVector newStatesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false); + for (auto const& oldStateWithoutRew : statesWithoutReward) { + newStatesWithoutReward.set(ecElimResult.oldToNewStateMapping[oldStateWithoutRew]); + } + return newStatesWithoutReward; + }, + [&] () { + storm::storage::BitVector newChoicesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false); + for (uint64_t newChoice = 0; newChoice < ecElimResult.matrix.getRowCount(); ++newChoice) { + if (choicesWithoutReward.get(ecElimResult.newToOldChoiceMapping[newChoice])) { + newChoicesWithoutReward.set(newChoice); + } + } + return newChoicesWithoutReward; + }); + } + } + } + template template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index 920bb4d47..b1de7a442 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -55,6 +55,9 @@ namespace storm { template static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); + template + static MDPSparseModelCheckingHelperReturnType computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + template static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); diff --git a/src/storm/transformer/EndComponentEliminator.h b/src/storm/transformer/EndComponentEliminator.h index 635cba7b6..378edc86a 100644 --- a/src/storm/transformer/EndComponentEliminator.h +++ b/src/storm/transformer/EndComponentEliminator.h @@ -18,7 +18,7 @@ namespace storm { // The resulting matrix storm::storage::SparseMatrix matrix; // Index mapping that gives for each row of the resulting matrix the corresponding row in the original matrix. - // For the empty rows added to EC states, an arbitrary row of the original matrix that stays inside the EC is given. + // For the sink rows added to EC states, an arbitrary row of the original matrix that stays inside the EC is given. std::vector newToOldRowMapping; // Gives for each state (=rowGroup) of the original matrix the corresponding state in the resulting matrix. // States of a removed ECs are mapped to the state that substitutes the EC. @@ -38,9 +38,10 @@ namespace storm { * * For each such EC (that is not contained in another EC), we add a new state and redirect all incoming and outgoing * transitions of the EC to (and from) this state. - * If addEmptyRowStates is true for at least one state of an eliminated EC, an empty row is added to the new state (representing the choice to stay at the EC forever). + * If addSinkRowStates is true for at least one state of an eliminated EC, a row is added to the new state (representing the choice to stay at the EC forever). + * If addSelfLoopAtSinkStates is true, such rows get a selfloop (with value 1). Otherwise, the row remains empty. */ - static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix const& originalMatrix, storm::storage::BitVector const& subsystemStates, storm::storage::BitVector const& possibleECRows, storm::storage::BitVector const& addEmptyRowStates) { + static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix const& originalMatrix, storm::storage::BitVector const& subsystemStates, storm::storage::BitVector const& possibleECRows, storm::storage::BitVector const& addSinkRowStates, bool addSelfLoopAtSinkStates = false) { STORM_LOG_DEBUG("Invoked EndComponentEliminator on matrix with " << originalMatrix.getRowGroupCount() << " row groups."); storm::storage::MaximalEndComponentDecomposition ecs = computeECs(originalMatrix, possibleECRows, subsystemStates); @@ -57,7 +58,7 @@ namespace storm { EndComponentEliminatorReturnType result; std::vector newRowGroupIndices; result.oldToNewStateMapping = std::vector(originalMatrix.getRowGroupCount(), std::numeric_limits::max()); - storm::storage::BitVector emptyRows(originalMatrix.getRowCount(), false); // will be resized as soon as the rowCount of the resulting matrix is known + storm::storage::BitVector sinkRows(originalMatrix.getRowCount(), false); // will be resized as soon as the rowCount of the resulting matrix is known for(auto keptState : keptStates) { result.oldToNewStateMapping[keptState] = newRowGroupIndices.size(); // i.e., the current number of processed states @@ -68,7 +69,7 @@ namespace storm { } for (auto const& ec : ecs) { newRowGroupIndices.push_back(result.newToOldRowMapping.size()); - bool ecGetsEmptyRow = false; + bool ecGetsSinkRow = false; for (auto const& stateActionsPair : ec) { result.oldToNewStateMapping[stateActionsPair.first] = newRowGroupIndices.size()-1; for(uint_fast64_t row = originalMatrix.getRowGroupIndices()[stateActionsPair.first]; row < originalMatrix.getRowGroupIndices()[stateActionsPair.first +1]; ++row) { @@ -76,18 +77,18 @@ namespace storm { result.newToOldRowMapping.push_back(row); } } - ecGetsEmptyRow |= addEmptyRowStates.get(stateActionsPair.first); + ecGetsSinkRow |= addSinkRowStates.get(stateActionsPair.first); } - if(ecGetsEmptyRow) { + if(ecGetsSinkRow) { STORM_LOG_ASSERT(result.newToOldRowMapping.size() < originalMatrix.getRowCount(), "Didn't expect to see more rows in the reduced matrix than in the original one."); - emptyRows.set(result.newToOldRowMapping.size(), true); + sinkRows.set(result.newToOldRowMapping.size(), true); result.newToOldRowMapping.push_back(*ec.begin()->second.begin()); } } newRowGroupIndices.push_back(result.newToOldRowMapping.size()); - emptyRows.resize(result.newToOldRowMapping.size()); + sinkRows.resize(result.newToOldRowMapping.size()); - result.matrix = buildTransformedMatrix(originalMatrix, newRowGroupIndices, result.newToOldRowMapping, result.oldToNewStateMapping, emptyRows); + result.matrix = buildTransformedMatrix(originalMatrix, newRowGroupIndices, result.newToOldRowMapping, result.oldToNewStateMapping, sinkRows, addSelfLoopAtSinkStates); STORM_LOG_DEBUG("EndComponentEliminator is done. Resulting matrix has " << result.matrix.getRowGroupCount() << " row groups."); return result; } @@ -136,15 +137,20 @@ namespace storm { std::vector const& newRowGroupIndices, std::vector const& newToOldRowMapping, std::vector const& oldToNewStateMapping, - storm::storage::BitVector const& emptyRows) { + storm::storage::BitVector const& sinkRows, + bool addSelfLoopAtSinkStates) { uint_fast64_t numRowGroups = newRowGroupIndices.size()-1; uint_fast64_t newRow = 0; storm::storage::SparseMatrixBuilder builder(newToOldRowMapping.size(), numRowGroups, originalMatrix.getEntryCount(), false, true, numRowGroups); - for(uint_fast64_t newRowGroup = 0; newRowGroup < numRowGroups; ++newRowGroup) { + for (uint_fast64_t newRowGroup = 0; newRowGroup < numRowGroups; ++newRowGroup) { builder.newRowGroup(newRow); - for(; newRow < newRowGroupIndices[newRowGroup+1]; ++newRow) { - if(!emptyRows.get(newRow)) { + for (; newRow < newRowGroupIndices[newRowGroup + 1]; ++newRow) { + if (sinkRows.get(newRow)) { + if (addSelfLoopAtSinkStates) { + builder.addNextValue(newRow, newRowGroup, storm::utility::one()); + } + } else { // Make sure that the entries for this row are inserted in the right order. // Also, transitions to the same EC need to be merged and transitions to states that are erased need to be ignored std::map sortedEntries; From 0be012609552e11ba920107c00b51556b96e45a4 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sun, 24 Jun 2018 15:07:23 +0200 Subject: [PATCH 368/647] fixed support for highlevel counterex for expected rewards in dtmcs --- src/storm-cli-utilities/model-handling.h | 5 ++++- .../SMTMinimalLabelSetGenerator.h | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 41faf8732..41df3fabf 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -422,7 +422,10 @@ namespace storm { STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Counterexample generation is currently only supported for sparse models."); auto sparseModel = model->as>(); - + for (auto& rewModel : sparseModel->getRewardModels()) { + rewModel.second.reduceToStateBasedRewards(sparseModel->getTransitionMatrix(), true); + } + STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "Counterexample is currently only supported for discrete-time models."); auto counterexampleSettings = storm::settings::getModule(); diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index a3dfbd066..52a24d0dd 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1516,7 +1516,7 @@ namespace storm { * Returns the sub-model obtained from removing all choices that do not originate from the specified filterLabelSet. * Also returns the Labelsets of the sub-model. */ - static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional absorbState = boost::none) { + static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional const& rewardName = boost::none, boost::optional absorbState = boost::none) { bool customRowGrouping = model.isOfType(storm::models::ModelType::Mdp); @@ -1556,13 +1556,19 @@ namespace storm { resultLabelSet.emplace_back(); ++currentRow; } + } - + + if (rewardName) { + auto const &origRewModel = model.getRewardModel(rewardName.get()); + assert(origRewModel.hasOnlyStateRewards()); + } + std::shared_ptr> resultModel; if (model.isOfType(storm::models::ModelType::Dtmc)) { - resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling())); + resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling()), model.getRewardModels()); } else { - resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling())); + resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling()), model.getRewardModels()); } return std::make_pair(resultModel, std::move(resultLabelSet)); @@ -1748,7 +1754,7 @@ namespace storm { } - auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, psiStates.getNextSetIndex(0)); + auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, rewardName, psiStates.getNextSetIndex(0)); std::shared_ptr> const& subModel = subChoiceOrigins.first; std::vector> const& subLabelSets = subChoiceOrigins.second; @@ -1958,7 +1964,8 @@ namespace storm { rewardName = rewardOperator.getRewardModelName(); STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for probability formulas."); - + STORM_LOG_THROW(model.hasRewardModel(rewardName.get()), storm::exceptions::InvalidPropertyException, "Property refers to reward " << rewardName.get() << " but model does not contain such a reward model."); + STORM_LOG_THROW(model.getRewardModel(rewardName.get()).hasOnlyStateRewards(), storm::exceptions::NotSupportedException, "We only support state-based rewards at the moment."); } bool strictBound = comparisonType == storm::logic::ComparisonType::Less; storm::logic::Formula const& subformula = formula->asOperatorFormula().getSubformula(); From b3edae870762db1a0747cdc7a229e94c77a442b3 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 11:21:31 +0200 Subject: [PATCH 369/647] fixed fragment specification: total reward formulas should not be supported for hybrid/dd right now --- src/storm/logic/FragmentSpecification.cpp | 2 -- .../prctl/SparseDtmcPrctlModelChecker.cpp | 2 +- .../prctl/SparseMdpPrctlModelChecker.cpp | 13 ++++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index ad7678d79..cdcfc6ecd 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -59,7 +59,6 @@ namespace storm { prctl.setCumulativeRewardFormulasAllowed(true); prctl.setInstantaneousFormulasAllowed(true); prctl.setReachabilityRewardFormulasAllowed(true); - prctl.setTotalRewardFormulasAllowed(true); prctl.setLongRunAverageOperatorsAllowed(true); prctl.setStepBoundedCumulativeRewardFormulasAllowed(true); prctl.setTimeBoundedCumulativeRewardFormulasAllowed(true); @@ -82,7 +81,6 @@ namespace storm { csrl.setCumulativeRewardFormulasAllowed(true); csrl.setInstantaneousFormulasAllowed(true); csrl.setReachabilityRewardFormulasAllowed(true); - csrl.setTotalRewardFormulasAllowed(true); csrl.setLongRunAverageOperatorsAllowed(true); csrl.setTimeBoundedCumulativeRewardFormulasAllowed(true); diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 240657e81..082ddd813 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -31,7 +31,7 @@ namespace storm { template bool SparseDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true)); } template diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index 074a679b6..ba5aac431 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -38,7 +38,7 @@ namespace storm { template bool SparseMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true))) { + if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -172,6 +172,17 @@ namespace storm { } return result; } + + template + std::unique_ptr SparseMdpPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + if (checkTask.isProduceSchedulersSet() && ret.scheduler) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + } + return result; + } template std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { From b5566fa861d8b57342101f03403135f68c942880 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 11:22:02 +0200 Subject: [PATCH 370/647] more on total reward formulas for mdps --- src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h | 1 + .../modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 5ea9a010a..5667549e3 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -27,6 +27,7 @@ namespace storm { virtual std::unique_ptr computeConditionalProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index e2ce02120..4b29d2324 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -846,7 +846,7 @@ namespace storm { MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { // Reduce to reachability rewards - if (goal.minimize) { + if (goal.minimize()) { STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented"); // Identify the states from which no reward can be collected under some scheduler storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix); @@ -883,7 +883,7 @@ namespace storm { return computeReachabilityRewardsHelper(env, std::move(goal), ecElimResult.matrix, ecElimResult.matrix.transpose(true), [&] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { std::vector result; - std::vector oldChoiceRewards = rewardModel.getTotalRewardVector(rowCount, transitionMatrix); + std::vector oldChoiceRewards = rewardModel.getTotalRewardVector(transitionMatrix); result.reserve(rowCount); for (uint64_t newState : maybeStates) { for (uint64_t newChoice = transitionMatrix.getRowGroupIndices()[newState]; newChoice < transitionMatrix.getRowGroupIndices()[newState + 1]; ++newChoice) { @@ -904,7 +904,7 @@ namespace storm { [&] () { storm::storage::BitVector newChoicesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false); for (uint64_t newChoice = 0; newChoice < ecElimResult.matrix.getRowCount(); ++newChoice) { - if (choicesWithoutReward.get(ecElimResult.newToOldChoiceMapping[newChoice])) { + if (choicesWithoutReward.get(ecElimResult.newToOldRowMapping[newChoice])) { newChoicesWithoutReward.set(newChoice); } } @@ -1761,6 +1761,7 @@ namespace storm { template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); template double SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); @@ -1771,6 +1772,7 @@ namespace storm { template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); From 8df9b461cb8319ceccaf2ce6cc47fcda41f5f993 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 11:22:31 +0200 Subject: [PATCH 371/647] total reward formulas for ctmcs and markov automata --- .../csl/SparseCtmcCslModelChecker.cpp | 10 ++++- .../csl/SparseCtmcCslModelChecker.h | 1 + .../SparseMarkovAutomatonCslModelChecker.cpp | 11 +++++- .../SparseMarkovAutomatonCslModelChecker.h | 1 + .../csl/helper/SparseCtmcCslHelper.cpp | 37 +++++++++++++++++++ .../csl/helper/SparseCtmcCslHelper.h | 3 ++ .../helper/SparseMarkovAutomatonCslHelper.cpp | 18 +++++++++ .../helper/SparseMarkovAutomatonCslHelper.h | 3 ++ 8 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp index 52d49815e..3cedc1fab 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -37,14 +37,14 @@ namespace storm { template::SupportsExponential, int>::type> bool SparseCtmcCslModelChecker::canHandleImplementation(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true)); + return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true)); } template template::SupportsExponential, int>::type> bool SparseCtmcCslModelChecker::canHandleImplementation(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true)); } template @@ -117,6 +117,12 @@ namespace storm { return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } + template + std::unique_ptr SparseCtmcCslModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } + template std::unique_ptr SparseCtmcCslModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h index 9bf94fe93..5bf4735d0 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -33,6 +33,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; private: template::SupportsExponential, int>::type = 0> diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 74c976fd6..d72503cae 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -89,7 +89,16 @@ namespace storm { return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } - + + template + std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute reachability rewards in non-closed Markov automaton."); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeTotalRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); + + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); + } + template std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 60cf49d37..3bd557dd4 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -24,6 +24,7 @@ namespace storm { virtual std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 99bad8ce1..f888ed1b6 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -329,6 +329,38 @@ namespace storm { return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative); } + template + std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, bool qualitative) { + STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + + storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + + std::vector totalRewardVector; + if (rewardModel.hasStateRewards()) { + totalRewardVector = rewardModel.getStateRewardVector(); + typename std::vector::const_iterator it2 = exitRateVector.begin(); + for (typename std::vector::iterator it1 = totalRewardVector.begin(), ite1 = totalRewardVector.end(); it1 != ite1; ++it1, ++it2) { + *it1 /= *it2; + } + if (rewardModel.hasStateActionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, rewardModel.getStateActionRewardVector(), totalRewardVector); + } + if (rewardModel.hasTransitionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, probabilityMatrix.getPointwiseProductRowSumVector(rewardModel.getTransitionRewardMatrix()), totalRewardVector); + } + } else if (rewardModel.hasTransitionRewards()) { + totalRewardVector = probabilityMatrix.getPointwiseProductRowSumVector(rewardModel.getTransitionRewardMatrix()); + if (rewardModel.hasStateActionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, rewardModel.getStateActionRewardVector(), totalRewardVector); + } + } else { + totalRewardVector = rewardModel.getStateActionRewardVector(); + } + + RewardModelType dtmcRewardModel(std::move(totalRewardVector)); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeTotalRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, dtmcRewardModel, qualitative); + } + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector) { @@ -743,6 +775,8 @@ namespace storm { template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); @@ -772,6 +806,9 @@ namespace storm { template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h index 28125c7c9..b6e7b508c 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h @@ -44,6 +44,9 @@ namespace storm { template static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + + template + static std::vector computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, bool qualitative); template static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 8eb688d55..6e6a39acf 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -583,6 +583,20 @@ namespace storm { return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false).values); } + template + std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel) { + + // Get a reward model where the state rewards are scaled accordingly + std::vector stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero()); + for (auto const markovianState : markovianStates) { + stateRewardWeights[markovianState] = storm::utility::one() / exitRateVector[markovianState]; + } + std::vector totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights); + RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector)); + + return SparseMdpPrctlHelper::computeTotalRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, false, false).values; + } + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates) { @@ -1020,6 +1034,8 @@ namespace storm { template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); + template std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); @@ -1038,6 +1054,8 @@ namespace storm { template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); + template std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index fbfeaa7dd..6b6a94a50 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -26,6 +26,9 @@ namespace storm { template static std::vector computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); + template + static std::vector computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel); + template static std::vector computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates); From 1f4c0325be6b9d9103cd98a87e68c2fa161bf34b Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 11:22:52 +0200 Subject: [PATCH 372/647] test cases for ctmcs and markov automata --- resources/examples/testfiles/ctmc/simple2.sm | 28 ++ resources/examples/testfiles/ma/simple2.ma | 40 +++ .../modelchecker/CtmcCslModelCheckerTest.cpp | 23 ++ .../MarkovAutomatonCslModelCheckerTest.cpp | 264 ++++++++++++++++++ 4 files changed, 355 insertions(+) create mode 100644 resources/examples/testfiles/ctmc/simple2.sm create mode 100644 resources/examples/testfiles/ma/simple2.ma create mode 100644 src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp diff --git a/resources/examples/testfiles/ctmc/simple2.sm b/resources/examples/testfiles/ctmc/simple2.sm new file mode 100644 index 000000000..5fcc0dcab --- /dev/null +++ b/resources/examples/testfiles/ctmc/simple2.sm @@ -0,0 +1,28 @@ + +ctmc + + +module main + + s : [0..4]; // current state: + + + <> s=0 -> 4 : (s'=1) + 4 : (s'=2); + <> s=1 -> 0.3 : (s'=2) + 0.7 : (s'=1); + <> s=2 -> 0.5 : (s'=2) + 0.5 : (s'=3); + <> s=3 -> 1 : (s'=4); + <> s=4 -> 1 : (s'=3); + +endmodule + +rewards "rew1" + s=0 : 7; + [] s=2 : 1; +endrewards + + +rewards "rew2" + s=0 : 7; + [] s=2 : 1; + [] s=4 : 100; +endrewards diff --git a/resources/examples/testfiles/ma/simple2.ma b/resources/examples/testfiles/ma/simple2.ma new file mode 100644 index 000000000..95e0059b7 --- /dev/null +++ b/resources/examples/testfiles/ma/simple2.ma @@ -0,0 +1,40 @@ + +ma + + +module main + + s : [0..4]; // current state: + + + <> s=0 -> 4 : (s'=1) + 4 : (s'=2); + [alpha] s=1 -> 1 : (s'=0); + [beta] s=1 -> 0.3 : (s'=2) + 0.7 : (s'=1); + [gamma] s=2 -> 1 : (s'=1); + [delta] s=2 -> 0.5 : (s'=2) + 0.5 : (s'=3); + <> s=3 -> 1 : (s'=4); + [lambda] s=4 -> 1 : (s'=3); + +endmodule + +rewards "rew0" + [delta] s=2 : 1; +endrewards + +rewards "rew1" + s=0 : 7; + [delta] s=2 : 1; +endrewards + + +rewards "rew2" + s=0 : 7; + [delta] s=2 : 1; + [lambda] s=4 : 100; +endrewards + +rewards "rew3" + s=0 : 7; + [delta] s=2 : 1; + [gamma] s=4 : 100; +endrewards diff --git a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp index 1b83be1c6..11d7d48a4 100644 --- a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp @@ -140,6 +140,7 @@ namespace { ValueType precision() const { return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");} bool isSparseModel() const { return std::is_same::value; } bool isSymbolicModel() const { return std::is_same::value; } + storm::settings::modules::CoreSettings::Engine getEngine() const { return TestType::engine; } template typename std::enable_if::value, std::pair, std::vector>>>::type @@ -362,7 +363,29 @@ namespace { result = checker->check(this->env(), tasks[6]); EXPECT_NEAR(this->parseNumber("0.9100373532"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + } + + TYPED_TEST(CtmcCslModelCheckerTest, simple2) { + std::string formulasString = "R{\"rew1\"}=? [ C ]"; + formulasString += "; R{\"rew2\"}=? [ C ]"; + auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ctmc/simple2.sm", formulasString); + auto model = std::move(modelFormulas.first); + auto tasks = this->getTasks(modelFormulas.second); + EXPECT_EQ(5ul, model->getNumberOfStates()); + EXPECT_EQ(8ul, model->getNumberOfTransitions()); + ASSERT_EQ(model->getType(), storm::models::ModelType::Ctmc); + auto checker = this->createModelChecker(model); + std::unique_ptr result; + + // Total reward formulas are currently not supported for non-sparse models. + if (this->isSparseModel()) { + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("23/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result), this->precision())); + } } } \ No newline at end of file diff --git a/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp b/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp new file mode 100644 index 000000000..4bbf93b75 --- /dev/null +++ b/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp @@ -0,0 +1,264 @@ +#include "gtest/gtest.h" +#include "storm-config.h" + +#include "test/storm_gtest.h" + +#include "storm/api/builder.h" +#include "storm-parsers/api/model_descriptions.h" +#include "storm/api/properties.h" +#include "storm-parsers/api/properties.h" + +#include "storm/models/sparse/MarkovAutomaton.h" +#include "storm/models/symbolic/MarkovAutomaton.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h" +#include "storm/modelchecker/results/QuantitativeCheckResult.h" +#include "storm/modelchecker/results/QualitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" +#include "storm/settings/modules/CoreSettings.h" +#include "storm/logic/Formulas.h" +#include "storm/storage/jani/Property.h" +#include "storm/exceptions/UncheckedRequirementException.h" + +namespace { + class SparseDoubleValueIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::MarkovAutomaton ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::ValueIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-10)); + return env; + } + }; + class SparseDoubleIntervalIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = false; + typedef double ValueType; + typedef storm::models::sparse::MarkovAutomaton ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().setForceSoundness(true); + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::IntervalIteration); + env.solver().minMax().setPrecision(storm::utility::convertNumber(1e-6)); + env.solver().minMax().setRelativeTerminationCriterion(false); + return env; + } + }; + class SparseRationalPolicyIterationEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = true; + typedef storm::RationalNumber ValueType; + typedef storm::models::sparse::MarkovAutomaton ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::PolicyIteration); + return env; + } + }; + class SparseRationalRationalSearchEnvironment { + public: + static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models + static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse; + static const bool isExact = true; + typedef storm::RationalNumber ValueType; + typedef storm::models::sparse::MarkovAutomaton ModelType; + static storm::Environment createEnvironment() { + storm::Environment env; + env.solver().minMax().setMethod(storm::solver::MinMaxMethod::RationalSearch); + return env; + } + }; + + template + class MarkovAutomatonCslModelCheckerTest : public ::testing::Test { + public: + typedef typename TestType::ValueType ValueType; + typedef typename storm::models::sparse::MarkovAutomaton SparseModelType; + typedef typename storm::models::symbolic::MarkovAutomaton SymbolicModelType; + + MarkovAutomatonCslModelCheckerTest() : _environment(TestType::createEnvironment()) {} + storm::Environment const& env() const { return _environment; } + ValueType parseNumber(std::string const& input) const { return storm::utility::convertNumber(input);} + ValueType precision() const { return TestType::isExact ? parseNumber("0") : parseNumber("1e-6");} + bool isSparseModel() const { return std::is_same::value; } + bool isSymbolicModel() const { return std::is_same::value; } + + template + typename std::enable_if::value, std::pair, std::vector>>>::type + buildModelFormulas(std::string const& pathToPrismFile, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const { + std::pair, std::vector>> result; + storm::prism::Program program = storm::api::parseProgram(pathToPrismFile); + program = storm::utility::prism::preprocess(program, constantDefinitionString); + result.second = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); + result.first = storm::api::buildSparseModel(program, result.second)->template as(); + return result; + } + + template + typename std::enable_if::value, std::pair, std::vector>>>::type + buildModelFormulas(std::string const& pathToPrismFile, std::string const& formulasAsString, std::string const& constantDefinitionString = "") const { + std::pair, std::vector>> result; + storm::prism::Program program = storm::api::parseProgram(pathToPrismFile); + program = storm::utility::prism::preprocess(program, constantDefinitionString); + result.second = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulasAsString, program)); + result.first = storm::api::buildSymbolicModel(program, result.second)->template as(); + return result; + } + + std::vector> getTasks(std::vector> const& formulas) const { + std::vector> result; + for (auto const& f : formulas) { + result.emplace_back(*f); + } + return result; + } + + template + typename std::enable_if::value, std::shared_ptr>>::type + createModelChecker(std::shared_ptr const& model) const { + if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Sparse) { + return std::make_shared>(*model); + } + } + + template + typename std::enable_if::value, std::shared_ptr>>::type + createModelChecker(std::shared_ptr const& model) const { + if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { + return std::make_shared>(*model); + } else if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Dd) { + return std::make_shared>(*model); + } + } + + bool getQualitativeResultAtInitialState(std::shared_ptr> const& model, std::unique_ptr& result) { + auto filter = getInitialStateFilter(model); + result->filter(*filter); + return result->asQualitativeCheckResult().forallTrue(); + } + + ValueType getQuantitativeResultAtInitialState(std::shared_ptr> const& model, std::unique_ptr& result) { + auto filter = getInitialStateFilter(model); + result->filter(*filter); + return result->asQuantitativeCheckResult().getMin(); + } + + private: + storm::Environment _environment; + + std::unique_ptr getInitialStateFilter(std::shared_ptr> const& model) const { + if (isSparseModel()) { + return std::make_unique(model->template as()->getInitialStates()); + } else { + return std::make_unique>(model->template as()->getReachableStates(), model->template as()->getInitialStates()); + } + } + }; + + typedef ::testing::Types< + SparseDoubleValueIterationEnvironment, + SparseDoubleIntervalIterationEnvironment, + SparseRationalPolicyIterationEnvironment, + SparseRationalRationalSearchEnvironment, + > TestingTypes; + + TYPED_TEST_CASE(MarkovAutomatonCslModelCheckerTest, TestingTypes); + + + TYPED_TEST(MarkovAutomatonCslModelCheckerTest, server) { + std::string formulasString = "Tmax=? [F \"error\"]"; + formulasString += "; Pmax=? [F \"processB\"]"; + formulasString += "; Pmax=? [F<1 \"error\"]"; + + auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/server.ma", formulasString); + auto model = std::move(modelFormulas.first); + auto tasks = this->getTasks(modelFormulas.second); + EXPECT_EQ(6ul, model->getNumberOfStates()); + EXPECT_EQ(10ul, model->getNumberOfTransitions()); + ASSERT_EQ(model->getType(), storm::models::ModelType::MarkovAutomaton); + auto checker = this->createModelChecker(model); + std::unique_ptr result; + + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("11/6"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_NEAR(this->parseNumber("2/3"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[2]); + EXPECT_NEAR(this->parseNumber("0.455504"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + } + + TYPED_TEST(MarkovAutomatonCslModelCheckerTest, simple) { + std::string formulasString = "Pmin=? [F<1 s>2]"; + formulasString += "; Pmax=? [F<1.3 s=3]"; + + auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/simple.ma", formulasString); + auto model = std::move(modelFormulas.first); + auto tasks = this->getTasks(modelFormulas.second); + EXPECT_EQ(5ul, model->getNumberOfStates()); + EXPECT_EQ(8ul, model->getNumberOfTransitions()); + ASSERT_EQ(model->getType(), storm::models::ModelType::MarkovAutomaton); + auto checker = this->createModelChecker(model); + std::unique_ptr result; + + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("0.6321205588"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_NEAR(this->parseNumber("0.727468207"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + } + + TYPED_TEST(MarkovAutomatonCslModelCheckerTest, simple2) { + std::string formulasString = "R{\"rew0\"}max=? [C]"; + formulasString += "; R{\"rew0\"}min=? [C]"; + formulasString += "; R{\"rew1\"}max=? [C]"; + formulasString += "; R{\"rew1\"}min=? [C]"; + formulasString += "; R{\"rew2\"}max=? [C]"; + formulasString += "; R{\"rew2\"}min=? [C]"; + formulasString += "; R{\"rew3\"}min=? [C]"; + + auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/simple2.nm", formulasString); + auto model = std::move(modelFormulas.first); + auto tasks = this->getTasks(modelFormulas.second); + EXPECT_EQ(5ul, model->getNumberOfStates()); + EXPECT_EQ(8ul, model->getNumberOfTransitions()); + ASSERT_EQ(model->getType(), storm::models::ModelType::MarkovAutomaton); + auto checker = this->createModelChecker(model); + std::unique_ptr result; + + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("2"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_NEAR(this->parseNumber("0"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[2]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[3]); + EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[4]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + result = checker->check(this->env(), tasks[5]); + EXPECT_NEAR(this->parseNumber("7/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[6]); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); + + } +} \ No newline at end of file From 5a16b2befa3134d13e1c6c261f75902e50c83018 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 15:23:25 +0200 Subject: [PATCH 373/647] minor fixes to let the total reward tests compile and pass --- resources/examples/testfiles/ma/simple2.ma | 8 ++-- .../SparseMarkovAutomatonCslModelChecker.cpp | 2 +- .../modelchecker/CtmcCslModelCheckerTest.cpp | 2 +- .../MarkovAutomatonCslModelCheckerTest.cpp | 40 +++++++++++-------- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/resources/examples/testfiles/ma/simple2.ma b/resources/examples/testfiles/ma/simple2.ma index 95e0059b7..46fa2207b 100644 --- a/resources/examples/testfiles/ma/simple2.ma +++ b/resources/examples/testfiles/ma/simple2.ma @@ -4,12 +4,13 @@ ma module main - s : [0..4]; // current state: + s : [0..5]; // current state: <> s=0 -> 4 : (s'=1) + 4 : (s'=2); [alpha] s=1 -> 1 : (s'=0); - [beta] s=1 -> 0.3 : (s'=2) + 0.7 : (s'=1); + [beta] s=1 -> 0.3 : (s'=5) + 0.7 : (s'=1); + <> s=5 -> 1 : (s'=2); [gamma] s=2 -> 1 : (s'=1); [delta] s=2 -> 0.5 : (s'=2) + 0.5 : (s'=3); <> s=3 -> 1 : (s'=4); @@ -36,5 +37,6 @@ endrewards rewards "rew3" s=0 : 7; [delta] s=2 : 1; - [gamma] s=4 : 100; + [gamma] s=2 : 100; + [lambda] s=4 : 27; endrewards diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index d72503cae..929ea8721 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -29,7 +29,7 @@ namespace storm { template bool SparseMarkovAutomatonCslModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true))) { + if(formula.isInFragment(storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula diff --git a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp index 11d7d48a4..bf6f8654f 100644 --- a/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/CtmcCslModelCheckerTest.cpp @@ -384,7 +384,7 @@ namespace { EXPECT_NEAR(this->parseNumber("23/8"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); result = checker->check(this->env(), tasks[1]); - EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result), this->precision())); + EXPECT_TRUE(storm::utility::isInfinity(this->getQuantitativeResultAtInitialState(model, result))); } } diff --git a/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp b/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp index 4bbf93b75..c979c3777 100644 --- a/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/MarkovAutomatonCslModelCheckerTest.cpp @@ -135,11 +135,12 @@ namespace { template typename std::enable_if::value, std::shared_ptr>>::type createModelChecker(std::shared_ptr const& model) const { - if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { - return std::make_shared>(*model); - } else if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Dd) { - return std::make_shared>(*model); - } +// if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Hybrid) { +// return std::make_shared>(*model); +// } else if (TestType::engine == storm::settings::modules::CoreSettings::Engine::Dd) { +// return std::make_shared>(*model); +// } + return nullptr; } bool getQualitativeResultAtInitialState(std::shared_ptr> const& model, std::unique_ptr& result) { @@ -161,7 +162,8 @@ namespace { if (isSparseModel()) { return std::make_unique(model->template as()->getInitialStates()); } else { - return std::make_unique>(model->template as()->getReachableStates(), model->template as()->getInitialStates()); + // return std::make_unique>(model->template as()->getReachableStates(), model->template as()->getInitialStates()); + return nullptr; } } }; @@ -170,7 +172,7 @@ namespace { SparseDoubleValueIterationEnvironment, SparseDoubleIntervalIterationEnvironment, SparseRationalPolicyIterationEnvironment, - SparseRationalRationalSearchEnvironment, + SparseRationalRationalSearchEnvironment > TestingTypes; TYPED_TEST_CASE(MarkovAutomatonCslModelCheckerTest, TestingTypes); @@ -196,8 +198,10 @@ namespace { result = checker->check(this->env(), tasks[1]); EXPECT_NEAR(this->parseNumber("2/3"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - result = checker->check(this->env(), tasks[2]); - EXPECT_NEAR(this->parseNumber("0.455504"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + if (!storm::utility::isZero(this->precision())) { + result = checker->check(this->env(), tasks[2]); + EXPECT_NEAR(this->parseNumber("0.455504"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + } } @@ -214,11 +218,13 @@ namespace { auto checker = this->createModelChecker(model); std::unique_ptr result; - result = checker->check(this->env(), tasks[0]); - EXPECT_NEAR(this->parseNumber("0.6321205588"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); - - result = checker->check(this->env(), tasks[1]); - EXPECT_NEAR(this->parseNumber("0.727468207"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + if (!storm::utility::isZero(this->precision())) { + result = checker->check(this->env(), tasks[0]); + EXPECT_NEAR(this->parseNumber("0.6321205588"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + + result = checker->check(this->env(), tasks[1]); + EXPECT_NEAR(this->parseNumber("0.727468207"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); + } } TYPED_TEST(MarkovAutomatonCslModelCheckerTest, simple2) { @@ -230,11 +236,11 @@ namespace { formulasString += "; R{\"rew2\"}min=? [C]"; formulasString += "; R{\"rew3\"}min=? [C]"; - auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/simple2.nm", formulasString); + auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/ma/simple2.ma", formulasString); auto model = std::move(modelFormulas.first); auto tasks = this->getTasks(modelFormulas.second); - EXPECT_EQ(5ul, model->getNumberOfStates()); - EXPECT_EQ(8ul, model->getNumberOfTransitions()); + EXPECT_EQ(6ul, model->getNumberOfStates()); + EXPECT_EQ(11ul, model->getNumberOfTransitions()); ASSERT_EQ(model->getType(), storm::models::ModelType::MarkovAutomaton); auto checker = this->createModelChecker(model); std::unique_ptr result; From ca2295be1ddaae7a9d90c14bc90af0ddb66337d7 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 25 Jun 2018 15:24:13 +0200 Subject: [PATCH 374/647] updated changelog: support for expected total rewards --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54be35d3f..150d5ef1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Version 1.2.x - `storm-dft`: test cases for DFT analysis - Sound value iteration (SVI) for DTMCs and MDPs - Topological solver for linear equation systems and MinMax equation systems. +- Added support for expected total rewards in the sparse engine ### Version 1.2.1 (2018/02) From 1f6fc7e2737b085f3d235cb4c368958b243d16c0 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 27 Jun 2018 15:55:33 +0200 Subject: [PATCH 375/647] Better conversion of MA to CTMC if there are only Markovian states --- src/storm/models/sparse/MarkovAutomaton.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/storm/models/sparse/MarkovAutomaton.cpp b/src/storm/models/sparse/MarkovAutomaton.cpp index 587a28a7b..e7c296b07 100644 --- a/src/storm/models/sparse/MarkovAutomaton.cpp +++ b/src/storm/models/sparse/MarkovAutomaton.cpp @@ -171,7 +171,7 @@ namespace storm { template bool MarkovAutomaton::isConvertibleToCtmc() const { - return markovianStates.full(); + return isClosed() && markovianStates.full(); } template @@ -203,6 +203,21 @@ namespace storm { template std::shared_ptr> MarkovAutomaton::convertToCtmc() const { + if (isClosed() && markovianStates.full()) { + storm::storage::sparse::ModelComponents components(this->getTransitionMatrix(), this->getStateLabeling(), this->getRewardModels(), false); + components.transitionMatrix.makeRowGroupingTrivial(); + components.exitRates = this->getExitRates(); + if (this->hasChoiceLabeling()) { + components.choiceLabeling = this->getChoiceLabeling(); + } + if (this->hasStateValuations()) { + components.stateValuations = this->getStateValuations(); + } + if (this->hasChoiceOrigins()) { + components.choiceOrigins = this->getChoiceOrigins(); + } + return std::make_shared>(std::move(components)); + } STORM_LOG_TRACE("MA matrix:" << std::endl << this->getTransitionMatrix()); STORM_LOG_TRACE("Markovian states: " << getMarkovianStates()); @@ -249,12 +264,10 @@ namespace storm { //TODO update reward models and choice labels according to kept states STORM_LOG_WARN_COND(this->getRewardModels().empty(), "Conversion of MA to CTMC does not preserve rewards."); - std::unordered_map rewardModels = this->getRewardModels(); STORM_LOG_WARN_COND(!this->hasChoiceLabeling(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasStateValuations(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasChoiceOrigins(), "Conversion of MA to CTMC does not preserve choice labels."); - - return std::make_shared>(std::move(rateMatrix), std::move(stateLabeling), std::move(rewardModels)); + return std::make_shared>(std::move(rateMatrix), std::move(stateLabeling)); } From c4bed85dc4c7d062a00cfffd1ed2816a3475d8d0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 29 Jun 2018 15:56:12 +0200 Subject: [PATCH 376/647] switching to native linear equation solver by default and power iteration --- src/storm/settings/modules/CoreSettings.cpp | 2 +- src/storm/settings/modules/NativeEquationSolverSettings.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index 8419f209f..b7f76b66c 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -45,7 +45,7 @@ namespace storm { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, eqSolverOptionName, false, "Sets which solver is preferred for solving systems of linear equations.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("native").build()).build()); std::vector ddLibraries = {"cudd", "sylvan"}; this->addOption(storm::settings::OptionBuilder(moduleName, ddLibraryOptionName, false, "Sets which library is preferred for decision-diagram operations.") diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 3f0282f0a..e54aba127 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -27,7 +27,7 @@ namespace storm { NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; - this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("power").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); From 50aa6d14240344b9695c483e01663d849d9d728a Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 29 Jun 2018 19:33:10 +0200 Subject: [PATCH 377/647] assuming the only global real transient variable is the reward when exporting JANI and no reward model is mentioned in the property (issues a warning) --- src/storm/storage/jani/JSONExporter.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 0c0c212a0..d41cf86af 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -398,8 +398,22 @@ namespace storm { opDecl["op"] = "Emin"; opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } - STORM_LOG_THROW(f.hasRewardModelName(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); - opDecl["exp"] = f.getRewardModelName(); + std::string rewardModelName; + if (f.hasRewardModelName()) { + rewardModelName = f.getRewardModelName(); + } else { + if (model.getGlobalVariables().getNumberOfRealTransientVariables() == 1) { + for (auto const& variable : model.getGlobalVariables().getRealVariables()) { + if (variable.isTransient()) { + rewardModelName = variable.getName(); + STORM_LOG_WARN("Reward model name was not given, assuming the only global real transient variable '" << rewardModelName << "' to measure the reward."); + break; + } + } + } + } + STORM_LOG_THROW(!rewardModelName.empty(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); + opDecl["exp"] = rewardModelName; opDecl["accumulate"] = modernjson::json(accvec); } return opDecl; @@ -408,7 +422,6 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::TotalRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support a total reward formula"); } - boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const { modernjson::json opDecl; From 86069b8552ee5f0fa1ba93c08b72090d0500c83d Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 29 Jun 2018 21:58:30 +0200 Subject: [PATCH 378/647] fix typo in JSON exporter --- src/storm/storage/jani/JSONExporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index d41cf86af..41878b209 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -196,12 +196,12 @@ namespace storm { modernjson::json propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive); auto tbr = f.getTimeBoundReference(); - if(tbr.isStepBound()) { + if (tbr.isStepBound()) { opDecl["step-bounds"] = propertyInterval; } else if(tbr.isRewardBound()) { - opDecl["time-bounds"] = propertyInterval; - } else { opDecl["reward-bounds"] = propertyInterval; + } else { + opDecl["time-bounds"] = propertyInterval; } return opDecl; } From db6f43ed9d0a39bc7d8d03be6473ce3aa9950c3c Mon Sep 17 00:00:00 2001 From: dehnert Date: Sat, 30 Jun 2018 11:04:22 +0200 Subject: [PATCH 379/647] made LRA computation for deterministic systems able to respect that the underlying solver requires a fixed-point formulation --- .../csl/helper/SparseCtmcCslHelper.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index f888ed1b6..f9e6da475 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -478,6 +478,17 @@ namespace storm { } } + // Build a different system depending on the problem format of the equation solver. + // Check solver requirements. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; + auto requirements = linearEquationSolverFactory.getRequirements(env); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); + + bool fixedPointSystem = false; + if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::FixedPointSystem) { + fixedPointSystem = true; + } + // Now build the final equation system matrix, the initial guess and the right-hand side in one go. std::vector bsccEquationSystemRightSide(bsccEquationSystem.getColumnCount(), zero); storm::storage::SparseMatrixBuilder builder; @@ -486,7 +497,7 @@ namespace storm { // If the current row is the first one belonging to a BSCC, we substitute it by the constraint that the // values for states of this BSCC must sum to one. However, in order to have a non-zero value on the // diagonal, we add the constraint of the BSCC that produces a 1 on the diagonal. - if (firstStatesInBsccs.get(row)) { + if (!fixedPointSystem && firstStatesInBsccs.get(row)) { uint_fast64_t requiredBscc = stateToBsccIndexMap[row]; storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[requiredBscc]; @@ -499,14 +510,13 @@ namespace storm { } else { // Otherwise, we copy the row, and subtract 1 from the diagonal. for (auto& entry : bsccEquationSystem.getRow(row)) { - if (entry.getColumn() == row) { - builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); - } else { + if (fixedPointSystem || entry.getColumn() != row) { builder.addNextValue(row, entry.getColumn(), entry.getValue()); + } else { + builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); } } } - } // Create the initial guess for the LRAs. We take a uniform distribution over all states in a BSCC. @@ -522,12 +532,6 @@ namespace storm { bsccEquationSystem = builder.build(); { - // Check solver requirements - storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; - auto requirements = linearEquationSolverFactory.getRequirements(env); - STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); - // Check whether we have the right input format for the solver. - STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(bsccEquationSystem)); solver->solveEquations(env, bsccEquationSystemSolution, bsccEquationSystemRightSide); } From 98969e627ce5477329b6ba70e07e79f2e7660a37 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sat, 30 Jun 2018 12:36:10 +0200 Subject: [PATCH 380/647] updated counterexamples to support statistics to be exported --- .../SMTMinimalLabelSetGenerator.h | 63 +++++++------------ .../CounterexampleGeneratorSettings.cpp | 2 +- src/storm/api/export.cpp | 11 +++- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 52a24d0dd..8a43e6cc5 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -59,10 +59,6 @@ namespace storm { std::map> relevantChoicesForRelevantStates; }; - struct GeneratorStats { - - }; - struct VariableInformation { // The manager responsible for the constraints we are building. std::shared_ptr manager; @@ -271,21 +267,6 @@ namespace storm { return variableInformation; } - /*! - * Asserts the constraints that are initially needed for the Fu-Malik procedure. - * - * @param solver The solver in which to assert the constraints. - * @param variableInformation A structure with information about the variables for the labels. - */ - static void assertFuMalikInitialConstraints(z3::solver& solver, VariableInformation const& variableInformation) { - // Assert that at least one of the labels must be taken. - z3::expr formula = variableInformation.labelVariables.at(0); - for (uint_fast64_t index = 1; index < variableInformation.labelVariables.size(); ++index) { - formula = formula || variableInformation.labelVariables.at(index); - } - solver.add(formula); - } - static storm::expressions::Expression getOtherSynchronizationEnabledFormula(boost::container::flat_set const& labelSet, std::map>> const& synchronizingLabels, boost::container::flat_map, storm::expressions::Expression> const& labelSetToFormula, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation) { // Taking all commands of a combination does not necessarily mean that a following label set needs to be taken. // This is because it could be that the commands are taken to enable other synchronizations. Therefore, we need @@ -970,22 +951,7 @@ namespace storm { } solver.add(disjunction); } - - /*! - * Asserts that the conjunction of the given formulae holds. If the content of the conjunction is empty, - * this corresponds to asserting true. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param formulaVector A vector of expressions that shall form the conjunction. - */ - static void assertConjunction(z3::context& context, z3::solver& solver, std::vector const& formulaVector) { - z3::expr conjunction = context.bool_val(true); - for (auto expr : formulaVector) { - conjunction = conjunction && expr; - } - solver.add(conjunction); - } + /*! * Creates a full-adder for the two inputs and returns the resulting bit as well as the carry bit. @@ -1617,6 +1583,13 @@ namespace storm { uint64_t maximumCounterexamples = 1; uint64_t multipleCounterexampleSizeCap = 100000000; }; + + struct GeneratorStats { + std::chrono::milliseconds setupTime; + std::chrono::milliseconds solverTime; + std::chrono::milliseconds modelCheckingTime; + std::chrono::milliseconds analysisTime; + }; /*! * Computes the minimal command set that is needed in the given model to exceed the given probability threshold for satisfying phi until psi. @@ -1630,7 +1603,7 @@ namespace storm { * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). * @param options A set of options for customization. */ - static std::vector> getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double propertyThreshold, boost::optional const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { + static std::vector> getMinimalLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double propertyThreshold, boost::optional const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 std::vector> result; // Set up all clocks used for time measurement. @@ -1821,12 +1794,19 @@ namespace storm { // Compute and emit the time measurements if the corresponding flag was set. totalTime = std::chrono::high_resolution_clock::now() - totalClock; + + stats.analysisTime = std::chrono::duration_cast(totalAnalysisTime); + stats.setupTime = std::chrono::duration_cast(totalSetupTime); + stats.modelCheckingTime = std::chrono::duration_cast(totalModelCheckingTime); + stats.solverTime = std::chrono::duration_cast(totalSolverTime); + if (storm::settings::getModule().isShowStatisticsSet()) { boost::container::flat_set allLabels; for (auto const& e : labelSets) { allLabels.insert(e.begin(), e.end()); } - + + std::cout << "Metrics:" << std::endl; std::cout << " * all labels: " << allLabels.size() << std::endl; std::cout << " * known labels: " << relevancyInformation.knownLabels.size() << std::endl; @@ -1851,7 +1831,7 @@ namespace storm { #endif } - static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool silent = false) { + static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool silent = false) { auto startTime = std::chrono::high_resolution_clock::now(); // Create sub-model that only contains the choices allowed by the given command set. @@ -1935,7 +1915,7 @@ namespace storm { } - static std::vector> computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { + static std::vector> computeCounterexampleLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); if (!options.silent) { std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; @@ -2027,7 +2007,7 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSets = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, rewardName, strictBound, dontCareLabels, options); + auto labelSets = getMinimalLabelSet(env, stats, symbolicModel, model, phiStates, psiStates, threshold, rewardName, strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); if (!options.silent) { for (auto const& labelSet : labelSets) { @@ -2049,7 +2029,8 @@ namespace storm { static std::shared_ptr computeCounterexample(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { #ifdef STORM_HAVE_Z3 - auto labelSets = computeCounterexampleLabelSet(env, symbolicModel, model, formula); + GeneratorStats stats; + auto labelSets = computeCounterexampleLabelSet(env, stats, symbolicModel, model, formula); if (symbolicModel.isPrismProgram()) { diff --git a/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp index 9fe9d3d36..5b2142ee3 100644 --- a/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp @@ -1,4 +1,4 @@ -#include "CounterexampleGeneratorSettings.h" +#include "storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/exceptions/InvalidSettingsException.h" diff --git a/src/storm/api/export.cpp b/src/storm/api/export.cpp index 193ec0668..e1acf9b8d 100644 --- a/src/storm/api/export.cpp +++ b/src/storm/api/export.cpp @@ -5,13 +5,18 @@ namespace storm { void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { auto janiSettings = storm::settings::getModule(); - + + storm::jani::Model modelForExport = model; + if (janiSettings.isExportFlattenedSet()) { + modelForExport = modelForExport.flattenComposition(); + } + if (janiSettings.isExportAsStandardJaniSet()) { - storm::jani::Model normalisedModel = model; + storm::jani::Model normalisedModel = modelForExport; normalisedModel.makeStandardJaniCompliant(); storm::jani::JsonExporter::toFile(normalisedModel, properties, filename); } else { - storm::jani::JsonExporter::toFile(model, properties, filename); + storm::jani::JsonExporter::toFile(modelForExport, properties, filename); } } From 749ba87254ada79ca0b0f9397dddf3e2db93bea8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 2 Jul 2018 10:57:13 +0200 Subject: [PATCH 381/647] Made SVI log output more clear --- src/storm/solver/helper/SoundValueIterationHelper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index 6e47bfe3e..081c4a51d 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -301,14 +301,14 @@ namespace storm { storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) -> ValueType { return xi + yi * meanBound; }); - STORM_LOG_INFO("Sound Value Iteration terminated with lower value bound " + STORM_LOG_INFO("Sound Value Iteration terminated with lower bound (over all states) " << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") - << " and upper value bound " - << (hasUpperBound ? upperBound : storm::utility::zero()) << (hasUpperBound ? "" : "(none)") + << " and upper bound (over all states)" + << (hasUpperBound ? upperBound : storm::utility::infinity()) << (hasUpperBound ? "" : "(none)") << ". Decision value is " - << (hasDecisionValue ? decisionValue : storm::utility::zero()) << (hasDecisionValue ? "" : "(none)") + << (hasDecisionValue ? decisionValue : -storm::utility::infinity()) << (hasDecisionValue ? "" : "(none)") << "."); - } + } template bool SoundValueIterationHelper::checkCustomTerminationCondition(storm::solver::TerminationCondition const& condition) { From d638972bc80d5baf728df5562568bc51b8bed89c Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 3 Jul 2018 15:22:53 +0200 Subject: [PATCH 382/647] enabled pushing location assignments to edges --- src/storm/storage/jani/Automaton.cpp | 29 ++++++++++++++++++- src/storm/storage/jani/Automaton.h | 6 ++++ src/storm/storage/jani/Model.cpp | 5 ++++ src/storm/storage/jani/OrderedAssignments.cpp | 28 ++++++++++-------- src/storm/storage/jani/OrderedAssignments.h | 4 ++- src/storm/storage/jani/TemplateEdge.cpp | 6 ++-- src/storm/storage/jani/TemplateEdge.h | 4 ++- .../storage/jani/TemplateEdgeDestination.cpp | 4 +-- .../storage/jani/TemplateEdgeDestination.h | 2 +- 9 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index f4c65c759..e962562d2 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -8,6 +8,7 @@ #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidTypeException.h" +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace jani { @@ -419,6 +420,33 @@ namespace storm { edges.pushAssignmentsToDestinations(); } + void Automaton::pushTransientRealLocationAssignmentsToEdges() { + std::set> encounteredTemplateEdges; + + for (uint64_t locationIndex = 0; locationIndex < locations.size(); ++locationIndex) { + auto& location = locations[locationIndex]; + auto edges = this->getEdgesFromLocation(locationIndex); + + for (auto& edge : edges) { + STORM_LOG_THROW(encounteredTemplateEdges.find(edge.getTemplateEdge()) == encounteredTemplateEdges.end(), storm::exceptions::NotSupportedException, "Pushing location assignments to edges is only supported for automata with unique template edges."); + + auto& templateEdge = edge.getTemplateEdge(); + encounteredTemplateEdges.insert(templateEdge); + + storm::jani::Location newLocation(location.getName()); + for (auto const& assignment : location.getAssignments().getTransientAssignments()) { + if (assignment.getVariable().isTransient() && assignment.getVariable().isRealVariable()) { + templateEdge->addTransientAssignment(assignment, true); + } else { + newLocation.addTransientAssignment(assignment); + } + } + + location = std::move(newLocation); + } + } + } + bool Automaton::hasTransientEdgeDestinationAssignments() const { for (auto const& edge : this->getEdges()) { if (edge.hasTransientEdgeDestinationAssignments()) { @@ -440,7 +468,6 @@ namespace storm { return true; } - bool Automaton::usesAssignmentLevels() const { return edges.usesAssignmentLevels(); } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index c549ecca8..238f26896 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -294,6 +294,12 @@ namespace storm { */ void pushEdgeAssignmentsToDestinations(); + /*! + * Pushes the assignments to real-valued transient variables to the edges. + * Note: This is currently only supported if the template edges are uniquely coupled with one source location. + */ + void pushTransientRealLocationAssignmentsToEdges(); + /*! * Retrieves whether there is any transient edge destination assignment in the automaton. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 47533126c..0cbbaae14 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -1107,6 +1107,11 @@ namespace storm { void Model::makeStandardJaniCompliant() { for (auto& automaton : automata) { + // For discrete-time models, we push the assignments to real-valued transient variables (rewards) to the + // edges. + if (this->isDiscreteTimeModel()) { + automaton.pushTransientRealLocationAssignmentsToEdges(); + } automaton.pushEdgeAssignmentsToDestinations(); } } diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 99eb415a8..564baed9f 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -17,7 +17,7 @@ namespace storm { add(assignment); } - bool OrderedAssignments::add(Assignment const& assignment) { + bool OrderedAssignments::add(Assignment const& assignment, bool addToExisting) { // If the element is contained in this set of assignment, nothing needs to be added. if (this->contains(assignment)) { return false; @@ -27,18 +27,22 @@ namespace storm { auto it = lowerBound(assignment, allAssignments); if (it != allAssignments.end()) { - STORM_LOG_THROW(assignment.getExpressionVariable() != (*it)->getExpressionVariable(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); - } - - // Finally, insert the new element in the correct vectors. - auto elementToInsert = std::make_shared(assignment); - allAssignments.emplace(it, elementToInsert); - if (assignment.isTransient()) { - auto transientIt = lowerBound(assignment, transientAssignments); - transientAssignments.emplace(transientIt, elementToInsert); + if ((!addToExisting || !assignment.getExpressionVariable().hasNumericalType())) { + STORM_LOG_THROW(assignment.getExpressionVariable() != (*it)->getExpressionVariable(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); + } else if (addToExisting && assignment.getExpressionVariable().hasNumericalType()) { + (*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression()); + } } else { - auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); - nonTransientAssignments.emplace(nonTransientIt, elementToInsert); + // Finally, insert the new element in the correct vectors. + auto elementToInsert = std::make_shared(assignment); + allAssignments.emplace(it, elementToInsert); + if (assignment.isTransient()) { + auto transientIt = lowerBound(assignment, transientAssignments); + transientAssignments.emplace(transientIt, elementToInsert); + } else { + auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); + nonTransientAssignments.emplace(nonTransientIt, elementToInsert); + } } return true; diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 8e307e6e0..428912bf1 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -26,9 +26,11 @@ namespace storm { /*! * Adds the given assignment to the set of assignments. * + * @addToExisting If true the value of the assigned expression is added to a (potentially) previous assignment + * to the variable. If false and there is already an assignment, an exception is thrown. * @return True iff the assignment was added. */ - bool add(Assignment const& assignment); + bool add(Assignment const& assignment, bool addToExisting = false); /*! * Removes the given assignment from this set of assignments. diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 987e4f6de..89d56a0d3 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -20,8 +20,8 @@ namespace storm { destinations.emplace_back(destination); } - bool TemplateEdge::addTransientAssignment(Assignment const& assignment) { - return assignments.add(assignment); + bool TemplateEdge::addTransientAssignment(Assignment const& assignment, bool addToExisting) { + return assignments.add(assignment, addToExisting); } void TemplateEdge::finalize(Model const& containingModel) { @@ -106,7 +106,7 @@ namespace storm { STORM_LOG_ASSERT(!destinations.empty(), "Need non-empty destinations for this transformation."); for (auto const& assignment : this->getAssignments()) { for (auto& destination : destinations) { - destination.addAssignment(assignment); + destination.addAssignment(assignment, true); } } this->assignments.clear(); diff --git a/src/storm/storage/jani/TemplateEdge.h b/src/storm/storage/jani/TemplateEdge.h index cccc1bb7f..dac58144b 100644 --- a/src/storm/storage/jani/TemplateEdge.h +++ b/src/storm/storage/jani/TemplateEdge.h @@ -40,9 +40,11 @@ namespace storm { * Adds a transient assignment to this edge. * * @param assignment The transient assignment to add. + * @param addToExisting Determines if adding the assigned expression to an already existing assignment is + * allowed (if the assigned variable is quantitative). * @return True if the assignment was added. */ - bool addTransientAssignment(Assignment const& assignment); + bool addTransientAssignment(Assignment const& assignment, bool addToExisting = false); /*! * Retrieves a set of (global) variables that are written by at least one of the edge's destinations. diff --git a/src/storm/storage/jani/TemplateEdgeDestination.cpp b/src/storm/storage/jani/TemplateEdgeDestination.cpp index 2d99a1ad1..b30bbda92 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.cpp +++ b/src/storm/storage/jani/TemplateEdgeDestination.cpp @@ -31,8 +31,8 @@ namespace storm { return assignments.remove(assignment); } - void TemplateEdgeDestination::addAssignment(Assignment const& assignment) { - assignments.add(assignment); + void TemplateEdgeDestination::addAssignment(Assignment const& assignment, bool addToExisting) { + assignments.add(assignment, addToExisting); } bool TemplateEdgeDestination::hasAssignment(Assignment const& assignment) const { diff --git a/src/storm/storage/jani/TemplateEdgeDestination.h b/src/storm/storage/jani/TemplateEdgeDestination.h index bb94125f9..e6ad889b8 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.h +++ b/src/storm/storage/jani/TemplateEdgeDestination.h @@ -27,7 +27,7 @@ namespace storm { // Convenience methods to access the assignments. bool hasAssignment(Assignment const& assignment) const; bool removeAssignment(Assignment const& assignment); - void addAssignment(Assignment const& assignment); + void addAssignment(Assignment const& assignment, bool addToExisting = false); /*! * Retrieves whether this destination has transient assignments. From 8114437ceeb2e7739558dbf0fca5a9bf8f05a995 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 3 Jul 2018 16:12:19 +0200 Subject: [PATCH 383/647] allowing cumulative and instantaneous reward properties to be transformed to JANI --- src/storm/storage/jani/JSONExporter.cpp | 68 ++++++++++++++++--------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 41878b209..f891e5e0f 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -264,7 +264,7 @@ namespace storm { } boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const { - modernjson::json opDecl; + modernjson::json opDecl; if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); @@ -288,7 +288,6 @@ namespace storm { } } return opDecl; - } boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageRewardFormula const&, boost::any const&) const { @@ -369,52 +368,73 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; std::vector accvec; - if(model.isDiscreteTimeModel()) { + std::string instantName; + if (model.isDiscreteTimeModel()) { accvec.push_back("steps"); + instantName = "step-instant"; } else { accvec.push_back("time"); + instantName = "time-instant"; + } + + std::string rewardModelName; + if (f.hasRewardModelName()) { + rewardModelName = f.getRewardModelName(); + } else { + if (model.getGlobalVariables().getNumberOfRealTransientVariables() == 1) { + for (auto const& variable : model.getGlobalVariables().getRealVariables()) { + if (variable.isTransient()) { + rewardModelName = variable.getName(); + STORM_LOG_WARN("Reward model name was not given, assuming the only global real transient variable '" << rewardModelName << "' to measure the reward."); + break; + } + } + } } + STORM_LOG_THROW(!rewardModelName.empty(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); + if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin"; + } + if (f.getSubformula().isEventuallyFormula()) { opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else if (f.getSubformula().isCumulativeRewardFormula()) { + opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + } else if (f.getSubformula().isInstantaneousRewardFormula()) { + opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } STORM_LOG_THROW(f.hasRewardModelName(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); - opDecl["left"]["exp"] = f.getRewardModelName(); - opDecl["left"]["accumulate"] = modernjson::json(accvec); + opDecl["left"]["exp"] = rewardModelName; + if (f.getSubformula().isReachabilityRewardFormula() || f.getSubformula().isCumulativeRewardFormula()) { + opDecl["left"]["accumulate"] = modernjson::json(accvec); + } opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { - if(f.hasOptimalityType()) { + if (f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } else { // TODO add checks opDecl["op"] = "Emin"; - opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } - std::string rewardModelName; - if (f.hasRewardModelName()) { - rewardModelName = f.getRewardModelName(); - } else { - if (model.getGlobalVariables().getNumberOfRealTransientVariables() == 1) { - for (auto const& variable : model.getGlobalVariables().getRealVariables()) { - if (variable.isTransient()) { - rewardModelName = variable.getName(); - STORM_LOG_WARN("Reward model name was not given, assuming the only global real transient variable '" << rewardModelName << "' to measure the reward."); - break; - } - } - } + + if (f.getSubformula().isEventuallyFormula()) { + opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else if (f.getSubformula().isCumulativeRewardFormula()) { + opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + } else if (f.getSubformula().isInstantaneousRewardFormula()) { + opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } - STORM_LOG_THROW(!rewardModelName.empty(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); + opDecl["exp"] = rewardModelName; - opDecl["accumulate"] = modernjson::json(accvec); + if (f.getSubformula().isReachabilityRewardFormula() || f.getSubformula().isCumulativeRewardFormula()) { + opDecl["accumulate"] = modernjson::json(accvec); + } } return opDecl; } From dff67450e02794e77738a49be95ed37eadb80cc8 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 3 Jul 2018 20:55:46 +0200 Subject: [PATCH 384/647] fixed recently introduced bug in JANI export --- src/storm/storage/jani/JSONExporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index f891e5e0f..419973272 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -424,11 +424,11 @@ namespace storm { } if (f.getSubformula().isEventuallyFormula()) { - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } else if (f.getSubformula().isCumulativeRewardFormula()) { - opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + opDecl[instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } else if (f.getSubformula().isInstantaneousRewardFormula()) { - opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + opDecl[instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } opDecl["exp"] = rewardModelName; From a7caf709aeb07c3f8feb28af59734d06c713c5c1 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 4 Jul 2018 11:43:42 +0200 Subject: [PATCH 385/647] default to topological equation solver --- src/storm/settings/modules/CoreSettings.cpp | 2 +- src/storm/settings/modules/NativeEquationSolverSettings.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index b7f76b66c..343d3c3d1 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -45,7 +45,7 @@ namespace storm { std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, eqSolverOptionName, false, "Sets which solver is preferred for solving systems of linear equations.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("native").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("topological").build()).build()); std::vector ddLibraries = {"cudd", "sylvan"}; this->addOption(storm::settings::OptionBuilder(moduleName, ddLibraryOptionName, false, "Sets which library is preferred for decision-diagram operations.") diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index e54aba127..3f0282f0a 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -27,7 +27,7 @@ namespace storm { NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; - this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("power").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); From 4500f98ae184d7b396641915f3ca20b00e5b52c9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Jul 2018 14:12:36 +0200 Subject: [PATCH 386/647] fixing typo --- src/storm/solver/TopologicalLinearEquationSolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 7568f3c65..0e6896370 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -68,7 +68,7 @@ namespace storm { storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); - STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << "SCCs. Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); + STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << " SCC(s). Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); if (this->longestSccChainSize) { STORM_LOG_INFO("Longest SCC chain size is " << this->longestSccChainSize.get() << "."); } From e609a240a9268210440c819c05c70dd869dd52c2 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 5 Jul 2018 19:56:47 +0200 Subject: [PATCH 387/647] selecting minmax topological by default --- src/storm/settings/modules/MinMaxEquationSolverSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 186f0caf9..d82125ec9 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -25,7 +25,7 @@ namespace storm { MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("topological").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); From 0c0f61e27b726a5fb13aaf1a8453ea08c4d4aa7c Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 6 Jul 2018 09:28:54 +0200 Subject: [PATCH 388/647] Fix: Only access counterexample settings in model-handling, if they are available. --- src/storm-cli-utilities/model-handling.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 41faf8732..3f9967a3a 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -186,11 +186,15 @@ namespace storm { template std::shared_ptr buildModelSparse(SymbolicInput const& input, storm::settings::modules::BuildSettings const& buildSettings) { - auto counterexampleGeneratorSettings = storm::settings::getModule(); storm::builder::BuilderOptions options(createFormulasToRespect(input.properties)); options.setBuildChoiceLabels(buildSettings.isBuildChoiceLabelsSet()); options.setBuildStateValuations(buildSettings.isBuildStateValuationsSet()); - options.setBuildChoiceOrigins(counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet()); + if (storm::settings::manager().hasModule(storm::settings::modules::CounterexampleGeneratorSettings::moduleName)) { + auto counterexampleGeneratorSettings = storm::settings::getModule(); + options.setBuildChoiceOrigins(counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet()); + } else { + options.setBuildChoiceOrigins(false); + } options.setBuildAllLabels(buildSettings.isBuildFullModelSet()); options.setBuildAllRewardModels(buildSettings.isBuildFullModelSet()); options.setAddOutOfBoundsState(buildSettings.isBuildOutOfBoundsStateSet()); From 9d528db2fc2a1aabf0bd63c54f94c15d2e0ce215 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 6 Jul 2018 16:22:45 +0200 Subject: [PATCH 389/647] adding translation of expressions used in formulas to symbolic-to-sparse transformers --- src/storm-cli-utilities/model-handling.h | 16 ++-- src/storm/api/transformation.h | 8 +- .../SymbolicToSparseTransformer.cpp | 74 ++++++++++++++++--- .../transformer/SymbolicToSparseTransformer.h | 7 +- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 41faf8732..e4ae114bf 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -359,18 +359,12 @@ namespace storm { result->second = true; std::shared_ptr> symbolicModel = result->first->template as>(); - if (symbolicModel->isOfType(storm::models::ModelType::Dtmc)) { - storm::transformer::SymbolicDtmcToSparseDtmcTransformer transformer; - result->first = transformer.translate(*symbolicModel->template as>()); - } else if (symbolicModel->isOfType(storm::models::ModelType::Ctmc)) { - storm::transformer::SymbolicCtmcToSparseCtmcTransformer transformer; - result->first = transformer.translate(*symbolicModel->template as>()); - } else if (symbolicModel->isOfType(storm::models::ModelType::Mdp)) { - storm::transformer::SymbolicMdpToSparseMdpTransformer transformer; - result->first = transformer.translate(*symbolicModel->template as>()); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The translation to a sparse model is not supported for the given model type."); + std::vector> formulas; + for (auto const& property : input.properties) { + formulas.emplace_back(property.getRawFormula()); } + result->first = storm::api::transformSymbolicToSparseModel(symbolicModel, formulas); + STORM_LOG_THROW(result, storm::exceptions::NotSupportedException, "The translation to a sparse model is not supported for the given model type."); } return *result; diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h index 204e283db..d26f32ea1 100644 --- a/src/storm/api/transformation.h +++ b/src/storm/api/transformation.h @@ -62,14 +62,14 @@ namespace storm { * Transforms the given symbolic model to a sparse model. */ template - std::shared_ptr> transformSymbolicToSparseModel(std::shared_ptr> const& symbolicModel) { + std::shared_ptr> transformSymbolicToSparseModel(std::shared_ptr> const& symbolicModel, std::vector> const& formulas = std::vector>()) { switch (symbolicModel->getType()) { case storm::models::ModelType::Dtmc: - return storm::transformer::SymbolicDtmcToSparseDtmcTransformer().translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicDtmcToSparseDtmcTransformer().translate(*symbolicModel->template as>(), formulas); case storm::models::ModelType::Mdp: - return storm::transformer::SymbolicMdpToSparseMdpTransformer::translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicMdpToSparseMdpTransformer::translate(*symbolicModel->template as>(), formulas); case storm::models::ModelType::Ctmc: - return storm::transformer::SymbolicCtmcToSparseCtmcTransformer::translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicCtmcToSparseCtmcTransformer::translate(*symbolicModel->template as>(), formulas); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not supported."); } diff --git a/src/storm/transformer/SymbolicToSparseTransformer.cpp b/src/storm/transformer/SymbolicToSparseTransformer.cpp index 8ebac17de..66d3dd1b3 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.cpp +++ b/src/storm/transformer/SymbolicToSparseTransformer.cpp @@ -7,12 +7,35 @@ #include "storm/models/sparse/StandardRewardModel.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotImplementedException.h" +#include "storm/logic/AtomicExpressionFormula.h" +#include "storm/logic/AtomicLabelFormula.h" namespace storm { namespace transformer { + struct LabelInformation { + LabelInformation(std::vector> const& formulas) { + for (auto const& formula : formulas) { + std::vector> atomicLabelFormulas = formula->getAtomicLabelFormulas(); + for (auto const& labelFormula : atomicLabelFormulas) { + atomicLabels.insert(labelFormula->getLabel()); + } + + std::vector> atomicExpressionFormulas = formula->getAtomicExpressionFormulas(); + for (auto const& expressionFormula : atomicExpressionFormulas) { + std::stringstream ss; + ss << expressionFormula->getExpression(); + expressionLabels[ss.str()] = expressionFormula->getExpression(); + } + } + } + + std::set atomicLabels; + std::map expressionLabels; + }; + template - std::shared_ptr> SymbolicDtmcToSparseDtmcTransformer::translate(storm::models::symbolic::Dtmc const& symbolicDtmc) { + std::shared_ptr> SymbolicDtmcToSparseDtmcTransformer::translate(storm::models::symbolic::Dtmc const& symbolicDtmc, std::vector> const& formulas) { this->odd = symbolicDtmc.getReachableStates().createOdd(); storm::storage::SparseMatrix transitionMatrix = symbolicDtmc.getTransitionMatrix().toMatrix(this->odd, this->odd); @@ -36,8 +59,18 @@ namespace storm { labelling.addLabel("init", symbolicDtmc.getInitialStates().toVector(this->odd)); labelling.addLabel("deadlock", symbolicDtmc.getDeadlockStates().toVector(this->odd)); - for(auto const& label : symbolicDtmc.getLabels()) { - labelling.addLabel(label, symbolicDtmc.getStates(label).toVector(this->odd)); + if (formulas.empty()) { + for (auto const& label : symbolicDtmc.getLabels()) { + labelling.addLabel(label, symbolicDtmc.getStates(label).toVector(this->odd)); + } + } else { + LabelInformation labelInfo(formulas); + for (auto const& label : labelInfo.atomicLabels) { + labelling.addLabel(label, symbolicDtmc.getStates(label).toVector(this->odd)); + } + for (auto const& expressionLabel : labelInfo.expressionLabels) { + labelling.addLabel(expressionLabel.first, symbolicDtmc.getStates(expressionLabel.second).toVector(this->odd)); + } } return std::make_shared>(transitionMatrix, labelling, rewardModels); } @@ -48,7 +81,7 @@ namespace storm { } template - std::shared_ptr> SymbolicMdpToSparseMdpTransformer::translate(storm::models::symbolic::Mdp const& symbolicMdp) { + std::shared_ptr> SymbolicMdpToSparseMdpTransformer::translate(storm::models::symbolic::Mdp const& symbolicMdp, std::vector> const& formulas) { storm::dd::Odd odd = symbolicMdp.getReachableStates().createOdd(); storm::storage::SparseMatrix transitionMatrix = symbolicMdp.getTransitionMatrix().toMatrix(symbolicMdp.getNondeterminismVariables(), odd, odd); std::unordered_map> rewardModels; @@ -69,15 +102,25 @@ namespace storm { labelling.addLabel("init", symbolicMdp.getInitialStates().toVector(odd)); labelling.addLabel("deadlock", symbolicMdp.getDeadlockStates().toVector(odd)); - for(auto const& label : symbolicMdp.getLabels()) { - labelling.addLabel(label, symbolicMdp.getStates(label).toVector(odd)); + if (formulas.empty()) { + for (auto const& label : symbolicMdp.getLabels()) { + labelling.addLabel(label, symbolicMdp.getStates(label).toVector(odd)); + } + } else { + LabelInformation labelInfo(formulas); + for (auto const& label : labelInfo.atomicLabels) { + labelling.addLabel(label, symbolicMdp.getStates(label).toVector(odd)); + } + for (auto const& expressionLabel : labelInfo.expressionLabels) { + labelling.addLabel(expressionLabel.first, symbolicMdp.getStates(expressionLabel.second).toVector(odd)); + } } + return std::make_shared>(transitionMatrix, labelling, rewardModels); } template - std::shared_ptr> SymbolicCtmcToSparseCtmcTransformer::translate( - storm::models::symbolic::Ctmc const& symbolicCtmc) { + std::shared_ptr> SymbolicCtmcToSparseCtmcTransformer::translate(storm::models::symbolic::Ctmc const& symbolicCtmc, std::vector> const& formulas) { storm::dd::Odd odd = symbolicCtmc.getReachableStates().createOdd(); storm::storage::SparseMatrix transitionMatrix = symbolicCtmc.getTransitionMatrix().toMatrix(odd, odd); std::unordered_map> rewardModels; @@ -100,9 +143,20 @@ namespace storm { labelling.addLabel("init", symbolicCtmc.getInitialStates().toVector(odd)); labelling.addLabel("deadlock", symbolicCtmc.getDeadlockStates().toVector(odd)); - for(auto const& label : symbolicCtmc.getLabels()) { - labelling.addLabel(label, symbolicCtmc.getStates(label).toVector(odd)); + if (formulas.empty()) { + for (auto const& label : symbolicCtmc.getLabels()) { + labelling.addLabel(label, symbolicCtmc.getStates(label).toVector(odd)); + } + } else { + LabelInformation labelInfo(formulas); + for (auto const& label : labelInfo.atomicLabels) { + labelling.addLabel(label, symbolicCtmc.getStates(label).toVector(odd)); + } + for (auto const& expressionLabel : labelInfo.expressionLabels) { + labelling.addLabel(expressionLabel.first, symbolicCtmc.getStates(expressionLabel.second).toVector(odd)); + } } + return std::make_shared>(transitionMatrix, labelling, rewardModels); } diff --git a/src/storm/transformer/SymbolicToSparseTransformer.h b/src/storm/transformer/SymbolicToSparseTransformer.h index 5f4bed6c4..e2c191b49 100644 --- a/src/storm/transformer/SymbolicToSparseTransformer.h +++ b/src/storm/transformer/SymbolicToSparseTransformer.h @@ -1,5 +1,6 @@ #pragma once +#include "storm/logic/Formula.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/symbolic/Dtmc.h" #include "storm/models/sparse/Mdp.h" @@ -15,7 +16,7 @@ namespace storm { template class SymbolicDtmcToSparseDtmcTransformer { public: - std::shared_ptr> translate(storm::models::symbolic::Dtmc const& symbolicDtmc); + std::shared_ptr> translate(storm::models::symbolic::Dtmc const& symbolicDtmc, std::vector> const& formulas = std::vector>()); storm::dd::Odd const& getOdd() const; private: @@ -25,13 +26,13 @@ namespace storm { template class SymbolicMdpToSparseMdpTransformer { public: - static std::shared_ptr> translate(storm::models::symbolic::Mdp const& symbolicMdp); + static std::shared_ptr> translate(storm::models::symbolic::Mdp const& symbolicMdp, std::vector> const& formulas = std::vector>()); }; template class SymbolicCtmcToSparseCtmcTransformer { public: - static std::shared_ptr> translate(storm::models::symbolic::Ctmc const& symbolicCtmc); + static std::shared_ptr> translate(storm::models::symbolic::Ctmc const& symbolicCtmc, std::vector> const& formulas = std::vector>()); }; } } From b73f0ef94e9c829307afec8b235ebd658f4dd7a3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 9 Jul 2018 21:49:13 +0200 Subject: [PATCH 390/647] fixing issue in jani-to-prism label replacement --- src/storm/logic/LabelSubstitutionVisitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/logic/LabelSubstitutionVisitor.cpp b/src/storm/logic/LabelSubstitutionVisitor.cpp index 1e17649a3..08726901c 100644 --- a/src/storm/logic/LabelSubstitutionVisitor.cpp +++ b/src/storm/logic/LabelSubstitutionVisitor.cpp @@ -24,14 +24,14 @@ namespace storm { if (it != labelToExpressionMapping->end()) { return std::static_pointer_cast(std::make_shared(it->second)); } else { - return f.asSharedPointer(); + return std::static_pointer_cast(std::make_shared(f.getLabel())); } } else { auto it = labelToLabelMapping->find(f.getLabel()); if (it != labelToLabelMapping->end()) { return std::static_pointer_cast(std::make_shared(it->second)); } else { - return f.asSharedPointer(); + return std::static_pointer_cast(std::make_shared(f.getLabel())); } } } From 9ed6f084e7f1a34489a603489d3c6f2c184f1742 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 10 Jul 2018 11:07:04 +0200 Subject: [PATCH 391/647] adding uniqueness constraint in LRA computation also for fixed-point formulation --- .../csl/helper/SparseCtmcCslHelper.cpp | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index f9e6da475..697eab80a 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -488,27 +488,36 @@ namespace storm { if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::FixedPointSystem) { fixedPointSystem = true; } - + // Now build the final equation system matrix, the initial guess and the right-hand side in one go. std::vector bsccEquationSystemRightSide(bsccEquationSystem.getColumnCount(), zero); storm::storage::SparseMatrixBuilder builder; for (uint_fast64_t row = 0; row < bsccEquationSystem.getRowCount(); ++row) { - + // If the current row is the first one belonging to a BSCC, we substitute it by the constraint that the // values for states of this BSCC must sum to one. However, in order to have a non-zero value on the // diagonal, we add the constraint of the BSCC that produces a 1 on the diagonal. - if (!fixedPointSystem && firstStatesInBsccs.get(row)) { + if (firstStatesInBsccs.get(row)) { uint_fast64_t requiredBscc = stateToBsccIndexMap[row]; storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[requiredBscc]; - - for (auto const& state : bscc) { - builder.addNextValue(row, indexInStatesInBsccs[state], one); + + if (fixedPointSystem) { + for (auto const& state : bscc) { + if (row == indexInStatesInBsccs[state]) { + builder.addNextValue(row, indexInStatesInBsccs[state], zero); + } else { + builder.addNextValue(row, indexInStatesInBsccs[state], -one); + } + } + } else { + for (auto const& state : bscc) { + builder.addNextValue(row, indexInStatesInBsccs[state], one); + } } bsccEquationSystemRightSide[row] = one; - } else { - // Otherwise, we copy the row, and subtract 1 from the diagonal. + // Otherwise, we copy the row, and subtract 1 from the diagonal (only for the equation solver format). for (auto& entry : bsccEquationSystem.getRow(row)) { if (fixedPointSystem || entry.getColumn() != row) { builder.addNextValue(row, entry.getColumn(), entry.getValue()); @@ -530,7 +539,6 @@ namespace storm { } bsccEquationSystem = builder.build(); - { std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(bsccEquationSystem)); solver->solveEquations(env, bsccEquationSystemSolution, bsccEquationSystemRightSide); From a46e6439eb6aa028d850b4a40b78d75e39b22d13 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 10 Jul 2018 14:18:41 +0200 Subject: [PATCH 392/647] enabled switching of methods if unsupported method chosen in symbolic min-max equation solver --- src/storm/solver/GmmxxLinearEquationSolver.cpp | 4 ++-- src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index 83d5b6ef6..d2fefc60d 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -103,10 +103,10 @@ namespace storm { // Check if the solver converged and issue a warning otherwise. if (iter.converged()) { - STORM_LOG_INFO("Iterative solver converged after " << iter.get_iteration() << " iterations."); + STORM_LOG_INFO("Iterative solver converged after " << iter.get_iteration() << " iteration(s)."); return true; } else { - STORM_LOG_WARN("Iterative solver did not converge."); + STORM_LOG_WARN("Iterative solver did not converge within " << iter.get_iteration() << " iteration(s)."); return false; } } diff --git a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp index b599face7..c54df3acf 100644 --- a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp @@ -40,7 +40,10 @@ namespace storm { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } } - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + if (method != MinMaxMethod::ValueIteration && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { + STORM_LOG_WARN("Selected method is not supported for this solver, switching to value iteration."); + method = MinMaxMethod::ValueIteration; + } return method; } From 33c189bd32e95c71ff9c70469a37ce4a26e287a2 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Sat, 30 Jun 2018 12:37:02 +0200 Subject: [PATCH 393/647] export setting for flattening --- src/storm/settings/modules/JaniExportSettings.cpp | 6 ++++++ src/storm/settings/modules/JaniExportSettings.h | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/storm/settings/modules/JaniExportSettings.cpp b/src/storm/settings/modules/JaniExportSettings.cpp index a56cbc668..d6275834b 100644 --- a/src/storm/settings/modules/JaniExportSettings.cpp +++ b/src/storm/settings/modules/JaniExportSettings.cpp @@ -16,11 +16,13 @@ namespace storm { const std::string JaniExportSettings::janiFileOptionShortName = "output"; const std::string JaniExportSettings::standardCompliantOptionName = "standard-compliant"; const std::string JaniExportSettings::standardCompliantOptionShortName = "standard"; + const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Export in standard compliant variant.").build()); } bool JaniExportSettings::isJaniFileSet() const { @@ -34,6 +36,10 @@ namespace storm { bool JaniExportSettings::isExportAsStandardJaniSet() const { return this->getOption(standardCompliantOptionName).getHasOptionBeenSet(); } + + bool JaniExportSettings::isExportFlattenedSet() const { + return this->getOption(exportFlattenOptionName).getHasOptionBeenSet(); + } void JaniExportSettings::finalize() { diff --git a/src/storm/settings/modules/JaniExportSettings.h b/src/storm/settings/modules/JaniExportSettings.h index 397eb183a..fd6639869 100644 --- a/src/storm/settings/modules/JaniExportSettings.h +++ b/src/storm/settings/modules/JaniExportSettings.h @@ -25,7 +25,9 @@ namespace storm { std::string getJaniFilename() const; bool isExportAsStandardJaniSet() const; - + + bool isExportFlattenedSet() const; + bool check() const override; void finalize() override; @@ -36,6 +38,7 @@ namespace storm { static const std::string janiFileOptionShortName; static const std::string standardCompliantOptionName; static const std::string standardCompliantOptionShortName; + static const std::string exportFlattenOptionName; }; } From 6275c52779809fdcdf27d3e26d810b5e4752a664 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 11 Jul 2018 15:48:48 +0200 Subject: [PATCH 394/647] several convenience additions to jani data structures --- src/storm/storage/jani/Assignment.cpp | 2 +- src/storm/storage/jani/Assignment.h | 3 ++- src/storm/storage/jani/Automaton.cpp | 4 ++++ src/storm/storage/jani/Automaton.h | 2 ++ src/storm/storage/jani/JSONExporter.cpp | 1 + src/storm/storage/jani/Location.cpp | 4 ++++ src/storm/storage/jani/Location.h | 3 ++- src/storm/storage/jani/Model.cpp | 10 +++++++++- src/storm/storage/jani/Model.h | 13 +++++++++++++ src/storm/storage/jani/OrderedAssignments.cpp | 8 ++++++++ src/storm/storage/jani/OrderedAssignments.h | 4 +++- 11 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 25fa036af..747679385 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -37,7 +37,7 @@ namespace storm { } void Assignment::substitute(std::map const& substitution) { - this->setAssignedExpression(this->getAssignedExpression().substitute(substitution)); + this->setAssignedExpression(this->getAssignedExpression().substitute(substitution).simplify()); } int64_t Assignment::getLevel() const { diff --git a/src/storm/storage/jani/Assignment.h b/src/storm/storage/jani/Assignment.h index a4e2dbd23..3ab3b5581 100644 --- a/src/storm/storage/jani/Assignment.h +++ b/src/storm/storage/jani/Assignment.h @@ -14,7 +14,8 @@ namespace storm { * Creates an assignment of the given expression to the given variable. */ Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0); - + + Assignment(Assignment const&) = default; bool operator==(Assignment const& other) const; /*! diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index f4c65c759..da0d0a91c 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -53,6 +53,10 @@ namespace storm { return variables.addVariable(variable); } + bool Automaton::hasVariable(std::string const& name) const { + return variables.hasVariable(name); + } + VariableSet& Automaton::getVariables() { return variables; } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index c549ecca8..986ea794d 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -79,6 +79,8 @@ namespace storm { * Retrieves the variables of this automaton. */ VariableSet const& getVariables() const; + + bool hasVariable(std::string const& name) const; /*! * Retrieves all expression variables used by this automaton. diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 0c0c212a0..435da6818 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -35,6 +35,7 @@ namespace storm { modernjson::json buildExpression(storm::expressions::Expression const& exp, std::vector const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet()) { + STORM_LOG_TRACE("Exporting " << exp); return ExpressionToJson::translate(exp, constants, globalVariables, localVariables); } diff --git a/src/storm/storage/jani/Location.cpp b/src/storm/storage/jani/Location.cpp index b957d5e9a..5ab431734 100644 --- a/src/storm/storage/jani/Location.cpp +++ b/src/storm/storage/jani/Location.cpp @@ -10,6 +10,10 @@ namespace storm { Location::Location(std::string const& name, std::vector const& transientAssignments) : name(name), assignments(transientAssignments) { // Intentionally left empty. } + + Location::Location(std::string const& name, OrderedAssignments const& assignments) : name(name), assignments(assignments) { + // Intentionally left empty. + } std::string const& Location::getName() const { return name; diff --git a/src/storm/storage/jani/Location.h b/src/storm/storage/jani/Location.h index b2bda7b23..75e53d575 100644 --- a/src/storm/storage/jani/Location.h +++ b/src/storm/storage/jani/Location.h @@ -18,7 +18,8 @@ namespace storm { * Creates a new location. */ Location(std::string const& name, std::vector const& transientAssignments = {}); - + + Location(std::string const& name, OrderedAssignments const& assignments); /*! * Retrieves the name of the location. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 47533126c..2d51910cc 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -711,7 +711,15 @@ namespace storm { std::vector const& Model::getAutomata() const { return automata; } - + + bool Model::hasAutomaton(std::string const& name) const { + return automatonToIndex.find(name) != automatonToIndex.end(); + } + + void Model::replaceAutomaton(uint64_t index, Automaton const& automaton) { + automata[index] = automaton; + } + Automaton& Model::getAutomaton(std::string const& name) { auto it = automatonToIndex.find(name); STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'."); diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 2dc69d147..86555a2d4 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -245,6 +245,19 @@ namespace storm { */ std::vector const& getAutomata() const; + /** + * Replaces the automaton at index with a new automaton. + * @param index + * @param newAutomaton + */ + void replaceAutomaton(uint64_t index, Automaton const& newAutomaton); + + /*! + * Rerieves whether there exists an automaton with the given name. + * @param name + * @return + */ + bool hasAutomaton(std::string const& name) const; /*! * Retrieves the automaton with the given name. */ diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 99eb415a8..68ae7f7c7 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -16,6 +16,14 @@ namespace storm { OrderedAssignments::OrderedAssignments(Assignment const& assignment) { add(assignment); } + + OrderedAssignments OrderedAssignments::clone() const { + OrderedAssignments result; + for (auto const& assignment : allAssignments) { + result.add(Assignment(*assignment)); + } + return result; + } bool OrderedAssignments::add(Assignment const& assignment) { // If the element is contained in this set of assignment, nothing needs to be added. diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 8e307e6e0..9d5a6a7b5 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -140,7 +140,9 @@ namespace storm { bool areLinear() const; friend std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments); - + + OrderedAssignments clone() const; + private: uint64_t isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; uint64_t isWrittenBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; From f9e420826849fa3674d3ea021343c588bbe49265 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 11 Jul 2018 15:49:37 +0200 Subject: [PATCH 395/647] export jani with comment expressions to ease debugging jani models --- src/storm/storage/jani/JSONExporter.cpp | 38 ++++++++++++++++--------- src/storm/storage/jani/JSONExporter.h | 4 +-- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 435da6818..c829d3634 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -648,7 +648,7 @@ namespace storm { } - modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { std::vector assignmentDeclarations; bool addIndex = orderedAssignments.hasMultipleLevels(); for(auto const& assignment : orderedAssignments) { @@ -659,18 +659,21 @@ namespace storm { assignmentEntry["index"] = assignment.getLevel(); } assignmentDeclarations.push_back(assignmentEntry); + if (commentExpressions) { + assignmentEntry["comment"] = assignment.getVariable().getName() + " <- " + assignment.getAssignedExpression().toString(); + } } return modernjson::json(assignmentDeclarations); } - modernjson::json buildLocationsArray(std::vector const& locations, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json buildLocationsArray(std::vector const& locations, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { std::vector locationDeclarations; for(auto const& location : locations) { modernjson::json locEntry; locEntry["name"] = location.getName(); // TODO support invariants? if (!location.getAssignments().empty()) { - locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables); + locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables, commentExpressions); } locationDeclarations.push_back(locEntry); } @@ -685,7 +688,7 @@ namespace storm { return modernjson::json(names); } - modernjson::json buildDestinations(std::vector const& destinations, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json buildDestinations(std::vector const& destinations, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { assert(destinations.size() > 0); std::vector destDeclarations; for(auto const& destination : destinations) { @@ -699,16 +702,19 @@ namespace storm { } if (!prob1) { destEntry["probability"]["exp"] = buildExpression(destination.getProbability(), constants, globalVariables, localVariables); + if (commentExpressions) { + destEntry["probability"]["comment"] = destination.getProbability().toString(); + } } if (!destination.getOrderedAssignments().empty()) { - destEntry["assignments"] = buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables); + destEntry["assignments"] = buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables, commentExpressions); } destDeclarations.push_back(destEntry); } return modernjson::json(destDeclarations); } - modernjson::json buildEdges(std::vector const& edges , std::map const& actionNames, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json buildEdges(std::vector const& edges , std::map const& actionNames, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { std::vector edgeDeclarations; for(auto const& edge : edges) { if (edge.getGuard().isFalse()) { @@ -722,13 +728,19 @@ namespace storm { } if(edge.hasRate()) { edgeEntry["rate"]["exp"] = buildExpression(edge.getRate(), constants, globalVariables, localVariables); + if (commentExpressions) { + edgeEntry["rate"]["comment"] = edge.getRate().toString(); + } } if (!edge.getGuard().isTrue()) { edgeEntry["guard"]["exp"] = buildExpression(edge.getGuard(), constants, globalVariables, localVariables); + if (commentExpressions) { + edgeEntry["guard"]["comment"] = edge.getGuard().toString(); + } } - edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables); + edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables, commentExpressions); if (!edge.getAssignments().empty()) { - edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables); + edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables, commentExpressions); } edgeDeclarations.push_back(edgeEntry); @@ -736,7 +748,7 @@ namespace storm { return modernjson::json(edgeDeclarations); } - modernjson::json buildAutomataArray(std::vector const& automata, std::map const& actionNames, std::vector const& constants, VariableSet const& globalVariables) { + modernjson::json buildAutomataArray(std::vector const& automata, std::map const& actionNames, std::vector const& constants, VariableSet const& globalVariables, bool commentExpressions) { std::vector automataDeclarations; for(auto const& automaton : automata) { modernjson::json autoEntry; @@ -745,16 +757,16 @@ namespace storm { if(automaton.hasRestrictedInitialStates()) { autoEntry["restrict-initial"]["exp"] = buildExpression(automaton.getInitialStatesRestriction(), constants, globalVariables, automaton.getVariables()); } - autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables()); + autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables(), commentExpressions); autoEntry["initial-locations"] = buildInitialLocations(automaton); - autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables, automaton.getVariables()); + autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables, automaton.getVariables(), commentExpressions); automataDeclarations.push_back(autoEntry); } return modernjson::json(automataDeclarations); } - void JsonExporter::convertModel(storm::jani::Model const& janiModel) { + void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) { jsonStruct["jani-version"] = janiModel.getJaniVersion(); jsonStruct["name"] = janiModel.getName(); jsonStruct["type"] = to_string(janiModel.getModelType()); @@ -762,7 +774,7 @@ namespace storm { jsonStruct["constants"] = buildConstantsArray(janiModel.getConstants()); jsonStruct["variables"] = buildVariablesArray(janiModel.getGlobalVariables(), janiModel.getConstants(), janiModel.getGlobalVariables()); jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction(), janiModel.getConstants(), janiModel.getGlobalVariables()); - jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables()); + jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables(), commentExpressions); jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition()); std::vector standardFeatureVector = {"derived-operators"}; jsonStruct["features"] = standardFeatureVector; diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 17fa97ad6..1bf098bca 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -3,7 +3,7 @@ #include "storm/storage/expressions/ExpressionVisitor.h" #include "storm/logic/FormulaVisitor.h" -#include "Model.h" +#include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" #include "storm/adapters/RationalNumberAdapter.h" // JSON parser @@ -80,7 +80,7 @@ namespace storm { private: - void convertModel(storm::jani::Model const& model); + void convertModel(storm::jani::Model const& model, bool commentExpressions = true); void convertProperties(std::vector const& formulas, storm::jani::Model const& model); void appendVariableDeclaration(storm::jani::Variable const& variable); From e64e293d59e18a4d035752c57b444d259a9498ae Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 11 Jul 2018 15:50:16 +0200 Subject: [PATCH 396/647] jani transformer which changes a variable into a location --- src/storm/api/export.cpp | 16 ++- .../settings/modules/JaniExportSettings.cpp | 27 +++- .../settings/modules/JaniExportSettings.h | 5 + .../storage/jani/JaniLocationExpander.cpp | 121 ++++++++++++++++++ src/storm/storage/jani/JaniLocationExpander.h | 26 ++++ 5 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 src/storm/storage/jani/JaniLocationExpander.cpp create mode 100644 src/storm/storage/jani/JaniLocationExpander.h diff --git a/src/storm/api/export.cpp b/src/storm/api/export.cpp index 193ec0668..78951fd27 100644 --- a/src/storm/api/export.cpp +++ b/src/storm/api/export.cpp @@ -1,17 +1,27 @@ #include "storm/api/export.h" +#include "storm/storage/jani/JaniLocationExpander.h" namespace storm { namespace api { void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { auto janiSettings = storm::settings::getModule(); - + + storm::jani::Model exportModel = model; + if (janiSettings.isLocationVariablesSet()) { + for(auto const& pair : janiSettings.getLocationVariables()) { + storm::jani::JaniLocationExpander expander(exportModel); + expander.transform(pair.first, pair.second); + exportModel = expander.getResult(); + } + } + if (janiSettings.isExportAsStandardJaniSet()) { - storm::jani::Model normalisedModel = model; + storm::jani::Model normalisedModel = exportModel; normalisedModel.makeStandardJaniCompliant(); storm::jani::JsonExporter::toFile(normalisedModel, properties, filename); } else { - storm::jani::JsonExporter::toFile(model, properties, filename); + storm::jani::JsonExporter::toFile(exportModel, properties, filename); } } diff --git a/src/storm/settings/modules/JaniExportSettings.cpp b/src/storm/settings/modules/JaniExportSettings.cpp index d6275834b..a47a9914b 100644 --- a/src/storm/settings/modules/JaniExportSettings.cpp +++ b/src/storm/settings/modules/JaniExportSettings.cpp @@ -7,6 +7,8 @@ #include "storm/settings/ArgumentBuilder.h" #include "storm/settings/Argument.h" +#include + namespace storm { namespace settings { namespace modules { @@ -17,12 +19,15 @@ namespace storm { const std::string JaniExportSettings::standardCompliantOptionName = "standard-compliant"; const std::string JaniExportSettings::standardCompliantOptionShortName = "standard"; const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; + const std::string JaniExportSettings::locationVariablesOptionName = "location-variables"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Export in standard compliant variant.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Export in standard compliant variant.").build()); + } bool JaniExportSettings::isJaniFileSet() const { @@ -40,7 +45,25 @@ namespace storm { bool JaniExportSettings::isExportFlattenedSet() const { return this->getOption(exportFlattenOptionName).getHasOptionBeenSet(); } - + + bool JaniExportSettings::isLocationVariablesSet() const { + return this->getOption(locationVariablesOptionName).getHasOptionBeenSet(); + } + + std::vector> JaniExportSettings::getLocationVariables() const { + std::string argument = this->getOption(locationVariablesOptionName).getArgumentByName("variables").getValueAsString(); + std::vector arguments; + boost::split( arguments, argument, boost::is_any_of(",")); + std::vector> result; + for (auto const& pair : arguments) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of(".")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::IllegalArgumentException, "Expected a name of the form AUTOMATON.VARIABLE (with no further dots) but got " << pair); + result.emplace_back(keyvaluepair.at(0), keyvaluepair.at(1)); + } + return result; + } + void JaniExportSettings::finalize() { } diff --git a/src/storm/settings/modules/JaniExportSettings.h b/src/storm/settings/modules/JaniExportSettings.h index fd6639869..d61b923fc 100644 --- a/src/storm/settings/modules/JaniExportSettings.h +++ b/src/storm/settings/modules/JaniExportSettings.h @@ -28,6 +28,10 @@ namespace storm { bool isExportFlattenedSet() const; + bool isLocationVariablesSet() const; + + std::vector> getLocationVariables() const; + bool check() const override; void finalize() override; @@ -39,6 +43,7 @@ namespace storm { static const std::string standardCompliantOptionName; static const std::string standardCompliantOptionShortName; static const std::string exportFlattenOptionName; + static const std::string locationVariablesOptionName; }; } diff --git a/src/storm/storage/jani/JaniLocationExpander.cpp b/src/storm/storage/jani/JaniLocationExpander.cpp new file mode 100644 index 000000000..d955a7754 --- /dev/null +++ b/src/storm/storage/jani/JaniLocationExpander.cpp @@ -0,0 +1,121 @@ +#include "storm/storage/jani/JaniLocationExpander.h" + +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/IllegalArgumentException.h" + + +namespace storm { + namespace jani { + JaniLocationExpander::JaniLocationExpander(Model const& origModel) : original(origModel) { + + } + + void JaniLocationExpander::transform(std::string const& automatonName, std::string const& variableName) { + STORM_LOG_THROW(original.hasAutomaton(automatonName), storm::exceptions::IllegalArgumentException, "Model has no automaton with name " << automatonName << ". "); + STORM_LOG_THROW(original.getAutomaton(automatonName).hasVariable(variableName), storm::exceptions::IllegalArgumentException, "Automaton " << automatonName << " has no variable with name " << variableName << ". "); + newModel = original; + newModel.replaceAutomaton(newModel.getAutomatonIndex(automatonName), transformAutomaton(original.getAutomaton(automatonName), variableName)); + } + + + Model const& JaniLocationExpander::getResult() const { + return newModel; + } + + Automaton JaniLocationExpander::transformAutomaton(Automaton const& automaton, std::string const& variableName) { + + Automaton newAutomaton(automaton.getName(), automaton.getLocationExpressionVariable()); + int64_t initialVariableValue; + int64_t variableLowerBound; + int64_t variableUpperBound; + storm::expressions::Variable eliminatedExpressionVariable; + const storm::jani::Variable* variable; + + for (auto const& var : automaton.getVariables()) { + if (var.getName() == variableName) { + // This variable will be eliminated in the new automaton. + STORM_LOG_THROW(var.hasInitExpression(), storm::exceptions::IllegalArgumentException, "Variable to be eliminated has to have an initexpression."); + STORM_LOG_THROW(var.isBoundedIntegerVariable(), storm::exceptions::IllegalArgumentException, "Variable to be eliminated has to be an bounded integer variable."); + STORM_LOG_THROW(!var.isTransient(), storm::exceptions::IllegalArgumentException, "Cannot eliminate transient variable"); + + variableUpperBound = var.asBoundedIntegerVariable().getUpperBound().evaluateAsInt(); + variableLowerBound = var.asBoundedIntegerVariable().getLowerBound().evaluateAsInt(); + initialVariableValue = var.getInitExpression().evaluateAsInt(); + variable = &var; + eliminatedExpressionVariable = var.getExpressionVariable(); + + } else { + // Other variables are just copied. + newAutomaton.addVariable(var); + } + } + + STORM_LOG_THROW(!automaton.getInitialStatesRestriction().containsVariable({eliminatedExpressionVariable}), storm::exceptions::NotSupportedException, "Elimination of variable that occurs in the initial state restriction is not allowed"); + newAutomaton.setInitialStatesRestriction(automaton.getInitialStatesRestriction()); + + + std::map substitutionMap; + std::map> locationNames; + std::map> locationVariableValueMap; + for (auto const& loc : automaton.getLocations()) { + locationNames[loc.getName()] = std::vector(); + uint64_t origIndex = automaton.getLocationIndex(loc.getName()); + + for (int64_t i = variableLowerBound; i <= variableUpperBound; i++) { + std::string newLocationName = loc.getName() + "_" + variableName + "_" + std::to_string(i); + substitutionMap[eliminatedExpressionVariable] = original.getExpressionManager().integer(i); + std::cout << "eliminate " << eliminatedExpressionVariable.getName() << " with " << i << std::endl; + OrderedAssignments newAssignments = loc.getAssignments().clone(); + newAssignments.substitute(substitutionMap); + std::cout << newAssignments << std::endl; + uint64_t newLocationIndex = newAutomaton.addLocation(Location(newLocationName, newAssignments)); + + locationVariableValueMap[origIndex][i] = newLocationIndex; + locationNames[loc.getName()].push_back(newLocationName); + } + } + + + + for (auto const& edge : automaton.getEdges()) { + for (auto const& newValueAndLocation : locationVariableValueMap[edge.getSourceLocationIndex()]) { + substitutionMap[eliminatedExpressionVariable] = original.getExpressionManager().integer(newValueAndLocation.first); + + uint64_t newSourceIndex = newValueAndLocation.second; + storm::expressions::Expression newGuard = edge.getGuard().substitute(substitutionMap).simplify(); + if (!newGuard.containsVariables() && !newGuard.evaluateAsBool()) { + continue; + } + std::shared_ptr templateEdge = std::make_shared(newGuard); + + STORM_LOG_THROW(edge.getAssignments().empty(), storm::exceptions::NotImplementedException, "Support for edge-assignments is not implemented"); + + std::vector> destinationLocationsAndProbabilities; + for (auto const& destination : edge.getDestinations()) { + OrderedAssignments oa(destination.getOrderedAssignments().clone()); + oa.substitute(substitutionMap); + int64_t value; + for (auto const& assignment : oa) { + if (assignment.getVariable() == *variable) { + oa.remove(assignment); + value = assignment.getAssignedExpression().evaluateAsInt(); + break; + } + } + TemplateEdgeDestination ted(oa); + templateEdge->addDestination(ted); + destinationLocationsAndProbabilities.emplace_back(locationVariableValueMap[destination.getLocationIndex()][value], destination.getProbability().substitute((substitutionMap))); + } + newAutomaton.addEdge(storm::jani::Edge(newSourceIndex, edge.getActionIndex(), edge.hasRate() ? boost::optional(edge.getRate().substitute(substitutionMap)) : boost::none, templateEdge, destinationLocationsAndProbabilities)); + + } + } + return newAutomaton; + + + } + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/JaniLocationExpander.h b/src/storm/storage/jani/JaniLocationExpander.h new file mode 100644 index 000000000..6b4ec0709 --- /dev/null +++ b/src/storm/storage/jani/JaniLocationExpander.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Automaton.h" + + +namespace storm { + namespace jani { + class JaniLocationExpander { + public: + JaniLocationExpander(Model const& original); + void transform(std::string const& automatonName, std::string const& variableName); + Model const& getResult() const; + + private: + Model const& original; + Model newModel; + + Automaton transformAutomaton(Automaton const& automaton, std::string const& variableName); + + + + }; + } + +} From a616e2743dfcfe51a2d04f1734cc1593bd06d9e3 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 11 Jul 2018 15:51:12 +0200 Subject: [PATCH 397/647] fixes to standard-compliant prism-to-jani conversion --- src/storm/storage/jani/Automaton.cpp | 11 +++++-- src/storm/storage/jani/Model.cpp | 5 --- src/storm/storage/prism/ToJaniConverter.cpp | 35 ++++++++++++++++++++- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index e962562d2..790a0489d 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -427,23 +427,28 @@ namespace storm { auto& location = locations[locationIndex]; auto edges = this->getEdgesFromLocation(locationIndex); + storm::jani::Location newLocation(location.getName()); + bool createNewLocation = true; for (auto& edge : edges) { STORM_LOG_THROW(encounteredTemplateEdges.find(edge.getTemplateEdge()) == encounteredTemplateEdges.end(), storm::exceptions::NotSupportedException, "Pushing location assignments to edges is only supported for automata with unique template edges."); auto& templateEdge = edge.getTemplateEdge(); encounteredTemplateEdges.insert(templateEdge); - storm::jani::Location newLocation(location.getName()); for (auto const& assignment : location.getAssignments().getTransientAssignments()) { if (assignment.getVariable().isTransient() && assignment.getVariable().isRealVariable()) { templateEdge->addTransientAssignment(assignment, true); - } else { + } else if (createNewLocation) { newLocation.addTransientAssignment(assignment); } } - location = std::move(newLocation); + if (createNewLocation) { + createNewLocation = false; + } } + + location = std::move(newLocation); } } diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 0cbbaae14..30072fa56 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -742,11 +742,6 @@ namespace storm { } std::shared_ptr Model::getStandardSystemComposition() const { - // If there's just one automaton, we must not use the parallel composition operator. - if (this->getNumberOfAutomata() == 1) { - return std::make_shared(this->getAutomata().front().getName()); - } - // Determine the action indices used by each of the automata and create the standard subcompositions. std::set allActionIndices; std::vector> automatonActionIndices; diff --git a/src/storm/storage/prism/ToJaniConverter.cpp b/src/storm/storage/prism/ToJaniConverter.cpp index 9712a52a7..36a47d7f9 100644 --- a/src/storm/storage/prism/ToJaniConverter.cpp +++ b/src/storm/storage/prism/ToJaniConverter.cpp @@ -7,6 +7,9 @@ #include "storm/storage/jani/Model.h" #include "storm/storage/jani/TemplateEdge.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/JaniExportSettings.h" + #include "storm/utility/macros.h" #include "storm/exceptions/NotImplementedException.h" @@ -15,6 +18,8 @@ namespace storm { storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal, std::string suffix) { std::shared_ptr manager = program.getManager().getSharedPointer(); + + bool produceStateRewards = !storm::settings::getModule().isExportAsStandardJaniSet() || program.getModelType() == storm::prism::Program::ModelType::CTMC; // Start by creating an empty JANI model. storm::jani::ModelType modelType; @@ -153,6 +158,20 @@ namespace storm { } STORM_LOG_THROW(transientEdgeAssignments.empty() || transientLocationAssignments.empty() || !program.specifiesSystemComposition(), storm::exceptions::NotImplementedException, "Cannot translate reward models from PRISM to JANI that specify a custom system composition."); + // If we are not allowed to produce state rewards, we need to create a mapping from action indices to transient + // location assignments. This is done so that all assignments are added only *once* for synchronizing actions. + std::map> transientRewardLocationAssignmentsPerAction; + if (!produceStateRewards) { + for (auto const& action : program.getActions()) { + auto& list = transientRewardLocationAssignmentsPerAction[janiModel.getActionIndex(action)]; + for (auto const& assignment : transientLocationAssignments) { + if (assignment.isTransient() && assignment.getVariable().isRealVariable()) { + list.emplace_back(assignment); + } + } + } + } + // Now create the separate JANI automata from the modules of the PRISM program. While doing so, we use the // previously built mapping to make variables global that are read by more than one module. std::set firstModules; @@ -195,10 +214,13 @@ namespace storm { automaton.addInitialLocation(onlyLocationIndex); // If we are translating the first module that has the action, we need to add the transient assignments to the location. + // However, in standard compliant JANI, there are no state rewards if (firstModule) { storm::jani::Location& onlyLocation = automaton.getLocation(onlyLocationIndex); for (auto const& assignment : transientLocationAssignments) { - onlyLocation.addTransientAssignment(assignment); + if (assignment.getVariable().isBooleanVariable() || produceStateRewards) { + onlyLocation.addTransientAssignment(assignment); + } } } @@ -243,6 +265,12 @@ namespace storm { templateEdge->addTransientAssignment(assignment); } } + if (!produceStateRewards) { + transientEdgeAssignmentsToAdd = transientRewardLocationAssignmentsPerAction.find(janiModel.getActionIndex(command.getActionName())); + for (auto const& assignment : transientEdgeAssignmentsToAdd->second) { + templateEdge->addTransientAssignment(assignment, true); + } + } // Create the edge object. storm::jani::Edge newEdge; @@ -261,6 +289,11 @@ namespace storm { // NOTE: This only works for the standard composition and not for any custom compositions. This case // must be checked for earlier. for (auto actionIndex : actionIndicesOfModule) { + // Do not delete rewards dealt out on non-synchronizing edges. + if (actionIndex == janiModel.getActionIndex("")) { + continue; + } + auto it = transientEdgeAssignments.find(actionIndex); if (it != transientEdgeAssignments.end()) { transientEdgeAssignments.erase(it); From f2a7621e0abceaa7166a18e9db984e7d097abf21 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 11 Jul 2018 15:52:48 +0200 Subject: [PATCH 398/647] updated changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 150d5ef1b..bda25081d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,10 @@ Version 1.2.x - Sound value iteration (SVI) for DTMCs and MDPs - Topological solver for linear equation systems and MinMax equation systems. - Added support for expected total rewards in the sparse engine - +- `storm-parsers` extracted to reduce linking time +- `storm-counterexamples` extracted to reduce linking time +- Improved export for jani models +- Several extensions to high-level counterexamples ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. From 54c0bbb7c349c8f9558ad68230c8147081eae1c8 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 11 Jul 2018 19:50:03 +0200 Subject: [PATCH 399/647] flatten of jani models before export via appropriate setting --- src/storm/api/export.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/api/export.cpp b/src/storm/api/export.cpp index 78951fd27..1a69a34da 100644 --- a/src/storm/api/export.cpp +++ b/src/storm/api/export.cpp @@ -16,6 +16,10 @@ namespace storm { } } + if (janiSettings.isExportFlattenedSet()) { + exportModel = exportModel.flattenComposition(); + } + if (janiSettings.isExportAsStandardJaniSet()) { storm::jani::Model normalisedModel = exportModel; normalisedModel.makeStandardJaniCompliant(); From cb89ab7509c7ed3ca8f1f06f766742a2ac0943e4 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 11 Jul 2018 20:39:21 +0200 Subject: [PATCH 400/647] clearing end-component requirement in topological solver --- src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 92692b966..d6c1b69e1 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -190,6 +190,10 @@ namespace storm { if (req.lowerBounds() && this->hasLowerBound()) { req.clearLowerBounds(); } + + // If all requirements of the underlying solver have been passed as requirements to the calling site, we can + // assume that the system has no end components if the underlying solver requires this. + req.clearNoEndComponents(); STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); this->sccSolver->setRequirementsChecked(true); From 601b73608a5ab29c16f2c5517e45ccf11100826f Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 11 Jul 2018 21:06:52 +0200 Subject: [PATCH 401/647] adapting changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bda25081d..b75150e65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Version 1.2.x - `storm-dft`: improvements in Galileo parser - `storm-dft`: test cases for DFT analysis - Sound value iteration (SVI) for DTMCs and MDPs -- Topological solver for linear equation systems and MinMax equation systems. +- Topological solver for linear equation systems and MinMax equation systems (enabled by default) - Added support for expected total rewards in the sparse engine - `storm-parsers` extracted to reduce linking time - `storm-counterexamples` extracted to reduce linking time From 10da10a7d1d6d6f39725a737633fc9165053e5ff Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 11 Jul 2018 22:39:53 +0200 Subject: [PATCH 402/647] started on enabling sampling of parametric models from command line --- src/storm-pars-cli/storm-pars.cpp | 154 +++++++++++++++--- .../settings/modules/ParametricSettings.cpp | 9 +- .../settings/modules/ParametricSettings.h | 8 + 3 files changed, 145 insertions(+), 26 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 8546f81d1..ff7c075f8 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -41,6 +41,69 @@ namespace storm { return result; } + template + std::map::type, std::vector::type>> parseSamples(std::shared_ptr const& model, std::string const& sampleString) { + STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); + + std::map::type, std::vector::type>> samplesForVariables; + if (sampleString.empty()) { + return samplesForVariables; + } + + // Get all parameters from the model. + std::set::type> modelParameters; + auto const& sparseModel = *model->as>(); + modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); + auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + // Get the values string for each variable. + std::vector valuesForVariables; + boost::split(valuesForVariables, sampleString, boost::is_any_of(",")); + for (auto& values : valuesForVariables) { + boost::trim(values); + } + + std::set::type> encounteredParameters; + for (auto const& varValues : valuesForVariables) { + auto equalsPosition = varValues.find("="); + STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); + std::string variableName = varValues.substr(0, equalsPosition); + boost::trim(variableName); + std::string values = varValues.substr(equalsPosition + 1); + boost::trim(values); + + bool foundParameter = false; + typename utility::parametric::VariableType::type theParameter; + for (auto const& parameter : modelParameters) { + std::stringstream parameterStream; + parameterStream << parameter; + std::cout << parameterStream.str() << " vs " << variableName << std::endl; + if (parameterStream.str() == variableName) { + foundParameter = true; + theParameter = parameter; + encounteredParameters.insert(parameter); + } + } + STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); + + std::vector splitValues; + boost::split(splitValues, values, boost::is_any_of(":")); + STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); + + auto& list = samplesForVariables[theParameter]; + for (auto& value : splitValues) { + boost::trim(value); + + list.push_back(storm::utility::convertNumber::type>(value)); + } + } + + STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples.") + + return samplesForVariables; + } + template std::pair, bool> preprocessSparseModel(std::shared_ptr> const& model, SymbolicInput const& input) { auto generalSettings = storm::settings::getModule(); @@ -152,23 +215,65 @@ namespace storm { } template - void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input) { - verifyProperties(input.properties, - [&model] (std::shared_ptr const& formula) { - std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); - if (result) { - result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); - } - return result; - }, - [&model] (std::unique_ptr const& result) { - auto parametricSettings = storm::settings::getModule(); - if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmc = model->template as>(); - boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; - storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); - } - }); + void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::map::type, std::vector::type>> const& samples) { + + if (samples.empty()) { + verifyProperties(input.properties, + [&model] (std::shared_ptr const& formula) { + std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); + } + return result; + }, + [&model] (std::unique_ptr const& result) { + auto parametricSettings = storm::settings::getModule(); + if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmc = model->template as>(); + boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; + storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); + } + }); + } else { + STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs."); + + // When samples are provided, we create an instantiation model checker. + std::unique_ptr, double>> modelchecker(*model->template as>()); + + for (auto const& property : input.properties) { + storm::cli::printModelCheckingProperty(property); + + modelchecker->specifyFormula(property.getRawFormula(storm::api::createTask(property.getRawFormula(), true))); + + // TODO: check. + modelchecker->setInstantiationsAreGraphPreserving(true); + + storm::utility::parametric::Valuation valuation; + + // Enumerate all sample points. + for () { + bool first = true; + std::stringstream ss; + ss << "Treating instance ["; + for (auto const& entry : valuation) { + if (!first) { + ss << ", "; + } else { + first = false; + } + ss << entry.first << ": " << entry.second; + } + ss << "]..."; + STORM_PRINT_AND_LOG(ss.str()); + + storm::utility::Stopwatch watch(true); + std::unique_ptr result = modelchecker->check(Environment(), valuation); + watch.stop(); + + printInitialStatesResult(result, property, &watch); + } + } + } } template @@ -226,18 +331,18 @@ namespace storm { } template - void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions) { + void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, std::map::type, std::vector::type>> const& samples) { if (regions.empty()) { - storm::pars::verifyPropertiesWithSparseEngine(model, input); + storm::pars::verifyPropertiesWithSparseEngine(model, input, samples); } else { storm::pars::verifyRegionsWithSparseEngine(model, input, regions); } } template - void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions) { + void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, std::map::type, std::vector::type>> const& samples) { STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); - storm::pars::verifyWithSparseEngine(model->as>(), input, regions); + storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } template @@ -271,9 +376,8 @@ namespace storm { } std::vector> regions = parseRegions(model); - - - + std::map::type, std::vector::type>> samples = parseSamples(model, parSettings.getSamples()); + if (model) { storm::cli::exportModel(model, input); } @@ -285,7 +389,7 @@ namespace storm { } if (model) { - verifyParametricModel(model, input, regions); + verifyParametricModel(model, input, regions, samples); } } diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 28975aa5c..a02851dac 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -18,6 +18,7 @@ namespace storm { const std::string ParametricSettings::transformContinuousOptionName = "transformcontinuous"; const std::string ParametricSettings::transformContinuousShortOptionName = "tc"; const std::string ParametricSettings::onlyWellformednessConstraintsOptionName = "onlyconstraints"; + const std::string ParametricSettings::samplesOptionName = "samples"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -25,6 +26,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, false, "Sets whether to generate the derivatives of the resulting rational function.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, transformContinuousOptionName, false, "Sets whether to transform a continuous time input model to a discrete time model.").setShortName(transformContinuousShortOptionName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, onlyWellformednessConstraintsOptionName, false, "Sets whether you only want to obtain the wellformedness constraints").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesOptionName, false, "The points at which to sample the model.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples given in the form 'Var1=Val1:Val2:...:Valk,Var2=...").setDefaultValueString("").build()).build()); } bool ParametricSettings::exportResultToFile() const { @@ -46,7 +49,11 @@ namespace storm { bool ParametricSettings::onlyObtainConstraints() const { return this->getOption(onlyWellformednessConstraintsOptionName).getHasOptionBeenSet(); } - + + std::string ParametricSettings::getSamples() const { + return this->getOption(samplesOptionName).getArgumentByName("samples").getValueAsString(); + } + } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index e610f033d..195b0936c 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -47,6 +47,13 @@ namespace storm { */ bool onlyObtainConstraints() const; + /*! + * Retrieves the samples as a comma-separated list of samples for each (relevant) variable, where the + * samples are colon-separated values. For example, 'N=1:2:3,K=2:4' means that N takes the values 1 to + * 3 and K either 2 or 4. + */ + std::string getSamples() const; + const static std::string moduleName; private: @@ -55,6 +62,7 @@ namespace storm { const static std::string transformContinuousOptionName; const static std::string transformContinuousShortOptionName; const static std::string onlyWellformednessConstraintsOptionName; + const static std::string samplesOptionName; }; } // namespace modules From caf997510901e6bfec66fee63d017616f5ed091c Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 12 Jul 2018 11:18:26 +0200 Subject: [PATCH 403/647] Fixed an issue with topological min max solver --- src/storm/environment/solver/TopologicalSolverEnvironment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp index 678c6cb6c..aa580d67c 100644 --- a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp @@ -14,7 +14,7 @@ namespace storm { underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); underlyingMinMaxMethod = topologicalSettings.getUnderlyingMinMaxMethod(); - underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingMinMaxMethodSetFromDefaultValue(); + underlyingMinMaxMethodSetFromDefault = topologicalSettings.isUnderlyingMinMaxMethodSetFromDefaultValue(); } TopologicalSolverEnvironment::~TopologicalSolverEnvironment() { From a08cb4ac1854491a5852977a8bc8c08457734f3c Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Jul 2018 11:51:11 +0200 Subject: [PATCH 404/647] making game solver respect equation solver format --- src/storm-pars-cli/storm-pars.cpp | 252 ++++++++++++------ .../SparseCtmcInstantiationModelChecker.cpp | 27 ++ .../SparseCtmcInstantiationModelChecker.h | 28 ++ .../SparseDtmcInstantiationModelChecker.cpp | 6 +- .../SparseInstantiationModelChecker.cpp | 6 +- .../SparseMdpInstantiationModelChecker.cpp | 2 +- .../settings/modules/ParametricSettings.cpp | 6 + .../settings/modules/ParametricSettings.h | 6 + src/storm/solver/StandardGameSolver.cpp | 4 +- .../TopologicalLinearEquationSolver.cpp | 4 +- 10 files changed, 245 insertions(+), 96 deletions(-) create mode 100644 src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp create mode 100644 src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ff7c075f8..32d63ae52 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -15,6 +15,8 @@ #include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" + #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" @@ -29,7 +31,19 @@ namespace storm { typedef typename storm::cli::SymbolicInput SymbolicInput; - + template + struct SampleInformation { + SampleInformation(bool graphPreserving = false) : graphPreserving(graphPreserving) { + // Intentionally left empty. + } + + bool empty() const { + return cartesianProducts.empty(); + } + + std::vector::type, std::vector::type>>> cartesianProducts; + bool graphPreserving; + }; template std::vector> parseRegions(std::shared_ptr const& model) { @@ -42,12 +56,12 @@ namespace storm { } template - std::map::type, std::vector::type>> parseSamples(std::shared_ptr const& model, std::string const& sampleString) { + SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); - std::map::type, std::vector::type>> samplesForVariables; + SampleInformation sampleInfo(graphPreserving); if (sampleString.empty()) { - return samplesForVariables; + return sampleInfo; } // Get all parameters from the model. @@ -56,52 +70,59 @@ namespace storm { modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - // Get the values string for each variable. - std::vector valuesForVariables; - boost::split(valuesForVariables, sampleString, boost::is_any_of(",")); - for (auto& values : valuesForVariables) { - boost::trim(values); - } - - std::set::type> encounteredParameters; - for (auto const& varValues : valuesForVariables) { - auto equalsPosition = varValues.find("="); - STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); - std::string variableName = varValues.substr(0, equalsPosition); - boost::trim(variableName); - std::string values = varValues.substr(equalsPosition + 1); - boost::trim(values); + + std::vector cartesianProducts; + boost::split(cartesianProducts, sampleString, boost::is_any_of(";")); + for (auto& product : cartesianProducts) { + boost::trim(product); - bool foundParameter = false; - typename utility::parametric::VariableType::type theParameter; - for (auto const& parameter : modelParameters) { - std::stringstream parameterStream; - parameterStream << parameter; - std::cout << parameterStream.str() << " vs " << variableName << std::endl; - if (parameterStream.str() == variableName) { - foundParameter = true; - theParameter = parameter; - encounteredParameters.insert(parameter); - } + // Get the values string for each variable. + std::vector valuesForVariables; + boost::split(valuesForVariables, product, boost::is_any_of(",")); + for (auto& values : valuesForVariables) { + boost::trim(values); } - STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); - - std::vector splitValues; - boost::split(splitValues, values, boost::is_any_of(":")); - STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); - auto& list = samplesForVariables[theParameter]; - for (auto& value : splitValues) { - boost::trim(value); + std::set::type> encounteredParameters; + sampleInfo.cartesianProducts.emplace_back(); + auto& newCartesianProduct = sampleInfo.cartesianProducts.back(); + for (auto const& varValues : valuesForVariables) { + auto equalsPosition = varValues.find("="); + STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); + std::string variableName = varValues.substr(0, equalsPosition); + boost::trim(variableName); + std::string values = varValues.substr(equalsPosition + 1); + boost::trim(values); + + bool foundParameter = false; + typename utility::parametric::VariableType::type theParameter; + for (auto const& parameter : modelParameters) { + std::stringstream parameterStream; + parameterStream << parameter; + if (parameterStream.str() == variableName) { + foundParameter = true; + theParameter = parameter; + encounteredParameters.insert(parameter); + } + } + STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); + + std::vector splitValues; + boost::split(splitValues, values, boost::is_any_of(":")); + STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); - list.push_back(storm::utility::convertNumber::type>(value)); + auto& list = newCartesianProduct[theParameter]; + + for (auto& value : splitValues) { + boost::trim(value); + list.push_back(storm::utility::convertNumber::type>(value)); + } } + + STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples."); } - STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples.") - - return samplesForVariables; + return sampleInfo; } template @@ -169,9 +190,24 @@ namespace storm { } template - void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) { + void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation const* valuation = nullptr) { if (result) { - STORM_PRINT_AND_LOG("Result (initial states): " << std::endl); + STORM_PRINT_AND_LOG("Result (initial states)"); + if (valuation) { + bool first = true; + std::stringstream ss; + for (auto const& entry : *valuation) { + if (!first) { + ss << ", "; + } else { + first = false; + } + ss << entry.first << "=" << entry.second; + } + + STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]"); + } + STORM_PRINT_AND_LOG(": ") auto const* regionCheckResult = dynamic_cast const*>(result.get()); if (regionCheckResult != nullptr) { @@ -195,7 +231,7 @@ namespace storm { STORM_PRINT_AND_LOG(*result << std::endl); } if (watch) { - STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl); + STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl << std::endl); } } else { STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); @@ -214,8 +250,78 @@ namespace storm { } } + template class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double> + void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation const& samples) { + + // When samples are provided, we create an instantiation model checker. + ModelCheckerType modelchecker(model); + + for (auto const& property : input.properties) { + storm::cli::printModelCheckingProperty(property); + + modelchecker.specifyFormula(storm::api::createTask(property.getRawFormula(), true)); + modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving); + + storm::utility::parametric::Valuation valuation; + + std::vector::type> parameters; + std::vector::type>::const_iterator> iterators; + std::vector::type>::const_iterator> iteratorEnds; + + storm::utility::Stopwatch watch(true); + for (auto const& product : samples.cartesianProducts) { + parameters.clear(); + iterators.clear(); + iteratorEnds.clear(); + + for (auto const& entry : product) { + parameters.push_back(entry.first); + iterators.push_back(entry.second.cbegin()); + iteratorEnds.push_back(entry.second.cend()); + } + + bool done = false; + while (!done) { + // Read off valuation. + for (uint64_t i = 0; i < parameters.size(); ++i) { + valuation[parameters[i]] = *iterators[i]; + } + + storm::utility::Stopwatch valuationWatch(true); + std::unique_ptr result = modelchecker.check(Environment(), valuation); + valuationWatch.stop(); + + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates())); + } + printInitialStatesResult(result, property, &valuationWatch, &valuation); + + for (uint64_t i = 0; i < parameters.size(); ++i) { + ++iterators[i]; + if (iterators[i] == iteratorEnds[i]) { + // Reset iterator and proceed to move next iterator. + iterators[i] = product.at(parameters[i]).cbegin(); + + // If the last iterator was removed, we are done. + if (i == parameters.size() - 1) { + done = true; + } + } else { + // If an iterator was moved but not reset, we have another valuation to check. + break; + } + } + + } + } + + watch.stop(); + STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl); + } + } + template - void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::map::type, std::vector::type>> const& samples) { + void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { if (samples.empty()) { verifyProperties(input.properties, @@ -235,43 +341,15 @@ namespace storm { } }); } else { - STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc), storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs."); - - // When samples are provided, we create an instantiation model checker. - std::unique_ptr, double>> modelchecker(*model->template as>()); - - for (auto const& property : input.properties) { - storm::cli::printModelCheckingProperty(property); - - modelchecker->specifyFormula(property.getRawFormula(storm::api::createTask(property.getRawFormula(), true))); - - // TODO: check. - modelchecker->setInstantiationsAreGraphPreserving(true); - - storm::utility::parametric::Valuation valuation; - - // Enumerate all sample points. - for () { - bool first = true; - std::stringstream ss; - ss << "Treating instance ["; - for (auto const& entry : valuation) { - if (!first) { - ss << ", "; - } else { - first = false; - } - ss << entry.first << ": " << entry.second; - } - ss << "]..."; - STORM_PRINT_AND_LOG(ss.str()); - - storm::utility::Stopwatch watch(true); - std::unique_ptr result = modelchecker->check(Environment(), valuation); - watch.stop(); - - printInitialStatesResult(result, property, &watch); - } + STORM_LOG_TRACE("Sampling the model at given points."); + if (model->isOfType(storm::models::ModelType::Dtmc)) { + verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); } } } @@ -331,7 +409,7 @@ namespace storm { } template - void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, std::map::type, std::vector::type>> const& samples) { + void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { if (regions.empty()) { storm::pars::verifyPropertiesWithSparseEngine(model, input, samples); } else { @@ -340,7 +418,7 @@ namespace storm { } template - void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, std::map::type, std::vector::type>> const& samples) { + void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } @@ -376,7 +454,7 @@ namespace storm { } std::vector> regions = parseRegions(model); - std::map::type, std::vector::type>> samples = parseSamples(model, parSettings.getSamples()); + SampleInformation samples = parseSamples(model, parSettings.getSamples(), parSettings.isSamplesAreGraphPreservingSet()); if (model) { storm::cli::exportModel(model, input); diff --git a/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp new file mode 100644 index 000000000..4af65eb19 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp @@ -0,0 +1,27 @@ +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" + +#include "storm/modelchecker/csl/SparseCtmcCslModelChecker.h" + +#include "storm/exceptions/InvalidStateException.h" + +namespace storm { + namespace modelchecker { + + template + SparseCtmcInstantiationModelChecker::SparseCtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker(parametricModel), modelInstantiator(parametricModel) { + //Intentionally left empty + } + + template + std::unique_ptr SparseCtmcInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { + STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); + auto const& instantiatedModel = modelInstantiator.instantiate(valuation); + storm::modelchecker::SparseCtmcCslModelChecker> modelChecker(instantiatedModel); + + return modelChecker.check(env, *this->currentCheckTask); + } + + template class SparseCtmcInstantiationModelChecker, double>; + template class SparseCtmcInstantiationModelChecker, storm::RationalNumber>; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h new file mode 100644 index 000000000..4e4b7643f --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" +#include "storm-pars/utility/ModelInstantiator.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to efficiently check a formula on a parametric model with different parameter instantiations. + */ + template + class SparseCtmcInstantiationModelChecker : public SparseInstantiationModelChecker { + public: + SparseCtmcInstantiationModelChecker(SparseModelType const& parametricModel); + + virtual std::unique_ptr check(Environment const& env, storm::utility::parametric::Valuation const& valuation) override; + + storm::utility::ModelInstantiator> modelInstantiator; + }; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp index d13f3bf44..5de3d8fd3 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp @@ -20,11 +20,11 @@ namespace storm { std::unique_ptr SparseDtmcInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + STORM_LOG_THROW(instantiatedModel.getTransitionMatrix().isProbabilistic(), storm::exceptions::InvalidArgumentException, "Instantiation point is invalid as the transition matrix becomes non-stochastic."); storm::modelchecker::SparseDtmcPrctlModelChecker> modelChecker(instantiatedModel); // Check if there are some optimizations implemented for the specified property - if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { + if (this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { return checkReachabilityProbabilityFormula(env, modelChecker); } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { return checkReachabilityRewardFormula(env, modelChecker); @@ -144,4 +144,4 @@ namespace storm { template class SparseDtmcInstantiationModelChecker, storm::RationalNumber>; } -} \ No newline at end of file +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp index d81d5b9a6..7d5143a50 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp @@ -2,6 +2,7 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Ctmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -12,10 +13,9 @@ namespace storm { template SparseInstantiationModelChecker::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) { - //Intentionally left empty + // Intentionally left empty } - template void SparseInstantiationModelChecker::specifyFormula(storm::modelchecker::CheckTask const& checkTask) { currentFormula = checkTask.getFormula().asSharedPointer(); @@ -33,9 +33,11 @@ namespace storm { } template class SparseInstantiationModelChecker, double>; + template class SparseInstantiationModelChecker, double>; template class SparseInstantiationModelChecker, double>; template class SparseInstantiationModelChecker, storm::RationalNumber>; + template class SparseInstantiationModelChecker, storm::RationalNumber>; template class SparseInstantiationModelChecker, storm::RationalNumber>; } diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp index a2a6c0094..3dc4866d3 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp @@ -23,7 +23,7 @@ namespace storm { std::unique_ptr SparseMdpInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + STORM_LOG_THROW(instantiatedModel.getTransitionMatrix().isProbabilistic(), storm::exceptions::InvalidArgumentException, "Instantiation point is invalid as the transition matrix becomes non-stochastic."); storm::modelchecker::SparseMdpPrctlModelChecker> modelChecker(instantiatedModel); // Check if there are some optimizations implemented for the specified property diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index a02851dac..54b959e05 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string ParametricSettings::transformContinuousShortOptionName = "tc"; const std::string ParametricSettings::onlyWellformednessConstraintsOptionName = "onlyconstraints"; const std::string ParametricSettings::samplesOptionName = "samples"; + const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") @@ -28,6 +29,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, onlyWellformednessConstraintsOptionName, false, "Sets whether you only want to obtain the wellformedness constraints").build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesOptionName, false, "The points at which to sample the model.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples given in the form 'Var1=Val1:Val2:...:Valk,Var2=...").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); } bool ParametricSettings::exportResultToFile() const { @@ -54,6 +56,10 @@ namespace storm { return this->getOption(samplesOptionName).getArgumentByName("samples").getValueAsString(); } + bool ParametricSettings::isSamplesAreGraphPreservingSet() const { + return this->getOption(samplesGraphPreservingOptionName).getHasOptionBeenSet(); + } + } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 195b0936c..374c8e839 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -54,6 +54,11 @@ namespace storm { */ std::string getSamples() const; + /*! + * Retrieves whether the samples are graph preserving. + */ + bool isSamplesAreGraphPreservingSet() const; + const static std::string moduleName; private: @@ -63,6 +68,7 @@ namespace storm { const static std::string transformContinuousShortOptionName; const static std::string onlyWellformednessConstraintsOptionName; const static std::string samplesOptionName; + const static std::string samplesGraphPreservingOptionName; }; } // namespace modules diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 6140a5c15..9656af643 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -123,7 +123,9 @@ namespace storm { } else { // Update the solver. getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); - submatrix.convertToEquationSystem(); + if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { + submatrix.convertToEquationSystem(); + } submatrixSolver->setMatrix(std::move(submatrix)); } diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp index 0e6896370..877ba76dd 100644 --- a/src/storm/solver/TopologicalLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -169,8 +169,8 @@ namespace storm { if (asEquationSystem) { sccA.convertToEquationSystem(); } - //std::cout << "Solving SCC " << scc << std::endl; - //std::cout << "Matrix is " << sccA << std::endl; +// std::cout << "Solving SCC " << scc << std::endl; +// std::cout << "Matrix is " << sccA << std::endl; this->sccSolver->setMatrix(std::move(sccA)); // x Vector From c2870e42b0d40cf753f9831da1919a702b125a39 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Jul 2018 12:27:20 +0200 Subject: [PATCH 405/647] changed help slightly --- src/storm-pars/settings/modules/ParametricSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 54b959e05..d5b3c151d 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -28,7 +28,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, transformContinuousOptionName, false, "Sets whether to transform a continuous time input model to a discrete time model.").setShortName(transformContinuousShortOptionName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, onlyWellformednessConstraintsOptionName, false, "Sets whether you only want to obtain the wellformedness constraints").build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesOptionName, false, "The points at which to sample the model.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples given in the form 'Var1=Val1:Val2:...:Valk,Var2=...").setDefaultValueString("").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples are semicolon-separated entries of the form 'Var1=Val1:Val2:...:Valk,Var2=... that span the sample spaces.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); } From cc1fc8a7beeb6541f69394d26df132d5d46b481b Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Jul 2018 13:35:55 +0200 Subject: [PATCH 406/647] adding exact sampling for parametric systems --- src/storm-pars-cli/storm-pars.cpp | 28 +++++++++++++------ .../settings/modules/ParametricSettings.cpp | 8 +++++- .../settings/modules/ParametricSettings.h | 6 ++++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 32d63ae52..ec3f65f29 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -33,7 +33,7 @@ namespace storm { template struct SampleInformation { - SampleInformation(bool graphPreserving = false) : graphPreserving(graphPreserving) { + SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) { // Intentionally left empty. } @@ -43,6 +43,7 @@ namespace storm { std::vector::type, std::vector::type>>> cartesianProducts; bool graphPreserving; + bool exact; }; template @@ -320,6 +321,19 @@ namespace storm { } } + template + void verifyPropertiesAtSamplePoints(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + if (model->isOfType(storm::models::ModelType::Dtmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); + } + } + template void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { @@ -342,14 +356,11 @@ namespace storm { }); } else { STORM_LOG_TRACE("Sampling the model at given points."); - if (model->isOfType(storm::models::ModelType::Dtmc)) { - verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); - } else if (model->isOfType(storm::models::ModelType::Ctmc)) { - verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); - } else if (model->isOfType(storm::models::ModelType::Ctmc)) { - verifyPropertiesAtSamplePoints, ValueType, double>(*model->template as>(), input, samples); + + if (samples.exact) { + verifyPropertiesAtSamplePoints(model, input, samples); } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); + verifyPropertiesAtSamplePoints(model, input, samples); } } } @@ -455,6 +466,7 @@ namespace storm { std::vector> regions = parseRegions(model); SampleInformation samples = parseSamples(model, parSettings.getSamples(), parSettings.isSamplesAreGraphPreservingSet()); + samples.exact = parSettings.isSampleExactSet(); if (model) { storm::cli::exportModel(model, input); diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index d5b3c151d..7ecbd6166 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -20,7 +20,8 @@ namespace storm { const std::string ParametricSettings::onlyWellformednessConstraintsOptionName = "onlyconstraints"; const std::string ParametricSettings::samplesOptionName = "samples"; const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; - + const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; + ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); @@ -30,6 +31,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, samplesOptionName, false, "The points at which to sample the model.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples are semicolon-separated entries of the form 'Var1=Val1:Val2:...:Valk,Var2=... that span the sample spaces.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); } bool ParametricSettings::exportResultToFile() const { @@ -60,6 +62,10 @@ namespace storm { return this->getOption(samplesGraphPreservingOptionName).getHasOptionBeenSet(); } + bool ParametricSettings::isSampleExactSet() const { + return this->getOption(sampleExactOptionName).getHasOptionBeenSet(); + } + } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index 374c8e839..1f10a4b35 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -59,6 +59,11 @@ namespace storm { */ bool isSamplesAreGraphPreservingSet() const; + /*! + * Retrieves whether samples are to be computed exactly. + */ + bool isSampleExactSet() const; + const static std::string moduleName; private: @@ -69,6 +74,7 @@ namespace storm { const static std::string onlyWellformednessConstraintsOptionName; const static std::string samplesOptionName; const static std::string samplesGraphPreservingOptionName; + const static std::string sampleExactOptionName; }; } // namespace modules From 264d9158c8d0fb4efdf07ec4add8df3c05a02d7b Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 12 Jul 2018 15:30:19 +0200 Subject: [PATCH 407/647] bugfix for dd-based MA building from JANI --- src/storm/builder/DdJaniModelBuilder.cpp | 47 +++++++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 091c3fe6d..4260c7c7f 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -653,6 +653,40 @@ namespace storm { ActionDd multiplyTransitions(storm::dd::Add const& factor) const { return ActionDd(guard, transitions * factor, transientEdgeAssignments, localNondeterminismVariables, variableToWritingFragment, illegalFragment); } + + ActionDd add(ActionDd const& other) const { + storm::dd::Bdd newGuard = this->guard || other.guard; + storm::dd::Add newTransitions = this->transitions + other.transitions; + + // Join the transient edge assignments. + std::map> newTransientEdgeAssignments(this->transientEdgeAssignments); + for (auto const& entry : other.transientEdgeAssignments) { + auto it = newTransientEdgeAssignments.find(entry.first); + if (it == newTransientEdgeAssignments.end()) { + newTransientEdgeAssignments[entry.first] = entry.second; + } else { + it->second += entry.second; + } + } + + std::pair newLocalNondeterminismVariables = std::make_pair(std::min(this->localNondeterminismVariables.first, other.localNondeterminismVariables.first), std::max(this->localNondeterminismVariables.second, other.localNondeterminismVariables.second)); + + // Join variable-to-writing-fragment maps. + std::map> newVariableToWritingFragment(this->variableToWritingFragment); + for (auto const& entry : other.variableToWritingFragment) { + auto it = newVariableToWritingFragment.find(entry.first); + if (it == newVariableToWritingFragment.end()) { + newVariableToWritingFragment[entry.first] = entry.second; + } else { + it->second |= entry.second; + } + } + + // Join illegal fragments. + storm::dd::Bdd newIllegalFragment = this->illegalFragment || other.illegalFragment; + + return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment, newIllegalFragment); + } bool isInputEnabled() const { return inputEnabled; @@ -975,7 +1009,16 @@ namespace storm { // Finally, combine (potentially) multiple action DDs. for (auto const& actionDds : actions) { - ActionDd combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front(); + ActionDd combinedAction; + if (actionDds.first == silentMarkovianActionIdentification) { + // For the Markovian transitions, we can simply add the actions. + combinedAction = actionDds.second.front(); + for (uint64_t i = 1; i < actionDds.second.size(); ++i) { + combinedAction = combinedAction.add(actionDds.second[i]); + } + } else { + combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front(); + } result.actions[actionDds.first] = combinedAction; result.extendLocalNondeterminismVariables(combinedAction.getLocalNondeterminismVariables()); } @@ -1333,7 +1376,7 @@ namespace storm { } else if (modelType == storm::jani::ModelType::MDP || modelType == storm::jani::ModelType::LTS) { return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset); } else if (modelType == storm::jani::ModelType::MA) { - if (instantiation.isMarkovian()){ + if (instantiation.isMarkovian()) { return combineEdgesToActionDeterministic(edgeDds); } else { return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset); From 93da59fa04424a8f209c7fba810706d430f70e21 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 12 Jul 2018 18:16:26 +0200 Subject: [PATCH 408/647] fixed an issue with jani properties for expected time not being parsed as requested --- src/storm-parsers/parser/JaniParser.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 725ab0a9d..aa97e38f7 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -230,7 +230,8 @@ namespace storm { } std::shared_ptr reach; if (propertyStructure.count("reach") > 0) { - reach = std::make_shared(parseFormula(propertyStructure.at("reach"), time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward, globalVars, constants, "Reach-expression of operator " + opString)); + auto context = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; + reach = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Total reward is currently not supported"); } @@ -304,9 +305,12 @@ namespace storm { //STORM_LOG_THROW(!accTime && !accSteps, storm::exceptions::NotSupportedException, "Storm only allows accumulation if a step- or time-bound is given."); if (rewExpr.isVariable()) { + assert(!time); std::string rewardName = rewExpr.getVariables().begin()->getName(); return std::make_shared(reach, rewardName, opInfo); } else if (!rewExpr.containsVariables()) { + assert(time); + assert(reach->isTimePathFormula()); if(rewExpr.hasIntegerType()) { if (rewExpr.evaluateAsInt() == 1) { @@ -480,6 +484,7 @@ namespace storm { STORM_LOG_THROW(propertyStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Property must have a name"); // TODO check unique name std::string name = getString(propertyStructure.at("name"), "property-name"); + STORM_LOG_TRACE("Parsing property named: " << name); std::string comment = ""; if (propertyStructure.count("comment") > 0) { comment = getString(propertyStructure.at("comment"), "comment for property named '" + name + "'."); From f0c451aae9353d0694a610740e32af786d44229b Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 12 Jul 2018 18:17:25 +0200 Subject: [PATCH 409/647] fixed a case where time path propreties were not identified as such, and ensured for debugging that time operators now get a time path formula --- CHANGELOG.md | 1 + src/storm/logic/EventuallyFormula.cpp | 2 +- src/storm/logic/TimeOperatorFormula.cpp | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b75150e65..a77718885 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Version 1.2.x - `storm-counterexamples` extracted to reduce linking time - Improved export for jani models - Several extensions to high-level counterexamples +- A fix in parsing jani properties ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. diff --git a/src/storm/logic/EventuallyFormula.cpp b/src/storm/logic/EventuallyFormula.cpp index 5b7a2cdac..2f1243f8a 100644 --- a/src/storm/logic/EventuallyFormula.cpp +++ b/src/storm/logic/EventuallyFormula.cpp @@ -31,7 +31,7 @@ namespace storm { } bool EventuallyFormula::isProbabilityPathFormula() const { - return this->isEventuallyFormula(); + return this->isReachabilityProbabilityFormula(); } bool EventuallyFormula::isRewardPathFormula() const { diff --git a/src/storm/logic/TimeOperatorFormula.cpp b/src/storm/logic/TimeOperatorFormula.cpp index 7ae4b7fea..f32568cdc 100644 --- a/src/storm/logic/TimeOperatorFormula.cpp +++ b/src/storm/logic/TimeOperatorFormula.cpp @@ -1,5 +1,5 @@ #include "storm/logic/TimeOperatorFormula.h" - +#include "storm/logic/EventuallyFormula.h" #include "storm/logic/FormulaVisitor.h" #include "storm/utility/macros.h" @@ -8,6 +8,7 @@ namespace storm { namespace logic { TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr const& subformula, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardMeasureType(rewardMeasureType) { + assert(subformula->isTimePathFormula()); // Intentionally left empty. } From 7a5b93bdfa94acfb8e8addef024d301ee326ecc7 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 13 Jul 2018 10:41:54 +0200 Subject: [PATCH 410/647] Updated changelog --- CHANGELOG.md | 14 ++++++++------ doc/checklist_new_release.md | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a77718885..ecf9acd2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,19 @@ The releases of major and minor versions contain an overview of changes since th Version 1.2.x ------------- -### Version 1.2.2 (to be released) -- `storm-dft`: improvements in Galileo parser -- `storm-dft`: test cases for DFT analysis +### Version 1.2.2 (2018/07) - Sound value iteration (SVI) for DTMCs and MDPs - Topological solver for linear equation systems and MinMax equation systems (enabled by default) - Added support for expected total rewards in the sparse engine -- `storm-parsers` extracted to reduce linking time -- `storm-counterexamples` extracted to reduce linking time - Improved export for jani models -- Several extensions to high-level counterexamples - A fix in parsing jani properties +- Several extensions to high-level counterexamples +- `storm-parsers` extracted to reduce linking time +- `storm-counterexamples` extracted to reduce linking time +- `storm-dft`: improvements in Galileo parser +- `storm-dft`: test cases for DFT analysis +- Improved Storm installation +- Several bug fixes ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. diff --git a/doc/checklist_new_release.md b/doc/checklist_new_release.md index 05be534aa..a55349ef5 100644 --- a/doc/checklist_new_release.md +++ b/doc/checklist_new_release.md @@ -1,5 +1,5 @@ The following steps should be performed before releasing a new storm version. -Note that in most case a simultaneous release of [carl](https://github.com/smtrat/carl), [storm](https://github.com/moves-rwth/storm), [pycarl](https://github.com/moves-rwth/pycarl/) and [stormpy](https://github.com/moves-rwth/stormpy/) is preferred. +Note that in most cases a simultaneous release of [carl](https://github.com/smtrat/carl), [storm](https://github.com/moves-rwth/storm), [pycarl](https://github.com/moves-rwth/pycarl/) and [stormpy](https://github.com/moves-rwth/stormpy/) is preferred. 1. Update `CHANGELOG.md` To get all the commits from an author since the last tag execute: From 6a1ab53e35d6e082c5ab00a66b3a8c61dd744d39 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Fri, 13 Jul 2018 10:45:09 +0200 Subject: [PATCH 411/647] Use carl version 18.06 if building from within Storm --- resources/3rdparty/carl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/3rdparty/carl/CMakeLists.txt b/resources/3rdparty/carl/CMakeLists.txt index 3bb50d1b1..e74d53de6 100644 --- a/resources/3rdparty/carl/CMakeLists.txt +++ b/resources/3rdparty/carl/CMakeLists.txt @@ -8,7 +8,7 @@ message(STATUS "Carl - Storm 3rdparty binary dir: ${STORM_3RDPARTY_BINARY_DIR}") ExternalProject_Add(carl-config GIT_REPOSITORY https://github.com/smtrat/carl - GIT_TAG 17.12 + GIT_TAG 18.06 PREFIX here SOURCE_DIR source_dir BINARY_DIR ${STORM_3RDPARTY_BINARY_DIR}/carl From 274d51795cc8415d6bd3c8ec6f2ea51da6583b0f Mon Sep 17 00:00:00 2001 From: TimQu Date: Sat, 14 Jul 2018 16:36:17 +0100 Subject: [PATCH 412/647] removed default value for maximal iteration count --- src/storm/settings/modules/EigenEquationSolverSettings.cpp | 2 +- src/storm/settings/modules/GameSolverSettings.cpp | 2 +- src/storm/settings/modules/GmmxxEquationSolverSettings.cpp | 2 +- src/storm/settings/modules/MinMaxEquationSolverSettings.cpp | 2 +- src/storm/settings/modules/NativeEquationSolverSettings.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/storm/settings/modules/EigenEquationSolverSettings.cpp b/src/storm/settings/modules/EigenEquationSolverSettings.cpp index 78eff7cef..f339a852e 100644 --- a/src/storm/settings/modules/EigenEquationSolverSettings.cpp +++ b/src/storm/settings/modules/EigenEquationSolverSettings.cpp @@ -34,7 +34,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, restartOptionName, true, "The number of iteration until restarted methods are actually restarted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of iterations.").setDefaultValueUnsignedInteger(50).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); } diff --git a/src/storm/settings/modules/GameSolverSettings.cpp b/src/storm/settings/modules/GameSolverSettings.cpp index 58cbd3529..84feaba4f 100644 --- a/src/storm/settings/modules/GameSolverSettings.cpp +++ b/src/storm/settings/modules/GameSolverSettings.cpp @@ -23,7 +23,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which game solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a game solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(gameSolvingTechniques)).setDefaultValueString("vi").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); diff --git a/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp b/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp index 76da580a6..46b7f58fb 100644 --- a/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp @@ -34,7 +34,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, restartOptionName, true, "The number of iteration until restarted methods are actually restarted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of iterations.").setDefaultValueUnsignedInteger(50).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index d82125ec9..95accf94b 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -27,7 +27,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("topological").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 3f0282f0a..f96bd8714 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -29,7 +29,7 @@ namespace storm { std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); From e1047e787fc9154f994ce057e88492a29e0106c8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Sun, 15 Jul 2018 13:44:29 +0100 Subject: [PATCH 413/647] handled case where no threshold for the number of iterations is provided --- .../environment/solver/EigenSolverEnvironment.cpp | 10 +++++++--- src/storm/environment/solver/GameSolverEnvironment.cpp | 6 +++++- .../environment/solver/GmmxxSolverEnvironment.cpp | 6 +++++- .../environment/solver/MinMaxSolverEnvironment.cpp | 6 +++++- .../environment/solver/NativeSolverEnvironment.cpp | 6 +++++- src/storm/solver/EigenLinearEquationSolver.cpp | 5 ++++- src/storm/solver/GmmxxLinearEquationSolver.cpp | 6 +++++- 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/storm/environment/solver/EigenSolverEnvironment.cpp b/src/storm/environment/solver/EigenSolverEnvironment.cpp index a36bd0062..4b1c561e0 100644 --- a/src/storm/environment/solver/EigenSolverEnvironment.cpp +++ b/src/storm/environment/solver/EigenSolverEnvironment.cpp @@ -14,7 +14,11 @@ namespace storm { methodSetFromDefault = eigenSettings.isLinearEquationSystemMethodSetFromDefault(); preconditioner = eigenSettings.getPreconditioningMethod(); restartThreshold = eigenSettings.getRestartIterationCount(); - maxIterationCount = eigenSettings.getMaximalIterationCount(); + if (eigenSettings.isMaximalIterationCountSet()) { + maxIterationCount = eigenSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(eigenSettings.getPrecision()); } @@ -44,11 +48,11 @@ namespace storm { } uint64_t const& EigenSolverEnvironment::getRestartThreshold() const { - return maxIterationCount; + return restartThreshold; } void EigenSolverEnvironment::setRestartThreshold(uint64_t value) { - maxIterationCount = value; + restartThreshold = value; } uint64_t const& EigenSolverEnvironment::getMaximalNumberOfIterations() const { diff --git a/src/storm/environment/solver/GameSolverEnvironment.cpp b/src/storm/environment/solver/GameSolverEnvironment.cpp index aea27278d..9793312d3 100644 --- a/src/storm/environment/solver/GameSolverEnvironment.cpp +++ b/src/storm/environment/solver/GameSolverEnvironment.cpp @@ -12,7 +12,11 @@ namespace storm { gameMethod = gameSettings.getGameSolvingMethod(); methodSetFromDefault = gameSettings.isGameSolvingMethodSetFromDefaultValue(); - maxIterationCount = gameSettings.getMaximalIterationCount(); + if (gameSettings.isMaximalIterationCountSet()) { + maxIterationCount = gameSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(gameSettings.getPrecision()); considerRelativeTerminationCriterion = gameSettings.getConvergenceCriterion() == storm::settings::modules::GameSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || gameSettings.getConvergenceCriterion() == storm::settings::modules::GameSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); diff --git a/src/storm/environment/solver/GmmxxSolverEnvironment.cpp b/src/storm/environment/solver/GmmxxSolverEnvironment.cpp index 8b8992db4..d78f3e039 100644 --- a/src/storm/environment/solver/GmmxxSolverEnvironment.cpp +++ b/src/storm/environment/solver/GmmxxSolverEnvironment.cpp @@ -13,7 +13,11 @@ namespace storm { method = gmmxxSettings.getLinearEquationSystemMethod(); preconditioner = gmmxxSettings.getPreconditioningMethod(); restartThreshold = gmmxxSettings.getRestartIterationCount(); - maxIterationCount = gmmxxSettings.getMaximalIterationCount(); + if (gmmxxSettings.isMaximalIterationCountSet()) { + maxIterationCount = gmmxxSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(gmmxxSettings.getPrecision()); } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index 536bf5913..63cf5c698 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -12,7 +12,11 @@ namespace storm { minMaxMethod = minMaxSettings.getMinMaxEquationSolvingMethod(); methodSetFromDefault = minMaxSettings.isMinMaxEquationSolvingMethodSetFromDefaultValue(); - maxIterationCount = minMaxSettings.getMaximalIterationCount(); + if (minMaxSettings.isMaximalIterationCountSet()) { + maxIterationCount = minMaxSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(minMaxSettings.getPrecision()); considerRelativeTerminationCriterion = minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); diff --git a/src/storm/environment/solver/NativeSolverEnvironment.cpp b/src/storm/environment/solver/NativeSolverEnvironment.cpp index 149a2feb6..9d152f92f 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.cpp +++ b/src/storm/environment/solver/NativeSolverEnvironment.cpp @@ -12,7 +12,11 @@ namespace storm { method = nativeSettings.getLinearEquationSystemMethod(); methodSetFromDefault = nativeSettings.isLinearEquationSystemTechniqueSetFromDefaultValue(); - maxIterationCount = nativeSettings.getMaximalIterationCount(); + if (nativeSettings.isMaximalIterationCountSet()) { + maxIterationCount = nativeSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(nativeSettings.getPrecision()); considerRelativeTerminationCriterion = nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); diff --git a/src/storm/solver/EigenLinearEquationSolver.cpp b/src/storm/solver/EigenLinearEquationSolver.cpp index afbc88a3b..55046a495 100644 --- a/src/storm/solver/EigenLinearEquationSolver.cpp +++ b/src/storm/solver/EigenLinearEquationSolver.cpp @@ -116,7 +116,10 @@ namespace storm { } else { bool converged = false; uint64_t numberOfIterations = 0; - uint64_t maxIter = env.solver().eigen().getMaximalNumberOfIterations(); + StormEigen::Index maxIter = std::numeric_limits::max(); + if (env.solver().eigen().getMaximalNumberOfIterations() < static_cast(maxIter)) { + maxIter = env.solver().eigen().getMaximalNumberOfIterations(); + } uint64_t restartThreshold = env.solver().eigen().getRestartThreshold(); ValueType precision = storm::utility::convertNumber(env.solver().eigen().getPrecision()); EigenLinearEquationSolverPreconditioner preconditioner = env.solver().eigen().getPreconditioner(); diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index d2fefc60d..9ce51fa72 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -65,7 +65,11 @@ namespace storm { } // Prepare an iteration object that determines the accuracy and the maximum number of iterations. - gmm::iteration iter(storm::utility::convertNumber(env.solver().gmmxx().getPrecision()), 0, env.solver().gmmxx().getMaximalNumberOfIterations()); + gmm::size_type maxIter = std::numeric_limits::max(); + if (env.solver().gmmxx().getMaximalNumberOfIterations() < static_cast(maxIter)) { + maxIter = env.solver().gmmxx().getMaximalNumberOfIterations(); + } + gmm::iteration iter(storm::utility::convertNumber(env.solver().gmmxx().getPrecision()), 0, maxIter); // Invoke gmm with the corresponding settings if (method == GmmxxLinearEquationSolverMethod::Bicgstab) { From 41c20c7b6381110634614d14404f3f2ef87442a9 Mon Sep 17 00:00:00 2001 From: TimQu Date: Sun, 15 Jul 2018 13:50:00 +0100 Subject: [PATCH 414/647] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecf9acd2e..af9b3d6a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Version 1.2.x - Sound value iteration (SVI) for DTMCs and MDPs - Topological solver for linear equation systems and MinMax equation systems (enabled by default) - Added support for expected total rewards in the sparse engine +- By default, iteration-based solvers are no longer aborted after a given number of steps. - Improved export for jani models - A fix in parsing jani properties - Several extensions to high-level counterexamples From 2cfdb56450519b72fcb73e699bbb140c3a289049 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Mon, 16 Jul 2018 17:13:59 +0200 Subject: [PATCH 415/647] Storm version 1.2.2 --- version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.cmake b/version.cmake index 9a0907e74..6a9d667db 100644 --- a/version.cmake +++ b/version.cmake @@ -1,4 +1,4 @@ set(STORM_VERSION_MAJOR 1) set(STORM_VERSION_MINOR 2) -set(STORM_VERSION_PATCH 1) +set(STORM_VERSION_PATCH 2) From 9902bb9dff49052ecd04817f31c9ade4cc948273 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 17 Jul 2018 14:22:21 +0200 Subject: [PATCH 416/647] Fixed version parsing for 'commits ahead' --- CMakeLists.txt | 34 +++++++++++++++---------------- src/storm/utility/storm-version.h | 8 ++++---- storm-version.cpp.in | 2 +- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee6c1117c..2dec13d80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -420,16 +420,22 @@ set(STORM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(STORM_VERSION_MINOR "${CMAKE_MATCH_2}") set(STORM_VERSION_PATCH "${CMAKE_MATCH_3}") set(STORM_GIT_VERSION_REST "${CMAKE_MATCH_4}") -# parse rest of the form (-label)-commitsahead-hash-appendix +# parse rest of the form (-label)-commitsahead-hash(-appendix) string(REGEX MATCH "^(\\-([a-z][a-z0-9\\.]+))?\\-([0-9]+)\\-([a-z0-9]+)(\\-.*)?$" STORM_VERSION_REST_MATCH "${STORM_GIT_VERSION_REST}") set(STORM_VERSION_LABEL "${CMAKE_MATCH_2}") # might be empty set(STORM_VERSION_COMMITS_AHEAD "${CMAKE_MATCH_3}") -set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") +set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") # is not used set(STORM_VERSION_APPENDIX "${CMAKE_MATCH_5}") # might be empty - -set(STORM_VERSION_DIRTY boost::none) -if (NOT "${STORM_GIT_VERSION_STRING}" STREQUAL "") +# check whether the git version lookup failed +if (STORM_GIT_VERSION_STRING MATCHES "NOTFOUND") + set(STORM_VERSION_SOURCE "VersionSource::Static") + set(STORM_VERSION_COMMITS_AHEAD 0) + set(STORM_VERSION_DIRTY boost::none) + include(version.cmake) + message(WARNING "Storm - Git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") +else() + set(STORM_VERSION_SOURCE "VersionSource::Git") if ("${STORM_VERSION_APPENDIX}" MATCHES "^.*dirty.*$") set(STORM_VERSION_DIRTY "true") else() @@ -437,15 +443,6 @@ if (NOT "${STORM_GIT_VERSION_STRING}" STREQUAL "") endif() endif() -# now check whether the git version lookup failed -set(STORM_VERSION_SOURCE "VersionSource::Git") -if (STORM_GIT_VERSION_STRING MATCHES "NOTFOUND") - set(STORM_VERSION_SOURCE "VersionSource::Static") - set(STORM_VERSION_COMMITS_AHEAD "boost::none") - include(version.cmake) - message(WARNING "Storm - Git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") -endif() - # check whether there is a label ('alpha', 'pre', etc.) if ("${STORM_VERSION_LABEL}" STREQUAL "") set(STORM_VERSION_LABEL_STRING "") @@ -454,18 +451,19 @@ else() endif() # check for development version with commits ahead of latest tag -set(STORM_VERSION_DEV "false") -set(STORM_VERSION_DEV_STRING "") if(STORM_VERSION_COMMITS_AHEAD) + set(STORM_VERSION_DEV "true") + set(STORM_VERSION_DEV_STRING " (dev)") if ("${STORM_VERSION_LABEL}" STREQUAL "") # increase patch number to indicate newer version MATH(EXPR STORM_VERSION_DEV_PATCH "${STORM_VERSION_PATCH}+1") else() set(STORM_VERSION_DEV_PATCH "${STORM_VERSION_PATCH}") endif() - set(STORM_VERSION_DEV "true") - set(STORM_VERSION_DEV_STRING " (dev)") else() + set(STORM_VERSION_COMMITS_AHEAD 0) + set(STORM_VERSION_DEV "false") + set(STORM_VERSION_DEV_STRING "") set(STORM_VERSION_DEV_PATCH ${STORM_VERSION_PATCH}) endif() diff --git a/src/storm/utility/storm-version.h b/src/storm/utility/storm-version.h index b6b1d3d2e..e87cbd489 100644 --- a/src/storm/utility/storm-version.h +++ b/src/storm/utility/storm-version.h @@ -30,12 +30,12 @@ namespace storm { /// The source of the versioning information. const static VersionSource versionSource; - + /// The short hash of the git commit this build is based on const static std::string gitRevisionHash; /// How many commits passed since the tag was last set. - const static boost::optional commitsAhead; + const static unsigned commitsAhead; /// 0 iff there no files were modified in the checkout, 1 otherwise. If none, no information about dirtyness is given. const static boost::optional dirty; @@ -70,8 +70,8 @@ namespace storm { if (versionSource == VersionSource::Static) { sstream << " (derived statically)"; } - if (commitsAhead) { - sstream << " (+ " << commitsAhead.get() << " commits)"; + if (commitsAhead > 0) { + sstream << " (+ " << commitsAhead << " commits)"; } if (!gitRevisionHash.empty()) { sstream << " build from revision " << gitRevisionHash; diff --git a/storm-version.cpp.in b/storm-version.cpp.in index 6e3706bae..f74b2cbc7 100644 --- a/storm-version.cpp.in +++ b/storm-version.cpp.in @@ -11,7 +11,7 @@ namespace storm { const bool StormVersion::versionDev = @STORM_VERSION_DEV@; const StormVersion::VersionSource StormVersion::versionSource = @STORM_VERSION_SOURCE@; const std::string StormVersion::gitRevisionHash = "@STORM_VERSION_GIT_HASH@"; - const boost::optional StormVersion::commitsAhead = @STORM_VERSION_COMMITS_AHEAD@; + const unsigned StormVersion::commitsAhead = @STORM_VERSION_COMMITS_AHEAD@; const boost::optional StormVersion::dirty = @STORM_VERSION_DIRTY@; const std::string StormVersion::systemName = "@CMAKE_SYSTEM_NAME@"; const std::string StormVersion::systemVersion = "@CMAKE_SYSTEM_VERSION@"; From b895911c7d75da63102ed3c9e3ad5a13d5dce1a5 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Tue, 17 Jul 2018 16:48:13 +0200 Subject: [PATCH 417/647] New storm version containing fix for version parsing --- CHANGELOG.md | 3 +++ version.cmake | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af9b3d6a8..21ad6718a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The releases of major and minor versions contain an overview of changes since th Version 1.2.x ------------- +### Version 1.2.3 (2018/07) +- Fix in version parsing + ### Version 1.2.2 (2018/07) - Sound value iteration (SVI) for DTMCs and MDPs - Topological solver for linear equation systems and MinMax equation systems (enabled by default) diff --git a/version.cmake b/version.cmake index 6a9d667db..b82fc11c5 100644 --- a/version.cmake +++ b/version.cmake @@ -1,4 +1,4 @@ set(STORM_VERSION_MAJOR 1) set(STORM_VERSION_MINOR 2) -set(STORM_VERSION_PATCH 2) +set(STORM_VERSION_PATCH 3) From abe7510ae94e421119de3df25dd96d7b6d15f4a0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 17 Jul 2018 18:58:51 +0200 Subject: [PATCH 418/647] added clearing requirements --- src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 697eab80a..634eaf806 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -482,6 +482,8 @@ namespace storm { // Check solver requirements. storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto requirements = linearEquationSolverFactory.getRequirements(env); + requirements.clearLowerBounds(); + requirements.clearUpperBounds(); STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); bool fixedPointSystem = false; @@ -541,6 +543,8 @@ namespace storm { bsccEquationSystem = builder.build(); { std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(bsccEquationSystem)); + solver->setLowerBound(storm::utility::zero()); + solver->setUpperBound(storm::utility::one()); solver->solveEquations(env, bsccEquationSystemSolution, bsccEquationSystemRightSide); } From 85671ef6f11de77af719869c334920895cbab1e7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 18 Jul 2018 13:56:16 +0200 Subject: [PATCH 419/647] fixing segfault pointed out by Paul Gainer --- src/storm-pars-cli/storm-pars.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index ec3f65f29..badcb0212 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -58,7 +58,7 @@ namespace storm { template SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { - STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); + STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); SampleInformation sampleInfo(graphPreserving); if (sampleString.empty()) { @@ -465,8 +465,12 @@ namespace storm { } std::vector> regions = parseRegions(model); - SampleInformation samples = parseSamples(model, parSettings.getSamples(), parSettings.isSamplesAreGraphPreservingSet()); - samples.exact = parSettings.isSampleExactSet(); + std::string samplesAsString = parSettings.getSamples(); + SampleInformation samples; + if (!samplesAsString.empty()) { + samples = parseSamples(model, samplesAsString, parSettings.isSamplesAreGraphPreservingSet()); + samples.exact = parSettings.isSampleExactSet(); + } if (model) { storm::cli::exportModel(model, input); From 6e2e3d452d637058b5c4a08ab20d06b4d82d2dad Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 18 Jul 2018 16:54:34 +0200 Subject: [PATCH 420/647] minor fixes in counterexample generation --- .../counterexamples/SMTMinimalLabelSetGenerator.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 4a829b9cb..ce0b94204 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1200,8 +1200,8 @@ namespace storm { solver.add(variableInformation.auxiliaryVariables.back()); variableInformation.auxiliaryVariables.push_back(assertLessOrEqualKRelaxed(solver, variableInformation, ++currentBound)); assumption = !variableInformation.auxiliaryVariables.back(); - if (currentBound > (1 << variableInformation.minimalityLabelVariables.size())) { - STORM_LOG_DEBUG("Constraint system fully explored: Bound exceeds maximum of " << (1 << variableInformation.minimalityLabelVariables.size())); + if (currentBound > variableInformation.minimalityLabelVariables.size()) { + STORM_LOG_DEBUG("Constraint system fully explored: Bound exceeds maximum of " << variableInformation.minimalityLabelVariables.size()); return boost::none; } } @@ -1525,11 +1525,6 @@ namespace storm { } - if (rewardName) { - auto const &origRewModel = model.getRewardModel(rewardName.get()); - assert(origRewModel.hasOnlyStateRewards()); - } - std::shared_ptr> resultModel; if (model.isOfType(storm::models::ModelType::Dtmc)) { resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling()), model.getRewardModels()); From 6051363782d5652cda66bd17b249dd67f70936a2 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Wed, 18 Jul 2018 16:55:00 +0200 Subject: [PATCH 421/647] initial support for multi-reward structures in counterexample generation --- .../SMTMinimalLabelSetGenerator.h | 156 +++++++++++------- 1 file changed, 99 insertions(+), 57 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index ce0b94204..65143dfb5 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1482,7 +1482,7 @@ namespace storm { * Returns the sub-model obtained from removing all choices that do not originate from the specified filterLabelSet. * Also returns the Labelsets of the sub-model. */ - static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional const& rewardName = boost::none, boost::optional absorbState = boost::none) { + static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional absorbState = boost::none) { bool customRowGrouping = model.isOfType(storm::models::ModelType::Mdp); @@ -1535,30 +1535,42 @@ namespace storm { return std::make_pair(resultModel, std::move(resultLabelSet)); } - static T computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional const& rewardName) { - T result = storm::utility::zero(); - + static std::vector computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional> const& rewardName) { + std::vector results; + std::vector allStatesResult; STORM_LOG_DEBUG("Invoking model checker."); if (model.isOfType(storm::models::ModelType::Dtmc)) { if (rewardName == boost::none) { + results.push_back(storm::utility::zero()); allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } } else { - allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), model.getRewardModel(rewardName.get()), psiStates, false); + for (auto const &rewName : rewardName.get()) { + results.push_back(storm::utility::zero()); + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), model.getRewardModel(rewName), psiStates, false); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } + } } } else { if (rewardName == boost::none) { + results.push_back(storm::utility::zero()); storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(),model.getBackwardTransitions(), phiStates,psiStates, false, false).values); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } } else { STORM_LOG_THROW(rewardName != boost::none, storm::exceptions::NotSupportedException, "Reward property counterexample generation is currently only supported for DTMCs."); } } - for (auto state : model.getInitialStates()) { - result = std::max(result, allStatesResult[state]); - } - return result; + + return results; } public: @@ -1598,8 +1610,10 @@ namespace storm { * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). * @param options A set of options for customization. */ - static std::vector> getMinimalLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double propertyThreshold, boost::optional const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { + static std::vector> getMinimalLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector propertyThreshold, boost::optional> const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 + STORM_LOG_THROW(propertyThreshold.size() > 0, storm::exceptions::InvalidArgumentException, "At least one threshold has to be specified."); + STORM_LOG_THROW(propertyThreshold.size() == 1 || (rewardName && rewardName.get().size() == propertyThreshold.size()), storm::exceptions::InvalidArgumentException, "Multiple thresholds is only supported for multiple reward structures"); std::vector> result; // Set up all clocks used for time measurement. auto totalClock = std::chrono::high_resolution_clock::now(); @@ -1638,12 +1652,15 @@ namespace storm { assert(labelSets.size() == model.getNumberOfChoices()); // (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set. - double maximalReachabilityProbability = 0; + std::vector maximalReachabilityProbability; if (options.checkThresholdFeasible) { maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates, rewardName); - - STORM_LOG_THROW((strictBound && maximalReachabilityProbability >= propertyThreshold) || (!strictBound && maximalReachabilityProbability > propertyThreshold), storm::exceptions::InvalidArgumentException, "Given probability threshold " << propertyThreshold << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability << "."); - std::cout << std::endl << "Maximal property value in model is " << maximalReachabilityProbability << "." << std::endl << std::endl; + + for (uint64_t i = 0; i < maximalReachabilityProbability.size(); ++i) { + STORM_LOG_THROW((strictBound && maximalReachabilityProbability[i] >= propertyThreshold[i]) || (!strictBound && maximalReachabilityProbability[i] > propertyThreshold[i]), storm::exceptions::InvalidArgumentException, "Given probability threshold " << propertyThreshold[i] << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability[i] << "."); + std::cout << std::endl << "Maximal property value in model is " << maximalReachabilityProbability[i] << "." << std::endl << std::endl; + } + } // (2) Identify all states and commands that are relevant, because only these need to be considered later. @@ -1695,7 +1712,7 @@ namespace storm { uint_fast64_t lastSize = 0; uint_fast64_t iterations = 0; uint_fast64_t currentBound = 0; - double maximalPropertyValue = 0; + std::vector maximalPropertyValue; uint_fast64_t zeroProbabilityCount = 0; uint64_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive u uint64_t progressDelay = storm::settings::getModule().getShowProgressDelay(); @@ -1722,7 +1739,7 @@ namespace storm { } - auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, rewardName, psiStates.getNextSetIndex(0)); + auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, psiStates.getNextSetIndex(0)); std::shared_ptr> const& subModel = subChoiceOrigins.first; std::vector> const& subLabelSets = subChoiceOrigins.second; @@ -1732,8 +1749,13 @@ namespace storm { // Depending on whether the threshold was successfully achieved or not, we proceed by either analyzing the bad solution or stopping the iteration process. analysisClock = std::chrono::high_resolution_clock::now(); - if ((strictBound && maximalPropertyValue < propertyThreshold) || (!strictBound && maximalPropertyValue <= propertyThreshold)) { - if (maximalPropertyValue == storm::utility::zero()) { + bool violation = false; + for (uint64_t i = 0; i < maximalPropertyValue.size(); i++) { + violation |= (strictBound && maximalPropertyValue[i] < propertyThreshold[i]) || (!strictBound && maximalPropertyValue[i] <= propertyThreshold[i]); + } + + if (violation) { + if (!rewardName && maximalPropertyValue.front() == storm::utility::zero()) { ++zeroProbabilityCount; } @@ -1910,47 +1932,57 @@ namespace storm { } - static std::vector> computeCounterexampleLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { - STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); - if (!options.silent) { - std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; - } + struct CexInput { storm::logic::ComparisonType comparisonType; - double threshold; - boost::optional rewardName = boost::none; - + std::vector threshold; + boost::optional> rewardName = boost::none; + bool lowerBoundedFormula = false; + bool strictBound; + storm::storage::BitVector phiStates; + storm::storage::BitVector psiStates; + + void addRewardThresholdCombination(std::string reward, double thresh) { + STORM_LOG_THROW(rewardName, storm::exceptions::InvalidOperationException, "Can only add more reward names if a reward name is already set"); + rewardName.get().push_back(reward); + threshold.push_back(thresh); + } + }; + + static CexInput precompute(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { + + CexInput result; STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); if (formula->isProbabilityOperatorFormula()) { storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); STORM_LOG_THROW(probabilityOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); - comparisonType = probabilityOperator.getComparisonType(); - threshold = probabilityOperator.getThresholdAs(); + result.comparisonType = probabilityOperator.getComparisonType(); + result.threshold.push_back(probabilityOperator.getThresholdAs()); } else { assert(formula->isRewardOperatorFormula()); storm::logic::RewardOperatorFormula const& rewardOperator = formula->asRewardOperatorFormula(); STORM_LOG_THROW(rewardOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); STORM_LOG_THROW( rewardOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'F phi' for counterexample generation."); - - comparisonType = rewardOperator.getComparisonType(); - threshold = rewardOperator.getThresholdAs(); - rewardName = rewardOperator.getRewardModelName(); - STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for probability formulas."); - STORM_LOG_THROW(model.hasRewardModel(rewardName.get()), storm::exceptions::InvalidPropertyException, "Property refers to reward " << rewardName.get() << " but model does not contain such a reward model."); - STORM_LOG_THROW(model.getRewardModel(rewardName.get()).hasOnlyStateRewards(), storm::exceptions::NotSupportedException, "We only support state-based rewards at the moment."); + result.comparisonType = rewardOperator.getComparisonType(); + result.threshold.push_back(rewardOperator.getThresholdAs()); + result.rewardName = std::vector(); + result.rewardName.get().push_back(rewardOperator.getRewardModelName()); + + STORM_LOG_THROW(!storm::logic::isLowerBound(result.comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for probability formulas."); + STORM_LOG_THROW(model.hasRewardModel(result.rewardName.get().front()), storm::exceptions::InvalidPropertyException, "Property refers to reward " << result.rewardName.get().front() << " but model does not contain such a reward model."); + STORM_LOG_THROW(model.getRewardModel(result.rewardName.get().front()).hasOnlyStateRewards(), storm::exceptions::NotSupportedException, "We only support state-based rewards at the moment."); } - bool strictBound = comparisonType == storm::logic::ComparisonType::Less; + result.strictBound = result.comparisonType == storm::logic::ComparisonType::Less; storm::logic::Formula const& subformula = formula->asOperatorFormula().getSubformula(); - - storm::storage::BitVector phiStates; - storm::storage::BitVector psiStates; + + storm::modelchecker::SparsePropositionalModelChecker> modelchecker(model); if (subformula.isUntilFormula()) { - STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for eventually formulas."); + STORM_LOG_THROW(!storm::logic::isLowerBound(result.comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for eventually formulas."); storm::logic::UntilFormula const& untilFormula = subformula.asUntilFormula(); std::unique_ptr leftResult = modelchecker.check(env, untilFormula.getLeftSubformula()); @@ -1959,8 +1991,8 @@ namespace storm { storm::modelchecker::ExplicitQualitativeCheckResult const& leftQualitativeResult = leftResult->asExplicitQualitativeCheckResult(); storm::modelchecker::ExplicitQualitativeCheckResult const& rightQualitativeResult = rightResult->asExplicitQualitativeCheckResult(); - phiStates = leftQualitativeResult.getTruthValuesVector(); - psiStates = rightQualitativeResult.getTruthValuesVector(); + result.phiStates = leftQualitativeResult.getTruthValuesVector(); + result.psiStates = rightQualitativeResult.getTruthValuesVector(); } else if (subformula.isEventuallyFormula()) { storm::logic::EventuallyFormula const& eventuallyFormula = subformula.asEventuallyFormula(); @@ -1968,12 +2000,12 @@ namespace storm { storm::modelchecker::ExplicitQualitativeCheckResult const& subQualitativeResult = subResult->asExplicitQualitativeCheckResult(); - phiStates = storm::storage::BitVector(model.getNumberOfStates(), true); - psiStates = subQualitativeResult.getTruthValuesVector(); + result.phiStates = storm::storage::BitVector(model.getNumberOfStates(), true); + result.psiStates = subQualitativeResult.getTruthValuesVector(); } bool lowerBoundedFormula = false; - if (storm::logic::isLowerBound(comparisonType)) { + if (storm::logic::isLowerBound(result.comparisonType)) { // If the formula specifies a lower bound, we need to modify the phi and psi states. // More concretely, we convert P(min)>lambda(F psi) to P(max)<(1-lambda)(G !psi) = P(max)<(1-lambda)(!psi U prob0E(psi)) // where prob0E(psi) is the set of states for which there exists a strategy \sigma_0 that avoids @@ -1982,27 +2014,32 @@ namespace storm { // This means that from all states in prob0E(psi) we need to include labels such that \sigma_0 // is actually included in the resulting model. This prevents us from guaranteeing the minimality of // the returned counterexample, so we warn about that. - if (!options.silent) { - STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); - } + // Modify bound appropriately. - comparisonType = storm::logic::invertPreserveStrictness(comparisonType); - threshold = storm::utility::one() - threshold; + result.comparisonType = storm::logic::invertPreserveStrictness(result.comparisonType); + result.threshold.back() = storm::utility::one() - result.threshold.back(); // Modify the phi and psi states appropriately. - storm::storage::BitVector statesWithProbability0E = storm::utility::graph::performProb0E(model.getTransitionMatrix(), model.getTransitionMatrix().getRowGroupIndices(), model.getBackwardTransitions(), phiStates, psiStates); - phiStates = ~psiStates; - psiStates = std::move(statesWithProbability0E); + storm::storage::BitVector statesWithProbability0E = storm::utility::graph::performProb0E(model.getTransitionMatrix(), model.getTransitionMatrix().getRowGroupIndices(), model.getBackwardTransitions(), result.phiStates, result.psiStates); + result.phiStates = ~result.psiStates; + result.psiStates = std::move(statesWithProbability0E); // Remember our transformation so we can add commands to guarantee that the prob0E(a) states actually // have a strategy that voids a states. lowerBoundedFormula = true; } + return result; + + } + + + static std::vector> computeCounterexampleLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, CexInput const& counterexInput, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { + STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSets = getMinimalLabelSet(env, stats, symbolicModel, model, phiStates, psiStates, threshold, rewardName, strictBound, dontCareLabels, options); + auto labelSets = getMinimalLabelSet(env, stats, symbolicModel, model, counterexInput.phiStates, counterexInput.psiStates, counterexInput.threshold, counterexInput.rewardName, counterexInput.strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); if (!options.silent) { for (auto const& labelSet : labelSets) { @@ -2015,8 +2052,8 @@ namespace storm { // Extend the command set properly. for (auto& labelSet : labelSets) { - if (lowerBoundedFormula) { - extendLabelSetLowerBound(model, labelSet, phiStates, psiStates, options.silent); + if (counterexInput.lowerBoundedFormula) { + extendLabelSetLowerBound(model, labelSet, counterexInput.phiStates, counterexInput.psiStates, options.silent); } } return labelSets; @@ -2024,8 +2061,13 @@ namespace storm { static std::shared_ptr computeCounterexample(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { #ifdef STORM_HAVE_Z3 + std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; GeneratorStats stats; - auto labelSets = computeCounterexampleLabelSet(env, stats, symbolicModel, model, formula); + CexInput prec = precompute(env, symbolicModel, model, formula); + if (prec.lowerBoundedFormula) { + STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); + } + auto labelSets = computeCounterexampleLabelSet(env, stats, symbolicModel, model, prec); if (symbolicModel.isPrismProgram()) { From db72a053587e601a991f59961931b17d3c64274c Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 19 Jul 2018 10:04:44 +0200 Subject: [PATCH 422/647] fixed log output --- src/storm/solver/helper/SoundValueIterationHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp index 081c4a51d..674ea5160 100644 --- a/src/storm/solver/helper/SoundValueIterationHelper.cpp +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -303,7 +303,7 @@ namespace storm { STORM_LOG_INFO("Sound Value Iteration terminated with lower bound (over all states) " << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") - << " and upper bound (over all states)" + << " and upper bound (over all states) " << (hasUpperBound ? upperBound : storm::utility::infinity()) << (hasUpperBound ? "" : "(none)") << ". Decision value is " << (hasDecisionValue ? decisionValue : -storm::utility::infinity()) << (hasDecisionValue ? "" : "(none)") From 2e035f39578c64798b4cff6b2b2c02cfc11480a0 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 23 Jul 2018 10:11:42 +0200 Subject: [PATCH 423/647] started working on conversion binary --- src/CMakeLists.txt | 3 +- src/storm-conv-cli/CMakeLists.txt | 9 + src/storm-conv-cli/storm-conv.cpp | 539 ++++++++++++++++++++++++++++++ src/storm-conv/CMakeLists.txt | 40 +++ src/storm-conv/api/storm-conv.h | 4 + 5 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 src/storm-conv-cli/CMakeLists.txt create mode 100644 src/storm-conv-cli/storm-conv.cpp create mode 100644 src/storm-conv/CMakeLists.txt create mode 100644 src/storm-conv/api/storm-conv.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7239a9676..6c61656ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,8 @@ add_subdirectory(storm-dft) add_subdirectory(storm-dft-cli) add_subdirectory(storm-pars) add_subdirectory(storm-pars-cli) - +add_subdirectory(storm-conv) +add_subdirectory(storm-conv-cli) add_subdirectory(test) diff --git a/src/storm-conv-cli/CMakeLists.txt b/src/storm-conv-cli/CMakeLists.txt new file mode 100644 index 000000000..72a311b11 --- /dev/null +++ b/src/storm-conv-cli/CMakeLists.txt @@ -0,0 +1,9 @@ +# Create storm-conv. +add_executable(storm-conv-cli ${PROJECT_SOURCE_DIR}/src/storm-conv-cli/storm-conv.cpp) +target_link_libraries(storm-conv-cli storm-conv storm-cli-utilities) # Adding headers for xcode +set_target_properties(storm-conv-cli PROPERTIES OUTPUT_NAME "storm-conv") + +add_dependencies(binaries storm-conv-cli) + +# installation +install(TARGETS storm-conv-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp new file mode 100644 index 000000000..badcb0212 --- /dev/null +++ b/src/storm-conv-cli/storm-conv.cpp @@ -0,0 +1,539 @@ + +#include "storm-pars/api/storm-pars.h" +#include "storm-pars/settings/ParsSettings.h" +#include "storm-pars/settings/modules/ParametricSettings.h" +#include "storm-pars/settings/modules/RegionSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/api/storm.h" +#include "storm-cli-utilities/cli.h" +#include "storm-cli-utilities/model-handling.h" +#include "storm/models/ModelBase.h" +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/utility/file.h" +#include "storm/utility/initialize.h" +#include "storm/utility/Stopwatch.h" +#include "storm/utility/macros.h" + +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" + +#include "storm/settings/modules/GeneralSettings.h" +#include "storm/settings/modules/CoreSettings.h" +#include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/BisimulationSettings.h" + +#include "storm/exceptions/BaseException.h" +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace pars { + + typedef typename storm::cli::SymbolicInput SymbolicInput; + + template + struct SampleInformation { + SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) { + // Intentionally left empty. + } + + bool empty() const { + return cartesianProducts.empty(); + } + + std::vector::type, std::vector::type>>> cartesianProducts; + bool graphPreserving; + bool exact; + }; + + template + std::vector> parseRegions(std::shared_ptr const& model) { + std::vector> result; + auto regionSettings = storm::settings::getModule(); + if (regionSettings.isRegionSet()) { + result = storm::api::parseRegions(regionSettings.getRegionString(), *model); + } + return result; + } + + template + SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { + STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); + + SampleInformation sampleInfo(graphPreserving); + if (sampleString.empty()) { + return sampleInfo; + } + + // Get all parameters from the model. + std::set::type> modelParameters; + auto const& sparseModel = *model->as>(); + modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); + auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + std::vector cartesianProducts; + boost::split(cartesianProducts, sampleString, boost::is_any_of(";")); + for (auto& product : cartesianProducts) { + boost::trim(product); + + // Get the values string for each variable. + std::vector valuesForVariables; + boost::split(valuesForVariables, product, boost::is_any_of(",")); + for (auto& values : valuesForVariables) { + boost::trim(values); + } + + std::set::type> encounteredParameters; + sampleInfo.cartesianProducts.emplace_back(); + auto& newCartesianProduct = sampleInfo.cartesianProducts.back(); + for (auto const& varValues : valuesForVariables) { + auto equalsPosition = varValues.find("="); + STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); + std::string variableName = varValues.substr(0, equalsPosition); + boost::trim(variableName); + std::string values = varValues.substr(equalsPosition + 1); + boost::trim(values); + + bool foundParameter = false; + typename utility::parametric::VariableType::type theParameter; + for (auto const& parameter : modelParameters) { + std::stringstream parameterStream; + parameterStream << parameter; + if (parameterStream.str() == variableName) { + foundParameter = true; + theParameter = parameter; + encounteredParameters.insert(parameter); + } + } + STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); + + std::vector splitValues; + boost::split(splitValues, values, boost::is_any_of(":")); + STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); + + auto& list = newCartesianProduct[theParameter]; + + for (auto& value : splitValues) { + boost::trim(value); + list.push_back(storm::utility::convertNumber::type>(value)); + } + } + + STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples."); + } + + return sampleInfo; + } + + template + std::pair, bool> preprocessSparseModel(std::shared_ptr> const& model, SymbolicInput const& input) { + auto generalSettings = storm::settings::getModule(); + auto bisimulationSettings = storm::settings::getModule(); + auto parametricSettings = storm::settings::getModule(); + + std::pair, bool> result = std::make_pair(model, false); + + if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) { + result.first = storm::cli::preprocessSparseMarkovAutomaton(result.first->template as>()); + result.second = true; + } + + if (generalSettings.isBisimulationSet()) { + result.first = storm::cli::preprocessSparseModelBisimulation(result.first->template as>(), input, bisimulationSettings); + result.second = true; + } + + if (parametricSettings.transformContinuousModel() && (result.first->isOfType(storm::models::ModelType::Ctmc) || result.first->isOfType(storm::models::ModelType::MarkovAutomaton))) { + result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first->template as>()), storm::api::extractFormulasFromProperties(input.properties)); + result.second = true; + } + + return result; + } + + template + std::pair, bool> preprocessDdModel(std::shared_ptr> const& model, SymbolicInput const& input) { + + std::pair, bool> result = std::make_pair(model, false); + + auto coreSettings = storm::settings::getModule(); + if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) { + // Currently, hybrid engine for parametric models just referrs to building the model symbolically. + STORM_LOG_INFO("Translating symbolic model to sparse model..."); + result.first = storm::api::transformSymbolicToSparseModel(model); + result.second = true; + // Invoke preprocessing on the sparse model + auto sparsePreprocessingResult = storm::pars::preprocessSparseModel(result.first->as>(), input); + if (sparsePreprocessingResult.second) { + result.first = sparsePreprocessingResult.first; + } + } + return result; + } + + template + std::pair, bool> preprocessModel(std::shared_ptr const& model, SymbolicInput const& input) { + storm::utility::Stopwatch preprocessingWatch(true); + + std::pair, bool> result = std::make_pair(model, false); + if (model->isSparseModel()) { + result = storm::pars::preprocessSparseModel(result.first->as>(), input); + } else { + STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); + result = storm::pars::preprocessDdModel(result.first->as>(), input); + } + + if (result.second) { + STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); + } + return result; + } + + template + void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation const* valuation = nullptr) { + if (result) { + STORM_PRINT_AND_LOG("Result (initial states)"); + if (valuation) { + bool first = true; + std::stringstream ss; + for (auto const& entry : *valuation) { + if (!first) { + ss << ", "; + } else { + first = false; + } + ss << entry.first << "=" << entry.second; + } + + STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]"); + } + STORM_PRINT_AND_LOG(": ") + + auto const* regionCheckResult = dynamic_cast const*>(result.get()); + if (regionCheckResult != nullptr) { + auto regionSettings = storm::settings::getModule(); + std::stringstream outStream; + if (regionSettings.isPrintFullResultSet()) { + regionCheckResult->writeToStream(outStream); + } else { + regionCheckResult->writeCondensedToStream(outStream); + } + outStream << std::endl; + if (!regionSettings.isPrintNoIllustrationSet()) { + auto const* regionRefinementCheckResult = dynamic_cast const*>(regionCheckResult); + if (regionRefinementCheckResult != nullptr) { + regionRefinementCheckResult->writeIllustrationToStream(outStream); + } + } + outStream << std::endl; + STORM_PRINT_AND_LOG(outStream.str()); + } else { + STORM_PRINT_AND_LOG(*result << std::endl); + } + if (watch) { + STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl << std::endl); + } + } else { + STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); + } + } + + template + void verifyProperties(std::vector const& properties, std::function(std::shared_ptr const& formula)> const& verificationCallback, std::function const&)> const& postprocessingCallback) { + for (auto const& property : properties) { + storm::cli::printModelCheckingProperty(property); + storm::utility::Stopwatch watch(true); + std::unique_ptr result = verificationCallback(property.getRawFormula()); + watch.stop(); + printInitialStatesResult(result, property, &watch); + postprocessingCallback(result); + } + } + + template class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double> + void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation const& samples) { + + // When samples are provided, we create an instantiation model checker. + ModelCheckerType modelchecker(model); + + for (auto const& property : input.properties) { + storm::cli::printModelCheckingProperty(property); + + modelchecker.specifyFormula(storm::api::createTask(property.getRawFormula(), true)); + modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving); + + storm::utility::parametric::Valuation valuation; + + std::vector::type> parameters; + std::vector::type>::const_iterator> iterators; + std::vector::type>::const_iterator> iteratorEnds; + + storm::utility::Stopwatch watch(true); + for (auto const& product : samples.cartesianProducts) { + parameters.clear(); + iterators.clear(); + iteratorEnds.clear(); + + for (auto const& entry : product) { + parameters.push_back(entry.first); + iterators.push_back(entry.second.cbegin()); + iteratorEnds.push_back(entry.second.cend()); + } + + bool done = false; + while (!done) { + // Read off valuation. + for (uint64_t i = 0; i < parameters.size(); ++i) { + valuation[parameters[i]] = *iterators[i]; + } + + storm::utility::Stopwatch valuationWatch(true); + std::unique_ptr result = modelchecker.check(Environment(), valuation); + valuationWatch.stop(); + + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates())); + } + printInitialStatesResult(result, property, &valuationWatch, &valuation); + + for (uint64_t i = 0; i < parameters.size(); ++i) { + ++iterators[i]; + if (iterators[i] == iteratorEnds[i]) { + // Reset iterator and proceed to move next iterator. + iterators[i] = product.at(parameters[i]).cbegin(); + + // If the last iterator was removed, we are done. + if (i == parameters.size() - 1) { + done = true; + } + } else { + // If an iterator was moved but not reset, we have another valuation to check. + break; + } + } + + } + } + + watch.stop(); + STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl); + } + } + + template + void verifyPropertiesAtSamplePoints(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + if (model->isOfType(storm::models::ModelType::Dtmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); + } + } + + template + void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + + if (samples.empty()) { + verifyProperties(input.properties, + [&model] (std::shared_ptr const& formula) { + std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); + } + return result; + }, + [&model] (std::unique_ptr const& result) { + auto parametricSettings = storm::settings::getModule(); + if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmc = model->template as>(); + boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; + storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); + } + }); + } else { + STORM_LOG_TRACE("Sampling the model at given points."); + + if (samples.exact) { + verifyPropertiesAtSamplePoints(model, input, samples); + } else { + verifyPropertiesAtSamplePoints(model, input, samples); + } + } + } + + template + void verifyRegionsWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions) { + STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions."); + + auto parametricSettings = storm::settings::getModule(); + auto regionSettings = storm::settings::getModule(); + + std::function(std::shared_ptr const& formula)> verificationCallback; + std::function const&)> postprocessingCallback; + + STORM_PRINT_AND_LOG(std::endl); + if (regionSettings.isHypothesisSet()) { + STORM_PRINT_AND_LOG("Checking hypothesis " << regionSettings.getHypothesis() << " on "); + } else { + STORM_PRINT_AND_LOG("Analyzing "); + } + if (regions.size() == 1) { + STORM_PRINT_AND_LOG("parameter region " << regions.front()); + } else { + STORM_PRINT_AND_LOG(regions.size() << " parameter regions"); + } + auto engine = regionSettings.getRegionCheckEngine(); + STORM_PRINT_AND_LOG(" using " << engine); + + // Check the given set of regions with or without refinement + if (regionSettings.isRefineSet()) { + STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions."); + STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getCoverageThreshold()) * 100.0 << "% is covered." << (regionSettings.isDepthLimitSet() ? " Depth limit is " + std::to_string(regionSettings.getDepthLimit()) + "." : "") << std::endl); + verificationCallback = [&] (std::shared_ptr const& formula) { + ValueType refinementThreshold = storm::utility::convertNumber(regionSettings.getCoverageThreshold()); + boost::optional optionalDepthLimit; + if (regionSettings.isDepthLimitSet()) { + optionalDepthLimit = regionSettings.getDepthLimit(); + } + std::unique_ptr> result = storm::api::checkAndRefineRegionWithSparseEngine(model, storm::api::createTask(formula, true), regions.front(), engine, refinementThreshold, optionalDepthLimit, regionSettings.getHypothesis()); + return result; + }; + } else { + STORM_PRINT_AND_LOG("." << std::endl); + verificationCallback = [&] (std::shared_ptr const& formula) { + std::unique_ptr result = storm::api::checkRegionsWithSparseEngine(model, storm::api::createTask(formula, true), regions, engine, regionSettings.getHypothesis()); + return result; + }; + } + + postprocessingCallback = [&] (std::unique_ptr const& result) { + if (parametricSettings.exportResultToFile()) { + storm::api::exportRegionCheckResultToFile(result, parametricSettings.exportResultPath()); + } + }; + + verifyProperties(input.properties, verificationCallback, postprocessingCallback); + } + + template + void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { + if (regions.empty()) { + storm::pars::verifyPropertiesWithSparseEngine(model, input, samples); + } else { + storm::pars::verifyRegionsWithSparseEngine(model, input, regions); + } + } + + template + void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { + STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); + storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); + } + + template + void processInputWithValueTypeAndDdlib(SymbolicInput& input) { + auto coreSettings = storm::settings::getModule(); + auto ioSettings = storm::settings::getModule(); + + auto buildSettings = storm::settings::getModule(); + auto parSettings = storm::settings::getModule(); + + auto engine = coreSettings.getEngine(); + STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); + + std::shared_ptr model; + if (!buildSettings.isNoBuildModelSet()) { + model = storm::cli::buildModel(engine, input, ioSettings); + } + + if (model) { + model->printModelInformationToStream(std::cout); + } + + STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); + + if (model) { + auto preprocessingResult = storm::pars::preprocessModel(model, input); + if (preprocessingResult.second) { + model = preprocessingResult.first; + model->printModelInformationToStream(std::cout); + } + } + + std::vector> regions = parseRegions(model); + std::string samplesAsString = parSettings.getSamples(); + SampleInformation samples; + if (!samplesAsString.empty()) { + samples = parseSamples(model, samplesAsString, parSettings.isSamplesAreGraphPreservingSet()); + samples.exact = parSettings.isSampleExactSet(); + } + + if (model) { + storm::cli::exportModel(model, input); + } + + if (parSettings.onlyObtainConstraints()) { + STORM_LOG_THROW(parSettings.exportResultToFile(), storm::exceptions::InvalidSettingsException, "When computing constraints, export path has to be specified."); + storm::api::exportParametricResultToFile(boost::none, storm::analysis::ConstraintCollector(*(model->as>())), parSettings.exportResultPath()); + return; + } + + if (model) { + verifyParametricModel(model, input, regions, samples); + } + } + + void processOptions() { + // Start by setting some urgent options (log levels, resources, etc.) + storm::cli::setUrgentOptions(); + + // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) + SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); + + auto coreSettings = storm::settings::getModule(); + auto engine = coreSettings.getEngine(); + STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); + + processInputWithValueTypeAndDdlib(symbolicInput); + } + + } +} + + +/*! + * Main entry point of the executable storm-pars. + */ +int main(const int argc, const char** argv) { + + try { + storm::utility::setUp(); + storm::cli::printHeader("Storm-pars", argc, argv); + storm::settings::initializeParsSettings("Storm-pars", "storm-pars"); + + storm::utility::Stopwatch totalTimer(true); + if (!storm::cli::parseOptions(argc, argv)) { + return -1; + } + + storm::pars::processOptions(); + + totalTimer.stop(); + if (storm::settings::getModule().isPrintTimeAndMemorySet()) { + storm::cli::printTimeAndMemoryStatistics(totalTimer.getTimeInMilliseconds()); + } + + storm::utility::cleanUp(); + return 0; + } catch (storm::exceptions::BaseException const& exception) { + STORM_LOG_ERROR("An exception caused Storm-pars to terminate. The message of the exception is: " << exception.what()); + return 1; + } catch (std::exception const& exception) { + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-pars to terminate. The message of this exception is: " << exception.what()); + return 2; + } +} diff --git a/src/storm-conv/CMakeLists.txt b/src/storm-conv/CMakeLists.txt new file mode 100644 index 000000000..4ead2828e --- /dev/null +++ b/src/storm-conv/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-conv/*.h ${PROJECT_SOURCE_DIR}/src/storm-conv/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-conv) + + + +file(GLOB_RECURSE STORM_CONV_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-conv/*/*.cpp) +file(GLOB_RECURSE STORM_CONV_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-conv/*/*.h) + + +# Create storm-conv. +add_library(storm-conv SHARED ${STORM_CONV_SOURCES} ${STORM_CONV_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-conv PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-conv) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-conv PUBLIC storm ${STORM_CONV_LINK_LIBRARIES}) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_CONV_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_CONV_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_conv_headers DEPENDS ${STORM_CONV_OUTPUT_HEADERS} ${STORM_CONV_HEADERS}) +add_dependencies(storm-conv copy_storm_conv_headers) + +# installation +install(TARGETS storm-conv EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h new file mode 100644 index 000000000..a1a32ac05 --- /dev/null +++ b/src/storm-conv/api/storm-conv.h @@ -0,0 +1,4 @@ +#pragma once + +#include "storm-pars/api/region.h" +#include "storm-pars/api/export.h" \ No newline at end of file From e5e6e1bd79d61a4c66a95868493589f9d0136efe Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 10:55:01 +0200 Subject: [PATCH 424/647] worked on prism to jani converter --- src/storm-conv-cli/storm-conv.cpp | 568 +++--------------- src/storm-conv/api/storm-conv.h | 61 +- .../options/JaniConversionOptions.cpp | 11 + .../converter/options/JaniConversionOptions.h | 25 + .../options/PrismToJaniConverterOptions.cpp | 12 + .../options/PrismToJaniConverterOptions.h | 21 + src/storm-conv/settings/ConvSettings.cpp | 22 + src/storm-conv/settings/ConvSettings.h | 11 + .../modules/ConversionGeneralSettings.cpp | 77 +++ .../modules/ConversionGeneralSettings.h | 88 +++ .../modules/ConversionInputSettings.cpp | 82 +++ .../modules/ConversionInputSettings.h | 86 +++ .../modules/ConversionOutputSettings.cpp | 59 ++ .../modules/ConversionOutputSettings.h | 49 ++ .../settings/modules/JaniExportSettings.cpp | 3 +- .../settings/modules/JaniExportSettings.h | 0 16 files changed, 696 insertions(+), 479 deletions(-) create mode 100644 src/storm-conv/converter/options/JaniConversionOptions.cpp create mode 100644 src/storm-conv/converter/options/JaniConversionOptions.h create mode 100644 src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp create mode 100644 src/storm-conv/converter/options/PrismToJaniConverterOptions.h create mode 100644 src/storm-conv/settings/ConvSettings.cpp create mode 100644 src/storm-conv/settings/ConvSettings.h create mode 100644 src/storm-conv/settings/modules/ConversionGeneralSettings.cpp create mode 100644 src/storm-conv/settings/modules/ConversionGeneralSettings.h create mode 100644 src/storm-conv/settings/modules/ConversionInputSettings.cpp create mode 100644 src/storm-conv/settings/modules/ConversionInputSettings.h create mode 100644 src/storm-conv/settings/modules/ConversionOutputSettings.cpp create mode 100644 src/storm-conv/settings/modules/ConversionOutputSettings.h rename src/{storm => storm-conv}/settings/modules/JaniExportSettings.cpp (96%) rename src/{storm => storm-conv}/settings/modules/JaniExportSettings.h (100%) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index badcb0212..97fbcdfaf 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -1,539 +1,157 @@ -#include "storm-pars/api/storm-pars.h" -#include "storm-pars/settings/ParsSettings.h" -#include "storm-pars/settings/modules/ParametricSettings.h" -#include "storm-pars/settings/modules/RegionSettings.h" +#include "storm-conv/api/storm-conv.h" #include "storm/settings/SettingsManager.h" +#include "storm-conv/settings/ConvSettings.h" +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" +#include "storm-conv/settings/modules/ConversionInputSettings.h" +#include "storm-conv/settings/modules/ConversionOutputSettings.h" + #include "storm/api/storm.h" -#include "storm-cli-utilities/cli.h" -#include "storm-cli-utilities/model-handling.h" -#include "storm/models/ModelBase.h" -#include "storm/storage/SymbolicModelDescription.h" -#include "storm/utility/file.h" +#include "storm-parsers/api/storm-parsers.h" #include "storm/utility/initialize.h" -#include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" -#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" +#include "storm/storage/SymbolicModelDescription.h" -#include "storm/settings/modules/GeneralSettings.h" -#include "storm/settings/modules/CoreSettings.h" -#include "storm/settings/modules/IOSettings.h" -#include "storm/settings/modules/BisimulationSettings.h" -#include "storm/exceptions/BaseException.h" -#include "storm/exceptions/InvalidSettingsException.h" -#include "storm/exceptions/NotSupportedException.h" +#include "storm-cli-utilities/cli.h" namespace storm { - namespace pars { - - typedef typename storm::cli::SymbolicInput SymbolicInput; - - template - struct SampleInformation { - SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) { - // Intentionally left empty. - } - - bool empty() const { - return cartesianProducts.empty(); - } - - std::vector::type, std::vector::type>>> cartesianProducts; - bool graphPreserving; - bool exact; - }; - - template - std::vector> parseRegions(std::shared_ptr const& model) { - std::vector> result; - auto regionSettings = storm::settings::getModule(); - if (regionSettings.isRegionSet()) { - result = storm::api::parseRegions(regionSettings.getRegionString(), *model); - } - return result; - } + namespace conv { - template - SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { - STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); - - SampleInformation sampleInfo(graphPreserving); - if (sampleString.empty()) { - return sampleInfo; - } - - // Get all parameters from the model. - std::set::type> modelParameters; - auto const& sparseModel = *model->as>(); - modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); - auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); - modelParameters.insert(rewParameters.begin(), rewParameters.end()); - - std::vector cartesianProducts; - boost::split(cartesianProducts, sampleString, boost::is_any_of(";")); - for (auto& product : cartesianProducts) { - boost::trim(product); - - // Get the values string for each variable. - std::vector valuesForVariables; - boost::split(valuesForVariables, product, boost::is_any_of(",")); - for (auto& values : valuesForVariables) { - boost::trim(values); - } - - std::set::type> encounteredParameters; - sampleInfo.cartesianProducts.emplace_back(); - auto& newCartesianProduct = sampleInfo.cartesianProducts.back(); - for (auto const& varValues : valuesForVariables) { - auto equalsPosition = varValues.find("="); - STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); - std::string variableName = varValues.substr(0, equalsPosition); - boost::trim(variableName); - std::string values = varValues.substr(equalsPosition + 1); - boost::trim(values); - - bool foundParameter = false; - typename utility::parametric::VariableType::type theParameter; - for (auto const& parameter : modelParameters) { - std::stringstream parameterStream; - parameterStream << parameter; - if (parameterStream.str() == variableName) { - foundParameter = true; - theParameter = parameter; - encounteredParameters.insert(parameter); - } - } - STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); - - std::vector splitValues; - boost::split(splitValues, values, boost::is_any_of(":")); - STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); - - auto& list = newCartesianProduct[theParameter]; - - for (auto& value : splitValues) { - boost::trim(value); - list.push_back(storm::utility::convertNumber::type>(value)); - } - } - - STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples."); - } - - return sampleInfo; - } - - template - std::pair, bool> preprocessSparseModel(std::shared_ptr> const& model, SymbolicInput const& input) { - auto generalSettings = storm::settings::getModule(); - auto bisimulationSettings = storm::settings::getModule(); - auto parametricSettings = storm::settings::getModule(); - - std::pair, bool> result = std::make_pair(model, false); - - if (result.first->isOfType(storm::models::ModelType::MarkovAutomaton)) { - result.first = storm::cli::preprocessSparseMarkovAutomaton(result.first->template as>()); - result.second = true; - } + void setUrgentOptions() { - if (generalSettings.isBisimulationSet()) { - result.first = storm::cli::preprocessSparseModelBisimulation(result.first->template as>(), input, bisimulationSettings); - result.second = true; - } - - if (parametricSettings.transformContinuousModel() && (result.first->isOfType(storm::models::ModelType::Ctmc) || result.first->isOfType(storm::models::ModelType::MarkovAutomaton))) { - result.first = storm::api::transformContinuousToDiscreteTimeSparseModel(std::move(*result.first->template as>()), storm::api::extractFormulasFromProperties(input.properties)); - result.second = true; - } - - return result; - } - - template - std::pair, bool> preprocessDdModel(std::shared_ptr> const& model, SymbolicInput const& input) { - - std::pair, bool> result = std::make_pair(model, false); - - auto coreSettings = storm::settings::getModule(); - if (coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Hybrid) { - // Currently, hybrid engine for parametric models just referrs to building the model symbolically. - STORM_LOG_INFO("Translating symbolic model to sparse model..."); - result.first = storm::api::transformSymbolicToSparseModel(model); - result.second = true; - // Invoke preprocessing on the sparse model - auto sparsePreprocessingResult = storm::pars::preprocessSparseModel(result.first->as>(), input); - if (sparsePreprocessingResult.second) { - result.first = sparsePreprocessingResult.first; - } - } - return result; - } - - template - std::pair, bool> preprocessModel(std::shared_ptr const& model, SymbolicInput const& input) { - storm::utility::Stopwatch preprocessingWatch(true); - - std::pair, bool> result = std::make_pair(model, false); - if (model->isSparseModel()) { - result = storm::pars::preprocessSparseModel(result.first->as>(), input); + // Set the correct log level + if (storm::settings::getModule().isStdOutOutputEnabled()) { + storm::utility::setLogLevel(l3pp::LogLevel::OFF); } else { - STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - result = storm::pars::preprocessDdModel(result.first->as>(), input); - } - - if (result.second) { - STORM_PRINT_AND_LOG(std::endl << "Time for model preprocessing: " << preprocessingWatch << "." << std::endl << std::endl); - } - return result; - } - - template - void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation const* valuation = nullptr) { - if (result) { - STORM_PRINT_AND_LOG("Result (initial states)"); - if (valuation) { - bool first = true; - std::stringstream ss; - for (auto const& entry : *valuation) { - if (!first) { - ss << ", "; - } else { - first = false; - } - ss << entry.first << "=" << entry.second; - } - - STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]"); + auto const& general = storm::settings::getModule(); + if (general.isVerboseSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::INFO); } - STORM_PRINT_AND_LOG(": ") - - auto const* regionCheckResult = dynamic_cast const*>(result.get()); - if (regionCheckResult != nullptr) { - auto regionSettings = storm::settings::getModule(); - std::stringstream outStream; - if (regionSettings.isPrintFullResultSet()) { - regionCheckResult->writeToStream(outStream); - } else { - regionCheckResult->writeCondensedToStream(outStream); - } - outStream << std::endl; - if (!regionSettings.isPrintNoIllustrationSet()) { - auto const* regionRefinementCheckResult = dynamic_cast const*>(regionCheckResult); - if (regionRefinementCheckResult != nullptr) { - regionRefinementCheckResult->writeIllustrationToStream(outStream); - } - } - outStream << std::endl; - STORM_PRINT_AND_LOG(outStream.str()); - } else { - STORM_PRINT_AND_LOG(*result << std::endl); + if (general.isDebugOutputSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::DEBUG); } - if (watch) { - STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl << std::endl); + if (general.isTraceOutputSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::TRACE); } - } else { - STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); } } - template - void verifyProperties(std::vector const& properties, std::function(std::shared_ptr const& formula)> const& verificationCallback, std::function const&)> const& postprocessingCallback) { - for (auto const& property : properties) { - storm::cli::printModelCheckingProperty(property); - storm::utility::Stopwatch watch(true); - std::unique_ptr result = verificationCallback(property.getRawFormula()); - watch.stop(); - printInitialStatesResult(result, property, &watch); - postprocessingCallback(result); - } - } - - template class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double> - void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation const& samples) { + void processPrismInputJaniOutput(storm::prism::Program const& prismProg, std::vector const& properties) { - // When samples are provided, we create an instantiation model checker. - ModelCheckerType modelchecker(model); - - for (auto const& property : input.properties) { - storm::cli::printModelCheckingProperty(property); - - modelchecker.specifyFormula(storm::api::createTask(property.getRawFormula(), true)); - modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving); - - storm::utility::parametric::Valuation valuation; - - std::vector::type> parameters; - std::vector::type>::const_iterator> iterators; - std::vector::type>::const_iterator> iteratorEnds; - - storm::utility::Stopwatch watch(true); - for (auto const& product : samples.cartesianProducts) { - parameters.clear(); - iterators.clear(); - iteratorEnds.clear(); - - for (auto const& entry : product) { - parameters.push_back(entry.first); - iterators.push_back(entry.second.cbegin()); - iteratorEnds.push_back(entry.second.cend()); - } - - bool done = false; - while (!done) { - // Read off valuation. - for (uint64_t i = 0; i < parameters.size(); ++i) { - valuation[parameters[i]] = *iterators[i]; - } - - storm::utility::Stopwatch valuationWatch(true); - std::unique_ptr result = modelchecker.check(Environment(), valuation); - valuationWatch.stop(); - - if (result) { - result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates())); - } - printInitialStatesResult(result, property, &valuationWatch, &valuation); - - for (uint64_t i = 0; i < parameters.size(); ++i) { - ++iterators[i]; - if (iterators[i] == iteratorEnds[i]) { - // Reset iterator and proceed to move next iterator. - iterators[i] = product.at(parameters[i]).cbegin(); - - // If the last iterator was removed, we are done. - if (i == parameters.size() - 1) { - done = true; - } - } else { - // If an iterator was moved but not reset, we have another valuation to check. - break; - } - } - - } - } - - watch.stop(); - STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl); - } - } - - template - void verifyPropertiesAtSamplePoints(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { - if (model->isOfType(storm::models::ModelType::Dtmc)) { - verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); - } else if (model->isOfType(storm::models::ModelType::Ctmc)) { - verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); - } else if (model->isOfType(storm::models::ModelType::Ctmc)) { - verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); - } - } - - template - void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + storm::converter::PrismToJaniConverterOptions options; + options.allVariablesGlobal = true; + // TODO: fill in options + auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); + - if (samples.empty()) { - verifyProperties(input.properties, - [&model] (std::shared_ptr const& formula) { - std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); - if (result) { - result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); - } - return result; - }, - [&model] (std::unique_ptr const& result) { - auto parametricSettings = storm::settings::getModule(); - if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmc = model->template as>(); - boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; - storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); - } - }); - } else { - STORM_LOG_TRACE("Sampling the model at given points."); - - if (samples.exact) { - verifyPropertiesAtSamplePoints(model, input, samples); - } else { - verifyPropertiesAtSamplePoints(model, input, samples); + auto const& output = storm::settings::getModule(); + auto const& input = storm::settings::getModule(); + std::string outputFilename = ""; + if (output.isJaniOutputFilenameSet()) { + outputFilename = output.getJaniOutputFilename(); + } else if (input.isPrismInputSet() && !output.isStdOutOutputEnabled()) { + std::string suffix = ""; + if (input.isConstantsSet()) { + suffix = input.getConstantDefinitionString(); + std::replace(suffix.begin(), suffix.end(), ',', '_'); } + suffix = suffix + ".jani"; + outputFilename = input.getPrismInputFilename() + suffix; } - } - - template - void verifyRegionsWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions) { - STORM_LOG_ASSERT(!regions.empty(), "Can not analyze an empty set of regions."); - auto parametricSettings = storm::settings::getModule(); - auto regionSettings = storm::settings::getModule(); - - std::function(std::shared_ptr const& formula)> verificationCallback; - std::function const&)> postprocessingCallback; - - STORM_PRINT_AND_LOG(std::endl); - if (regionSettings.isHypothesisSet()) { - STORM_PRINT_AND_LOG("Checking hypothesis " << regionSettings.getHypothesis() << " on "); - } else { - STORM_PRINT_AND_LOG("Analyzing "); + if (outputFilename != "") { + storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename); } - if (regions.size() == 1) { - STORM_PRINT_AND_LOG("parameter region " << regions.front()); - } else { - STORM_PRINT_AND_LOG(regions.size() << " parameter regions"); - } - auto engine = regionSettings.getRegionCheckEngine(); - STORM_PRINT_AND_LOG(" using " << engine); - - // Check the given set of regions with or without refinement - if (regionSettings.isRefineSet()) { - STORM_LOG_THROW(regions.size() == 1, storm::exceptions::NotSupportedException, "Region refinement is not supported for multiple initial regions."); - STORM_PRINT_AND_LOG(" with iterative refinement until " << (1.0 - regionSettings.getCoverageThreshold()) * 100.0 << "% is covered." << (regionSettings.isDepthLimitSet() ? " Depth limit is " + std::to_string(regionSettings.getDepthLimit()) + "." : "") << std::endl); - verificationCallback = [&] (std::shared_ptr const& formula) { - ValueType refinementThreshold = storm::utility::convertNumber(regionSettings.getCoverageThreshold()); - boost::optional optionalDepthLimit; - if (regionSettings.isDepthLimitSet()) { - optionalDepthLimit = regionSettings.getDepthLimit(); - } - std::unique_ptr> result = storm::api::checkAndRefineRegionWithSparseEngine(model, storm::api::createTask(formula, true), regions.front(), engine, refinementThreshold, optionalDepthLimit, regionSettings.getHypothesis()); - return result; - }; - } else { - STORM_PRINT_AND_LOG("." << std::endl); - verificationCallback = [&] (std::shared_ptr const& formula) { - std::unique_ptr result = storm::api::checkRegionsWithSparseEngine(model, storm::api::createTask(formula, true), regions, engine, regionSettings.getHypothesis()); - return result; - }; - } - - postprocessingCallback = [&] (std::unique_ptr const& result) { - if (parametricSettings.exportResultToFile()) { - storm::api::exportRegionCheckResultToFile(result, parametricSettings.exportResultPath()); - } - }; - verifyProperties(input.properties, verificationCallback, postprocessingCallback); - } - - template - void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { - if (regions.empty()) { - storm::pars::verifyPropertiesWithSparseEngine(model, input, samples); - } else { - storm::pars::verifyRegionsWithSparseEngine(model, input, regions); + if (output.isStdOutOutputEnabled()) { + storm::api::printJaniToStream(janiModelProperties.first, janiModelProperties.second, std::cout); } } - template - void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { - STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); - storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); - } - - template - void processInputWithValueTypeAndDdlib(SymbolicInput& input) { - auto coreSettings = storm::settings::getModule(); - auto ioSettings = storm::settings::getModule(); + void processPrismInput() { + auto const& input = storm::settings::getModule(); - auto buildSettings = storm::settings::getModule(); - auto parSettings = storm::settings::getModule(); - - auto engine = coreSettings.getEngine(); - STORM_LOG_THROW(engine == storm::settings::modules::CoreSettings::Engine::Sparse || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::Dd, storm::exceptions::InvalidSettingsException, "The selected engine is not supported for parametric models."); - - std::shared_ptr model; - if (!buildSettings.isNoBuildModelSet()) { - model = storm::cli::buildModel(engine, input, ioSettings); - } - - if (model) { - model->printModelInformationToStream(std::cout); - } - - STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); - - if (model) { - auto preprocessingResult = storm::pars::preprocessModel(model, input); - if (preprocessingResult.second) { - model = preprocessingResult.first; - model->printModelInformationToStream(std::cout); - } + // Parse the prism program + storm::storage::SymbolicModelDescription prismProg = storm::api::parseProgram(input.getPrismInputFilename(), input.isPrismCompatibilityEnabled()); + + // Parse properties (if available) + std::vector properties; + if (input.isPropertyInputSet()) { + boost::optional> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter()); + properties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), prismProg, propertyFilter); } - std::vector> regions = parseRegions(model); - std::string samplesAsString = parSettings.getSamples(); - SampleInformation samples; - if (!samplesAsString.empty()) { - samples = parseSamples(model, samplesAsString, parSettings.isSamplesAreGraphPreservingSet()); - samples.exact = parSettings.isSampleExactSet(); + // Substitute constant definitions in program and properties. + std::string constantDefinitionString = input.getConstantDefinitionString(); + auto constantDefinitions = prismProg.parseConstantDefinitions(constantDefinitionString); + prismProg = prismProg.preprocess(constantDefinitions); + if (!properties.empty()) { + properties = storm::api::substituteConstantsInProperties(properties, constantDefinitions); } - if (model) { - storm::cli::exportModel(model, input); - } - - if (parSettings.onlyObtainConstraints()) { - STORM_LOG_THROW(parSettings.exportResultToFile(), storm::exceptions::InvalidSettingsException, "When computing constraints, export path has to be specified."); - storm::api::exportParametricResultToFile(boost::none, storm::analysis::ConstraintCollector(*(model->as>())), parSettings.exportResultPath()); - return; - } - - if (model) { - verifyParametricModel(model, input, regions, samples); + // Branch on the type of output + auto const& output = storm::settings::getModule(); + if (output.isJaniOutputSet()) { + processPrismInputJaniOutput(prismProg.asPrismProgram(), properties); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible."); } } void processOptions() { - // Start by setting some urgent options (log levels, resources, etc.) - storm::cli::setUrgentOptions(); - - // Parse and preprocess symbolic input (PRISM, JANI, properties, etc.) - SymbolicInput symbolicInput = storm::cli::parseAndPreprocessSymbolicInput(); + // Start by setting some urgent options (log levels, etc.) + setUrgentOptions(); - auto coreSettings = storm::settings::getModule(); - auto engine = coreSettings.getEngine(); - STORM_LOG_WARN_COND(engine != storm::settings::modules::CoreSettings::Engine::Dd || engine != storm::settings::modules::CoreSettings::Engine::Hybrid || coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "The selected DD library does not support parametric models. Switching to Sylvan..."); - - processInputWithValueTypeAndDdlib(symbolicInput); + // Branch on the type of input + auto const& input = storm::settings::getModule(); + if (input.isPrismInputSet()) { + processPrismInput(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Could not find a supported input format."); + } } - } } /*! - * Main entry point of the executable storm-pars. + * Main entry point of the executable storm-conv. */ int main(const int argc, const char** argv) { try { storm::utility::setUp(); - storm::cli::printHeader("Storm-pars", argc, argv); - storm::settings::initializeParsSettings("Storm-pars", "storm-pars"); - - storm::utility::Stopwatch totalTimer(true); + + // Print header info only if output to sdtout is disabled + bool outputToStdOut = false; + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--" + storm::settings::modules::ConversionOutputSettings::stdoutOptionName) { + outputToStdOut = false; + } + } + if (outputToStdOut) { + storm::utility::setLogLevel(l3pp::LogLevel::OFF); + } else { + storm::cli::printHeader("Storm-conv", argc, argv); + } + + storm::settings::initializeConvSettings("Storm-conv", "storm-conv"); if (!storm::cli::parseOptions(argc, argv)) { return -1; } - storm::pars::processOptions(); - - totalTimer.stop(); - if (storm::settings::getModule().isPrintTimeAndMemorySet()) { - storm::cli::printTimeAndMemoryStatistics(totalTimer.getTimeInMilliseconds()); - } + storm::conv::processOptions(); storm::utility::cleanUp(); return 0; } catch (storm::exceptions::BaseException const& exception) { - STORM_LOG_ERROR("An exception caused Storm-pars to terminate. The message of the exception is: " << exception.what()); + STORM_LOG_ERROR("An exception caused Storm-conv to terminate. The message of the exception is: " << exception.what()); return 1; } catch (std::exception const& exception) { - STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-pars to terminate. The message of this exception is: " << exception.what()); + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-conv to terminate. The message of this exception is: " << exception.what()); return 2; } } diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h index a1a32ac05..6e05795a8 100644 --- a/src/storm-conv/api/storm-conv.h +++ b/src/storm-conv/api/storm-conv.h @@ -1,4 +1,61 @@ #pragma once -#include "storm-pars/api/region.h" -#include "storm-pars/api/export.h" \ No newline at end of file +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" +#include "storm-conv/converter/options/JaniConversionOptions.h" + +#include "storm/storage/prism/Program.h" +#include "storm/storage/jani/Property.h" +#include "storm/storage/jani/JaniLocationExpander.h" +#include "storm/storage/jani/JSONExporter.h" + +namespace storm { + namespace api { + + void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options) { + + if (!options.locationVariables.empty()) { + for (auto const& pair : options.locationVariables) { + storm::jani::JaniLocationExpander expander(janiModel); + expander.transform(pair.first, pair.second); + janiModel = expander.getResult(); + } + } + + if (options.exportFlattened) { + janiModel = janiModel.flattenComposition(); + } + + if (options.standardCompliant) { + janiModel.makeStandardJaniCompliant(); + } + } + + std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()) { + std::pair> res; + + // Perform conversion + auto modelAndRenaming = program.toJaniWithLabelRenaming(options.allVariablesGlobal, options.suffix); + res.first = std::move(modelAndRenaming.first); + + // Amend properties to potentially changed labels + for (auto const& property : properties) { + res.second.emplace_back(property.substituteLabels(modelAndRenaming.second)); + } + + // Postprocess Jani model based on the options + postprocessJani(res.first, options.janiOptions); + + return res; + } + + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { + storm::jani::JsonExporter::toFile(model, properties, filename); + } + + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream) { + storm::jani::JsonExporter::toStream(model, properties, ostream); + } + + + } +} \ No newline at end of file diff --git a/src/storm-conv/converter/options/JaniConversionOptions.cpp b/src/storm-conv/converter/options/JaniConversionOptions.cpp new file mode 100644 index 000000000..8e9ba344d --- /dev/null +++ b/src/storm-conv/converter/options/JaniConversionOptions.cpp @@ -0,0 +1,11 @@ +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" + +namespace storm { + namespace converter { + + JaniConversionOptions::JaniConversionOptions() : standardCompliant(false), exportFlattened(false) { + // Intentionally left empty + }; + } +} + diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h new file mode 100644 index 000000000..ddd0d88cc --- /dev/null +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace storm { + namespace converter { + + struct JaniConversionOptions { + + JaniConversionOptions(); + + /// (Automaton,Variable)-pairs that will be transformed to location variables of the respective automaton. + std::vector> locationVariables; + + /// If set, the model will be made standard compliant (e.g. no state rewards for discrete time models) + bool standardCompliant; + + /// If set, the model is transformed into a single automaton + bool exportFlattened; + + }; + } +} + diff --git a/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp b/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp new file mode 100644 index 000000000..a64f9edbc --- /dev/null +++ b/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp @@ -0,0 +1,12 @@ +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" + + +namespace storm { + namespace converter { + + PrismToJaniConverterOptions::PrismToJaniConverterOptions() : allVariablesGlobal(false), suffix("") { + // Intentionally left empty + }; + } +} + diff --git a/src/storm-conv/converter/options/PrismToJaniConverterOptions.h b/src/storm-conv/converter/options/PrismToJaniConverterOptions.h new file mode 100644 index 000000000..0d3d02c85 --- /dev/null +++ b/src/storm-conv/converter/options/PrismToJaniConverterOptions.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "storm-conv/converter/options/JaniConversionOptions.h" + + +namespace storm { + namespace converter { + + + struct PrismToJaniConverterOptions { + + PrismToJaniConverterOptions(); + + bool allVariablesGlobal; + std::string suffix; + JaniConversionOptions janiOptions; + }; + } +} + diff --git a/src/storm-conv/settings/ConvSettings.cpp b/src/storm-conv/settings/ConvSettings.cpp new file mode 100644 index 000000000..0582b80d8 --- /dev/null +++ b/src/storm-conv/settings/ConvSettings.cpp @@ -0,0 +1,22 @@ +#include "storm-conv/settings/ConvSettings.h" + +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" +#include "storm-conv/settings/modules/ConversionInputSettings.h" +#include "storm-conv/settings/modules/ConversionOutputSettings.h" + +#include "storm/settings/SettingsManager.h" + + +namespace storm { + namespace settings { + void initializeParsSettings(std::string const& name, std::string const& executableName) { + storm::settings::mutableManager().setName(name, executableName); + + // Register relevant settings modules. + storm::settings::addModule(); + storm::settings::addModule(); + storm::settings::addModule(); + } + + } +} diff --git a/src/storm-conv/settings/ConvSettings.h b/src/storm-conv/settings/ConvSettings.h new file mode 100644 index 000000000..21cbcab31 --- /dev/null +++ b/src/storm-conv/settings/ConvSettings.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace storm { + namespace settings { + + void initializeConvSettings(std::string const& name, std::string const& executableName); + + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp b/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp new file mode 100644 index 000000000..4f1c65e74 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp @@ -0,0 +1,77 @@ +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionGeneralSettings::moduleName = "general"; + const std::string ConversionGeneralSettings::helpOptionName = "help"; + const std::string ConversionGeneralSettings::helpOptionShortName = "h"; + const std::string ConversionGeneralSettings::versionOptionName = "version"; + const std::string ConversionGeneralSettings::verboseOptionName = "verbose"; + const std::string ConversionGeneralSettings::verboseOptionShortName = "v"; + const std::string ConversionGeneralSettings::debugOptionName = "debug"; + const std::string ConversionGeneralSettings::traceOptionName = "trace"; + const std::string ConversionGeneralSettings::configOptionName = "config"; + const std::string ConversionGeneralSettings::configOptionShortName = "c"; + + ConversionGeneralSettings::ConversionGeneralSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, helpOptionName, false, "Shows all available options, arguments and descriptions.").setShortName(helpOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("hint", "A regular expression to show help for all matching entities or 'all' for the complete help.").setDefaultValueString("all").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, versionOptionName, false, "Prints the version information.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, verboseOptionName, false, "Enables more verbose output.").setShortName(verboseOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, false, "Enables verbose and debug output.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, traceOptionName, false, "Enables verbose and debug and trace output.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, configOptionName, false, "If given, this file will be read and parsed for additional configuration settings.").setShortName(configOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the configuration.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + } + + bool ConversionGeneralSettings::isHelpSet() const { + return this->getOption(helpOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isVersionSet() const { + return this->getOption(versionOptionName).getHasOptionBeenSet(); + } + + std::string ConversionGeneralSettings::getHelpModuleName() const { + return this->getOption(helpOptionName).getArgumentByName("hint").getValueAsString(); + } + + bool ConversionGeneralSettings::isVerboseSet() const { + return this->getOption(verboseOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isDebugOutputSet() const { + return this->getOption(debugOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isTraceOutputSet() const { + return this->getOption(traceOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isConfigSet() const { + return this->getOption(configOptionName).getHasOptionBeenSet(); + } + + std::string ConversionGeneralSettings::getConfigFilename() const { + return this->getOption(configOptionName).getArgumentByName("filename").getValueAsString(); + } + + void ConversionGeneralSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionGeneralSettings::check() const { + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionGeneralSettings.h b/src/storm-conv/settings/modules/ConversionGeneralSettings.h new file mode 100644 index 000000000..dc7e79f27 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionGeneralSettings.h @@ -0,0 +1,88 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionGeneralSettings : public ModuleSettings { + public: + + ConversionGeneralSettings(); + + /*! + * Retrieves whether the help option was set. + * + * @return True if the help option was set. + */ + bool isHelpSet() const; + + /*! + * Retrieves whether the version option was set. + * + * @return True if the version option was set. + */ + bool isVersionSet() const; + + /*! + * Retrieves the name of the module for which to show the help or "all" to indicate that the full help + * needs to be shown. + * + * @return The name of the module for which to show the help or "all". + */ + std::string getHelpModuleName() const; + + /*! + * Retrieves whether the verbose option was set. + * + * @return True if the verbose option was set. + */ + bool isVerboseSet() const; + + /*! + * Retrieves whether the debug output option was set. + * + */ + bool isDebugOutputSet() const; + + /*! + * Retrieves whether the trace output option was set. + * + */ + bool isTraceOutputSet() const; + + /*! + * Retrieves whether the config option was set. + * + * @return True if the config option was set. + */ + bool isConfigSet() const; + + /*! + * Retrieves the name of the file that is to be scanned for settings. + * + * @return The name of the file that is to be scanned for settings. + */ + std::string getConfigFilename() const; + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string helpOptionName; + static const std::string helpOptionShortName; + static const std::string versionOptionName; + static const std::string verboseOptionName; + static const std::string verboseOptionShortName; + static const std::string debugOptionName; + static const std::string traceOptionName; + static const std::string configOptionName; + static const std::string configOptionShortName; + }; + } + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.cpp b/src/storm-conv/settings/modules/ConversionInputSettings.cpp new file mode 100644 index 000000000..e608aa0f3 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionInputSettings.cpp @@ -0,0 +1,82 @@ +#include "storm-conv/settings/modules/ConversionInputSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/exceptions/InvalidSettingsException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionInputSettings::moduleName = "input"; + const std::string ConversionInputSettings::propertyOptionName = "prop"; + const std::string ConversionInputSettings::propertyOptionShortName = "prop"; + const std::string ConversionInputSettings::constantsOptionName = "constants"; + const std::string ConversionInputSettings::constantsOptionShortName = "const"; + const std::string ConversionInputSettings::prismInputOptionName = "prism"; + const std::string ConversionInputSettings::prismCompatibilityOptionName = "prismcompat"; + const std::string ConversionInputSettings::prismCompatibilityOptionShortName = "pc"; + + + ConversionInputSettings::ConversionInputSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the properties to be checked on the model.").setShortName(propertyOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("property or filename", "The formula or the file containing the formulas.").build()) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filter", "The names of the properties to check.").setDefaultValueString("all").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + ").").setShortName(constantsOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, prismCompatibilityOptionName, false, "Enables PRISM compatibility. This may be necessary to process some PRISM models.").setShortName(prismCompatibilityOptionShortName).build()); + } + + bool ConversionInputSettings::isPrismInputSet() const { + return this->getOption(prismInputOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getPrismInputFilename() const { + return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool ConversionInputSettings::isPrismCompatibilityEnabled() const { + return this->getOption(prismCompatibilityOptionName).getHasOptionBeenSet(); + } + + bool ConversionInputSettings::isConstantsSet() const { + return this->getOption(constantsOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getConstantDefinitionString() const { + return this->getOption(constantsOptionName).getArgumentByName("values").getValueAsString(); + } + + bool ConversionInputSettings::isPropertyInputSet() const { + return this->getOption(propertyOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getPropertyInput() const { + return this->getOption(propertyOptionName).getArgumentByName("property or filename").getValueAsString(); + } + + std::string ConversionInputSettings::getPropertyInputFilter() const { + return this->getOption(propertyOptionName).getArgumentByName("filter").getValueAsString(); + } + + void ConversionInputSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionInputSettings::check() const { + // Ensure that exactly one input is specified + STORM_LOG_THROW(isPrismInputSet(), storm::exceptions::InvalidSettingsException, "No Input specified."); + return true; + } + + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.h b/src/storm-conv/settings/modules/ConversionInputSettings.h new file mode 100644 index 000000000..41cf6549e --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionInputSettings.h @@ -0,0 +1,86 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionInputSettings : public ModuleSettings { + public: + + ConversionInputSettings(); + + /*! + * Retrieves whether the property option was set. + * + * @return True if the property option was set. + */ + bool isPropertyInputSet() const; + + /*! + * Retrieves the property specified with the property option. + * + * @return The property specified with the property option. + */ + std::string getPropertyInput() const; + + /*! + * Retrieves the property filter. + * + * @return The property filter. + */ + std::string getPropertyInputFilter() const; + + /*! + * Retrieves whether constant definition option was set. + * + * @return True if the constant definition option was set. + */ + bool isConstantsSet() const; + + /*! + * Retrieves the string that defines the constants of a symbolic model (given via the symbolic option). + * + * @return The string that defines the constants of a symbolic model. + */ + std::string getConstantDefinitionString() const; + + /*! + * Retrieves whether the PRISM language option was set. + */ + bool isPrismInputSet() const; + + /*! + * Retrieves the name of the file that contains the PRISM model specification if the model was given + * using the PRISM input option. + */ + std::string getPrismInputFilename() const; + + /*! + * Retrieves whether the PRISM compatibility mode was enabled. + * + * @return True iff the PRISM compatibility mode was enabled. + */ + bool isPrismCompatibilityEnabled() const; + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string propertyOptionName; + static const std::string propertyOptionShortName; + static const std::string constantsOptionName; + static const std::string constantsOptionShortName; + static const std::string prismInputOptionName; + static const std::string prismCompatibilityOptionName; + static const std::string prismCompatibilityOptionShortName; + }; + + + } + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionOutputSettings.cpp b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp new file mode 100644 index 000000000..958bdfdd9 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp @@ -0,0 +1,59 @@ +#include "storm-conv/settings/modules/ConversionOutputSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/InvalidOperationException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionOutputSettings::moduleName = "output"; + const std::string ConversionOutputSettings::stdoutOptionName = "stdout"; + const std::string ConversionOutputSettings::janiOutputOptionName = "tojani"; + + ConversionOutputSettings::ConversionOutputSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, stdoutOptionName, false, "If set, the output will be printed to stdout.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, janiOutputOptionName, false, "converts the input model to Jani.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "the name of the output file (if not empty).").setDefaultValueString("")).build()); + } + + bool ConversionOutputSettings::isStdOutOutputEnabled() const { + return this->getOption(stdoutOptionName).getHasOptionBeenSet(); + } + + bool ConversionOutputSettings::isJaniOutputSet() const { + return this->getOption(janiOutputOptionName).getHasOptionBeenSet(); + } + + bool ConversionOutputSettings::isJaniOutputFilenameSet() const { + return isJaniOutputSet() + && !this->getOption(janiOutputOptionName).getArgumentByName("filename").wasSetFromDefaultValue() + && this->getOption(janiOutputOptionName).getArgumentByName("filename").getHasBeenSet() + && this->getOption(janiOutputOptionName).getArgumentByName("filename").getValueAsString() != ""; + } + + std::string ConversionOutputSettings::getJaniOutputFilename() const { + STORM_LOG_THROW(isJaniOutputFilenameSet(), storm::exceptions::InvalidOperationException, "Tried to get the jani output name although none was specified."); + return this->getOption(janiOutputOptionName).getArgumentByName("filename").getValueAsString(); + } + + void ConversionOutputSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionOutputSettings::check() const { + // Ensure that exactly one Output is specified + STORM_LOG_THROW(isJaniOutputSet(), storm::exceptions::InvalidSettingsException, "No Output specified."); + STORM_LOG_THROW(!isJaniOutputFilenameSet() || ArgumentValidatorFactory::createWritableFileValidator()->isValid(getJaniOutputFilename()), storm::exceptions::InvalidSettingsException, "Unable to write at file " + getJaniOutputFilename()); + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionOutputSettings.h b/src/storm-conv/settings/modules/ConversionOutputSettings.h new file mode 100644 index 000000000..e429cdd93 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionOutputSettings.h @@ -0,0 +1,49 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionOutputSettings : public ModuleSettings { + public: + + ConversionOutputSettings(); + + /*! + * Retrieves whether the output should be printed to stdout + */ + bool isStdOutOutputEnabled() const; + + /*! + * Retrieves whether the output should be in the Jani format + */ + bool isJaniOutputSet() const; + + /*! + * Retrieves whether an output filename for the jani file was specified + */ + bool isJaniOutputFilenameSet() const; + + /*! + * Retrieves the name of the jani output (if specified) + */ + std::string getJaniOutputFilename() const; + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + // name of the option that enables output to stdout. It needs to be public because we have to check this option very early + static const std::string stdoutOptionName; + + private: + // Define the string names of the options as constants. + static const std::string janiOutputOptionName; + }; + + + } + } +} \ No newline at end of file diff --git a/src/storm/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp similarity index 96% rename from src/storm/settings/modules/JaniExportSettings.cpp rename to src/storm-conv/settings/modules/JaniExportSettings.cpp index a47a9914b..09e236431 100644 --- a/src/storm/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -26,8 +26,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Export in standard compliant variant.").build()); - + this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); } bool JaniExportSettings::isJaniFileSet() const { diff --git a/src/storm/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h similarity index 100% rename from src/storm/settings/modules/JaniExportSettings.h rename to src/storm-conv/settings/modules/JaniExportSettings.h From 86f0195b1821ea91e981109ddf82a231759ee172 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 15:38:34 +0200 Subject: [PATCH 425/647] removed jani conversion in cli of main binary --- src/storm-cli-utilities/model-handling.h | 7 ++---- src/storm/api/export.cpp | 25 ------------------- src/storm/api/export.h | 10 ++++---- .../storage/SymbolicModelDescription.cpp | 8 +++--- src/storm/storage/SymbolicModelDescription.h | 4 +-- src/storm/storage/prism/Program.cpp | 8 +++--- src/storm/storage/prism/Program.h | 4 +-- src/storm/storage/prism/ToJaniConverter.cpp | 5 ++-- src/storm/storage/prism/ToJaniConverter.h | 2 +- 9 files changed, 22 insertions(+), 51 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 4f41c4d4f..54381f7d4 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -17,6 +17,7 @@ #include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Property.h" #include "storm/models/ModelBase.h" @@ -129,7 +130,7 @@ namespace storm { if (transformToJani) { storm::prism::Program const& model = output.model.get().asPrismProgram(); - auto modelAndRenaming = model.toJaniWithLabelRenaming(true); + auto modelAndRenaming = model.toJaniWithLabelRenaming(true, "", false); output.model = modelAndRenaming.first; if (!modelAndRenaming.second.empty()) { @@ -153,10 +154,6 @@ namespace storm { if (ioSettings.isExportJaniDotSet()) { storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename()); } - - if (model.isJaniModel() && storm::settings::getModule().isJaniFileSet()) { - storm::api::exportJaniModel(model.asJaniModel(), input.properties, storm::settings::getModule().getJaniFilename()); - } } } diff --git a/src/storm/api/export.cpp b/src/storm/api/export.cpp index 1a69a34da..80d45ed2c 100644 --- a/src/storm/api/export.cpp +++ b/src/storm/api/export.cpp @@ -4,31 +4,6 @@ namespace storm { namespace api { - void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { - auto janiSettings = storm::settings::getModule(); - - storm::jani::Model exportModel = model; - if (janiSettings.isLocationVariablesSet()) { - for(auto const& pair : janiSettings.getLocationVariables()) { - storm::jani::JaniLocationExpander expander(exportModel); - expander.transform(pair.first, pair.second); - exportModel = expander.getResult(); - } - } - - if (janiSettings.isExportFlattenedSet()) { - exportModel = exportModel.flattenComposition(); - } - - if (janiSettings.isExportAsStandardJaniSet()) { - storm::jani::Model normalisedModel = exportModel; - normalisedModel.makeStandardJaniCompliant(); - storm::jani::JsonExporter::toFile(normalisedModel, properties, filename); - } else { - storm::jani::JsonExporter::toFile(exportModel, properties, filename); - } - } - void exportJaniModelAsDot(storm::jani::Model const& model, std::string const& filename) { std::ofstream out; storm::utility::openFile(filename, out); diff --git a/src/storm/api/export.h b/src/storm/api/export.h index 3ba81525d..825a9de48 100644 --- a/src/storm/api/export.h +++ b/src/storm/api/export.h @@ -1,8 +1,5 @@ #pragma once -#include "storm/storage/jani/JSONExporter.h" - - #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/JaniExportSettings.h" @@ -11,10 +8,13 @@ #include "storm/utility/macros.h" namespace storm { + + namespace jani { + class Model; + } + namespace api { - void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename); - void exportJaniModelAsDot(storm::jani::Model const& model, std::string const& filename); template diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index b08166125..79a12f8b1 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -119,23 +119,23 @@ namespace storm { return result; } - SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal) const { + SymbolicModelDescription SymbolicModelDescription::toJani(bool makeVariablesGlobal, bool standardCompliant) const { if (this->isJaniModel()) { return *this; } if (this->isPrismProgram()) { - return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal)); + return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal, "", standardCompliant)); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); } } - std::pair> SymbolicModelDescription::toJaniWithLabelRenaming(bool makeVariablesGlobal) const { + std::pair> SymbolicModelDescription::toJaniWithLabelRenaming(bool makeVariablesGlobal, bool standardCompliant) const { if (this->isJaniModel()) { return std::make_pair(*this, std::map()); } if (this->isPrismProgram()) { - auto modelAndRenaming = this->asPrismProgram().toJaniWithLabelRenaming(makeVariablesGlobal); + auto modelAndRenaming = this->asPrismProgram().toJaniWithLabelRenaming(makeVariablesGlobal, "", standardCompliant); return std::make_pair(SymbolicModelDescription(modelAndRenaming.first), modelAndRenaming.second); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); diff --git a/src/storm/storage/SymbolicModelDescription.h b/src/storm/storage/SymbolicModelDescription.h index 137f1a7d4..3ab94ba5d 100644 --- a/src/storm/storage/SymbolicModelDescription.h +++ b/src/storm/storage/SymbolicModelDescription.h @@ -38,8 +38,8 @@ namespace storm { std::vector getParameterNames() const; - SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const; - std::pair> toJaniWithLabelRenaming(bool makeVariablesGlobal = true) const; + SymbolicModelDescription toJani(bool makeVariablesGlobal = true, bool standardCompliant = false) const; + std::pair> toJaniWithLabelRenaming(bool makeVariablesGlobal = true, bool standardCompliant = false) const; SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const; SymbolicModelDescription preprocess(std::map const& constantDefinitions) const; diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index 228df8541..f12686315 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -1711,16 +1711,16 @@ namespace storm { return Command(newCommandIndex, false, actionIndex, actionName, newGuard, newUpdates, this->getFilename(), 0); } - storm::jani::Model Program::toJani(bool allVariablesGlobal, std::string suffix) const { + storm::jani::Model Program::toJani(bool allVariablesGlobal, std::string suffix, bool standardCompliant) const { ToJaniConverter converter; - storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix); + storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix, standardCompliant); STORM_LOG_WARN_COND(!converter.labelsWereRenamed(), "Labels were renamed in PRISM-to-JANI conversion, but the mapping is not stored."); return resultingModel; } - std::pair> Program::toJaniWithLabelRenaming(bool allVariablesGlobal, std::string suffix) const { + std::pair> Program::toJaniWithLabelRenaming(bool allVariablesGlobal, std::string suffix, bool standardCompliant) const { ToJaniConverter converter; - storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix); + storm::jani::Model resultingModel = converter.convert(*this, allVariablesGlobal, suffix, standardCompliant); return std::make_pair(resultingModel, converter.getLabelRenaming()); } diff --git a/src/storm/storage/prism/Program.h b/src/storm/storage/prism/Program.h index 4d6d303fc..3adc3151f 100644 --- a/src/storm/storage/prism/Program.h +++ b/src/storm/storage/prism/Program.h @@ -603,13 +603,13 @@ namespace storm { /*! * Converts the PRISM model into an equivalent JANI model. */ - storm::jani::Model toJani(bool allVariablesGlobal = false, std::string suffix = "") const; + storm::jani::Model toJani(bool allVariablesGlobal = true, std::string suffix = "", bool standardCompliant = false) const; /*! * Converts the PRISM model into an equivalent JANI model and retrieves possible label renamings that had * to be performed in the process. */ - std::pair> toJaniWithLabelRenaming(bool allVariablesGlobal = false, std::string suffix = "") const; + std::pair> toJaniWithLabelRenaming(bool allVariablesGlobal = true, std::string suffix = "", bool standardCompliant = false) const; private: /*! diff --git a/src/storm/storage/prism/ToJaniConverter.cpp b/src/storm/storage/prism/ToJaniConverter.cpp index 36a47d7f9..dca6584a1 100644 --- a/src/storm/storage/prism/ToJaniConverter.cpp +++ b/src/storm/storage/prism/ToJaniConverter.cpp @@ -8,7 +8,6 @@ #include "storm/storage/jani/TemplateEdge.h" #include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotImplementedException.h" @@ -16,10 +15,10 @@ namespace storm { namespace prism { - storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal, std::string suffix) { + storm::jani::Model ToJaniConverter::convert(storm::prism::Program const& program, bool allVariablesGlobal, std::string suffix, bool standardCompliant) { std::shared_ptr manager = program.getManager().getSharedPointer(); - bool produceStateRewards = !storm::settings::getModule().isExportAsStandardJaniSet() || program.getModelType() == storm::prism::Program::ModelType::CTMC; + bool produceStateRewards = !standardCompliant || program.getModelType() == storm::prism::Program::ModelType::CTMC || program.getModelType() == storm::prism::Program::ModelType::MA; // Start by creating an empty JANI model. storm::jani::ModelType modelType; diff --git a/src/storm/storage/prism/ToJaniConverter.h b/src/storm/storage/prism/ToJaniConverter.h index e68c9612e..2ba1c870f 100644 --- a/src/storm/storage/prism/ToJaniConverter.h +++ b/src/storm/storage/prism/ToJaniConverter.h @@ -14,7 +14,7 @@ namespace storm { class ToJaniConverter { public: - storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = false, std::string suffix = ""); + storm::jani::Model convert(storm::prism::Program const& program, bool allVariablesGlobal = true, std::string suffix = "", bool standardCompliant = false); bool labelsWereRenamed() const; std::map const& getLabelRenaming() const; From fbb734fbe2674aa539836f2d1c77030be94c6117 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 15:39:07 +0200 Subject: [PATCH 426/647] Fixed using settings without the 'general' module --- src/storm/settings/SettingsManager.cpp | 4 +--- src/storm/settings/SettingsManager.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index f18f76bb1..ebc0bc0da 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -34,7 +34,6 @@ #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/AbstractionSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" #include "storm/settings/modules/MultiplierSettings.h" @@ -138,7 +137,7 @@ namespace storm { } // Include the options from a possibly specified configuration file, but don't overwrite existing settings. - if (storm::settings::getModule().isConfigSet()) { + if (storm::settings::hasModule() && storm::settings::getModule().isConfigSet()) { this->setFromConfigurationFile(storm::settings::getModule().getConfigFilename()); } @@ -546,7 +545,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm/settings/SettingsManager.h b/src/storm/settings/SettingsManager.h index 1ccb10bfa..1e02e4471 100644 --- a/src/storm/settings/SettingsManager.h +++ b/src/storm/settings/SettingsManager.h @@ -270,6 +270,20 @@ namespace storm { return dynamic_cast(manager().getModule(SettingsType::moduleName)); } + + /*! + * Returns true if the given module is registered. + * + */ + template + bool hasModule() { + static_assert(std::is_base_of::value, "Template argument must be derived from ModuleSettings"); + if (manager().hasModule(SettingsType::moduleName)) { + return dynamic_cast(&(manager().getModule(SettingsType::moduleName))) != nullptr; + } + return false; + } + /*! * Retrieves the core settings in a mutable form. This is only meant to be used for debug purposes or very * rare cases where it is necessary. From a4864f3c3dcaa615f392111335f6222b6721cbca Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 15:40:27 +0200 Subject: [PATCH 427/647] Using JaniExportSettings in storm-conv --- src/storm-conv-cli/storm-conv.cpp | 45 ++++++++++++++++--- src/storm-conv/api/storm-conv.h | 2 +- src/storm-conv/settings/ConvSettings.cpp | 4 +- .../modules/ConversionInputSettings.cpp | 2 - .../modules/ConversionOutputSettings.cpp | 4 +- .../settings/modules/JaniExportSettings.cpp | 11 ----- 6 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 97fbcdfaf..2c24a8721 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -16,6 +16,7 @@ #include "storm-cli-utilities/cli.h" +#include "storm/exceptions/OptionParserException.h" namespace storm { namespace conv { @@ -40,15 +41,18 @@ namespace storm { } void processPrismInputJaniOutput(storm::prism::Program const& prismProg, std::vector const& properties) { + auto const& output = storm::settings::getModule(); + auto const& input = storm::settings::getModule(); + auto const& jani = storm::settings::getModule(); storm::converter::PrismToJaniConverterOptions options; options.allVariablesGlobal = true; - // TODO: fill in options + options.suffix = ""; + options.janiOptions.standardCompliant = jani.isExportAsStandardJaniSet(); + options.janiOptions.locationVariables = jani.getLocationVariables(); + options.janiOptions.exportFlattened = jani.isExportFlattenedSet(); auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); - - auto const& output = storm::settings::getModule(); - auto const& input = storm::settings::getModule(); std::string outputFilename = ""; if (output.isJaniOutputFilenameSet()) { outputFilename = output.getJaniOutputFilename(); @@ -116,6 +120,35 @@ namespace storm { } } +bool parseOptions(const int argc, const char* argv[]) { + try { + storm::settings::mutableManager().setFromCommandLine(argc, argv); + } catch (storm::exceptions::OptionParserException& e) { + storm::settings::manager().printHelp(); + throw e; + return false; + } + + auto const& general = storm::settings::getModule(); + + // Set options from config file (if given) + if (general.isConfigSet()) { + storm::settings::mutableManager().setFromConfigurationFile(general.getConfigFilename()); + } + + bool result = true; + if (general.isHelpSet()) { + storm::settings::manager().printHelp(general.getHelpModuleName()); + result = false; + } + + if (general.isVersionSet()) { + storm::cli::printVersion("storm-conv"); + result = false;; + } + + return result; +} /*! * Main entry point of the executable storm-conv. @@ -129,7 +162,7 @@ int main(const int argc, const char** argv) { bool outputToStdOut = false; for (int i = 1; i < argc; ++i) { if (std::string(argv[i]) == "--" + storm::settings::modules::ConversionOutputSettings::stdoutOptionName) { - outputToStdOut = false; + outputToStdOut = true; } } if (outputToStdOut) { @@ -139,7 +172,7 @@ int main(const int argc, const char** argv) { } storm::settings::initializeConvSettings("Storm-conv", "storm-conv"); - if (!storm::cli::parseOptions(argc, argv)) { + if (!parseOptions(argc, argv)) { return -1; } diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h index 6e05795a8..499777517 100644 --- a/src/storm-conv/api/storm-conv.h +++ b/src/storm-conv/api/storm-conv.h @@ -34,7 +34,7 @@ namespace storm { std::pair> res; // Perform conversion - auto modelAndRenaming = program.toJaniWithLabelRenaming(options.allVariablesGlobal, options.suffix); + auto modelAndRenaming = program.toJaniWithLabelRenaming(options.allVariablesGlobal, options.suffix, options.janiOptions.standardCompliant); res.first = std::move(modelAndRenaming.first); // Amend properties to potentially changed labels diff --git a/src/storm-conv/settings/ConvSettings.cpp b/src/storm-conv/settings/ConvSettings.cpp index 0582b80d8..cbb872390 100644 --- a/src/storm-conv/settings/ConvSettings.cpp +++ b/src/storm-conv/settings/ConvSettings.cpp @@ -3,19 +3,21 @@ #include "storm-conv/settings/modules/ConversionGeneralSettings.h" #include "storm-conv/settings/modules/ConversionInputSettings.h" #include "storm-conv/settings/modules/ConversionOutputSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm/settings/SettingsManager.h" namespace storm { namespace settings { - void initializeParsSettings(std::string const& name, std::string const& executableName) { + void initializeConvSettings(std::string const& name, std::string const& executableName) { storm::settings::mutableManager().setName(name, executableName); // Register relevant settings modules. storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.cpp b/src/storm-conv/settings/modules/ConversionInputSettings.cpp index e608aa0f3..cc91d597c 100644 --- a/src/storm-conv/settings/modules/ConversionInputSettings.cpp +++ b/src/storm-conv/settings/modules/ConversionInputSettings.cpp @@ -71,8 +71,6 @@ namespace storm { } bool ConversionInputSettings::check() const { - // Ensure that exactly one input is specified - STORM_LOG_THROW(isPrismInputSet(), storm::exceptions::InvalidSettingsException, "No Input specified."); return true; } diff --git a/src/storm-conv/settings/modules/ConversionOutputSettings.cpp b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp index 958bdfdd9..61002078d 100644 --- a/src/storm-conv/settings/modules/ConversionOutputSettings.cpp +++ b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp @@ -20,7 +20,7 @@ namespace storm { ConversionOutputSettings::ConversionOutputSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, stdoutOptionName, false, "If set, the output will be printed to stdout.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, janiOutputOptionName, false, "converts the input model to Jani.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "the name of the output file (if not empty).").setDefaultValueString("")).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "the name of the output file (if not empty).").setDefaultValueString("").build()).build()); } bool ConversionOutputSettings::isStdOutOutputEnabled() const { @@ -48,8 +48,6 @@ namespace storm { } bool ConversionOutputSettings::check() const { - // Ensure that exactly one Output is specified - STORM_LOG_THROW(isJaniOutputSet(), storm::exceptions::InvalidSettingsException, "No Output specified."); STORM_LOG_THROW(!isJaniOutputFilenameSet() || ArgumentValidatorFactory::createWritableFileValidator()->isValid(getJaniOutputFilename()), storm::exceptions::InvalidSettingsException, "Unable to write at file " + getJaniOutputFilename()); return true; } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 09e236431..e9a9f9882 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -14,8 +14,6 @@ namespace storm { namespace modules { const std::string JaniExportSettings::moduleName = "exportJani"; - const std::string JaniExportSettings::janiFileOptionName = "jani-output"; - const std::string JaniExportSettings::janiFileOptionShortName = "output"; const std::string JaniExportSettings::standardCompliantOptionName = "standard-compliant"; const std::string JaniExportSettings::standardCompliantOptionShortName = "standard"; const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; @@ -23,20 +21,11 @@ namespace storm { JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { - this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); } - bool JaniExportSettings::isJaniFileSet() const { - return this->getOption(janiFileOptionName).getHasOptionBeenSet(); - } - - std::string JaniExportSettings::getJaniFilename() const { - return this->getOption(janiFileOptionName).getArgumentByName("filename").getValueAsString(); - } - bool JaniExportSettings::isExportAsStandardJaniSet() const { return this->getOption(standardCompliantOptionName).getHasOptionBeenSet(); } From 35aa166f5b63aede8a75a31a849ffd04f179615b Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 18:10:28 +0200 Subject: [PATCH 428/647] added possibility to check all available jani properties --- src/storm-cli-utilities/model-handling.h | 14 ++++++++++---- src/storm/settings/modules/IOSettings.cpp | 6 +++++- src/storm/settings/modules/IOSettings.h | 8 +++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 54381f7d4..8f3d44c55 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -67,10 +67,16 @@ namespace storm { auto const& janiPropertyInput = janiInput.second; if (ioSettings.isJaniPropertiesSet()) { - for (auto const& propName : ioSettings.getJaniProperties()) { - auto propertyIt = janiPropertyInput.find(propName); - STORM_LOG_THROW(propertyIt != janiPropertyInput.end(), storm::exceptions::InvalidArgumentException, "No JANI property with name '" << propName << "' is known."); - input.properties.emplace_back(propertyIt->second); + if (ioSettings.areJaniPropertiesSelected()) { + for (auto const& propName : ioSettings.getSelectedJaniProperties()) { + auto propertyIt = janiPropertyInput.find(propName); + STORM_LOG_THROW(propertyIt != janiPropertyInput.end(), storm::exceptions::InvalidArgumentException, "No JANI property with name '" << propName << "' is known."); + input.properties.emplace_back(propertyIt->second); + } + } else { + for (auto const& property : janiPropertyInput) { + input.properties.emplace_back(property.second); + } } } } diff --git a/src/storm/settings/modules/IOSettings.cpp b/src/storm/settings/modules/IOSettings.cpp index 658b59cbe..2dabdbdb9 100644 --- a/src/storm/settings/modules/IOSettings.cpp +++ b/src/storm/settings/modules/IOSettings.cpp @@ -207,7 +207,11 @@ namespace storm { return this->getOption(janiPropertyOptionName).getHasOptionBeenSet(); } - std::vector IOSettings::getJaniProperties() const { + bool IOSettings::areJaniPropertiesSelected() const { + return this->getOption(janiPropertyOptionName).getHasOptionBeenSet() && (this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString() != ""); + } + + std::vector IOSettings::getSelectedJaniProperties() const { return storm::parser::parseCommaSeperatedValues(this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString()); } diff --git a/src/storm/settings/modules/IOSettings.h b/src/storm/settings/modules/IOSettings.h index cc41176bf..09ed02acb 100644 --- a/src/storm/settings/modules/IOSettings.h +++ b/src/storm/settings/modules/IOSettings.h @@ -233,10 +233,16 @@ namespace storm { */ bool isJaniPropertiesSet() const; + /*! + * Retrieves whether one or more jani-properties have been selected + * @return + */ + bool areJaniPropertiesSelected() const; + /*! * @return The names of the jani properties to check */ - std::vector getJaniProperties() const; + std::vector getSelectedJaniProperties() const; /*! * Retrieves whether the property option was set. From 31efde52c22c4e64118b076245d9c975604f4b40 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 18:11:25 +0200 Subject: [PATCH 429/647] fixed case where no location variables were provided --- .../settings/modules/JaniExportSettings.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index e9a9f9882..5e56ed782 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -39,15 +39,17 @@ namespace storm { } std::vector> JaniExportSettings::getLocationVariables() const { - std::string argument = this->getOption(locationVariablesOptionName).getArgumentByName("variables").getValueAsString(); - std::vector arguments; - boost::split( arguments, argument, boost::is_any_of(",")); std::vector> result; - for (auto const& pair : arguments) { - std::vector keyvaluepair; - boost::split( keyvaluepair, pair, boost::is_any_of(".")); - STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::IllegalArgumentException, "Expected a name of the form AUTOMATON.VARIABLE (with no further dots) but got " << pair); - result.emplace_back(keyvaluepair.at(0), keyvaluepair.at(1)); + if (isLocationVariablesSet()) { + std::string argument = this->getOption(locationVariablesOptionName).getArgumentByName("variables").getValueAsString(); + std::vector arguments; + boost::split( arguments, argument, boost::is_any_of(",")); + for (auto const& pair : arguments) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of(".")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::IllegalArgumentException, "Expected a name of the form AUTOMATON.VARIABLE (with no further dots) but got " << pair); + result.emplace_back(keyvaluepair.at(0), keyvaluepair.at(1)); + } } return result; } From 636d92894c761d0bc306e4684372ad9b7cedc932 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 24 Jul 2018 18:12:47 +0200 Subject: [PATCH 430/647] Fixed an issue with time bounded properties specified in jani --- src/storm-parsers/parser/JaniParser.cpp | 37 ++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index aa97e38f7..d11c158f7 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -349,27 +349,32 @@ namespace storm { } if (propertyStructure.count("step-bounds") > 0) { storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports step-bounded until with an upper bound"); - if(pi.hasLowerBound()) { - STORM_LOG_THROW(pi.lowerBound.evaluateAsInt() == 0, storm::exceptions::NotSupportedException, "Storm only supports step-bounded until without a (non-trivial) lower-bound"); + boost::optional lowerBound, upperBound; + if (pi.hasLowerBound()) { + int64_t lowerBoundInt = pi.lowerBound.evaluateAsInt(); + STORM_LOG_THROW(lowerBoundInt >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); + lowerBound = storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound); } - int64_t upperBound = pi.upperBound.evaluateAsInt(); - if(pi.upperBoundStrict) { - upperBound--; + if (pi.hasUpperBound()) { + int64_t upperBoundInt = pi.upperBound.evaluateAsInt(); + STORM_LOG_THROW(upperBoundInt >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); + upperBound = storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound); } - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); - return std::make_shared(args[0], args[1], storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound), storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)); + return std::make_shared(args[0], args[1], lowerBound, upperBound, storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)); } else if (propertyStructure.count("time-bounds") > 0) { storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports time-bounded until with an upper bound."); - double lowerBound = 0.0; - if(pi.hasLowerBound()) { - lowerBound = pi.lowerBound.evaluateAsDouble(); + boost::optional lowerBound, upperBound; + if (pi.hasLowerBound()) { + double lowerBoundDouble = pi.lowerBound.evaluateAsInt(); + STORM_LOG_THROW(lowerBoundDouble >= 0, storm::exceptions::InvalidJaniException, "time-bounds cannot be negative"); + lowerBound = storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound); } - double upperBound = pi.upperBound.evaluateAsDouble(); - STORM_LOG_THROW(lowerBound >= 0, storm::exceptions::InvalidJaniException, "(Lower) time-bounds cannot be negative"); - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "(Upper) time-bounds cannot be negative"); - return std::make_shared(args[0], args[1], storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound), storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); + if (pi.hasUpperBound()) { + double upperBoundDouble = pi.upperBound.evaluateAsInt(); + STORM_LOG_THROW(upperBoundDouble >= 0, storm::exceptions::InvalidJaniException, "time-bounds cannot be negative"); + upperBound = storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound); + } + return std::make_shared(args[0], args[1], lowerBound, upperBound, storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); } else if (propertyStructure.count("reward-bounds") > 0 ) { std::vector> lowerBounds; From d343943cbd6be88d8e69a86f92478a40e41f7bbd Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 10:15:28 +0200 Subject: [PATCH 431/647] storm-conv should not fail if no input arguments were given --- src/storm-conv-cli/storm-conv.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 2c24a8721..211c727d0 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -113,8 +113,6 @@ namespace storm { auto const& input = storm::settings::getModule(); if (input.isPrismInputSet()) { processPrismInput(); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Could not find a supported input format."); } } } From 0fa361c39385d950c36c749c80708b1e79614577 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 10:22:36 +0200 Subject: [PATCH 432/647] displaying property name together with the property --- src/storm-cli-utilities/model-handling.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 8f3d44c55..412b909b6 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -512,7 +512,7 @@ namespace storm { } void printModelCheckingProperty(storm::jani::Property const& property) { - STORM_PRINT(std::endl << "Model checking property " << *property.getRawFormula() << " ..." << std::endl); + STORM_PRINT(std::endl << "Model checking property \"" << property.getName() << "\": " << *property.getRawFormula() << " ..." << std::endl); } template From 51c5c42319f51aa93cf7b4b2bbfdcd02772cac42 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 10:23:05 +0200 Subject: [PATCH 433/647] Fixed export of expected time properties to jani --- src/storm/storage/jani/JSONExporter.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 06a5e9b31..523294cb1 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -232,7 +232,11 @@ namespace storm { opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + if (f.getSubformula().isEventuallyFormula()) { + opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f); + } } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin"; opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); @@ -243,8 +247,11 @@ namespace storm { } else { if(f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); - + if (f.getSubformula().isEventuallyFormula()) { + opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f); + } } else { // TODO add checks opDecl["op"] = "Emin"; From 30d30a063ca47008afa32479d7ea6dcbb9ad07b1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 14:15:00 +0200 Subject: [PATCH 434/647] setting jani conversion options from settings --- src/storm-conv-cli/storm-conv.cpp | 4 +--- src/storm-conv/converter/options/JaniConversionOptions.cpp | 4 ++++ src/storm-conv/converter/options/JaniConversionOptions.h | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 211c727d0..e1199cc1d 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -48,9 +48,7 @@ namespace storm { storm::converter::PrismToJaniConverterOptions options; options.allVariablesGlobal = true; options.suffix = ""; - options.janiOptions.standardCompliant = jani.isExportAsStandardJaniSet(); - options.janiOptions.locationVariables = jani.getLocationVariables(); - options.janiOptions.exportFlattened = jani.isExportFlattenedSet(); + options.janiOptions = storm::converter::JaniConversionOptions(jani); auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); std::string outputFilename = ""; diff --git a/src/storm-conv/converter/options/JaniConversionOptions.cpp b/src/storm-conv/converter/options/JaniConversionOptions.cpp index 8e9ba344d..7b72c4797 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.cpp +++ b/src/storm-conv/converter/options/JaniConversionOptions.cpp @@ -6,6 +6,10 @@ namespace storm { JaniConversionOptions::JaniConversionOptions() : standardCompliant(false), exportFlattened(false) { // Intentionally left empty }; + + JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), standardCompliant(settings.isExportAsStandardJaniSet()), exportFlattened(settings.isExportFlattenedSet()) { + // Intentionally left empty + }; } } diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h index ddd0d88cc..bb809f1ea 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.h +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -2,6 +2,7 @@ #include #include +#include "storm-conv/settings/modules/JaniExportSettings.h" namespace storm { namespace converter { @@ -9,6 +10,7 @@ namespace storm { struct JaniConversionOptions { JaniConversionOptions(); + JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings); /// (Automaton,Variable)-pairs that will be transformed to location variables of the respective automaton. std::vector> locationVariables; From c268926568d0f2cde347e34eeafd88af84121108 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 14:15:42 +0200 Subject: [PATCH 435/647] storm-pars no longer uses export settings --- src/storm-pars/settings/ParsSettings.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index bf6065d62..d819f8e24 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -20,7 +20,6 @@ #include "storm/settings/modules/GameSolverSettings.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiplierSettings.h" @@ -49,7 +48,6 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); } From 4a7a82627f3978080c92a0b89d03ceece549015b Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 14:16:18 +0200 Subject: [PATCH 436/647] storm-gspn and storm-dft now use functionalities of storm-conv --- src/storm-dft/api/storm-dft.cpp | 33 ++++++++----------- src/storm-dft/settings/DftSettings.cpp | 2 +- src/storm-gspn-cli/storm-gspn.cpp | 8 +---- src/storm-gspn/CMakeLists.txt | 2 +- src/storm-gspn/api/storm-gspn.cpp | 14 +++++++- src/storm-gspn/api/storm-gspn.h | 4 ++- .../settings/modules/GSPNExportSettings.cpp | 11 ++++++- .../settings/modules/GSPNExportSettings.h | 11 ++++++- 8 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp index 91632739e..19c97a67f 100644 --- a/src/storm-dft/api/storm-dft.cpp +++ b/src/storm-dft/api/storm-dft.cpp @@ -34,25 +34,20 @@ namespace storm { storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - storm::api::handleGSPNExportSettings(*gspn); - - std::shared_ptr const& exprManager = gspn->getExpressionManager(); - storm::builder::JaniGSPNBuilder builder(*gspn); - storm::jani::Model* model = builder.build(); - storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); - - storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); - auto evtlFormula = std::make_shared(targetExpression); - auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - auto tbUntil = std::make_shared(tbFormula); - - auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); - auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - - storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); - if (janiSettings.isJaniFileSet()) { - storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); - } + storm::api::handleGSPNExportSettings(*gspn, [&]std::vector(storm::builder::JaniGSPNBuilder const& builder) { + std::shared_ptr const& exprManager = gspn->getExpressionManager(); + storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); + + storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); + auto evtlFormula = std::make_shared(targetExpression); + auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); + auto tbUntil = std::make_shared(tbFormula); + + auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); + auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); + return {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}; + } + ); delete model; delete gspn; diff --git a/src/storm-dft/settings/DftSettings.cpp b/src/storm-dft/settings/DftSettings.cpp index 361ccdc8f..b5c206d51 100644 --- a/src/storm-dft/settings/DftSettings.cpp +++ b/src/storm-dft/settings/DftSettings.cpp @@ -19,7 +19,7 @@ #include "storm/settings/modules/GameSolverSettings.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm-gspn/settings/modules/GSPNSettings.h" #include "storm-gspn/settings/modules/GSPNExportSettings.h" diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 46da4fea5..aff3a8fce 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -112,14 +112,8 @@ int main(const int argc, const char **argv) { gspn->setCapacities(capacities); } - storm::api::handleGSPNExportSettings(*gspn); + storm::api::handleGSPNExportSettings(*gspn, [&]std::vector(storm::builder::JaniGSPNBuilder const&) { return properties }); - if(storm::settings::getModule().isJaniFileSet()) { - storm::jani::Model* model = storm::api::buildJani(*gspn); - storm::api::exportJaniModel(*model, properties, storm::settings::getModule().getJaniFilename()); - delete model; - } - delete gspn; return 0; diff --git a/src/storm-gspn/CMakeLists.txt b/src/storm-gspn/CMakeLists.txt index 9312af543..a09b83621 100644 --- a/src/storm-gspn/CMakeLists.txt +++ b/src/storm-gspn/CMakeLists.txt @@ -12,7 +12,7 @@ file(GLOB_RECURSE STORM_GSPN_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-gspn/*/*.h) add_library(storm-gspn SHARED ${STORM_GSPN_SOURCES} ${STORM_GSPN_HEADERS}) list(APPEND STORM_TARGETS storm-gspn) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-gspn storm ${STORM_GSPN_LINK_LIBRARIES}) +target_link_libraries(storm-gspn storm storm-conv ${STORM_GSPN_LINK_LIBRARIES}) # installation install(TARGETS storm-gspn EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index 08796386b..7b4200189 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -3,6 +3,8 @@ #include "storm/settings/SettingsManager.h" #include "storm/utility/file.h" #include "storm-gspn/settings/modules/GSPNExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" +#include "storm-conv/api/storm-conv.h" namespace storm { @@ -13,7 +15,7 @@ namespace storm { return builder.build(); } - void handleGSPNExportSettings(storm::gspn::GSPN const& gspn) { + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, std::vector const& properties) { storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); if (exportSettings.isWriteToDotSet()) { std::ofstream fs; @@ -55,6 +57,16 @@ namespace storm { gspn.writeStatsToStream(fs); storm::utility::closeFile(fs); } + + if (exportSettings.isWriteToJaniSet()) { + auto const& jani = storm::settings::getModule(); + storm::converter::JaniConversionOptions options(jani); + + storm::jani::Model* model = storm::api::buildJani(gspn); + storm::api::postprocessJani(*model, options); + storm::api::exportJaniToFile(*model, properties, storm::settings::getModule().getWriteToJaniFilename()); + delete model; + } } } diff --git a/src/storm-gspn/api/storm-gspn.h b/src/storm-gspn/api/storm-gspn.h index 7687c35e4..7d2360946 100644 --- a/src/storm-gspn/api/storm-gspn.h +++ b/src/storm-gspn/api/storm-gspn.h @@ -12,6 +12,8 @@ namespace storm { */ storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn); - void handleGSPNExportSettings(storm::gspn::GSPN const& gspn); + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, + std::function(storm::builder::JaniGSPNBuilder const&)> const& janiProperyGetter = [](storm::builder::JaniGSPNBuilder const&) { return std::vector(); }); + } } diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp index 5b7653eef..295f963e2 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp @@ -1,5 +1,4 @@ #include "storm-gspn/settings/modules/GSPNExportSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/SettingMemento.h" @@ -20,6 +19,7 @@ namespace storm { const std::string GSPNExportSettings::writeToPnmlOptionName = "to-pnml"; const std::string GSPNExportSettings::writeToPnproOptionName = "to-pnpro"; const std::string GSPNExportSettings::writeToJsonOptionName = "to-json"; + const std::string GSPNExportSettings::writeToJaniOptionName = "to-jani"; const std::string GSPNExportSettings::writeStatsOptionName = "to-stats"; const std::string GSPNExportSettings::displayStatsOptionName = "show-stats"; @@ -31,6 +31,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, writeToPnmlOptionName, false, "Destination for the pnml output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToPnproOptionName, false, "Destination for the pnpro output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToJsonOptionName, false, "Destination for the json output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, writeToJaniOptionName, false, "Destination for the jani output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeStatsOptionName, false, "Destination for the stats file").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, displayStatsOptionName, false, "Print stats to stdout").build()); } @@ -67,6 +68,14 @@ namespace storm { return this->getOption(writeToJsonOptionName).getArgumentByName("filename").getValueAsString(); } + bool GSPNExportSettings::isWriteToJaniSet() const { + return this->getOption(writeToJaniOptionName).getHasOptionBeenSet(); + } + + std::string GSPNExportSettings::getWriteToJaniFilename() const { + return this->getOption(writeToJaniOptionName).getArgumentByName("filename").getValueAsString(); + } + bool GSPNExportSettings::isDisplayStatsSet() const { return this->getOption(displayStatsOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.h b/src/storm-gspn/settings/modules/GSPNExportSettings.h index ce203a841..fbe45a4eb 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.h +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.h @@ -10,7 +10,7 @@ namespace storm { class GSPNExportSettings : public ModuleSettings { public: /*! - * Creates a new JaniExport setting + * Creates a new GSPNExport setting */ GSPNExportSettings(); @@ -45,6 +45,14 @@ namespace storm { */ std::string getWriteToJsonFilename() const; + + bool isWriteToJaniSet() const; + + /** + * + */ + std::string getWriteToJaniFilename() const; + bool isDisplayStatsSet() const; bool isWriteStatsToFileSet() const; @@ -62,6 +70,7 @@ namespace storm { static const std::string writeToPnmlOptionName; static const std::string writeToPnproOptionName; static const std::string writeToJsonOptionName; + static const std::string writeToJaniOptionName; static const std::string displayStatsOptionName; static const std::string writeStatsOptionName; From f0d11afdb8757006271f8c20b97db81f29e88461 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:46:19 +0200 Subject: [PATCH 437/647] fixed compilation of tests --- .../storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp | 2 ++ .../storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp | 2 ++ src/test/storm-pars/utility/ModelInstantiatorTest.cpp | 2 ++ .../SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp | 1 + .../modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp | 1 + .../modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp | 1 + .../modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp | 1 + .../SparseMdpMultiDimensionalRewardUnfoldingTest.cpp | 1 + .../SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp | 1 + 9 files changed, 12 insertions(+) diff --git a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp index 94bedf559..f77b61544 100644 --- a/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp +++ b/src/test/storm-pars/modelchecker/SparseDtmcParameterLiftingTest.cpp @@ -11,6 +11,8 @@ #include "storm-parsers/api/storm-parsers.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/storage/jani/Property.h" + namespace { class DoubleViEnvironment { diff --git a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp index 48e71fd0b..30b11f15d 100644 --- a/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp +++ b/src/test/storm-pars/modelchecker/SparseMdpParameterLiftingTest.cpp @@ -11,6 +11,8 @@ #include "storm-parsers/api/storm-parsers.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/storage/jani/Property.h" + namespace { class DoubleViEnvironment { diff --git a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp index fa7bb16eb..f9fbd1bf0 100644 --- a/src/test/storm-pars/utility/ModelInstantiatorTest.cpp +++ b/src/test/storm-pars/utility/ModelInstantiatorTest.cpp @@ -18,6 +18,8 @@ #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/storage/jani/Property.h" + TEST(ModelInstantiatorTest, BrpProb) { carl::VariablePool::getInstance().clear(); diff --git a/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp b/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp index 3a20c997b..7819ec7e0 100644 --- a/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp +++ b/src/test/storm/modelchecker/SparseDtmcMultiDimensionalRewardUnfoldingTest.cpp @@ -3,6 +3,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/models/sparse/Dtmc.h" +#include "storm/storage/jani/Property.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/utility/constants.h" diff --git a/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp index 4970fff9d..090a38ef5 100644 --- a/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMaCbMultiObjectiveModelCheckerTest.cpp @@ -5,6 +5,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/models/sparse/MarkovAutomaton.h" +#include "storm/storage/jani/Property.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" #include "storm/settings/SettingsManager.h" diff --git a/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp index 58c8e7494..be709707c 100644 --- a/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMaPcaaMultiObjectiveModelCheckerTest.cpp @@ -10,6 +10,7 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/storage/geometry/Polytope.h" #include "storm/storage/geometry/Hyperrectangle.h" +#include "storm/storage/jani/Property.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" #include "storm/settings/SettingsManager.h" diff --git a/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp index f353092af..51193af47 100644 --- a/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpCbMultiObjectiveModelCheckerTest.cpp @@ -4,6 +4,7 @@ #include "storm/modelchecker/multiobjective/multiObjectiveModelChecking.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/models/sparse/Mdp.h" +#include "storm/storage/jani/Property.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/api/storm.h" diff --git a/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp b/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp index 4880564b0..05faeb81c 100644 --- a/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpMultiDimensionalRewardUnfoldingTest.cpp @@ -8,6 +8,7 @@ #include "storm/models/sparse/Mdp.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" +#include "storm/storage/jani/Property.h" #include "storm/utility/constants.h" #include "storm/api/storm.h" #include "storm-parsers/api/storm-parsers.h" diff --git a/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp index 8e4cb084c..01c3edbc9 100644 --- a/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp +++ b/src/test/storm/modelchecker/SparseMdpPcaaMultiObjectiveModelCheckerTest.cpp @@ -9,6 +9,7 @@ #include "storm/models/sparse/Mdp.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/SettingsManager.h" +#include "storm/storage/jani/Property.h" #include "storm/api/storm.h" #include "storm-parsers/api/storm-parsers.h" #include "storm/environment/Environment.h" From d9ec0f8fcf2a72f77b1513a25aba43e7eb5b20f2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:46:46 +0200 Subject: [PATCH 438/647] removed include of old janiexportsettings --- src/storm/api/export.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm/api/export.h b/src/storm/api/export.h index 825a9de48..39a3ba1b3 100644 --- a/src/storm/api/export.h +++ b/src/storm/api/export.h @@ -1,7 +1,6 @@ #pragma once #include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/utility/DirectEncodingExporter.h" #include "storm/utility/file.h" From 9563cb44cbe5552317527d42997e266ba6c8bf3d Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:47:17 +0200 Subject: [PATCH 439/647] made storm-pgcl use storm-conv --- src/storm-pgcl-cli/storm-pgcl.cpp | 13 ++++++++----- src/storm-pgcl/CMakeLists.txt | 2 +- src/storm-pgcl/settings/modules/PGCLSettings.cpp | 7 ++++++- src/storm-pgcl/settings/modules/PGCLSettings.h | 5 +++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/storm-pgcl-cli/storm-pgcl.cpp b/src/storm-pgcl-cli/storm-pgcl.cpp index bfbb6cad4..5ae5248b3 100644 --- a/src/storm-pgcl-cli/storm-pgcl.cpp +++ b/src/storm-pgcl-cli/storm-pgcl.cpp @@ -18,7 +18,8 @@ #include "storm-pgcl/settings/modules/PGCLSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" +#include "storm-conv/api/storm-conv.h" #include "storm/utility/file.h" @@ -38,11 +39,13 @@ void initializeSettings() { } void handleJani(storm::jani::Model& model) { - if (!storm::settings::getModule().isJaniFileSet()) { - // For now, we have to have a jani file - storm::jani::JsonExporter::toStream(model, {}, std::cout); + auto const& jani = storm::settings::getModule(); + storm::converter::JaniConversionOptions options(jani); + storm::api::postprocessJani(model, options); + if (storm::settings::getModule().isToJaniSet()) { + storm::api::exportJaniToFile(model, {}, storm::settings::getModule().getWriteToJaniFilename()); } else { - storm::jani::JsonExporter::toFile(model, {}, storm::settings::getModule().getJaniFilename()); + storm::api::printJaniToStream(model, {}, std::cout); } } diff --git a/src/storm-pgcl/CMakeLists.txt b/src/storm-pgcl/CMakeLists.txt index 7b86f73c3..1adf442c6 100644 --- a/src/storm-pgcl/CMakeLists.txt +++ b/src/storm-pgcl/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB_RECURSE STORM_PGCL_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-pgcl/*/*.h) # Create storm-pgcl. add_library(storm-pgcl SHARED ${STORM_PGCL_SOURCES} ${STORM_PGCL_HEADERS}) -target_link_libraries(storm-pgcl storm storm-parsers) +target_link_libraries(storm-pgcl storm storm-parsers storm-conv) # installation install(TARGETS storm-pgcl EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pgcl/settings/modules/PGCLSettings.cpp b/src/storm-pgcl/settings/modules/PGCLSettings.cpp index a70b87f6f..4225dcd39 100644 --- a/src/storm-pgcl/settings/modules/PGCLSettings.cpp +++ b/src/storm-pgcl/settings/modules/PGCLSettings.cpp @@ -26,7 +26,7 @@ namespace storm { PGCLSettings::PGCLSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, pgclFileOptionName, false, "Parses the pgcl program.").setShortName(pgclFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, pgclToJaniOptionName, false, "Transform to JANI.").setShortName(pgclToJaniOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, pgclToJaniOptionName, false, "Transform to JANI.").setShortName(pgclToJaniOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, programGraphToDotOptionName, false, "Destination for the program graph dot output.").setShortName(programGraphToDotShortOptionName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, programVariableRestrictionsOptionName, false, "Restrictions of program variables").setShortName(programVariableRestrictionShortOptionName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("description", "description of the variable restrictions").build()).build()); } @@ -43,6 +43,11 @@ namespace storm { return this->getOption(pgclToJaniOptionName).getHasOptionBeenSet(); } + std::string const& PGCLSettings::getWriteToJaniFilename() const { + return this->getOption(pgclToJaniOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool PGCLSettings::isProgramGraphToDotSet() const { return this->getOption(programGraphToDotOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-pgcl/settings/modules/PGCLSettings.h b/src/storm-pgcl/settings/modules/PGCLSettings.h index 29e689366..5870ccbe5 100644 --- a/src/storm-pgcl/settings/modules/PGCLSettings.h +++ b/src/storm-pgcl/settings/modules/PGCLSettings.h @@ -29,6 +29,11 @@ namespace storm { */ bool isToJaniSet() const; + /** + * returns the file name where jani output should be stored. + */ + std::string const& getWriteToJaniFilename() const; + /** * Whether the program graph should be drawn (dot output) */ From 41645c3f9a599e51c0d4c87b7ba07bc25c6bc30e Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:47:47 +0200 Subject: [PATCH 440/647] including the correct .h file in storm-parsers api --- src/storm-parsers/api/properties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-parsers/api/properties.cpp b/src/storm-parsers/api/properties.cpp index d5349544d..425fee410 100644 --- a/src/storm-parsers/api/properties.cpp +++ b/src/storm-parsers/api/properties.cpp @@ -1,4 +1,4 @@ - +#include "storm-parsers/api/properties.h" #include "storm-parsers/parser/FormulaParser.h" #include "storm/api/properties.h" From 52fc8c8e35537e0dd9157e3fbbc45efd79df522a Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:48:09 +0200 Subject: [PATCH 441/647] removed unused setting --- src/storm-gspn/settings/modules/GSPNSettings.cpp | 7 ------- src/storm-gspn/settings/modules/GSPNSettings.h | 5 ----- 2 files changed, 12 deletions(-) diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index 2a0588b3d..74bd7e28f 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -36,10 +36,6 @@ namespace storm { return this->getOption(gspnFileOptionName).getArgumentByName("filename").getValueAsString(); } - bool GSPNSettings::isToJaniSet() const { - return this->getOption(gspnToJaniOptionName).getHasOptionBeenSet(); - } - bool GSPNSettings::isCapacitiesFileSet() const { return this->getOption(capacitiesFileOptionName).getHasOptionBeenSet(); } @@ -54,9 +50,6 @@ namespace storm { bool GSPNSettings::check() const { if(!isGspnFileSet()) { - if(isToJaniSet()) { - return false; - } if(isCapacitiesFileSet()) { return false; } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.h b/src/storm-gspn/settings/modules/GSPNSettings.h index f4ff4ff2c..161990bf8 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.h +++ b/src/storm-gspn/settings/modules/GSPNSettings.h @@ -24,11 +24,6 @@ namespace storm { */ std::string getGspnFilename() const; - /** - * Whether the gspn should be transformed to Jani - */ - bool isToJaniSet() const; - /** * Retrievew whether the pgcl file option was set */ From 8f179217d0502936e609d7af987d3e54f930f4b5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 30 Jul 2018 20:48:53 +0200 Subject: [PATCH 442/647] fixes for storm-dft and storm-gspn --- src/storm-dft/api/storm-dft.cpp | 6 +++--- src/storm-gspn-cli/storm-gspn.cpp | 2 +- src/storm-gspn/api/storm-gspn.cpp | 9 +++++---- src/storm-gspn/builder/JaniGSPNBuilder.h | 2 +- src/storm-gspn/settings/modules/GSPNSettings.cpp | 3 --- src/storm-gspn/settings/modules/GSPNSettings.h | 2 -- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp index 19c97a67f..72105a763 100644 --- a/src/storm-dft/api/storm-dft.cpp +++ b/src/storm-dft/api/storm-dft.cpp @@ -34,7 +34,7 @@ namespace storm { storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - storm::api::handleGSPNExportSettings(*gspn, [&]std::vector(storm::builder::JaniGSPNBuilder const& builder) { + storm::api::handleGSPNExportSettings(*gspn, [&](storm::builder::JaniGSPNBuilder const& builder) { std::shared_ptr const& exprManager = gspn->getExpressionManager(); storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); @@ -45,11 +45,11 @@ namespace storm { auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - return {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}; + std::vector res({storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}); + return res; } ); - delete model; delete gspn; } diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index aff3a8fce..4db249042 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -112,7 +112,7 @@ int main(const int argc, const char **argv) { gspn->setCapacities(capacities); } - storm::api::handleGSPNExportSettings(*gspn, [&]std::vector(storm::builder::JaniGSPNBuilder const&) { return properties }); + storm::api::handleGSPNExportSettings(*gspn, [&](storm::builder::JaniGSPNBuilder const&) { return properties; }); delete gspn; return 0; diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index 7b4200189..45e579db1 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -15,7 +15,7 @@ namespace storm { return builder.build(); } - void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, std::vector const& properties) { + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, std::function(storm::builder::JaniGSPNBuilder const&)> const& janiProperyGetter) { storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); if (exportSettings.isWriteToDotSet()) { std::ofstream fs; @@ -62,12 +62,13 @@ namespace storm { auto const& jani = storm::settings::getModule(); storm::converter::JaniConversionOptions options(jani); - storm::jani::Model* model = storm::api::buildJani(gspn); + storm::builder::JaniGSPNBuilder builder(gspn); + storm::jani::Model* model = builder.build(); + storm::api::postprocessJani(*model, options); - storm::api::exportJaniToFile(*model, properties, storm::settings::getModule().getWriteToJaniFilename()); + storm::api::exportJaniToFile(*model, janiProperyGetter(builder), storm::settings::getModule().getWriteToJaniFilename()); delete model; } } - } } diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.h b/src/storm-gspn/builder/JaniGSPNBuilder.h index 474d04807..db890e36c 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.h +++ b/src/storm-gspn/builder/JaniGSPNBuilder.h @@ -21,7 +21,7 @@ namespace storm { storm::jani::Model* build(std::string const& automatonName = "gspn_automaton"); - storm::jani::Variable const& getPlaceVariable(uint64_t placeId) { + storm::jani::Variable const& getPlaceVariable(uint64_t placeId) const { return *vars.at(placeId); } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index 74bd7e28f..2cca4b2f9 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -16,15 +16,12 @@ namespace storm { const std::string GSPNSettings::gspnFileOptionName = "gspnfile"; const std::string GSPNSettings::gspnFileOptionShortName = "gspn"; - const std::string GSPNSettings::gspnToJaniOptionName = "to-jani"; - const std::string GSPNSettings::gspnToJaniOptionShortName = "tj"; const std::string GSPNSettings::capacitiesFileOptionName = "capacitiesfile"; const std::string GSPNSettings::capacitiesFileOptionShortName = "capacities"; GSPNSettings::GSPNSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, gspnFileOptionName, false, "Parses the GSPN.").setShortName(gspnFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, gspnToJaniOptionName, false, "Transform to JANI.").setShortName(gspnToJaniOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacitiesFileOptionName, false, "Capacaties as invariants for places.").setShortName(capacitiesFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.h b/src/storm-gspn/settings/modules/GSPNSettings.h index 161990bf8..e5128c30e 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.h +++ b/src/storm-gspn/settings/modules/GSPNSettings.h @@ -43,8 +43,6 @@ namespace storm { private: static const std::string gspnFileOptionName; static const std::string gspnFileOptionShortName; - static const std::string gspnToJaniOptionName; - static const std::string gspnToJaniOptionShortName; static const std::string capacitiesFileOptionName; static const std::string capacitiesFileOptionShortName; From 01549dfdea0bd11c33d0f5fea97e056647ca4210 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 16:41:23 +0200 Subject: [PATCH 443/647] fixed segfaults when lifting transient destination assignments to the edge --- src/storm/storage/jani/TemplateEdge.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 89d56a0d3..6e5af6695 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -81,6 +81,8 @@ namespace storm { if (!destinations.empty()) { auto const& destination = *destinations.begin(); + std::vector> assignmentsToLift; + for (auto const& assignment : destination.getOrderedAssignments().getTransientAssignments()) { // Check if we can lift the assignment to the edge. bool canBeLifted = true; @@ -91,12 +93,18 @@ namespace storm { } } - // If so, remove the assignment from all destinations. if (canBeLifted) { - this->addTransientAssignment(assignment); - for (auto& destination : destinations) { - destination.removeAssignment(assignment); - } + // Do not remove the assignment now, as we currently iterate over them. + // Also we need to make a copy of the assignment since we are about to delete it + assignmentsToLift.push_back(std::make_shared(assignment)); + } + } + + // now actually lift the assignments + for (auto const& assignment : assignmentsToLift) { + this->addTransientAssignment(*assignment); + for (auto& destination : destinations) { + destination.removeAssignment(*assignment); } } } From fe71dfdf9b148f5c0786ebccb8eb4aa037fab837 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 16:42:01 +0200 Subject: [PATCH 444/647] added export of reward-bounded until formulas --- src/storm/storage/jani/JSONExporter.cpp | 60 +++++++++++++++++-------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 523294cb1..002c93165 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -179,32 +179,56 @@ namespace storm { return opDecl; } boost::any FormulaToJaniJson::visit(storm::logic::BoundedUntilFormula const& f, boost::any const& data) const { + STORM_LOG_THROW(!f.hasMultiDimensionalSubformulas(), storm::exceptions::NotSupportedException, "Jani export of multi-dimensional bounded until formulas is not supported."); modernjson::json opDecl; opDecl["op"] = "U"; opDecl["left"] = boost::any_cast(f.getLeftSubformula().accept(*this, data)); opDecl["right"] = boost::any_cast(f.getRightSubformula().accept(*this, data)); - boost::optional lower, upper; - boost::optional lowerExclusive, upperExclusive; - if (f.hasLowerBound()) { - lower = f.getLowerBound(); - lowerExclusive = f.isLowerBoundStrict(); - } - if (f.hasUpperBound()) { - upper = f.getUpperBound(); - upperExclusive = f.isUpperBoundStrict(); + bool hasStepBounds(false), hasTimeBounds(false); + std::vector rewardBounds; + + for (uint64_t i = 0; i < f.getDimension(); ++i) { + boost::optional lower, upper; + boost::optional lowerExclusive, upperExclusive; + if (f.hasLowerBound(i)) { + lower = f.getLowerBound(i); + lowerExclusive = f.isLowerBoundStrict(i); + } + if (f.hasUpperBound(i)) { + upper = f.getUpperBound(i); + upperExclusive = f.isUpperBoundStrict(i); + } + modernjson::json propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive); + + auto tbr = f.getTimeBoundReference(i); + if (tbr.isStepBound()) { + STORM_LOG_THROW(!hasStepBounds, storm::exceptions::NotSupportedException, "Jani export of until formulas with multiple step bounds is not supported."); + hasStepBounds = true; + opDecl["step-bounds"] = propertyInterval; + } else if(tbr.isRewardBound()) { + modernjson::json rewbound; + rewbound["exp"] = tbr.getRewardName(); + std::vector accvec; + if (model.isDiscreteTimeModel()) { + accvec.push_back("steps"); + } else { + accvec.push_back("time"); + } + rewbound["accumulate"] = modernjson::json(accvec); + rewbound["bounds"] = propertyInterval; + rewardBounds.push_back(std::move(rewbound)); + } else { + STORM_LOG_THROW(!hasTimeBounds, storm::exceptions::NotSupportedException, "Jani export of until formulas with multiple step bounds is not supported."); + hasTimeBounds = true; + opDecl["time-bounds"] = propertyInterval; + } } - modernjson::json propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive); - - auto tbr = f.getTimeBoundReference(); - if (tbr.isStepBound()) { - opDecl["step-bounds"] = propertyInterval; - } else if(tbr.isRewardBound()) { - opDecl["reward-bounds"] = propertyInterval; - } else { - opDecl["time-bounds"] = propertyInterval; + if (!rewardBounds.empty()) { + opDecl["reward-bounds"] = modernjson::json(rewardBounds); } return opDecl; + } boost::any FormulaToJaniJson::visit(storm::logic::ConditionalFormula const&, boost::any const&) const { From 5937131ff2a9625009057d6a9f789d86ba7ed6d8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 16:43:04 +0200 Subject: [PATCH 445/647] fixed and extended parsing of jani formulas with Emin or Emax operator --- src/storm-parsers/parser/JaniParser.cpp | 102 +++++++++++++++--------- 1 file changed, 65 insertions(+), 37 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index d11c158f7..4f3419ec4 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -228,13 +228,7 @@ namespace storm { } else { time = true; } - std::shared_ptr reach; - if (propertyStructure.count("reach") > 0) { - auto context = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; - reach = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Total reward is currently not supported"); - } + storm::logic::OperatorInformation opInfo; opInfo.optimalityType = opString == "Emin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; opInfo.bound = bound; @@ -257,6 +251,9 @@ namespace storm { if (propertyStructure.count("step-instant") > 0) { + STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + context); + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + context); + storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), "Step instant in " + context, globalVars, constants); STORM_LOG_THROW(!stepInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant step-instants"); @@ -278,6 +275,8 @@ namespace storm { } } } else if (propertyStructure.count("time-instant") > 0) { + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a time-instant and a reward-instant in " + context); + storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); STORM_LOG_THROW(!timeInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); @@ -299,41 +298,71 @@ namespace storm { } } } else if (propertyStructure.count("reward-instants") > 0) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Instant Reward for reward constraints not supported currently."); - } - - //STORM_LOG_THROW(!accTime && !accSteps, storm::exceptions::NotSupportedException, "Storm only allows accumulation if a step- or time-bound is given."); - - if (rewExpr.isVariable()) { - assert(!time); - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(reach, rewardName, opInfo); - } else if (!rewExpr.containsVariables()) { - assert(time); - assert(reach->isTimePathFormula()); - if(rewExpr.hasIntegerType()) { - if (rewExpr.evaluateAsInt() == 1) { - - return std::make_shared(reach, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); + std::vector bounds; + std::vector boundReferences; + for (auto const& rewInst : propertyStructure.at("reward-instants")) { + storm::expressions::Expression rewInstExpression = parseExpression(rewInst.at("exp"), "Reward expression in " + context, globalVars, constants); + STORM_LOG_THROW(!rewInstExpression.isVariable(), storm::exceptions::NotSupportedException, "Reward bounded cumulative reward formulas should only argue over reward expressions."); + boundReferences.emplace_back(rewInstExpression.getVariables().begin()->getName()); + bool rewInstAccSteps(false), rewInstAccTime(false); + for (auto const& accEntry : rewInst.at("accumulate")) { + if (accEntry == "steps") { + rewInstAccSteps = true; + } else if (accEntry == "time") { + rewInstAccTime = true; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time', got " << accEntry.dump() << " in " << context); + } } - } else if (rewExpr.hasRationalType()){ - if (rewExpr.evaluateAsDouble() == 1.0) { - - return std::make_shared(reach, opInfo); + STORM_LOG_THROW((rewInstAccTime && !rewInstAccSteps) || (!rewInstAccTime && rewInstAccSteps), storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); + storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); + STORM_LOG_THROW(!rewInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); + double rewInstant = rewInstantExpr.evaluateAsDouble(); + STORM_LOG_THROW(rewInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative reward-instants are allowed"); + bounds.emplace_back(false, rewInstantExpr); + } + if (rewExpr.isVariable()) { + std::string rewardName = rewExpr.getVariables().begin()->getName(); + return std::make_shared(std::make_shared(bounds, boundReferences), rewardName, opInfo); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); + } + } else { + std::shared_ptr subformula; + if (propertyStructure.count("reach") > 0) { + auto context = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; + subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context); + } else { + subformula = std::make_shared(); + } + if (rewExpr.isVariable()) { + assert(!time); + std::string rewardName = rewExpr.getVariables().begin()->getName(); + return std::make_shared(subformula, rewardName, opInfo); + } else if (!rewExpr.containsVariables()) { + assert(time); + assert(subformula->isTotalRewardFormula() || subformula->isTimePathFormula()); + if(rewExpr.hasIntegerType()) { + if (rewExpr.evaluateAsInt() == 1) { + return std::make_shared(subformula, opInfo); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); + } + } else if (rewExpr.hasRationalType()){ + if (rewExpr.evaluateAsDouble() == 1.0) { + + return std::make_shared(subformula, opInfo); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); + } } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Only numerical reward expressions are allowed"); } + } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Only numerical reward expressions are allowed"); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex reward expressions are supported at the moment"); } - - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex reward expressions are supported at the moment"); } - - } else if (opString == "Smin" || opString == "Smax") { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Smin and Smax are currently not supported"); } else if (opString == "U" || opString == "F") { @@ -382,7 +411,6 @@ namespace storm { std::vector tbReferences; for (auto const& rbStructure : propertyStructure.at("reward-bounds")) { storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports time-bounded until with an upper bound."); STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), "Reward expression in " + context, globalVars, constants); STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); From 56a5dcf7cb6d5acb62123277dd7bcf72f0c5e939 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 16:43:41 +0200 Subject: [PATCH 446/647] added setting in storm-conv to make variables global --- src/storm-conv-cli/storm-conv.cpp | 2 +- src/storm-conv/settings/modules/JaniExportSettings.cpp | 6 ++++++ src/storm-conv/settings/modules/JaniExportSettings.h | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index e1199cc1d..c398ef69a 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -46,7 +46,7 @@ namespace storm { auto const& jani = storm::settings::getModule(); storm::converter::PrismToJaniConverterOptions options; - options.allVariablesGlobal = true; + options.allVariablesGlobal = jani.isGlobalVarsSet(); options.suffix = ""; options.janiOptions = storm::converter::JaniConversionOptions(jani); auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 5e56ed782..4a84e637b 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -18,12 +18,14 @@ namespace storm { const std::string JaniExportSettings::standardCompliantOptionShortName = "standard"; const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; const std::string JaniExportSettings::locationVariablesOptionName = "location-variables"; + const std::string JaniExportSettings::globalVariablesOptionName = "globalvars"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, true, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); } bool JaniExportSettings::isExportAsStandardJaniSet() const { @@ -54,6 +56,10 @@ namespace storm { return result; } + bool JaniExportSettings::isGlobalVarsSet() const { + return this->getOption(exportFlattenOptionName).getHasOptionBeenSet(); + } + void JaniExportSettings::finalize() { } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h index d61b923fc..90dc532f0 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.h +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -29,6 +29,8 @@ namespace storm { bool isExportFlattenedSet() const; bool isLocationVariablesSet() const; + + bool isGlobalVarsSet() const; std::vector> getLocationVariables() const; @@ -44,6 +46,7 @@ namespace storm { static const std::string standardCompliantOptionShortName; static const std::string exportFlattenOptionName; static const std::string locationVariablesOptionName; + static const std::string globalVariablesOptionName; }; } From b4a1244d01a730fd1d9f381ba641acfdb825775a Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 17:18:41 +0200 Subject: [PATCH 447/647] correct parsing of bounded until formulas with multiple bounds --- src/storm-parsers/parser/JaniParser.cpp | 63 ++++++++++--------------- 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 4f3419ec4..3351eac53 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -255,10 +255,6 @@ namespace storm { STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + context); storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), "Step instant in " + context, globalVars, constants); - STORM_LOG_THROW(!stepInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant step-instants"); - - int64_t stepInstant = stepInstantExpr.evaluateAsInt(); - STORM_LOG_THROW(stepInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative step-instants are allowed"); if(!accTime && !accSteps) { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); @@ -280,8 +276,6 @@ namespace storm { storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); STORM_LOG_THROW(!timeInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); - double timeInstant = timeInstantExpr.evaluateAsDouble(); - STORM_LOG_THROW(timeInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative time-instants are allowed"); if(!accTime && !accSteps) { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); @@ -317,8 +311,6 @@ namespace storm { STORM_LOG_THROW((rewInstAccTime && !rewInstAccSteps) || (!rewInstAccTime && rewInstAccSteps), storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); STORM_LOG_THROW(!rewInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); - double rewInstant = rewInstantExpr.evaluateAsDouble(); - STORM_LOG_THROW(rewInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative reward-instants are allowed"); bounds.emplace_back(false, rewInstantExpr); } if (rewExpr.isVariable()) { @@ -376,39 +368,40 @@ namespace storm { args.push_back(args[0]); args[0] = storm::logic::BooleanLiteralFormula::getTrueFormula(); } + + std::vector> lowerBounds, upperBounds; + std::vector tbReferences; if (propertyStructure.count("step-bounds") > 0) { storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds")); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { - int64_t lowerBoundInt = pi.lowerBound.evaluateAsInt(); - STORM_LOG_THROW(lowerBoundInt >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); - lowerBound = storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound); + lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); + } else { + lowerBounds.push_back(boost::none); } if (pi.hasUpperBound()) { - int64_t upperBoundInt = pi.upperBound.evaluateAsInt(); - STORM_LOG_THROW(upperBoundInt >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); - upperBound = storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound); + upperBounds.push_back(storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound)); + } else { + upperBounds.push_back(boost::none); } - return std::make_shared(args[0], args[1], lowerBound, upperBound, storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)); - } else if (propertyStructure.count("time-bounds") > 0) { + tbReferences.emplace_back(storm::logic::TimeBoundType::Steps); + } + if (propertyStructure.count("time-bounds") > 0) { storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds")); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { - double lowerBoundDouble = pi.lowerBound.evaluateAsInt(); - STORM_LOG_THROW(lowerBoundDouble >= 0, storm::exceptions::InvalidJaniException, "time-bounds cannot be negative"); - lowerBound = storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound); + lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); + } else { + lowerBounds.push_back(boost::none); } if (pi.hasUpperBound()) { - double upperBoundDouble = pi.upperBound.evaluateAsInt(); - STORM_LOG_THROW(upperBoundDouble >= 0, storm::exceptions::InvalidJaniException, "time-bounds cannot be negative"); - upperBound = storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound); + upperBounds.push_back(storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound)); + } else { + upperBounds.push_back(boost::none); } - return std::make_shared(args[0], args[1], lowerBound, upperBound, storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - - } else if (propertyStructure.count("reward-bounds") > 0 ) { - std::vector> lowerBounds; - std::vector> upperBounds; - std::vector tbReferences; + tbReferences.emplace_back(storm::logic::TimeBoundType::Time); + } + if (propertyStructure.count("reward-bounds") > 0 ) { for (auto const& rbStructure : propertyStructure.at("reward-bounds")) { storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds")); STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); @@ -416,13 +409,6 @@ namespace storm { STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); std::string rewardName = rewExpr.getVariables().begin()->getName(); STORM_LOG_WARN("Reward-type (steps, time) is deduced from model type."); - double lowerBound = 0.0; - if(pi.hasLowerBound()) { - lowerBound = pi.lowerBound.evaluateAsDouble(); - } - double upperBound = pi.upperBound.evaluateAsDouble(); - STORM_LOG_THROW(lowerBound >= 0, storm::exceptions::InvalidJaniException, "(Lower) time-bounds cannot be negative"); - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "(Upper) time-bounds cannot be negative"); if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); } else { @@ -435,11 +421,10 @@ namespace storm { } tbReferences.push_back(storm::logic::TimeBoundReference(rewardName)); } - auto res = std::make_shared(args[0], args[1], lowerBounds, upperBounds, tbReferences); - return res; - } - if (args[0]->isTrueFormula()) { + if (!tbReferences.empty()) { + return std::make_shared(args[0], args[1], lowerBounds, upperBounds, tbReferences); + } else if (args[0]->isTrueFormula()) { return std::make_shared(args[1], formulaContext); } else { return std::make_shared(args[0], args[1]); From 9487223dc106101c20fc2370abe6ffdc2843c2ec Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 17:19:01 +0200 Subject: [PATCH 448/647] --globalvars option no longer requires a module prefix --- src/storm-conv/settings/modules/JaniExportSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 4a84e637b..f5da440f3 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -25,7 +25,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, true, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); } bool JaniExportSettings::isExportAsStandardJaniSet() const { From 611428c01f061635d357da33a13dbc9fcd92edff Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 17:28:19 +0200 Subject: [PATCH 449/647] allowing constants in property bounds --- src/storm-parsers/parser/JaniParser.cpp | 18 ++++++------------ src/storm-parsers/parser/JaniParser.h | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 3351eac53..e7997814c 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -163,12 +163,10 @@ namespace storm { return { parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "Operand of operator " + opstring), parseFormula(propertyStructure.at("right"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; } - storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure) { + storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, std::unordered_map> const& constants) { storm::jani::PropertyInterval pi; if (piStructure.count("lower") > 0) { - pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, {}); - // TODO substitute constants. - STORM_LOG_THROW(!pi.lowerBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as lower bounds"); + pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, constants); } if (piStructure.count("lower-exclusive") > 0) { STORM_LOG_THROW(pi.lowerBound.isInitialized(), storm::exceptions::InvalidJaniException, "Lower-exclusive can only be set if a lower bound is present"); @@ -176,9 +174,7 @@ namespace storm { } if (piStructure.count("upper") > 0) { - pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval", {}, {}); - // TODO substitute constants. - STORM_LOG_THROW(!pi.upperBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as upper bounds"); + pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval", {}, constants); } if (piStructure.count("upper-exclusive") > 0) { @@ -274,7 +270,6 @@ namespace storm { STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a time-instant and a reward-instant in " + context); storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); - STORM_LOG_THROW(!timeInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); if(!accTime && !accSteps) { if (rewExpr.isVariable()) { @@ -310,7 +305,6 @@ namespace storm { } STORM_LOG_THROW((rewInstAccTime && !rewInstAccSteps) || (!rewInstAccTime && rewInstAccSteps), storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); - STORM_LOG_THROW(!rewInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); bounds.emplace_back(false, rewInstantExpr); } if (rewExpr.isVariable()) { @@ -372,7 +366,7 @@ namespace storm { std::vector> lowerBounds, upperBounds; std::vector tbReferences; if (propertyStructure.count("step-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds")); + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds"), constants); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); @@ -387,7 +381,7 @@ namespace storm { tbReferences.emplace_back(storm::logic::TimeBoundType::Steps); } if (propertyStructure.count("time-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds")); + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds"), constants); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); @@ -403,7 +397,7 @@ namespace storm { } if (propertyStructure.count("reward-bounds") > 0 ) { for (auto const& rbStructure : propertyStructure.at("reward-bounds")) { - storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds")); + storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds"), constants); STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), "Reward expression in " + context, globalVars, constants); STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index 9a6bdace6..1ac4a514f 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -65,7 +65,7 @@ namespace storm { std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); - storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure); + storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, std::unordered_map> const& constants); std::shared_ptr parseComposition(json const& compositionStructure); From 066facf3f1ac874458eb5b9032eece96f524fe23 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 17:51:32 +0200 Subject: [PATCH 450/647] fixed respecting the --globalvars option correctly... --- src/storm-conv/settings/modules/JaniExportSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index f5da440f3..588bde61a 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -57,7 +57,7 @@ namespace storm { } bool JaniExportSettings::isGlobalVarsSet() const { - return this->getOption(exportFlattenOptionName).getHasOptionBeenSet(); + return this->getOption(globalVariablesOptionName).getHasOptionBeenSet(); } void JaniExportSettings::finalize() { From b3be56588f515742cb8fae287715d961f77b5953 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 31 Jul 2018 22:27:02 +0200 Subject: [PATCH 451/647] fixing time operator formulas --- src/storm/storage/jani/JSONExporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 002c93165..befb793c5 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -263,7 +263,7 @@ namespace storm { } } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["left"]["exp"] = modernjson::json(1); opDecl["left"]["accumulate"] = modernjson::json(tvec); @@ -279,7 +279,7 @@ namespace storm { } else { // TODO add checks opDecl["op"] = "Emin"; - opDecl["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["exp"] = modernjson::json(1); opDecl["accumulate"] = modernjson::json(tvec); From 910b6e6b2260ef9903c94ec8aff7b7a5167fa1e1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 1 Aug 2018 11:38:39 +0200 Subject: [PATCH 452/647] fixed wrong include --- src/storm-cli-utilities/model-handling.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 412b909b6..f60a3ffb5 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -38,7 +38,6 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/AbstractionSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/utility/Stopwatch.h" From c9cea8804770746c60efe099b0fd6ee90171043b Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 2 Aug 2018 10:16:21 +0200 Subject: [PATCH 453/647] Export Storm-gspn headers as well --- src/storm-gspn-cli/CMakeLists.txt | 1 + src/storm-gspn/CMakeLists.txt | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/storm-gspn-cli/CMakeLists.txt b/src/storm-gspn-cli/CMakeLists.txt index f06ff4a53..7b9ebf7aa 100644 --- a/src/storm-gspn-cli/CMakeLists.txt +++ b/src/storm-gspn-cli/CMakeLists.txt @@ -1,3 +1,4 @@ +# Create storm-gspn. add_executable(storm-gspn-cli ${PROJECT_SOURCE_DIR}/src/storm-gspn-cli/storm-gspn.cpp) target_link_libraries(storm-gspn-cli storm-gspn storm-cli-utilities) # Adding headers for xcode set_target_properties(storm-gspn-cli PROPERTIES OUTPUT_NAME "storm-gspn") diff --git a/src/storm-gspn/CMakeLists.txt b/src/storm-gspn/CMakeLists.txt index a09b83621..c2b8dd896 100644 --- a/src/storm-gspn/CMakeLists.txt +++ b/src/storm-gspn/CMakeLists.txt @@ -8,11 +8,31 @@ file(GLOB_RECURSE STORM_GSPN_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-gspn/*/*.cp file(GLOB_RECURSE STORM_GSPN_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-gspn/*/*.h) -# Create storm-pgcl. +# Create storm-gspn. add_library(storm-gspn SHARED ${STORM_GSPN_SOURCES} ${STORM_GSPN_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-gspn PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) list(APPEND STORM_TARGETS storm-gspn) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-gspn storm storm-conv ${STORM_GSPN_LINK_LIBRARIES}) +target_link_libraries(storm-gspn PUBLIC storm storm-conv storm-parsers ${STORM_GSPN_LINK_LIBRARIES}) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_GSPN_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_GSPN_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_gspn_headers DEPENDS ${STORM_GSPN_OUTPUT_HEADERS} ${STORM_GSPN_HEADERS}) +add_dependencies(storm-gspn copy_storm_gspn_headers) # installation install(TARGETS storm-gspn EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) From e7eb80184e4481baf8294d870d2ded604601247d Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 2 Aug 2018 16:14:43 +0200 Subject: [PATCH 454/647] fixed wrong include.. --- src/storm-gspn-cli/storm-gspn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 4db249042..cb12de228 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -35,7 +35,7 @@ #include "storm-gspn/settings/modules/GSPNExportSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/ResourceSettings.h" From 6449dee6263fd9a8768fe6ebadfa26650ebd00c2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 2 Aug 2018 16:14:52 +0200 Subject: [PATCH 455/647] fixed typo --- src/storm-parsers/parser/JaniParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index e7997814c..7fa6f3462 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -817,7 +817,7 @@ namespace storm { if(opstring == "ite") { STORM_LOG_THROW(expressionStructure.count("if") == 1, storm::exceptions::InvalidJaniException, "If operator required"); STORM_LOG_THROW(expressionStructure.count("else") == 1, storm::exceptions::InvalidJaniException, "Else operator required"); - STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "If operator required"); + STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "Then operator required"); arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); From ed2de09ce385dea82fae0ee66b8fb2926e9554eb Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 3 Aug 2018 17:57:22 +0200 Subject: [PATCH 456/647] added function that reduces the nesting of expressions (e.g. when considering a big sum with many summands. This fixes stack overflows when translating expressions --- .../storage/expressions/BaseExpression.cpp | 8 +- .../storage/expressions/BaseExpression.h | 7 + src/storm/storage/expressions/Expression.cpp | 4 + src/storm/storage/expressions/Expression.h | 7 + .../expressions/ReduceNestingVisitor.cpp | 180 ++++++++++++++++++ .../expressions/ReduceNestingVisitor.h | 36 ++++ src/storm/storage/jani/JSONExporter.cpp | 7 +- src/storm/utility/ExpressionHelper.cpp | 17 +- 8 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 src/storm/storage/expressions/ReduceNestingVisitor.cpp create mode 100644 src/storm/storage/expressions/ReduceNestingVisitor.h diff --git a/src/storm/storage/expressions/BaseExpression.cpp b/src/storm/storage/expressions/BaseExpression.cpp index 4e07fd089..b6f652e3f 100644 --- a/src/storm/storage/expressions/BaseExpression.cpp +++ b/src/storm/storage/expressions/BaseExpression.cpp @@ -6,6 +6,7 @@ #include "storm/storage/expressions/Expressions.h" #include "storm/storage/expressions/ToRationalNumberVisitor.h" +#include "storm/storage/expressions/ReduceNestingVisitor.h" namespace storm { namespace expressions { @@ -63,7 +64,7 @@ namespace storm { } std::shared_ptr BaseExpression::getOperand(uint_fast64_t operandIndex) const { - STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression of arity 0."); + STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression '" << *this << "' of arity 0."); } std::string const& BaseExpression::getIdentifier() const { @@ -74,6 +75,11 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operator of non-function application expression."); } + std::shared_ptr BaseExpression::reduceNesting() const { + ReduceNestingVisitor v; + return v.reduceNesting(this->toExpression()).getBaseExpressionPointer(); + } + bool BaseExpression::containsVariables() const { return false; } diff --git a/src/storm/storage/expressions/BaseExpression.h b/src/storm/storage/expressions/BaseExpression.h index 93091e536..666c4d40b 100644 --- a/src/storm/storage/expressions/BaseExpression.h +++ b/src/storm/storage/expressions/BaseExpression.h @@ -185,6 +185,13 @@ namespace storm { */ virtual std::shared_ptr simplify() const = 0; + /*! + * Tries to flatten the syntax tree of the expression, e.g., 1 + (2 + (3 + 4)) becomes (1 + 2) + (3 + 4) + * + * @return A semantically equivalent expression with reduced nesting + */ + std::shared_ptr reduceNesting() const; + /*! * Accepts the given visitor by calling its visit method. * diff --git a/src/storm/storage/expressions/Expression.cpp b/src/storm/storage/expressions/Expression.cpp index 2ec1604a7..1d31f4c6f 100644 --- a/src/storm/storage/expressions/Expression.cpp +++ b/src/storm/storage/expressions/Expression.cpp @@ -73,6 +73,10 @@ namespace storm { return Expression(this->getBaseExpression().simplify()); } + Expression Expression::reduceNesting() const { + return Expression(this->getBaseExpression().reduceNesting()); + } + OperatorType Expression::getOperator() const { return this->getBaseExpression().getOperator(); } diff --git a/src/storm/storage/expressions/Expression.h b/src/storm/storage/expressions/Expression.h index 99d409e2e..5778f7214 100644 --- a/src/storm/storage/expressions/Expression.h +++ b/src/storm/storage/expressions/Expression.h @@ -152,6 +152,13 @@ namespace storm { */ Expression simplify() const; + /*! + * Tries to flatten the syntax tree of the expression, e.g., 1 + (2 + (3 + 4)) becomes (1 + 2) + (3 + 4) + * + * @return A semantically equivalent expression with reduced nesting + */ + Expression reduceNesting() const; + /*! * Retrieves the operator of a function application. This is only legal to call if the expression is * function application. diff --git a/src/storm/storage/expressions/ReduceNestingVisitor.cpp b/src/storm/storage/expressions/ReduceNestingVisitor.cpp new file mode 100644 index 000000000..5f77ca10c --- /dev/null +++ b/src/storm/storage/expressions/ReduceNestingVisitor.cpp @@ -0,0 +1,180 @@ +#include + +#include "storm/storage/expressions/ReduceNestingVisitor.h" +#include "storm/storage/expressions/Expressions.h" + +namespace storm { + namespace expressions { + + ReduceNestingVisitor::ReduceNestingVisitor() { + // Intentionally left empty. + } + + Expression ReduceNestingVisitor::reduceNesting(Expression const& expression) { + return Expression(boost::any_cast>(expression.getBaseExpression().accept(*this, boost::none))); + } + + boost::any ReduceNestingVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { + std::shared_ptr conditionExpression = boost::any_cast>(expression.getCondition()->accept(*this, data)); + std::shared_ptr thenExpression = boost::any_cast>(expression.getThenExpression()->accept(*this, data)); + std::shared_ptr elseExpression = boost::any_cast>(expression.getElseExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new IfThenElseExpression(expression.getManager(), expression.getType(), conditionExpression, thenExpression, elseExpression))); + } + } + + template + std::vector> getAllOperands(BinaryFunc const& binaryExpression) { + auto opType = binaryExpression.getOperatorType(); + std::vector> stack = {binaryExpression.getSharedPointer()}; + std::vector> res; + while (!stack.empty()) { + auto f = std::move(stack.back()); + stack.pop_back(); + + for (uint64_t opIndex = 0; opIndex < 2; ++opIndex) { + BinaryFunc const* subexp = dynamic_cast(f->getOperand(opIndex).get()); + if (subexp != nullptr && subexp->getOperatorType() == opType) { + stack.push_back(f->getOperand(opIndex)); + } else { + res.push_back(f->getOperand(opIndex)); + } + } + } + return res; + } + + boost::any ReduceNestingVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + + // Check if the operator is commutative and associative + if (expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Or || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::And || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Iff) { + + std::vector> operands = getAllOperands(expression); + + // Balance the syntax tree if there are enough operands + if (operands.size() >= 4) { + + for (auto& operand : operands) { + operand = boost::any_cast>(operand->accept(*this, data)); + } + + auto opIt = operands.begin(); + while (operands.size() > 1) { + if (opIt == operands.end() || opIt == operands.end() - 1) { + opIt = operands.begin(); + } + *opIt = std::const_pointer_cast(std::shared_ptr(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); + operands.pop_back(); + ++opIt; + } + return operands.front(); + } + } + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + // Check if the operator is commutative and associative + if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Times || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Max || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Min) { + + std::vector> operands = getAllOperands(expression); + + // Balance the syntax tree if there are enough operands + if (operands.size() >= 4) { + + for (auto& operand : operands) { + operand = boost::any_cast>(operand->accept(*this, data)); + } + + auto opIt = operands.begin(); + while (operands.size() > 1) { + if (opIt == operands.end() || opIt == operands.end() - 1) { + opIt = operands.begin(); + } + *opIt = std::const_pointer_cast(std::shared_ptr(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); + operands.pop_back(); + ++opIt; + } + return operands.front(); + } + } + + + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); + } + } + + boost::any ReduceNestingVisitor::visit(VariableExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr operandExpression = boost::any_cast>(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr operandExpression = boost::any_cast>(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BooleanLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(IntegerLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + } +} diff --git a/src/storm/storage/expressions/ReduceNestingVisitor.h b/src/storm/storage/expressions/ReduceNestingVisitor.h new file mode 100644 index 000000000..f7c9c1566 --- /dev/null +++ b/src/storm/storage/expressions/ReduceNestingVisitor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/expressions/ExpressionVisitor.h" + +namespace storm { + namespace expressions { + class ReduceNestingVisitor : public ExpressionVisitor { + public: + /*! + * Creates a new reduce nesting visitor. + */ + ReduceNestingVisitor(); + + /*! + * Reduces the nesting in the given expression + * + * @return A semantically equivalent expression with reduced nesting + */ + Expression reduceNesting(Expression const& expression); + + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; + + private: + }; + } +} diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index befb793c5..c48927a78 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -548,8 +548,13 @@ namespace storm { } modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + + // Simplify the expression first and reduce the nesting + auto simplifiedExpr = expr.simplify().reduceNesting(); + + ExpressionToJson visitor(constants, globalVariables, localVariables); - return boost::any_cast(expr.accept(visitor, boost::none)); + return boost::any_cast(simplifiedExpr.accept(visitor, boost::none)); } diff --git a/src/storm/utility/ExpressionHelper.cpp b/src/storm/utility/ExpressionHelper.cpp index 219d6e39c..fd99855f8 100644 --- a/src/storm/utility/ExpressionHelper.cpp +++ b/src/storm/utility/ExpressionHelper.cpp @@ -12,17 +12,16 @@ namespace storm { if (summands.empty()) { return manager->rational(storm::utility::zero()); } - // As the sum can potentially have many summands, we want to make sure that the formula tree is (roughly balanced) - auto it = summands.begin(); - while (summands.size() > 1) { - if (it == summands.end() || it == summands.end() - 1) { - it = summands.begin(); + storm::expressions::Expression res = summands.front(); + bool first = true; + for (auto& s : summands) { + if (first) { + first = false; + } else { + res = res + s; } - *it = *it + summands.back(); - summands.pop_back(); - ++it; } - return summands.front(); + return res.simplify().reduceNesting(); } } From da4dfc35a84643b3592aa28d0b111cf3ba9b42c0 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Sat, 4 Aug 2018 15:00:04 +0200 Subject: [PATCH 457/647] AbstractModelChecker: add getClassName() --- src/storm/modelchecker/AbstractModelChecker.cpp | 7 +++++++ src/storm/modelchecker/AbstractModelChecker.h | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index e6c4f282f..1408b8987 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -24,9 +24,16 @@ #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" +#include + namespace storm { namespace modelchecker { + template + std::string AbstractModelChecker::getClassName() const { + return std::string(boost::core::demangled_name(BOOST_CORE_TYPEID(*this))); + } + template std::unique_ptr AbstractModelChecker::check(CheckTask const& checkTask) { Environment env; diff --git a/src/storm/modelchecker/AbstractModelChecker.h b/src/storm/modelchecker/AbstractModelChecker.h index 3251ea1fa..44373de03 100644 --- a/src/storm/modelchecker/AbstractModelChecker.h +++ b/src/storm/modelchecker/AbstractModelChecker.h @@ -1,6 +1,7 @@ #ifndef STORM_MODELCHECKER_ABSTRACTMODELCHECKER_H_ #define STORM_MODELCHECKER_ABSTRACTMODELCHECKER_H_ +#include #include #include "storm/modelchecker/CheckTask.h" @@ -24,7 +25,12 @@ namespace storm { } typedef typename ModelType::ValueType ValueType; - + + /*! + * Returns the name of the model checker class (e.g., for display in error messages). + */ + virtual std::string getClassName() const; + /*! * Determines whether the model checker can handle the given verification task. If this method returns * false, the task must not be checked using this model checker. From d0e2d099bf6a257867180207b5dafc3f503107f8 Mon Sep 17 00:00:00 2001 From: Joachim Klein Date: Sat, 4 Aug 2018 15:01:55 +0200 Subject: [PATCH 458/647] AbstractModelChecker: In error messages, include class name of the actual model checker --- .../modelchecker/AbstractModelChecker.cpp | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index 1408b8987..42bb2a753 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -43,7 +43,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::check(Environment const& env, CheckTask const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); - STORM_LOG_THROW(this->canHandle(checkTask), storm::exceptions::InvalidArgumentException, "The model checker is not able to check the formula '" << formula << "'."); + STORM_LOG_THROW(this->canHandle(checkTask), storm::exceptions::InvalidArgumentException, "The model checker (" << getClassName() << ") is not able to check the formula '" << formula << "'."); if (formula.isStateFormula()) { return this->checkStateFormula(env, checkTask.substituteFormula(formula.asStateFormula())); } else if (formula.isMultiObjectiveFormula()){ @@ -73,12 +73,12 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeBoundedUntilProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeConditionalProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -90,17 +90,17 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeGloballyProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeNextProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -124,37 +124,37 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -163,12 +163,12 @@ namespace storm { if (timeFormula.isReachabilityTimeFormula()) { return this->computeReachabilityTimes(env, rewardMeasureType, checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); } - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -208,7 +208,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkAtomicLabelFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -234,7 +234,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkBooleanLiteralFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -308,7 +308,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } /////////////////////////////////////////////// From 0332935451c3343e6662a908353b11496078e8f9 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 6 Aug 2018 13:40:31 +0200 Subject: [PATCH 459/647] Supporting TimeOperatorFormulas for MDPs and DTMCs in Sparse, Hybrid, and Dd engine --- .../prctl/HybridDtmcPrctlModelChecker.cpp | 11 ++++++++++- .../prctl/HybridDtmcPrctlModelChecker.h | 1 + .../prctl/HybridMdpPrctlModelChecker.cpp | 11 ++++++++++- .../prctl/HybridMdpPrctlModelChecker.h | 1 + .../prctl/SparseDtmcPrctlModelChecker.cpp | 11 ++++++++++- .../prctl/SparseDtmcPrctlModelChecker.h | 2 +- .../prctl/SparseMdpPrctlModelChecker.cpp | 16 +++++++++++++++- .../prctl/SparseMdpPrctlModelChecker.h | 1 + .../prctl/SymbolicDtmcPrctlModelChecker.cpp | 12 +++++++++++- .../prctl/SymbolicDtmcPrctlModelChecker.h | 2 +- .../prctl/SymbolicMdpPrctlModelChecker.cpp | 11 ++++++++++- .../prctl/SymbolicMdpPrctlModelChecker.h | 2 +- .../prctl/helper/HybridDtmcPrctlHelper.cpp | 6 ++++++ .../prctl/helper/HybridDtmcPrctlHelper.h | 2 ++ .../prctl/helper/HybridMdpPrctlHelper.cpp | 7 +++++++ .../prctl/helper/HybridMdpPrctlHelper.h | 2 ++ .../prctl/helper/SparseDtmcPrctlHelper.cpp | 15 +++++++++++++++ .../prctl/helper/SparseDtmcPrctlHelper.h | 2 ++ .../prctl/helper/SparseMdpPrctlHelper.cpp | 16 ++++++++++++++++ .../prctl/helper/SparseMdpPrctlHelper.h | 2 ++ .../prctl/helper/SymbolicDtmcPrctlHelper.cpp | 6 ++++++ .../prctl/helper/SymbolicDtmcPrctlHelper.h | 2 ++ .../prctl/helper/SymbolicMdpPrctlHelper.cpp | 7 +++++++ .../prctl/helper/SymbolicMdpPrctlHelper.h | 2 ++ src/storm/storage/jani/JSONExporter.cpp | 12 ++++++++---- 25 files changed, 149 insertions(+), 13 deletions(-) diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 94b7ca4e1..0654a9788 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -33,7 +33,7 @@ namespace storm { template bool HybridDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -95,6 +95,15 @@ namespace storm { SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } + + template + std::unique_ptr HybridDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityTimes(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } template diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h index d76ae69ac..854fae195 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h @@ -31,6 +31,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index 6ae7ea4bc..9af47c767 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -39,7 +39,7 @@ namespace storm { template bool HybridMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false))) { + if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -117,6 +117,15 @@ namespace storm { SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } + + template + std::unique_ptr HybridMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } template std::unique_ptr HybridMdpPrctlModelChecker::checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) { diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h index 246a991d5..68eb12baa 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h @@ -35,6 +35,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; }; diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 082ddd813..f561d3e98 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -31,7 +31,7 @@ namespace storm { template bool SparseDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -124,6 +124,15 @@ namespace storm { return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } + template + std::unique_ptr SparseDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } + template std::unique_ptr SparseDtmcPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet(), checkTask.getHint()); diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index 6500da487..1aafc0efb 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -33,7 +33,7 @@ namespace storm { virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index ba5aac431..b78ad3856 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -38,7 +38,7 @@ namespace storm { template bool SparseMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true))) { + if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -173,6 +173,20 @@ namespace storm { return result; } + template + std::unique_ptr SparseMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + if (checkTask.isProduceSchedulersSet() && ret.scheduler) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + } + return result; + } + template std::unique_ptr SparseMdpPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 5667549e3..19c2cc6a1 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -29,6 +29,7 @@ namespace storm { virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp index e8af30350..a6a099833 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp @@ -30,7 +30,7 @@ namespace storm { template bool SymbolicDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -100,6 +100,16 @@ namespace storm { return std::make_unique>(this->getModel().getReachableStates(), numericResult); } + + template + std::unique_ptr SymbolicDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityTimes(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + return std::make_unique>(this->getModel().getReachableStates(), numericResult); + } + template class SymbolicDtmcPrctlModelChecker>; template class SymbolicDtmcPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h index 311669bf7..1186c0271 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h @@ -26,7 +26,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp index 3c813d001..713ce3295 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp @@ -30,7 +30,7 @@ namespace storm { template bool SymbolicMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -99,6 +99,15 @@ namespace storm { SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector()); } + + template + std::unique_ptr SymbolicMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); + } template class SymbolicMdpPrctlModelChecker>; template class SymbolicMdpPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h index b116af0fc..bf259e8b7 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h @@ -27,7 +27,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index 659a17cab..ce5bf4467 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -338,6 +338,12 @@ namespace storm { } } + template + std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, targetStates, qualitative); + } + template std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates) { // Create ODD for the translation. diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h index 67896c8bc..9e20c5e2c 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h @@ -37,6 +37,8 @@ namespace storm { static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + static std::unique_ptr computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative); + static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates); static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel); diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index cca377b9d..7cb054574 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -676,6 +676,13 @@ namespace storm { } } + template + std::unique_ptr HybridMdpPrctlHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, dir, model, transitionMatrix, rewardModel, targetStates, qualitative); + } + + template class HybridMdpPrctlHelper; template class HybridMdpPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h index 78ee1f7d3..ce7072624 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h @@ -37,6 +37,8 @@ namespace storm { static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + + static std::unique_ptr computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative); }; } diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index 2745569ad..0e5cf1849 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -423,6 +423,21 @@ namespace storm { hint); } + template + std::vector SparseDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { + + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, + [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const&) { + return std::vector(numberOfRows, storm::utility::one()); + }, + targetStates, qualitative, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); + }, + hint); + } + + // This function computes an upper bound on the reachability rewards (see Baier et al, CAV'17). template std::vector computeUpperRewardBounds(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& rewards, std::vector const& oneStepTargetProbabilities) { diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index 49fe21deb..16702ffed 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -47,6 +47,8 @@ namespace storm { static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); + + static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates); diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 4b29d2324..58c94a95b 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -933,6 +933,22 @@ namespace storm { hint); } + template + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { + return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, + [] (uint_fast64_t rowCount, storm::storage::SparseMatrix const&, storm::storage::BitVector const&) { + return std::vector(rowCount, storm::utility::one()); + }, + targetStates, qualitative, produceScheduler, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); + }, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowCount(), false); + }, + hint); + } + #ifdef STORM_HAVE_CARL template std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative) { diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index b1de7a442..0be4ad060 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -61,6 +61,8 @@ namespace storm { template static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + #ifdef STORM_HAVE_CARL static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative); #endif diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp index 2b64db267..8f2468a70 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp @@ -202,6 +202,12 @@ namespace storm { return infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), result); } + template + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, targetStates, qualitative, startValues); + } + template class SymbolicDtmcPrctlHelper; template class SymbolicDtmcPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h index 995936786..ecf6a6fe4 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h @@ -37,6 +37,8 @@ namespace storm { static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues = boost::none); static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); + + static storm::dd::Add computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues = boost::none); }; } diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp index d5c9fea6e..5080d90a8 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp @@ -300,6 +300,13 @@ namespace storm { } } + template + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, boost::optional> const& startValues) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, dir, model, transitionMatrix, rewardModel, targetStates, startValues); + } + + template class SymbolicMdpPrctlHelper; template class SymbolicMdpPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h index e21342008..51f5f7dd1 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h @@ -41,6 +41,8 @@ namespace storm { static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, boost::optional> const& startValues = boost::none); static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); + + static std::unique_ptr computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, boost::optional> const& startValues = boost::none); }; } diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index c48927a78..59ca13d86 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -249,8 +249,12 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector tvec; - tvec.push_back("time"); + std::vector accvec; + if (model.isDiscreteTimeModel()) { + accvec.push_back("steps"); + } else { + accvec.push_back("time"); + } if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); @@ -266,7 +270,7 @@ namespace storm { opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["left"]["exp"] = modernjson::json(1); - opDecl["left"]["accumulate"] = modernjson::json(tvec); + opDecl["left"]["accumulate"] = modernjson::json(accvec); opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if(f.hasOptimalityType()) { @@ -282,7 +286,7 @@ namespace storm { opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["exp"] = modernjson::json(1); - opDecl["accumulate"] = modernjson::json(tvec); + opDecl["accumulate"] = modernjson::json(accvec); } return opDecl; } From d8bc689259d62a6555b281fdc7a8c367ea46d316 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 7 Aug 2018 16:27:25 +0200 Subject: [PATCH 460/647] Throw an exception instead of assertion when 'wrong' jani was detected --- src/storm-parsers/parser/JaniParser.cpp | 2 +- src/storm/storage/jani/JSONExporter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 7fa6f3462..0d415d388 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -1022,7 +1022,7 @@ namespace storm { } STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported operator declaration found for complex expressions as " << expressionStructure.dump() << " in " << scopeDescription << "."); } - assert(false); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported expression found at " << expressionStructure.dump() << " in " << scopeDescription << "."); // Silly warning suppression. return storm::expressions::Expression(); diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 59ca13d86..42bc15d62 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -603,7 +603,7 @@ namespace storm { } } } - STORM_LOG_ASSERT(false, "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures."); return modernjson::json(); // should not reach this point. } boost::any ExpressionToJson::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) { From a21c6f724486e67d01dc9c7628457bd1a87d5751 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 7 Aug 2018 16:29:19 +0200 Subject: [PATCH 461/647] fixed wrong state action rewards in JaniNextStateGenerator. --- src/storm/generator/JaniNextStateGenerator.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 2df1784a1..cf7a7b43e 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -465,12 +465,12 @@ namespace storm { nextDistribution.add(newTargetState, probability); } } - - // Create the state-action reward for the newly created choice. - auto valueIt = stateActionRewards.begin(); - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); } + // Create the state-action reward for the newly created choice. + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + nextDistribution.compress(); // If there is one more command to come, shift the target states one time step back. From 919dfeebaeeb350edfb6749edf006852fbce7a50 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Tue, 7 Aug 2018 20:53:12 -0700 Subject: [PATCH 462/647] "number of edges" and "number of commands" in jani model / prism programs --- src/storm/storage/jani/Model.cpp | 10 +++++++++- src/storm/storage/jani/Model.h | 5 +++++ src/storm/storage/prism/Program.cpp | 8 ++++++++ src/storm/storage/prism/Program.h | 7 ++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index d91e0c3bc..222d31326 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -608,7 +608,15 @@ namespace storm { std::vector& Model::getConstants() { return constants; } - + + std::size_t Model::getNumberOfEdges() const { + size_t res = 0; + for (auto const& aut : getAutomata()) { + res += aut.getNumberOfEdges(); + } + return res; + } + Variable const& Model::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 86555a2d4..2954b1c9f 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -287,6 +287,11 @@ namespace storm { * Retrieves the number of automata in this model. */ std::size_t getNumberOfAutomata() const; + + /*! + * Retrieves the total number of edges in this model. + */ + std::size_t getNumberOfEdges() const; /*! * Sets the system composition expression of the JANI model. diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index f12686315..45a4f5a1c 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -192,6 +192,14 @@ namespace storm { bool Program::isDeterministicModel() const { return modelType == ModelType::DTMC || modelType == ModelType::CTMC; } + + size_t Program::getNumberOfCommands() const { + size_t res = 0; + for (auto const& module : this->getModules()) { + res += module.getNumberOfCommands(); + } + return res; + } bool Program::hasUndefinedConstants() const { for (auto const& constant : this->getConstants()) { diff --git a/src/storm/storage/prism/Program.h b/src/storm/storage/prism/Program.h index 3adc3151f..40c3e4a47 100644 --- a/src/storm/storage/prism/Program.h +++ b/src/storm/storage/prism/Program.h @@ -157,7 +157,12 @@ namespace storm { * @return */ std::vector usedConstants() const; - + + /*! + * The total number of commands in the prism file. + */ + size_t getNumberOfCommands() const; + /*! * Retrieves whether a global Boolean variable with the given name exists * From ac9d9d67789ec01c8f4b5a469b3364e64e2b6fcd Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Tue, 7 Aug 2018 20:56:30 -0700 Subject: [PATCH 463/647] fix in counterexamples for lower bounds that was recently introduced --- .../counterexamples/SMTMinimalLabelSetGenerator.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 65143dfb5..74c973aa0 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -2004,8 +2004,8 @@ namespace storm { result.psiStates = subQualitativeResult.getTruthValuesVector(); } - bool lowerBoundedFormula = false; if (storm::logic::isLowerBound(result.comparisonType)) { + STORM_LOG_DEBUG("Computing counterexample for a lowerbound."); // If the formula specifies a lower bound, we need to modify the phi and psi states. // More concretely, we convert P(min)>lambda(F psi) to P(max)<(1-lambda)(G !psi) = P(max)<(1-lambda)(!psi U prob0E(psi)) // where prob0E(psi) is the set of states for which there exists a strategy \sigma_0 that avoids @@ -2027,7 +2027,7 @@ namespace storm { // Remember our transformation so we can add commands to guarantee that the prob0E(a) states actually // have a strategy that voids a states. - lowerBoundedFormula = true; + result.lowerBoundedFormula = true; } return result; @@ -2053,6 +2053,7 @@ namespace storm { // Extend the command set properly. for (auto& labelSet : labelSets) { if (counterexInput.lowerBoundedFormula) { + STORM_LOG_DEBUG("Extending the counterexample due to lower bound computation."); extendLabelSetLowerBound(model, labelSet, counterexInput.phiStates, counterexInput.psiStates, options.silent); } } From 73900f1bbeb7da8ef662659b573376be32e1fcc6 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Tue, 7 Aug 2018 21:07:15 -0700 Subject: [PATCH 464/647] advanced stopping criteria for multi-counterexamples, additional measurements for cuts, an option to properly disable backward implications, and some cleaning --- .../SMTMinimalLabelSetGenerator.h | 215 +++++++++++------- 1 file changed, 128 insertions(+), 87 deletions(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 74c973aa0..dd0ce03e9 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -28,7 +28,20 @@ namespace storm { class Environment; namespace counterexamples { - + + /** + * Helper to avoid case disticinot between prism and jani + * Returns the number of edges/commands in a symbolic model description. + */ + size_t nrCommands(storm::storage::SymbolicModelDescription const& descr) { + if (descr.isJaniModel()) { + return descr.asJaniModel().getNumberOfEdges(); + } else { + assert(descr.isPrismModel()); + return descr.asPrismProgram().getNumberOfCommands(); + } + } + /*! * This class provides functionality to generate a minimal counterexample to a probabilistic reachability * property in terms of used labels. @@ -313,12 +326,18 @@ namespace storm { * @param context The Z3 context in which to build the expressions. * @param solver The solver to use for the satisfiability evaluation. */ - static void assertCuts(storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::vector> const& labelSets, storm::storage::BitVector const& psiStates, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation, storm::solver::SmtSolver& solver) { + static std::chrono::milliseconds assertCuts(storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::vector> const& labelSets, storm::storage::BitVector const& psiStates, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation, storm::solver::SmtSolver& solver, bool addBackwardImplications) { // Walk through the model and // * identify labels enabled in initial states // * identify labels that can directly precede a given action // * identify labels that directly reach a target state // * identify labels that can directly follow a given action + auto assertCutsClock = std::chrono::high_resolution_clock::now(); + + // + if (addBackwardImplications) { + STORM_LOG_THROW(!symbolicModel.isJaniModel() || !symbolicModel.asJaniModel().usesAssignmentLevels(), storm::exceptions::NotSupportedException, "Counterexample generation with backward implications is not supported for indexed assignments"); + } boost::container::flat_set initialLabels; std::set> initialCombinations; @@ -334,6 +353,7 @@ namespace storm { storm::storage::BitVector const& initialStates = model.getInitialStates(); for (auto currentState : relevancyInformation.relevantStates) { + bool isInitial = initialStates.get(currentState); for (auto currentChoice : relevancyInformation.relevantChoicesForRelevantStates.at(currentState)) { // If the choice is a synchronization choice, we need to record it. @@ -344,7 +364,7 @@ namespace storm { } // If the state is initial, we need to add all the choice labels to the initial label set. - if (initialStates.get(currentState)) { + if (isInitial) { initialLabels.insert(labelSets[currentChoice].begin(), labelSets[currentChoice].end()); initialCombinations.insert(labelSets[currentChoice]); } @@ -378,6 +398,7 @@ namespace storm { for (auto const& successorEntry : transitionMatrix.getRow(predecessorChoice)) { if (successorEntry.getColumn() == currentState) { choiceTargetsCurrentState = true; + break; } } @@ -389,11 +410,10 @@ namespace storm { } } } - + // Store the found implications in a container similar to the preceding label sets. std::map, std::set>> backwardImplications; - - if (!symbolicModel.isJaniModel() || !symbolicModel.asJaniModel().usesAssignmentLevels()) { + if (addBackwardImplications) { // Create a new solver over the same variables as the given symbolic model description to use it for // determining the symbolic cuts. std::unique_ptr localSolver; @@ -587,8 +607,7 @@ namespace storm { // Iterate over all possible combinations of updates of the preceding command set. std::vector formulae; - bool done = false; - while (!done) { + while (true) { std::map currentVariableUpdateCombinationMap; for (auto const& updateIterator : iteratorVector) { for (auto const& variableUpdatePair : *updateIterator) { @@ -616,7 +635,7 @@ namespace storm { // If we had to reset all iterator to the start, we are done. if (k == 0) { - done = true; + break; } } @@ -722,85 +741,88 @@ namespace storm { assertDisjunction(solver, formulae, *variableInformation.manager); } } - - STORM_LOG_DEBUG("Asserting taken labels are followed and preceeded by another label if they are not a target label or an initial label, respectively."); - boost::container::flat_map, storm::expressions::Expression> labelSetToFormula; - for (auto const& labelSet : relevancyInformation.relevantLabelSets) { - storm::expressions::Expression labelSetFormula = variableInformation.manager->boolean(false); - // Compute the set of unknown labels on the left-hand side of the implication. - boost::container::flat_set unknownLhsLabels; - std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLhsLabels, unknownLhsLabels.end())); - for (auto label : unknownLhsLabels) { - labelSetFormula = labelSetFormula || !variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); - } - - // Only build a constraint if the combination does not lead to a target state and - // no successor set is already known. - storm::expressions::Expression successorExpression; - if (targetCombinations.find(labelSet) == targetCombinations.end() && hasKnownSuccessor.find(labelSet) == hasKnownSuccessor.end()) { - successorExpression = variableInformation.manager->boolean(false); + if(addBackwardImplications) { - auto const& followingLabelSets = followingLabels.at(labelSet); + STORM_LOG_DEBUG("Asserting taken labels are followed and preceeded by another label if they are not a target label or an initial label, respectively."); + boost::container::flat_map, storm::expressions::Expression> labelSetToFormula; + for (auto const &labelSet : relevancyInformation.relevantLabelSets) { + storm::expressions::Expression labelSetFormula = variableInformation.manager->boolean(false); - for (auto const& followingSet : followingLabelSets) { - boost::container::flat_set tmpSet; - - // Check which labels of the current following set are not known. This set must be non-empty, because - // otherwise a successor combination would already be known and control cannot reach this point. - std::set_difference(followingSet.begin(), followingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); - - // Construct an expression that enables all unknown labels of the current following set. - storm::expressions::Expression conj = variableInformation.manager->boolean(true); - for (auto label : tmpSet) { - conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + // Compute the set of unknown labels on the left-hand side of the implication. + boost::container::flat_set unknownLhsLabels; + std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLhsLabels, unknownLhsLabels.end())); + for (auto label : unknownLhsLabels) { + labelSetFormula = labelSetFormula || !variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + + // Only build a constraint if the combination does not lead to a target state and + // no successor set is already known. + storm::expressions::Expression successorExpression; + if (targetCombinations.find(labelSet) == targetCombinations.end() && hasKnownSuccessor.find(labelSet) == hasKnownSuccessor.end()) { + successorExpression = variableInformation.manager->boolean(false); + + auto const &followingLabelSets = followingLabels.at(labelSet); + + for (auto const &followingSet : followingLabelSets) { + boost::container::flat_set tmpSet; + + // Check which labels of the current following set are not known. This set must be non-empty, because + // otherwise a successor combination would already be known and control cannot reach this point. + std::set_difference(followingSet.begin(), followingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); + + // Construct an expression that enables all unknown labels of the current following set. + storm::expressions::Expression conj = variableInformation.manager->boolean(true); + for (auto label : tmpSet) { + conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + successorExpression = successorExpression || conj; } - successorExpression = successorExpression || conj; + } else { + successorExpression = variableInformation.manager->boolean(true); } - } else { - successorExpression = variableInformation.manager->boolean(true); - } - // Constructed following cuts at this point. - - // Only build a constraint if the combination is no initial combination and no - // predecessor set is already known. - storm::expressions::Expression predecessorExpression; - if (initialCombinations.find(labelSet) == initialCombinations.end() && hasKnownPredecessor.find(labelSet) == hasKnownPredecessor.end()) { - predecessorExpression = variableInformation.manager->boolean(false); - + // Constructed following cuts at this point. + + // Only build a constraint if the combination is no initial combination and no + // predecessor set is already known. + storm::expressions::Expression predecessorExpression; + if (initialCombinations.find(labelSet) == initialCombinations.end() && hasKnownPredecessor.find(labelSet) == hasKnownPredecessor.end()) { + predecessorExpression = variableInformation.manager->boolean(false); + // std::cout << "labelSet" << std::endl; // for (auto const& e : labelSet) { // std::cout << e << ", "; // } // std::cout << std::endl; - auto const& preceedingLabelSets = backwardImplications.at(labelSet); + auto const &preceedingLabelSets = backwardImplications.at(labelSet); - for (auto const& preceedingSet : preceedingLabelSets) { - boost::container::flat_set tmpSet; - - // Check which labels of the current following set are not known. This set must be non-empty, because - // otherwise a predecessor combination would already be known and control cannot reach this point. - std::set_difference(preceedingSet.begin(), preceedingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); - - // Construct an expression that enables all unknown labels of the current following set. - storm::expressions::Expression conj = variableInformation.manager->boolean(true); - for (auto label : tmpSet) { - conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + for (auto const &preceedingSet : preceedingLabelSets) { + boost::container::flat_set tmpSet; + + // Check which labels of the current following set are not known. This set must be non-empty, because + // otherwise a predecessor combination would already be known and control cannot reach this point. + std::set_difference(preceedingSet.begin(), preceedingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); + + // Construct an expression that enables all unknown labels of the current following set. + storm::expressions::Expression conj = variableInformation.manager->boolean(true); + for (auto label : tmpSet) { + conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + predecessorExpression = predecessorExpression || conj; } - predecessorExpression = predecessorExpression || conj; + } else { + predecessorExpression = variableInformation.manager->boolean(true); } - } else { - predecessorExpression = variableInformation.manager->boolean(true); + + labelSetFormula = labelSetFormula || (successorExpression && predecessorExpression); + + labelSetToFormula[labelSet] = labelSetFormula; } - - labelSetFormula = labelSetFormula || (successorExpression && predecessorExpression); - labelSetToFormula[labelSet] = labelSetFormula; - } - - for (auto const& labelSetFormula : labelSetToFormula) { - solver.add(labelSetFormula.second || getOtherSynchronizationEnabledFormula(labelSetFormula.first, synchronizingLabels, labelSetToFormula, variableInformation, relevancyInformation)); + for (auto const &labelSetFormula : labelSetToFormula) { + solver.add(labelSetFormula.second || getOtherSynchronizationEnabledFormula(labelSetFormula.first, synchronizingLabels, labelSetToFormula, variableInformation, relevancyInformation)); + } } STORM_LOG_DEBUG("Asserting synchronization cuts."); @@ -837,6 +859,9 @@ namespace storm { assertDisjunction(solver, formulae, *variableInformation.manager); } } + + auto endTime = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(endTime - assertCutsClock); } /*! @@ -1021,10 +1046,12 @@ namespace storm { */ static std::vector> createAdderPairs(VariableInformation const& variableInformation, std::vector> const& in) { std::vector> result; - - result.reserve(in.size() / 2 + in.size() % 2); - - for (uint_fast64_t index = 0; index < in.size() / 2; ++index) { + + + uint64_t maxIndex = in.size() / 2; + result.reserve(maxIndex + in.size() % 2); + + for (uint_fast64_t index = 0; index < maxIndex; ++index) { result.push_back(createAdder(variableInformation, in[2 * index], in[2 * index + 1])); } @@ -1586,9 +1613,11 @@ namespace storm { bool encodeReachability; bool useDynamicConstraints; bool silent = false; + bool addBackwardImplicationCuts = true; uint64_t continueAfterFirstCounterexampleUntil = 0; uint64_t maximumCounterexamples = 1; uint64_t multipleCounterexampleSizeCap = 100000000; + uint64_t maximumExtraIterations = 100000000; }; struct GeneratorStats { @@ -1596,8 +1625,11 @@ namespace storm { std::chrono::milliseconds solverTime; std::chrono::milliseconds modelCheckingTime; std::chrono::milliseconds analysisTime; + std::chrono::milliseconds cutTime; + uint64_t iterations; }; - + + /*! * Computes the minimal command set that is needed in the given model to exceed the given probability threshold for satisfying phi until psi. * @@ -1679,19 +1711,19 @@ namespace storm { // and subsequently relax that. variableInformation.adderVariables = assertAdder(*solver, variableInformation); variableInformation.auxiliaryVariables.push_back(assertLessOrEqualKRelaxed(*solver, variableInformation, 0)); - + + // As we are done with the setup at this point, stop the clock for the setup time. + totalSetupTime = std::chrono::high_resolution_clock::now() - setupTimeClock; + // (6) Add constraints that cut off a lot of suboptimal solutions. STORM_LOG_DEBUG("Asserting cuts."); - assertCuts(symbolicModel, model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); + stats.cutTime = assertCuts(symbolicModel, model, labelSets, psiStates, variableInformation, relevancyInformation, *solver, options.addBackwardImplicationCuts); STORM_LOG_DEBUG("Asserted cuts."); if (options.encodeReachability) { assertReachabilityCuts(model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); STORM_LOG_DEBUG("Asserted reachability cuts."); } - - // As we are done with the setup at this point, stop the clock for the setup time. - totalSetupTime = std::chrono::high_resolution_clock::now() - setupTimeClock; - + // (7) Find the smallest set of commands that satisfies all constraints. If the probability of // satisfying phi until psi exceeds the given threshold, the set of labels is minimal and can be returned. // Otherwise, the current solution has to be ruled out and the next smallest solution is retrieved from @@ -1712,11 +1744,17 @@ namespace storm { uint_fast64_t lastSize = 0; uint_fast64_t iterations = 0; uint_fast64_t currentBound = 0; + uint64_t firstCounterexampleFound = 0; // The value is not queried before being set. std::vector maximalPropertyValue; uint_fast64_t zeroProbabilityCount = 0; - uint64_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive u + size_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive upper bound uint64_t progressDelay = storm::settings::getModule().getShowProgressDelay(); do { + ++iterations; + + if (result.size() > 0 && iterations > firstCounterexampleFound + options.maximumExtraIterations) { + break; + } STORM_LOG_DEBUG("Computing minimal command set."); solverClock = std::chrono::high_resolution_clock::now(); boost::optional> smallest = findSmallestCommandSet(*solver, variableInformation, currentBound); @@ -1781,19 +1819,21 @@ namespace storm { } } else { STORM_LOG_DEBUG("Found a counterexample."); + if (result.empty()) { + // If this is the first counterexample we find, we store when we found it. + firstCounterexampleFound = iterations; + } result.push_back(commandSet); if (options.maximumCounterexamples > result.size()) { STORM_LOG_DEBUG("Exclude counterexample for future."); ruleOutBiggerSolutions(*solver, commandSet, variableInformation, relevancyInformation); - } else { STORM_LOG_DEBUG("Stop searching for further counterexamples."); done = true; } - + smallestCounterexampleSize = std::min(smallestCounterexampleSize, commandSet.size()); } totalAnalysisTime += (std::chrono::high_resolution_clock::now() - analysisClock); - ++iterations; auto now = std::chrono::high_resolution_clock::now(); auto durationSinceLastMessage = std::chrono::duration_cast(now - timeOfLastMessage).count(); @@ -1816,6 +1856,7 @@ namespace storm { stats.setupTime = std::chrono::duration_cast(totalSetupTime); stats.modelCheckingTime = std::chrono::duration_cast(totalModelCheckingTime); stats.solverTime = std::chrono::duration_cast(totalSolverTime); + stats.iterations = iterations; if (storm::settings::getModule().isShowStatisticsSet()) { boost::container::flat_set allLabels; From a34ca5c9ac49f6d1af562da185824c340e98d77c Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Tue, 7 Aug 2018 21:08:01 -0700 Subject: [PATCH 465/647] dont go on as soon as trivial command set is necessary --- .../counterexamples/SMTMinimalLabelSetGenerator.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index dd0ce03e9..1152c3799 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -1776,6 +1776,10 @@ namespace storm { break; } + if (commandSet.size() == nrCommands(symbolicModel)) { + result.push_back(commandSet); + break; + } auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, psiStates.getNextSetIndex(0)); std::shared_ptr> const& subModel = subChoiceOrigins.first; From cbd709f0cde067d6b9e8a3e753c146e78a11e363 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 12:26:10 +0200 Subject: [PATCH 466/647] Fixed assertion --- .../counterexamples/SMTMinimalLabelSetGenerator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 1152c3799..624a13205 100644 --- a/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -37,7 +37,7 @@ namespace storm { if (descr.isJaniModel()) { return descr.asJaniModel().getNumberOfEdges(); } else { - assert(descr.isPrismModel()); + assert(descr.isPrismProgram()); return descr.asPrismProgram().getNumberOfCommands(); } } From 856d62513bc7e538e3752eaddc0e23ec474c3164 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 12:27:07 +0200 Subject: [PATCH 467/647] DFT: parse number from JSON --- src/storm-dft/parser/DFTJsonParser.cpp | 21 ++++++++++++++++----- src/storm-dft/parser/DFTJsonParser.h | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 0d6f312f2..6a8197fee 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -82,7 +82,7 @@ namespace storm { } else if (type == "or") { success = builder.addOrElement(name, childNames); } else if (type == "vot") { - std::string votThreshold = data.at("voting"); + std::string votThreshold = parseJsonNumber(data.at("voting")); success = builder.addVotElement(name, boost::lexical_cast(votThreshold), childNames); } else if (type == "pand") { success = builder.addPandElement(name, childNames); @@ -95,11 +95,11 @@ namespace storm { } else if (type== "fdep") { success = builder.addDepElement(name, childNames, storm::utility::one()); } else if (type== "pdep") { - ValueType probability = parseRationalExpression(data.at("prob")); + ValueType probability = parseRationalExpression(parseJsonNumber(data.at("prob"))); success = builder.addDepElement(name, childNames, probability); } else if (type == "be") { - ValueType failureRate = parseRationalExpression(data.at("rate")); - ValueType dormancyFactor = parseRationalExpression(data.at("dorm")); + ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); + ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); bool transient = false; if (data.count("transient") > 0) { transient = data.at("transient"); @@ -123,12 +123,23 @@ namespace storm { STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << element << "'."); } - std::string toplevelName = nameMapping[parsedJson.at("toplevel")]; + std::string toplevelName = nameMapping[parseJsonNumber(parsedJson.at("toplevel"))]; if(!builder.setTopLevel(toplevelName)) { STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown."); } } + template + std::string DFTJsonParser::parseJsonNumber(json number) { + if (number.is_string()) { + return number.get(); + } else { + std::stringstream stream; + stream << number; + return stream.str(); + } + } + template ValueType DFTJsonParser::parseRationalExpression(std::string const& expr) { STORM_LOG_ASSERT(false, "Specialized method should be called."); diff --git a/src/storm-dft/parser/DFTJsonParser.h b/src/storm-dft/parser/DFTJsonParser.h index 3b6812a76..6100d69dc 100644 --- a/src/storm-dft/parser/DFTJsonParser.h +++ b/src/storm-dft/parser/DFTJsonParser.h @@ -41,6 +41,8 @@ namespace storm { std::string generateUniqueName(std::string const& id, std::string const& name); ValueType parseRationalExpression(std::string const& expr); + + std::string parseJsonNumber(json number); }; } } From 369d106f995845c2292aa13b184a895650693b52 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 13:16:42 +0200 Subject: [PATCH 468/647] DFT: load json from string --- resources/examples/testfiles/dft/and.json | 71 +++++++++++++++++++ src/storm-dft-cli/storm-dft.cpp | 4 +- src/storm-dft/api/storm-dft.h | 19 ++++- src/storm-dft/parser/DFTJsonParser.cpp | 70 +++++++++--------- src/storm-dft/parser/DFTJsonParser.h | 8 ++- .../storm-dft/api/DftModelCheckerTest.cpp | 2 +- src/test/storm-dft/api/DftParserTest.cpp | 12 +++- 7 files changed, 142 insertions(+), 44 deletions(-) create mode 100644 resources/examples/testfiles/dft/and.json diff --git a/resources/examples/testfiles/dft/and.json b/resources/examples/testfiles/dft/and.json new file mode 100644 index 000000000..e6c0c0f2e --- /dev/null +++ b/resources/examples/testfiles/dft/and.json @@ -0,0 +1,71 @@ +{ + "toplevel": "2", + "parameters": {}, + "nodes": [ + { + "data": { + "id": "0", + "name": "A", + "type": "be", + "rate": "1", + "dorm": "1", + "label": "A (1)" + }, + "position": { + "x": 440, + "y": 260 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "be" + }, + { + "data": { + "id": "1", + "name": "B", + "type": "be", + "rate": "1", + "dorm": "1", + "label": "B (1)" + }, + "position": { + "x": 548, + "y": 265 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "be" + }, + { + "data": { + "id": "2", + "name": "Z", + "type": "and", + "children": [ + "0", + "1" + ], + "label": "Z" + }, + "position": { + "x": 505, + "y": 119 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "and" + } + ] +} diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 395985f7e..261193ff3 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -32,10 +32,10 @@ void processOptions() { std::shared_ptr> dft; if (dftIOSettings.isDftJsonFileSet()) { STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); - dft = storm::api::loadDFTJson(dftIOSettings.getDftJsonFilename()); + dft = storm::api::loadDFTJsonFile(dftIOSettings.getDftJsonFilename()); } else { STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); - dft = storm::api::loadDFTGalileo(dftIOSettings.getDftFilename()); + dft = storm::api::loadDFTGalileoFile(dftIOSettings.getDftFilename()); } if (dftIOSettings.isDisplayStatsSet()) { diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index db6d7b3e4..79831edbc 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -23,10 +23,23 @@ namespace storm { * @return DFT. */ template - std::shared_ptr> loadDFTGalileo(std::string const& file) { + std::shared_ptr> loadDFTGalileoFile(std::string const& file) { return std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(file)); } + /*! + * Load DFT from JSON string. + * + * @param jsonString String containing DFT description in JSON format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTJsonString(std::string const& jsonString) { + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJsonFromString(jsonString)); + } + /*! * Load DFT from JSON file. * @@ -35,9 +48,9 @@ namespace storm { * @return DFT. */ template - std::shared_ptr> loadDFTJson(std::string const& file) { + std::shared_ptr> loadDFTJsonFile(std::string const& file) { storm::parser::DFTJsonParser parser; - return std::make_shared>(parser.parseJson(file)); + return std::make_shared>(parser.parseJsonFromFile(file)); } /*! diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 6a8197fee..813c2a13e 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -15,34 +15,27 @@ namespace storm { namespace parser { template - storm::storage::DFT DFTJsonParser::parseJson(const std::string& filename) { - readFile(filename); - storm::storage::DFT dft = builder.build(); - STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); - STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); - return dft; + storm::storage::DFT DFTJsonParser::parseJsonFromFile(std::string const& filename) { + STORM_LOG_DEBUG("Parsing from JSON file"); + std::ifstream file; + storm::utility::openFile(filename, file); + json jsonInput; + jsonInput << file; + storm::utility::closeFile(file); + return parseJson(jsonInput); } template - std::string DFTJsonParser::generateUniqueName(std::string const& id, std::string const& name) { - std::string newId = name; - std::replace(newId.begin(), newId.end(), ' ', '_'); - std::replace(newId.begin(), newId.end(), '-', '_'); - return newId + "_" + id; + storm::storage::DFT DFTJsonParser::parseJsonFromString(std::string const& jsonString) { + STORM_LOG_DEBUG("Parsing from JSON string"); + json jsonInput = json::parse(jsonString); + return parseJson(jsonInput); } template - void DFTJsonParser::readFile(const std::string& filename) { - STORM_LOG_DEBUG("Parsing from JSON"); - - std::ifstream file; - storm::utility::openFile(filename, file); - json parsedJson; - parsedJson << file; - storm::utility::closeFile(file); - - json parameters = parsedJson.at("parameters"); -#ifdef STORM_HAVE_CARL + storm::storage::DFT DFTJsonParser::parseJson(json const& jsonInput) { + // Parse parameters + json parameters = jsonInput.at("parameters"); for (auto it = parameters.begin(); it != parameters.end(); ++it) { STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); std::string parameter = it.key(); @@ -51,18 +44,17 @@ namespace storm { parser.setIdentifierMapping(identifierMapping); STORM_LOG_TRACE("Added parameter: " << var.getName()); } -#endif - - json nodes = parsedJson.at("nodes"); + json nodes = jsonInput.at("nodes"); // Start by building mapping from ids to their unique names std::map nameMapping; - for (auto& element: nodes) { + for (auto& element : nodes) { json data = element.at("data"); std::string id = data.at("id"); nameMapping[id] = generateUniqueName(id, data.at("name")); } + // Parse nodes for (auto& element : nodes) { STORM_LOG_TRACE("Parsing: " << element); bool success = true; @@ -123,10 +115,25 @@ namespace storm { STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << element << "'."); } - std::string toplevelName = nameMapping[parseJsonNumber(parsedJson.at("toplevel"))]; + std::string toplevelName = nameMapping[parseJsonNumber(jsonInput.at("toplevel"))]; if(!builder.setTopLevel(toplevelName)) { STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown."); } + + // Build DFT + storm::storage::DFT dft = builder.build(); + STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); + STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); + return dft; + + } + + template + std::string DFTJsonParser::generateUniqueName(std::string const& id, std::string const& name) { + std::string newId = name; + std::replace(newId.begin(), newId.end(), ' ', '_'); + std::replace(newId.begin(), newId.end(), '-', '_'); + return newId + "_" + id; } template @@ -151,10 +158,6 @@ namespace storm { return boost::lexical_cast(expr); } - // Explicitly instantiate the class. - template class DFTJsonParser; - -#ifdef STORM_HAVE_CARL template<> storm::RationalFunction DFTJsonParser::parseRationalExpression(std::string const& expr) { STORM_LOG_TRACE("Translating expression: " << expr); @@ -165,8 +168,9 @@ namespace storm { return rationalFunction; } + + // Explicitly instantiate the class. + template class DFTJsonParser; template class DFTJsonParser; -#endif - } } diff --git a/src/storm-dft/parser/DFTJsonParser.h b/src/storm-dft/parser/DFTJsonParser.h index 6100d69dc..5187e3cc3 100644 --- a/src/storm-dft/parser/DFTJsonParser.h +++ b/src/storm-dft/parser/DFTJsonParser.h @@ -33,10 +33,12 @@ namespace storm { DFTJsonParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { } - storm::storage::DFT parseJson(std::string const& filename); - + storm::storage::DFT parseJsonFromString(std::string const& jsonString); + + storm::storage::DFT parseJsonFromFile(std::string const& filename); + private: - void readFile(std::string const& filename); + storm::storage::DFT parseJson(json const& jsonInput); std::string generateUniqueName(std::string const& id, std::string const& name); diff --git a/src/test/storm-dft/api/DftModelCheckerTest.cpp b/src/test/storm-dft/api/DftModelCheckerTest.cpp index b4e9534f9..71c440abd 100644 --- a/src/test/storm-dft/api/DftModelCheckerTest.cpp +++ b/src/test/storm-dft/api/DftModelCheckerTest.cpp @@ -63,7 +63,7 @@ namespace { } double analyzeMTTF(std::string const& file) { - std::shared_ptr> dft = storm::api::loadDFTGalileo(file); + std::shared_ptr> dft = storm::api::loadDFTGalileoFile(file); std::string property = "Tmin=? [F \"failed\"]"; std::vector> properties = storm::api::extractFormulasFromProperties(storm::api::parseProperties(property)); typename storm::modelchecker::DFTModelChecker::dft_results results = storm::api::analyzeDFT(*dft, properties, config.useSR, config.useMod, config.useDC, false); diff --git a/src/test/storm-dft/api/DftParserTest.cpp b/src/test/storm-dft/api/DftParserTest.cpp index 48a621ac1..93df569d1 100644 --- a/src/test/storm-dft/api/DftParserTest.cpp +++ b/src/test/storm-dft/api/DftParserTest.cpp @@ -5,9 +5,17 @@ namespace { - TEST(DftParserTest, LoadFromGalileo) { + TEST(DftParserTest, LoadFromGalileoFile) { std::string file = STORM_TEST_RESOURCES_DIR "/dft/and.dft"; - std::shared_ptr> dft = storm::api::loadDFTGalileo(file); + std::shared_ptr> dft = storm::api::loadDFTGalileoFile(file); + EXPECT_EQ(3ul, dft->nrElements()); + EXPECT_EQ(2ul, dft->nrBasicElements()); } + TEST(DftParserTest, LoadFromJsonFile) { + std::string file = STORM_TEST_RESOURCES_DIR "/dft/and.json"; + std::shared_ptr> dft = storm::api::loadDFTJsonFile(file); + EXPECT_EQ(3ul, dft->nrElements()); + EXPECT_EQ(2ul, dft->nrBasicElements()); + } } From 48efde755bb96ca339dd0dcc654df04434b32b81 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 13:22:54 +0200 Subject: [PATCH 469/647] DFT: export to JSON as string --- src/storm-dft-cli/storm-dft.cpp | 2 +- src/storm-dft/api/storm-dft.cpp | 16 ++++++++++++++-- src/storm-dft/api/storm-dft.h | 10 +++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 261193ff3..0e38d7757 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -46,7 +46,7 @@ void processOptions() { if (dftIOSettings.isExportToJson()) { // Export to json - storm::api::exportDFTToJson(*dft, dftIOSettings.getExportJsonFilename()); + storm::api::exportDFTToJsonFile(*dft, dftIOSettings.getExportJsonFilename()); return; } diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp index 72105a763..c2431d8e9 100644 --- a/src/storm-dft/api/storm-dft.cpp +++ b/src/storm-dft/api/storm-dft.cpp @@ -4,12 +4,24 @@ namespace storm { namespace api { template<> - void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file) { storm::storage::DftJsonExporter::toFile(dft, file); } template<> - void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file) { + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); + } + + template<> + std::string exportDFTToJsonString(storm::storage::DFT const& dft) { + std::stringstream stream; + storm::storage::DftJsonExporter::toStream(dft, stream); + return stream.str(); + } + + template<> + std::string exportDFTToJsonString(storm::storage::DFT const& dft) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); } diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h index 79831edbc..ec4e7166a 100644 --- a/src/storm-dft/api/storm-dft.h +++ b/src/storm-dft/api/storm-dft.h @@ -107,7 +107,15 @@ namespace storm { * @param file File. */ template - void exportDFTToJson(storm::storage::DFT const& dft, std::string const& file); + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file); + + /*! + * Export DFT to JSON string. + * + * @param dft DFT. + */ + template + std::string exportDFTToJsonString(storm::storage::DFT const& dft); /*! * Export DFT to SMT encoding. From 1990b0a1c94090a608999c972ed2178cbbee09a5 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 14:29:00 +0200 Subject: [PATCH 470/647] DFT: updated json export --- src/storm-dft/storage/dft/DftJsonExporter.cpp | 60 ++++--------------- src/storm-dft/storage/dft/DftJsonExporter.h | 9 +-- 2 files changed, 11 insertions(+), 58 deletions(-) diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index 30e0d2eec..cdae727c5 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -9,9 +9,6 @@ namespace storm { namespace storage { - template - size_t DftJsonExporter::currentId = 0; - template void DftJsonExporter::toFile(storm::storage::DFT const& dft, std::string const& filepath) { std::ofstream ofs; @@ -31,46 +28,34 @@ namespace storm { template modernjson::json DftJsonExporter::translate(storm::storage::DFT const& dft) { - modernjson::json jsonDft; - currentId = 0; - // Nodes modernjson::json jsonNodes; for (size_t i = 0; i < dft.nrElements(); ++i) { modernjson::json jsonNode = translateNode(dft.getElement(i)); - jsonDft.push_back(jsonNode); - } - - // Edges - modernjson::json jsonEdges; - for (size_t i = 0; i < dft.nrElements(); ++i) { - if (dft.isGate(i)) { - std::shared_ptr const> gate = dft.getGate(i); - for (size_t index = 0; index < gate->nrChildren(); ++index) { - DFTElementPointer child = gate->children()[index]; - modernjson::json jsonEdge = translateEdge(gate, child, index); - jsonDft.push_back(jsonEdge); - } - } + jsonNodes.push_back(jsonNode); } + modernjson::json jsonDft; + jsonDft["toplevel"] = std::to_string(dft.getTopLevelIndex()); + jsonDft["nodes"] = jsonNodes; return jsonDft; } template modernjson::json DftJsonExporter::translateNode(DFTElementCPointer const& element) { modernjson::json nodeData; - nodeData["id"] = element->id(); - ++currentId; - STORM_LOG_ASSERT(element->id() == currentId-1, "Ids do not correspond"); + nodeData["id"] = std::to_string(element->id()); nodeData["name"] = element->name(); + std::string type = storm::storage::toString(element->type()); + std::transform(type.begin(), type.end(), type.begin(), ::tolower); + nodeData["type"] = type; if (element->isGate()) { // Set children for gate std::shared_ptr const> gate = std::static_pointer_cast const>(element); - std::vector children; + std::vector children; for (DFTElementPointer const& child : gate->children()) { - children.push_back(child->id()); + children.push_back(std::to_string(child->id())); } nodeData["children"] = children; } else if (element->isBasicElement()) { @@ -86,39 +71,14 @@ namespace storm { modernjson::json jsonNode; jsonNode["data"] = nodeData; - jsonNode["group"] = "nodes"; - std::string type = storm::storage::toString(element->type()); - std::transform(type.begin(), type.end(), type.begin(), ::tolower); jsonNode["classes"] = type; return jsonNode; } - template - modernjson::json DftJsonExporter::translateEdge(std::shared_ptr const> const& gate, DFTElementCPointer const& child, size_t index) { - modernjson::json nodeData; - std::stringstream stream; - stream << gate->id() << "e" << child->id(); - nodeData["id"] = stream.str(); - ++currentId; - nodeData["source"] = gate->id(); - nodeData["target"] = child->id(); - nodeData["index"] = index; - - modernjson::json jsonNode; - jsonNode["data"] = nodeData; - - jsonNode["group"] = "edges"; - jsonNode["classes"] = ""; - return jsonNode; - } - // Explicitly instantiate the class. template class DftJsonExporter; - -#ifdef STORM_HAVE_CARL template class DftJsonExporter; -#endif } } diff --git a/src/storm-dft/storage/dft/DftJsonExporter.h b/src/storm-dft/storage/dft/DftJsonExporter.h index ef04750ba..646821bb6 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.h +++ b/src/storm-dft/storage/dft/DftJsonExporter.h @@ -29,19 +29,12 @@ namespace storm { static void toStream(storm::storage::DFT const& dft, std::ostream& os); - static modernjson::json translate(storm::storage::DFT const& dft); - - private: - static size_t currentId; + static modernjson::json translate(storm::storage::DFT const& dft); static modernjson::json translateNode(DFTElementCPointer const& element); - static modernjson::json translateEdge(std::shared_ptr const> const& gate, DFTElementCPointer const& child, size_t index); - - }; - } } From d4efcd49e37cfec862b2c333a9183df8aa3d7a17 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 14:55:04 +0200 Subject: [PATCH 471/647] DFT: no error for optional json arguments --- src/storm-dft/parser/DFTJsonParser.cpp | 41 +++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 813c2a13e..e44042980 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -34,15 +34,17 @@ namespace storm { template storm::storage::DFT DFTJsonParser::parseJson(json const& jsonInput) { - // Parse parameters - json parameters = jsonInput.at("parameters"); - for (auto it = parameters.begin(); it != parameters.end(); ++it) { - STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - std::string parameter = it.key(); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); + // Try to parse parameters + if (jsonInput.find("parameters") != jsonInput.end()) { + json parameters = jsonInput.at("parameters"); + STORM_LOG_THROW(parameters.empty() || (std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); + for (auto it = parameters.begin(); it != parameters.end(); ++it) { + std::string parameter = it.key(); + storm::expressions::Variable var = manager->declareRationalVariable(parameter); + identifierMapping.emplace(var.getName(), var); + parser.setIdentifierMapping(identifierMapping); + STORM_LOG_TRACE("Added parameter: " << var.getName()); + } } json nodes = jsonInput.at("nodes"); @@ -102,15 +104,18 @@ namespace storm { success = false; } - // Do not set layout for dependencies - // This does not work because dependencies might be splitted - // TODO: do splitting later in rewriting step - if (type != "fdep" && type != "pdep") { - // Set layout positions - json position = element.at("position"); - double x = position.at("x"); - double y = position.at("y"); - builder.addLayoutInfo(name, x / 7, y / 7); + // Try to set layout information + if (element.find("position") != element.end()) { + // Do not set layout for dependencies + // This does not work because dependencies might be splitted + // TODO: do splitting later in rewriting step + if (type != "fdep" && type != "pdep") { + // Set layout positions + json position = element.at("position"); + double x = position.at("x"); + double y = position.at("y"); + builder.addLayoutInfo(name, x / 7, y / 7); + } } STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << element << "'."); } From 020c480e9c8ffcefe3bd09f19b666f27ca39ef52 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 14:55:26 +0200 Subject: [PATCH 472/647] DFT: export gate dependent information to json --- src/storm-dft/storage/dft/DftJsonExporter.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index cdae727c5..8c76959b5 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -58,6 +58,24 @@ namespace storm { children.push_back(std::to_string(child->id())); } nodeData["children"] = children; + // Gate dependent export + switch (element->type()) { + case storm::storage::DFTElementType::VOT: + nodeData["voting"] = std::static_pointer_cast const>(element)->threshold(); + break; + case storm::storage::DFTElementType::PDEP: + { + ValueType probability = std::static_pointer_cast const>(element)->probability(); + if (!storm::utility::isOne(probability)) { + std::stringstream stream; + stream << probability; + nodeData["prob"] = stream.str(); + } + break; + } + default: + break; + } } else if (element->isBasicElement()) { // Set rates for BE std::shared_ptr const> be = std::static_pointer_cast const>(element); From 3e8959c8666932eb4381748a7d5ea5ccbee4058a Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 8 Aug 2018 15:07:28 +0200 Subject: [PATCH 473/647] DFT: fixed stringstream clearing --- src/storm-dft/storage/dft/DftJsonExporter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index 8c76959b5..d1bf4f42d 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -82,8 +82,9 @@ namespace storm { std::stringstream stream; stream << be->activeFailureRate(); nodeData["rate"] = stream.str(); - stream.clear(); - stream << (be->passiveFailureRate() / be->activeFailureRate()); + stream.str(std::string()); // Clear stringstream + ValueType dormancy = be->passiveFailureRate() / be->activeFailureRate(); + stream << dormancy; nodeData["dorm"] = stream.str(); } From 19c6472843d695151a4d752a0b3531403f920e51 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 9 Aug 2018 08:14:20 +0200 Subject: [PATCH 474/647] separating declaration/implementation for storm-conv api --- src/storm-conv/api/storm-conv.cpp | 58 ++++++++++++++++++++++++++++++ src/storm-conv/api/storm-conv.h | 59 +++++++------------------------ 2 files changed, 71 insertions(+), 46 deletions(-) create mode 100644 src/storm-conv/api/storm-conv.cpp diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp new file mode 100644 index 000000000..1b52092bb --- /dev/null +++ b/src/storm-conv/api/storm-conv.cpp @@ -0,0 +1,58 @@ +#include "storm-conv/api/storm-conv.h" + +#include "storm/storage/prism/Program.h" +#include "storm/storage/jani/Property.h" +#include "storm/storage/jani/JaniLocationExpander.h" +#include "storm/storage/jani/JSONExporter.h" + +namespace storm { + namespace api { + + void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options) { + + if (!options.locationVariables.empty()) { + for (auto const& pair : options.locationVariables) { + storm::jani::JaniLocationExpander expander(janiModel); + expander.transform(pair.first, pair.second); + janiModel = expander.getResult(); + } + } + + if (options.exportFlattened) { + janiModel = janiModel.flattenComposition(); + } + + if (options.standardCompliant) { + janiModel.makeStandardJaniCompliant(); + } + } + + std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties, storm::converter::PrismToJaniConverterOptions options) { + std::pair> res; + + // Perform conversion + auto modelAndRenaming = program.toJaniWithLabelRenaming(options.allVariablesGlobal, options.suffix, options.janiOptions.standardCompliant); + res.first = std::move(modelAndRenaming.first); + + // Amend properties to potentially changed labels + for (auto const& property : properties) { + res.second.emplace_back(property.substituteLabels(modelAndRenaming.second)); + } + + // Postprocess Jani model based on the options + postprocessJani(res.first, options.janiOptions); + + return res; + } + + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { + storm::jani::JsonExporter::toFile(model, properties, filename); + } + + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream) { + storm::jani::JsonExporter::toStream(model, properties, ostream); + } + + + } +} \ No newline at end of file diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h index 499777517..ec8a306df 100644 --- a/src/storm-conv/api/storm-conv.h +++ b/src/storm-conv/api/storm-conv.h @@ -3,58 +3,25 @@ #include "storm-conv/converter/options/PrismToJaniConverterOptions.h" #include "storm-conv/converter/options/JaniConversionOptions.h" -#include "storm/storage/prism/Program.h" -#include "storm/storage/jani/Property.h" -#include "storm/storage/jani/JaniLocationExpander.h" -#include "storm/storage/jani/JSONExporter.h" - namespace storm { + + namespace prism { + class Program; + } + namespace jani { + class Model; + class Property; + } + namespace api { - void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options) { - - if (!options.locationVariables.empty()) { - for (auto const& pair : options.locationVariables) { - storm::jani::JaniLocationExpander expander(janiModel); - expander.transform(pair.first, pair.second); - janiModel = expander.getResult(); - } - } + void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options); - if (options.exportFlattened) { - janiModel = janiModel.flattenComposition(); - } - - if (options.standardCompliant) { - janiModel.makeStandardJaniCompliant(); - } - } - - std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()) { - std::pair> res; - - // Perform conversion - auto modelAndRenaming = program.toJaniWithLabelRenaming(options.allVariablesGlobal, options.suffix, options.janiOptions.standardCompliant); - res.first = std::move(modelAndRenaming.first); - - // Amend properties to potentially changed labels - for (auto const& property : properties) { - res.second.emplace_back(property.substituteLabels(modelAndRenaming.second)); - } - - // Postprocess Jani model based on the options - postprocessJani(res.first, options.janiOptions); - - return res; - } + std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()); - void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { - storm::jani::JsonExporter::toFile(model, properties, filename); - } + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename); - void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream) { - storm::jani::JsonExporter::toStream(model, properties, ostream); - } + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream); } From fc453143c28295748b8e97733da549c35a870fe2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Sat, 11 Aug 2018 11:28:11 +0300 Subject: [PATCH 475/647] missing includes.. --- src/storm-conv-cli/storm-conv.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index c398ef69a..04169b2dc 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -13,6 +13,8 @@ #include "storm/utility/macros.h" #include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" #include "storm-cli-utilities/cli.h" From f638142ad9f20a374fa78f4f5ef79237ec1da709 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 15 Aug 2018 10:02:28 +0200 Subject: [PATCH 476/647] Travis: Use Ubuntu 18.04 after support for 17.10 ended --- .travis.yml | 58 +++++++++++++++++++-------------------- travis/generate_travis.py | 4 +-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a5dd952d..edeac6e25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,11 +40,11 @@ jobs: # Stage: Build Carl ### - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build Carl os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -53,11 +53,11 @@ jobs: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - docker commit carl movesrwth/carl:travis-debug; - docker push movesrwth/carl:travis-debug; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build Carl os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -99,11 +99,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (1st run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - rm -rf build - travis/install_linux.sh @@ -113,11 +113,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (1st run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - rm -rf build - travis/install_linux.sh @@ -186,11 +186,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (2nd run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -199,11 +199,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (2nd run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -269,11 +269,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (3rd run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -282,11 +282,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (3rd run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -352,11 +352,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (4th run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -365,11 +365,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (4th run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -435,11 +435,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Test all os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -452,11 +452,11 @@ jobs: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - docker commit storm movesrwth/storm:travis-debug; - docker push movesrwth/storm:travis-debug; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Test all os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -498,17 +498,17 @@ jobs: allow_failures: - stage: Build (1st run) os: linux - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc - stage: Build (2nd run) os: linux - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc - stage: Build (3rd run) os: linux - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc - stage: Build (4th run) os: linux - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc - stage: Test all os: linux - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc diff --git a/travis/generate_travis.py b/travis/generate_travis.py index 49723a13c..f7565c6bc 100644 --- a/travis/generate_travis.py +++ b/travis/generate_travis.py @@ -5,8 +5,8 @@ configs_linux = [ # OS, compiler, build type ("debian-9", "gcc", "DefaultDebug"), ("debian-9", "gcc", "DefaultRelease"), - ("ubuntu-17.10", "gcc", "DefaultDebugTravis"), - ("ubuntu-17.10", "gcc", "DefaultReleaseTravis"), + ("ubuntu-18.04", "gcc", "DefaultDebugTravis"), + ("ubuntu-18.04", "gcc", "DefaultReleaseTravis"), ("ubuntu-18.04", "gcc", "DefaultDebug"), ("ubuntu-18.04", "gcc", "DefaultRelease"), ] From 629c30545633504ec3a3b34b2bd6b4a928fc7432 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 10:16:09 +0200 Subject: [PATCH 477/647] Added option to specify one global capacity for all places of a gspn --- src/storm-gspn-cli/storm-gspn.cpp | 7 +++++++ src/storm-gspn/settings/modules/GSPNSettings.cpp | 15 +++++++++++++++ src/storm-gspn/settings/modules/GSPNSettings.h | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index cb12de228..70272e5b2 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -110,6 +110,13 @@ int main(const int argc, const char **argv) { if(storm::settings::getModule().isCapacitiesFileSet()) { auto capacities = parseCapacitiesList(storm::settings::getModule().getCapacitiesFilename()); gspn->setCapacities(capacities); + } else if (storm::settings::getModule().isCapacitySet()) { + uint64_t capacity = storm::settings::getModule().getCapacity(); + std::unordered_map capacities; + for (auto const& place : gspn->getPlaces()) { + capacities.emplace(place.getName(), capacity); + } + gspn->setCapacities(capacities); } storm::api::handleGSPNExportSettings(*gspn, [&](storm::builder::JaniGSPNBuilder const&) { return properties; }); diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index 2cca4b2f9..0efed0525 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -18,11 +18,13 @@ namespace storm { const std::string GSPNSettings::gspnFileOptionShortName = "gspn"; const std::string GSPNSettings::capacitiesFileOptionName = "capacitiesfile"; const std::string GSPNSettings::capacitiesFileOptionShortName = "capacities"; + const std::string GSPNSettings::capacityOptionName = "capacity"; GSPNSettings::GSPNSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, gspnFileOptionName, false, "Parses the GSPN.").setShortName(gspnFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacitiesFileOptionName, false, "Capacaties as invariants for places.").setShortName(capacitiesFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, capacityOptionName, false, "Global capacity as invariants for all places.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("value", "capacity").build()).build()); } bool GSPNSettings::isGspnFileSet() const { @@ -41,6 +43,14 @@ namespace storm { return this->getOption(capacitiesFileOptionName).getArgumentByName("filename").getValueAsString(); } + bool GSPNSettings::isCapacitySet() const { + return this->getOption(capacityOptionName).getHasOptionBeenSet(); + } + + uint64_t GSPNSettings::getCapacity() const { + return this->getOption(capacityOptionName).getArgumentByName("value").getValueAsUnsignedInteger(); + } + void GSPNSettings::finalize() { } @@ -51,6 +61,11 @@ namespace storm { return false; } } + + if (isCapacitiesFileSet() && isCapacitySet()) { + STORM_LOG_ERROR("Conflicting settings: Capacity file AND capacity was set."); + return false; + } return true; } } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.h b/src/storm-gspn/settings/modules/GSPNSettings.h index e5128c30e..665e588fb 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.h +++ b/src/storm-gspn/settings/modules/GSPNSettings.h @@ -34,6 +34,16 @@ namespace storm { */ std::string getCapacitiesFilename() const; + /** + * Retrievew whether a global capacity was set + */ + bool isCapacitySet() const; + + /** + * Retrieves the global capacity + */ + uint64_t getCapacity() const; + bool check() const override; void finalize() override; @@ -45,6 +55,7 @@ namespace storm { static const std::string gspnFileOptionShortName; static const std::string capacitiesFileOptionName; static const std::string capacitiesFileOptionShortName; + static const std::string capacityOptionName; }; } From 6a11927b5538201d55c9ab905b8b0b3fa43223b7 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 10:17:24 +0200 Subject: [PATCH 478/647] parsing pnpro files with constant definitions --- .../parser/GreatSpnEditorProjectParser.cpp | 81 +++++++++++++++++-- .../parser/GreatSpnEditorProjectParser.h | 8 ++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index ae17ca59b..f4b4418a2 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -9,6 +9,7 @@ #include "storm/exceptions/UnexpectedException.h" #include "storm/exceptions/WrongFormatException.h" +#include "storm/exceptions/NotSupportedException.h" #include "storm/utility/macros.h" namespace { @@ -22,7 +23,10 @@ namespace { namespace storm { namespace parser { - + GreatSpnEditorProjectParser::GreatSpnEditorProjectParser() : manager(std::make_shared()), expressionParser(*manager) { + // Intentionally left empty + } + storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) { if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { traverseProjectElement(elementRoot); @@ -31,8 +35,6 @@ namespace storm { // If the top-level node is not a "pnml" or "" node, then throw an exception. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n"); } - - } void GreatSpnEditorProjectParser::traverseProjectElement(xercesc::DOMNode const* const node) { @@ -118,6 +120,19 @@ namespace storm { } // traverse children + // First pass: find constant definitions + std::unordered_map identifierMapping; + expressionParser.setIdentifierMapping(identifierMapping); + for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { + auto child = node->getChildNodes()->item(i); + auto name = storm::adapters::getName(child); + if (name.compare("constant") == 0) { + traverseConstantElement(child, identifierMapping); + } + } + expressionParser.setIdentifierMapping(identifierMapping); + + // Second pass: traverse other children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); @@ -126,6 +141,8 @@ namespace storm { traversePlaceElement(child); } else if(name.compare("transition") == 0) { traverseTransitionElement(child); + } else if(name.compare("constant") == 0) { + // Ignore constant def in second pass } else if (isOnlyWhitespace(name)) { // ignore node (contains only whitespace) } else { @@ -136,6 +153,59 @@ namespace storm { } } + void GreatSpnEditorProjectParser::traverseConstantElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping) { + std::string identifier; + storm::expressions::Type type; + std::string valueStr = ""; + + // traverse attributes + for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { + auto attr = node->getAttributes()->item(i); + auto name = storm::adapters::getName(attr); + + if (name.compare("name") == 0) { + identifier = storm::adapters::XMLtoString(attr->getNodeValue()); + } else if (name.compare("consttype") == 0) { + if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("REAL") == 0) { + type = manager->getRationalType(); + } else { + STORM_PRINT_AND_LOG("Unknown consttype: " << storm::adapters::XMLtoString(attr->getNodeValue()) << std::endl); + } + } else if (name.compare("value") == 0) { + valueStr = storm::adapters::XMLtoString(attr->getNodeValue()); + } else if ((name == "x") || (name == "y")) { + // Ignore + } else { + // Found node or attribute which is at the moment not handled by this parser. + // Notify the user and continue the parsing. + STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); + } + } + + storm::expressions::Expression valueExpression; + if (type.isRationalType()) { + expressionParser.setAcceptDoubleLiterals(true); + valueExpression = manager->rational(expressionParser.parseFromString(valueStr).evaluateAsRational()); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unknown type of constant" << type << "."); + } + identifierMapping.emplace(identifier, valueExpression); + + // traverse children + for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { + auto child = node->getChildNodes()->item(i); + auto name = storm::adapters::getName(child); + + if (isOnlyWhitespace(name)) { + // ignore node (contains only whitespace) + } else { + // Found node or attribute which is at the moment nod handled by this parser. + // Notify the user and continue the parsing. + STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); + } + } + } + void GreatSpnEditorProjectParser::traverseEdgesElement(xercesc::DOMNode const* const node) { // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -217,7 +287,7 @@ namespace storm { bool ignoreTransitionAttribute(std::string const& name) { // TODO we should probably not ignore x-servers but check that it is 0.5. - if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x")) { + if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x") || (name == "delay-x") || (name == "delay-y") || (name == "rotation")) { return true; } return false; @@ -242,7 +312,8 @@ namespace storm { immediateTransition = true; } } else if(name.compare("delay") == 0) { - rate = std::stod(storm::adapters::XMLtoString(attr->getNodeValue())); + expressionParser.setAcceptDoubleLiterals(true); + rate = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); } else if (ignoreTransitionAttribute(name)) { // ignore node } else { diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h index 7c0f5e713..ba6f67a6a 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h @@ -7,6 +7,9 @@ #include #include +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm-parsers/parser/ExpressionParser.h" + #include "storm-gspn/storage/gspn/GSPN.h" #include "storm-gspn/storage/gspn/GspnBuilder.h" @@ -17,6 +20,8 @@ namespace storm { public: + GreatSpnEditorProjectParser(); + /*! * Parses the given file into the GSPN. * @@ -31,6 +36,7 @@ namespace storm { void traverseNodesElement(xercesc::DOMNode const* const node); void traverseEdgesElement(xercesc::DOMNode const* const node); + void traverseConstantElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping); void traversePlaceElement(xercesc::DOMNode const* const node); void traverseTransitionElement(xercesc::DOMNode const* const node); void traverseArcElement(xercesc::DOMNode const* const node); @@ -38,6 +44,8 @@ namespace storm { // the constructed gspn storm::gspn::GspnBuilder builder; + std::shared_ptr manager; + storm::parser::ExpressionParser expressionParser; }; } From 299f3f5c054ededa347ba1037c9cea25b455cf46 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 16:41:03 +0200 Subject: [PATCH 479/647] disallowing capacity 0 --- src/storm-gspn/settings/modules/GSPNSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index 0efed0525..fd274726f 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -24,7 +24,7 @@ namespace storm { GSPNSettings::GSPNSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, gspnFileOptionName, false, "Parses the GSPN.").setShortName(gspnFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacitiesFileOptionName, false, "Capacaties as invariants for places.").setShortName(capacitiesFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, capacityOptionName, false, "Global capacity as invariants for all places.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("value", "capacity").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, capacityOptionName, false, "Global capacity as invariants for all places.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("value", "capacity").addValidatorUnsignedInteger(ArgumentValidatorFactory::createUnsignedGreaterValidator(0)).build()).build()); } bool GSPNSettings::isGspnFileSet() const { From 17371e756ca8341a83b553e405a5ca785de8d8b2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 16:42:33 +0200 Subject: [PATCH 480/647] generate standard gspn properties automatically --- src/storm-gspn-cli/storm-gspn.cpp | 14 +- src/storm-gspn/api/storm-gspn.cpp | 9 +- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 123 +++++++++++++++++- src/storm-gspn/builder/JaniGSPNBuilder.h | 9 +- .../settings/modules/GSPNExportSettings.cpp | 6 + .../settings/modules/GSPNExportSettings.h | 6 + 6 files changed, 157 insertions(+), 10 deletions(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 70272e5b2..6b9c5e2ee 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -86,14 +86,16 @@ int main(const int argc, const char **argv) { if (!optionsCorrect) { return -1; } + + auto gspnSettings = storm::settings::getModule(); // parse gspn from file - if (!storm::settings::getModule().isGspnFileSet()) { + if (!gspnSettings.isGspnFileSet()) { return -1; } auto parser = storm::parser::GspnParser(); - auto gspn = parser.parse(storm::settings::getModule().getGspnFilename()); + auto gspn = parser.parse(gspnSettings.getGspnFilename()); std::string formulaString = ""; if (storm::settings::getModule().isPropertySet()) { @@ -107,11 +109,11 @@ int main(const int argc, const char **argv) { STORM_LOG_ERROR("The gspn is not valid."); } - if(storm::settings::getModule().isCapacitiesFileSet()) { - auto capacities = parseCapacitiesList(storm::settings::getModule().getCapacitiesFilename()); + if(gspnSettings.isCapacitiesFileSet()) { + auto capacities = parseCapacitiesList(gspnSettings.getCapacitiesFilename()); gspn->setCapacities(capacities); - } else if (storm::settings::getModule().isCapacitySet()) { - uint64_t capacity = storm::settings::getModule().getCapacity(); + } else if (gspnSettings.isCapacitySet()) { + uint64_t capacity = gspnSettings.getCapacity(); std::unordered_map capacities; for (auto const& place : gspn->getPlaces()) { capacities.emplace(place.getName(), capacity); diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index 45e579db1..b972b474c 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -63,10 +63,15 @@ namespace storm { storm::converter::JaniConversionOptions options(jani); storm::builder::JaniGSPNBuilder builder(gspn); - storm::jani::Model* model = builder.build(); + storm::jani::Model* model = builder.build("gspn_automaton", exportSettings.isAddJaniPropertiesSet()); storm::api::postprocessJani(*model, options); - storm::api::exportJaniToFile(*model, janiProperyGetter(builder), storm::settings::getModule().getWriteToJaniFilename()); + + auto properties = janiProperyGetter(builder); + if (exportSettings.isAddJaniPropertiesSet()) { + properties.insert(properties.end(), builder.getStandardProperties().begin(), builder.getStandardProperties().end()); + } + storm::api::exportJaniToFile(*model, properties, exportSettings.getWriteToJaniFilename()); delete model; } } diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index cd81bb266..45a2a5ebc 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -1,9 +1,12 @@ #include "JaniGSPNBuilder.h" +#include + +#include "storm/logic/Formulas.h" namespace storm { namespace builder { - storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName) { + storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName, bool buildStandardProperties) { storm::jani::Model* model = new storm::jani::Model(gspn.getName(), storm::jani::ModelType::MA, janiVersion, expressionManager); storm::jani::Automaton mainAutomaton(automatonName, expressionManager->declareIntegerVariable("loc")); addVariables(model); @@ -11,8 +14,15 @@ namespace storm { addEdges(mainAutomaton, locId); model->addAutomaton(mainAutomaton); model->setStandardSystemComposition(); + if (buildStandardProperties) { + buildProperties(model); + } return model; } + + std::vector const& JaniGSPNBuilder::getStandardProperties() const { + return standardProperties; + } void JaniGSPNBuilder::addVariables(storm::jani::Model* model) { for (auto const& place : gspn.getPlaces()) { @@ -150,5 +160,116 @@ namespace storm { } } + + storm::jani::Variable const& JaniGSPNBuilder::addDeadlockTransientVariable(storm::jani::Model* model, std::string name, bool ignoreCapacities, bool ignoreInhibitorArcs, bool ignoreEmptyPlaces) { + + storm::expressions::Expression transientValue = expressionManager->boolean(true); + + // build the conjunction over all transitions + std::vector transitions; + transitions.reserve(gspn.getNumberOfImmediateTransitions() + gspn.getNumberOfTimedTransitions()); + for (auto const& t : gspn.getImmediateTransitions()) { + transitions.push_back(&t); + } + for (auto const& t : gspn.getTimedTransitions()) { + transitions.push_back(&t); + } + bool firstTransition = true; + for (auto const& transition : transitions) { + + // build the disjunction over all in/out places and inhibitor arcs + storm::expressions::Expression transitionDisabled = expressionManager->boolean(false); + bool firstPlace = true; + if (!ignoreEmptyPlaces) { + for (auto const& placeIdMult : transition->getInputPlaces()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() < expressionManager->integer(placeIdMult.second)); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + if (!ignoreInhibitorArcs) { + for (auto const& placeIdMult : transition->getInhibitionPlaces()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() >= expressionManager->integer(placeIdMult.second)); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + if (!ignoreCapacities) { + for (auto const& placeIdMult : transition->getOutputPlaces()) { + auto const& place = gspn.getPlace(placeIdMult.first); + if (place->hasRestrictedCapacity()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() + expressionManager->integer(placeIdMult.second) > expressionManager->integer(place->getCapacity())); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + } + + if (firstTransition) { + transientValue = transitionDisabled; + firstTransition = false; + } else { + transientValue = transientValue && transitionDisabled; + } + } + + auto exprVar = expressionManager->declareBooleanVariable(name); + auto const& janiVar = model->addVariable(*storm::jani::makeBooleanVariable(name, exprVar, expressionManager->boolean(false), true)); + storm::jani::Assignment assignment(janiVar, transientValue); + model->getAutomata().front().getLocations().front().addTransientAssignment(assignment); + return janiVar; + } + + + std::string getUniqueVarName(storm::expressions::ExpressionManager const& manager, std::string name) { + std::string res = name; + while (manager.hasVariable(res)) { + res.append("_"); + } + return res; + } + + void JaniGSPNBuilder::buildProperties(storm::jani::Model* model) { + standardProperties.clear(); + + auto const& deadlockVar = addDeadlockTransientVariable(model, getUniqueVarName(*expressionManager, "deadl")); + auto deadlock = std::make_shared(deadlockVar.getExpressionVariable().getExpression()); + auto trueFormula = std::make_shared(true); + + auto maxReachDeadlock = std::make_shared( + std::make_shared(deadlock, storm::logic::FormulaContext::Probability), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MaxPrReachDeadlock", maxReachDeadlock, "The maximal probability to eventually reach a deadlock."); + + auto exprTB = expressionManager->declareIntegerVariable(getUniqueVarName(*expressionManager, "TIME_BOUND")); + auto janiTB = storm::jani::Constant(exprTB.getName(), exprTB); + model->addConstant(janiTB); + storm::logic::TimeBound tb(false, janiTB.getExpressionVariable().getExpression()); + storm::logic::TimeBoundReference tbr(storm::logic::TimeBoundType::Time); + auto maxReachDeadlockTimeBounded = std::make_shared( + std::make_shared(trueFormula, deadlock, boost::none, tb, tbr), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MaxPrReachDeadlockTB", maxReachDeadlockTimeBounded, "The maximal probability to reach a deadlock within 'TIME_BOUND' steps."); + + auto expTimeDeadlock = std::make_shared( + std::make_shared(deadlock, storm::logic::FormulaContext::Time), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MinExpTimeDeadlock", expTimeDeadlock, "The minimal expected time to reach a deadlock."); + + } + + } } \ No newline at end of file diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.h b/src/storm-gspn/builder/JaniGSPNBuilder.h index db890e36c..205f248e1 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.h +++ b/src/storm-gspn/builder/JaniGSPNBuilder.h @@ -19,11 +19,13 @@ namespace storm { } - storm::jani::Model* build(std::string const& automatonName = "gspn_automaton"); + storm::jani::Model* build(std::string const& automatonName = "gspn_automaton", bool buildStandardProperties = false); storm::jani::Variable const& getPlaceVariable(uint64_t placeId) const { return *vars.at(placeId); } + + std::vector const& getStandardProperties() const; private: @@ -33,11 +35,16 @@ namespace storm { void addEdges(storm::jani::Automaton& automaton, uint64_t locId); + storm::jani::Variable const& addDeadlockTransientVariable(storm::jani::Model* model, std::string name, bool ignoreCapacities = false, bool ignoreInhibitorArcs = false, bool ignoreEmptyPlaces = false); + void buildProperties(storm::jani::Model* model); + const uint64_t janiVersion = 1; storm::gspn::GSPN const& gspn; std::map vars; std::shared_ptr expressionManager; + std::vector standardProperties; + }; } } diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp index 295f963e2..895866cdf 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp @@ -20,6 +20,7 @@ namespace storm { const std::string GSPNExportSettings::writeToPnproOptionName = "to-pnpro"; const std::string GSPNExportSettings::writeToJsonOptionName = "to-json"; const std::string GSPNExportSettings::writeToJaniOptionName = "to-jani"; + const std::string GSPNExportSettings::addJaniPropertiesOptionName = "addprops"; const std::string GSPNExportSettings::writeStatsOptionName = "to-stats"; const std::string GSPNExportSettings::displayStatsOptionName = "show-stats"; @@ -32,6 +33,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, writeToPnproOptionName, false, "Destination for the pnpro output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToJsonOptionName, false, "Destination for the json output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToJaniOptionName, false, "Destination for the jani output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, addJaniPropertiesOptionName, false, "If set, a set of standard properties is added to the exported jani model.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeStatsOptionName, false, "Destination for the stats file").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, displayStatsOptionName, false, "Print stats to stdout").build()); } @@ -76,6 +78,10 @@ namespace storm { return this->getOption(writeToJaniOptionName).getArgumentByName("filename").getValueAsString(); } + bool GSPNExportSettings::isAddJaniPropertiesSet() const { + return this->getOption(addJaniPropertiesOptionName).getHasOptionBeenSet(); + } + bool GSPNExportSettings::isDisplayStatsSet() const { return this->getOption(displayStatsOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.h b/src/storm-gspn/settings/modules/GSPNExportSettings.h index fbe45a4eb..5ebb3ac5a 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.h +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.h @@ -53,6 +53,11 @@ namespace storm { */ std::string getWriteToJaniFilename() const; + /*! + * Returns whether a set of standard properties is to be added when exporting to jani + */ + bool isAddJaniPropertiesSet() const; + bool isDisplayStatsSet() const; bool isWriteStatsToFileSet() const; @@ -71,6 +76,7 @@ namespace storm { static const std::string writeToPnproOptionName; static const std::string writeToJsonOptionName; static const std::string writeToJaniOptionName; + static const std::string addJaniPropertiesOptionName; static const std::string displayStatsOptionName; static const std::string writeStatsOptionName; From 394ef9f5b3605e22539cf4901f3cabcc342b053a Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 17:36:41 +0200 Subject: [PATCH 481/647] writing the correct model name into the jani file --- src/storm-conv-cli/storm-conv.cpp | 23 +++++++++++++++++-- src/storm-conv/api/storm-conv.cpp | 15 +++++++++++- .../converter/options/JaniConversionOptions.h | 5 ++++ src/storm/storage/jani/Model.cpp | 4 ++++ src/storm/storage/jani/Model.h | 7 +++++- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 04169b2dc..294beea6b 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -51,20 +51,39 @@ namespace storm { options.allVariablesGlobal = jani.isGlobalVarsSet(); options.suffix = ""; options.janiOptions = storm::converter::JaniConversionOptions(jani); - auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); std::string outputFilename = ""; if (output.isJaniOutputFilenameSet()) { outputFilename = output.getJaniOutputFilename(); } else if (input.isPrismInputSet() && !output.isStdOutOutputEnabled()) { + outputFilename = input.getPrismInputFilename(); + // Remove extension if present + auto dotPos = outputFilename.rfind('.'); + if (dotPos != std::string::npos) { + outputFilename.erase(dotPos); + } std::string suffix = ""; if (input.isConstantsSet()) { suffix = input.getConstantDefinitionString(); std::replace(suffix.begin(), suffix.end(), ',', '_'); + std::replace(suffix.begin(), suffix.end(), '=', '-'); } suffix = suffix + ".jani"; - outputFilename = input.getPrismInputFilename() + suffix; + outputFilename += suffix; + } + auto startOfFilename = outputFilename.rfind("/"); + if (startOfFilename == std::string::npos) { + startOfFilename = 0; + } else { + ++startOfFilename; } + auto endOfFilename = outputFilename.rfind("."); + if (endOfFilename == std::string::npos) { + endOfFilename = outputFilename.size(); + } + options.janiOptions.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename); + + auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); if (outputFilename != "") { storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename); diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index 1b52092bb..a8d88a502 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -5,6 +5,9 @@ #include "storm/storage/jani/JaniLocationExpander.h" #include "storm/storage/jani/JSONExporter.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + namespace storm { namespace api { @@ -19,12 +22,22 @@ namespace storm { } if (options.exportFlattened) { - janiModel = janiModel.flattenComposition(); + std::shared_ptr smtSolverFactory; + if (storm::settings::hasModule()) { + smtSolverFactory = std::make_shared(); + } else { + smtSolverFactory = std::make_shared(); + } + janiModel = janiModel.flattenComposition(smtSolverFactory); } if (options.standardCompliant) { janiModel.makeStandardJaniCompliant(); } + + if (options.modelName) { + janiModel.setName(options.modelName.get()); + } } std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties, storm::converter::PrismToJaniConverterOptions options) { diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h index bb809f1ea..000d9cc3b 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.h +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -2,6 +2,8 @@ #include #include +#include + #include "storm-conv/settings/modules/JaniExportSettings.h" namespace storm { @@ -21,6 +23,9 @@ namespace storm { /// If set, the model is transformed into a single automaton bool exportFlattened; + /// If given, the model will get this name + boost::optional modelName; + }; } } diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 222d31326..089ac7f0e 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -116,6 +116,10 @@ namespace storm { return name; } + void Model::setName(std::string const& newName) { + name = newName; + } + struct ConditionalMetaEdge { ConditionalMetaEdge() : actionIndex(0) { // Intentionally left empty. diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 2954b1c9f..644f90f20 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -77,10 +77,15 @@ namespace storm { ModelType const& getModelType() const; /*! - * Retrievest the name of the model. + * Retrieves the name of the model. */ std::string const& getName() const; + /*! + * Sets the name of the model. + */ + void setName(std::string const& newName); + /*! * Flatten the composition to obtain an equivalent model that contains exactly one automaton that has the * standard composition. From bd475e99eb256aafacfcea9f1a136ad42271bfb1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 17:37:16 +0200 Subject: [PATCH 482/647] fixed flattening models with constants --- src/storm/storage/jani/Model.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 089ac7f0e..c74d049a2 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -446,6 +446,10 @@ namespace storm { variableRemapping.emplace(&variable, flattenedModel.addVariable(*renamedVariable)); } + for (auto const& constant : getConstants()) { + flattenedModel.addConstant(constant); + } + std::vector> composedAutomata; for (auto const& element : parallelComposition.getSubcompositions()) { STORM_LOG_THROW(element->isAutomatonComposition(), storm::exceptions::WrongFormatException, "Cannot flatten recursive (not standard-compliant) composition."); From 817c5a218bb79feaf3ac85f6c510f9347e4c30ba Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 18:35:33 +0200 Subject: [PATCH 483/647] making the time bound for generated gspn properties real valued --- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index 45a2a5ebc..aa8c64a4f 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -253,7 +253,7 @@ namespace storm { storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); standardProperties.emplace_back("MaxPrReachDeadlock", maxReachDeadlock, "The maximal probability to eventually reach a deadlock."); - auto exprTB = expressionManager->declareIntegerVariable(getUniqueVarName(*expressionManager, "TIME_BOUND")); + auto exprTB = expressionManager->declareRationalVariable(getUniqueVarName(*expressionManager, "TIME_BOUND")); auto janiTB = storm::jani::Constant(exprTB.getName(), exprTB); model->addConstant(janiTB); storm::logic::TimeBound tb(false, janiTB.getExpressionVariable().getExpression()); From 5b7839342517e16c8f46d4e625fa8615026bb592 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 16 Aug 2018 18:37:32 +0200 Subject: [PATCH 484/647] Fixed issues related to allowing local variables when converting from prism to jani --- src/storm/storage/prism/ToJaniConverter.cpp | 71 ++++++++++++++------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/storm/storage/prism/ToJaniConverter.cpp b/src/storm/storage/prism/ToJaniConverter.cpp index dca6584a1..25ecca79a 100644 --- a/src/storm/storage/prism/ToJaniConverter.cpp +++ b/src/storm/storage/prism/ToJaniConverter.cpp @@ -99,6 +99,14 @@ namespace storm { } } + // Create a mapping from variables to a flag indicating whether it should be made global + std::map variablesToMakeGlobal; + for (auto const& varMods : variablesToAccessingModuleIndices) { + assert(!varMods.second.empty()); + // If there is exactly one module reading and writing the variable, we can make the variable local to this module. + variablesToMakeGlobal[varMods.first] = allVariablesGlobal || (varMods.second.size() > 1); + } + // Go through the labels and construct assignments to transient variables that are added to the locations. std::vector transientLocationAssignments; for (auto const& label : program.getLabels()) { @@ -111,6 +119,24 @@ namespace storm { auto newExpressionVariable = manager->declareBooleanVariable(finalLabelName); storm::jani::BooleanVariable const& newTransientVariable = janiModel.addVariable(storm::jani::BooleanVariable(newExpressionVariable.getName(), newExpressionVariable, manager->boolean(false), true)); transientLocationAssignments.emplace_back(newTransientVariable, label.getStatePredicateExpression()); + + // Variables that are accessed in the label predicate expression should be made global. + std::set variables = label.getStatePredicateExpression().getVariables(); + for (auto const& variable : variables) { + variablesToMakeGlobal[variable] = true; + } + } + + // Create an initial state restriction if there was an initial construct in the program. + if (program.hasInitialConstruct()) { + janiModel.setInitialStatesRestriction(program.getInitialConstruct().getInitialStatesExpression()); + // Variables in the initial state expression should be made global + std::set variables = program.getInitialConstruct().getInitialStatesExpression().getVariables(); + for (auto const& variable : variables) { + variablesToMakeGlobal[variable] = true; + } + } else { + janiModel.setInitialStatesRestriction(manager->boolean(true)); } // Go through the reward models and construct assignments to the transient variables that are to be added to @@ -131,6 +157,11 @@ namespace storm { } } transientLocationAssignments.emplace_back(newTransientVariable, transientLocationExpression); + // Variables that are accessed in a reward term should be made global. + std::set variables = transientLocationExpression.getVariables(); + for (auto const& variable : variables) { + variablesToMakeGlobal[variable] = true; + } } std::map actionIndexToExpression; @@ -152,6 +183,11 @@ namespace storm { std::vector assignments = {storm::jani::Assignment(newTransientVariable, entry.second)}; transientEdgeAssignments.emplace(entry.first, assignments); } + // Variables that are accessed in a reward term should be made global. + std::set variables = entry.second.getVariables(); + for (auto const& variable : variables) { + variablesToMakeGlobal[variable] = true; + } } STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotImplementedException, "Transition reward translation currently not implemented."); } @@ -182,28 +218,24 @@ namespace storm { storm::jani::Automaton automaton(module.getName(), manager->declareIntegerVariable("_loc_prism2jani_" + module.getName() + "_" + suffix)); for (auto const& variable : module.getIntegerVariables()) { storm::jani::BoundedIntegerVariable newIntegerVariable = *storm::jani::makeBoundedIntegerVariable(variable.getName(), variable.getExpressionVariable(), variable.hasInitialValue() ? boost::make_optional(variable.getInitialValueExpression()) : boost::none, false, variable.getLowerBoundExpression(), variable.getUpperBoundExpression()); - std::set const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()]; - // If there is exactly one module reading and writing the variable, we can make the variable local to this module. - if (!allVariablesGlobal && accessingModuleIndices.size() == 1) { - storm::jani::BoundedIntegerVariable const& createdVariable = automaton.addVariable(newIntegerVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } else if (!accessingModuleIndices.empty()) { - // Otherwise, we need to make it global. - storm::jani::BoundedIntegerVariable const& createdVariable = janiModel.addVariable(newIntegerVariable); + auto findRes = variablesToMakeGlobal.find(variable.getExpressionVariable()); + if (findRes != variablesToMakeGlobal.end()) { + bool makeVarGlobal = findRes->second; + storm::jani::BoundedIntegerVariable const& createdVariable = makeVarGlobal ? janiModel.addVariable(newIntegerVariable) : automaton.addVariable(newIntegerVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } else { + STORM_LOG_INFO("Variable " << variable.getName() << " is declared but never used."); } } for (auto const& variable : module.getBooleanVariables()) { storm::jani::BooleanVariable newBooleanVariable = *storm::jani::makeBooleanVariable(variable.getName(), variable.getExpressionVariable(), variable.hasInitialValue() ? boost::make_optional(variable.getInitialValueExpression()) : boost::none, false); - std::set const& accessingModuleIndices = variablesToAccessingModuleIndices[variable.getExpressionVariable()]; - // If there is exactly one module reading and writing the variable, we can make the variable local to this module. - if (!allVariablesGlobal && accessingModuleIndices.size() == 1) { - storm::jani::BooleanVariable const& createdVariable = automaton.addVariable(newBooleanVariable); - variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); - } else if (!accessingModuleIndices.empty()) { - // Otherwise, we need to make it global. - storm::jani::BooleanVariable const& createdVariable = janiModel.addVariable(newBooleanVariable); + auto findRes = variablesToMakeGlobal.find(variable.getExpressionVariable()); + if (findRes != variablesToMakeGlobal.end()) { + bool makeVarGlobal = findRes->second; + storm::jani::BooleanVariable const& createdVariable = makeVarGlobal ? janiModel.addVariable(newBooleanVariable) : automaton.addVariable(newBooleanVariable); variableToVariableMap.emplace(variable.getExpressionVariable(), createdVariable); + } else { + STORM_LOG_INFO("Variable " << variable.getName() << " is declared but never used."); } } automaton.setInitialStatesRestriction(manager->boolean(true)); @@ -303,13 +335,6 @@ namespace storm { firstModule = false; } - // Create an initial state restriction if there was an initial construct in the program. - if (program.hasInitialConstruct()) { - janiModel.setInitialStatesRestriction(program.getInitialConstruct().getInitialStatesExpression()); - } else { - janiModel.setInitialStatesRestriction(manager->boolean(true)); - } - // Set the standard system composition. This is possible, because we reject non-standard compositions anyway. if (program.specifiesSystemComposition()) { CompositionToJaniVisitor visitor; From 8da922e4d5881b7869afc948f5dea5d32610cce5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 17 Aug 2018 08:31:26 +0200 Subject: [PATCH 485/647] started to include array support --- src/storm/storage/SymbolicModelDescription.cpp | 11 ++++------- src/storm/storage/jani/Model.cpp | 8 ++++++++ src/storm/storage/jani/Model.h | 10 ++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index 79a12f8b1..77c1a897d 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -144,18 +144,15 @@ namespace storm { SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const { std::map substitution = parseConstantDefinitions(constantDefinitionString); - if (this->isJaniModel()) { - storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(substitution).substituteConstants(); - return SymbolicModelDescription(preparedModel); - } else if (this->isPrismProgram()) { - return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(substitution).substituteConstants()); - } - return *this; + return preprocess(substitution); } SymbolicModelDescription SymbolicModelDescription::preprocess(std::map const& constantDefinitions) const { if (this->isJaniModel()) { storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(constantDefinitions).substituteConstants(); + if (preparedModel.hasArrayVariables()) { + preparedModel = preparedModel.convertArrays(); + } return SymbolicModelDescription(preparedModel); } else if (this->isPrismProgram()) { return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(constantDefinitions).substituteConstants()); diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index c74d049a2..040f73eba 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -923,6 +923,14 @@ namespace storm { return result; } + bool Model::hasArrayVariables() const { + return true; + } + + Model Model::convertArrays() const { + return *this; + } + void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { this->initialStatesRestriction = initialStatesRestriction; } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 644f90f20..2bcf13504 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -352,6 +352,16 @@ namespace storm { */ std::map getConstantsSubstitution() const; + /*! + * Returns true if at least one array variable occurs in the model. + */ + bool hasArrayVariables() const; + + /*! + * Converts occurring (fixed size) arrays into multiple variables. + */ + Model convertArrays() const; + /*! * Retrieves whether there is an expression restricting the legal initial values of the global variables. */ From 8202f779434d124b29a82d7a75590cd93cc76ae6 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 17 Aug 2018 17:17:43 +0200 Subject: [PATCH 486/647] array expressions --- .../storage/expressions/ExpressionManager.cpp | 33 ++- .../storage/expressions/ExpressionManager.h | 18 ++ src/storm/storage/expressions/Type.cpp | 41 ++- src/storm/storage/expressions/Type.h | 245 ++++++++++-------- .../expressions/ArrayAccessExpression.cpp | 36 +++ .../jani/expressions/ArrayAccessExpression.h | 33 +++ .../jani/expressions/ArrayExpression.cpp | 11 + .../jani/expressions/ArrayExpression.h | 33 +++ .../ConstructorArrayExpression.cpp | 72 +++++ .../expressions/ConstructorArrayExpression.h | 46 ++++ .../JaniExpressionSubstitutionVisitor.cpp | 51 ++++ .../JaniExpressionSubstitutionVisitor.h | 26 ++ .../jani/expressions/JaniExpressionVisitor.h | 19 ++ .../jani/expressions/JaniExpressions.h | 4 + .../jani/expressions/ValueArrayExpression.cpp | 68 +++++ .../jani/expressions/ValueArrayExpression.h | 42 +++ 16 files changed, 666 insertions(+), 112 deletions(-) create mode 100644 src/storm/storage/jani/expressions/ArrayAccessExpression.cpp create mode 100644 src/storm/storage/jani/expressions/ArrayAccessExpression.h create mode 100644 src/storm/storage/jani/expressions/ArrayExpression.cpp create mode 100644 src/storm/storage/jani/expressions/ArrayExpression.h create mode 100644 src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp create mode 100644 src/storm/storage/jani/expressions/ConstructorArrayExpression.h create mode 100644 src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp create mode 100644 src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h create mode 100644 src/storm/storage/jani/expressions/JaniExpressionVisitor.h create mode 100644 src/storm/storage/jani/expressions/JaniExpressions.h create mode 100644 src/storm/storage/jani/expressions/ValueArrayExpression.cpp create mode 100644 src/storm/storage/jani/expressions/ValueArrayExpression.h diff --git a/src/storm/storage/expressions/ExpressionManager.cpp b/src/storm/storage/expressions/ExpressionManager.cpp index d1b3d15cd..5cc3ffcd5 100644 --- a/src/storm/storage/expressions/ExpressionManager.cpp +++ b/src/storm/storage/expressions/ExpressionManager.cpp @@ -52,7 +52,7 @@ namespace storm { } } - ExpressionManager::ExpressionManager() : nameToIndexMapping(), indexToNameMapping(), indexToTypeMapping(), numberOfBooleanVariables(0), numberOfIntegerVariables(0), numberOfBitVectorVariables(0), numberOfRationalVariables(0), numberOfAuxiliaryVariables(0), numberOfAuxiliaryBooleanVariables(0), numberOfAuxiliaryIntegerVariables(0), numberOfAuxiliaryBitVectorVariables(0), numberOfAuxiliaryRationalVariables(0), freshVariableCounter(0) { + ExpressionManager::ExpressionManager() : nameToIndexMapping(), indexToNameMapping(), indexToTypeMapping(), numberOfBooleanVariables(0), numberOfIntegerVariables(0), numberOfBitVectorVariables(0), numberOfRationalVariables(0), numberOfArrayVariables(0), numberOfAuxiliaryVariables(0), numberOfAuxiliaryBooleanVariables(0), numberOfAuxiliaryIntegerVariables(0), numberOfAuxiliaryBitVectorVariables(0), numberOfAuxiliaryRationalVariables(0), numberOfAuxiliaryArrayVariables(0), freshVariableCounter(0) { // Intentionally left empty. } @@ -115,6 +115,11 @@ namespace storm { return rationalType.get(); } + Type const& ExpressionManager::getArrayType(Type elementType) const { + Type type(this->getSharedPointer(), std::shared_ptr(new ArrayType(elementType))); + return *arrayTypes.insert(type).first; + } + bool ExpressionManager::isValidVariableName(std::string const& name) { return name.size() < 2 || name.at(0) != '_' || name.at(1) != '_'; } @@ -149,6 +154,10 @@ namespace storm { Variable ExpressionManager::declareRationalVariable(std::string const& name, bool auxiliary) { return this->declareVariable(name, this->getRationalType(), auxiliary); } + + Variable ExpressionManager::declareArrayVariable(std::string const& name, Type const& elementType, bool auxiliary) { + return this->declareVariable(name, this->getArrayType(elementType), auxiliary); + } Variable ExpressionManager::declareOrGetVariable(std::string const& name, storm::expressions::Type const& variableType, bool auxiliary) { return declareOrGetVariable(name, variableType, auxiliary, true); @@ -168,8 +177,12 @@ namespace storm { offset = numberOfIntegerVariables++ + numberOfBitVectorVariables; } else if (variableType.isBitVectorType()) { offset = numberOfBitVectorVariables++ + numberOfIntegerVariables; - } else { + } else if (variableType.isRationalType()) { offset = numberOfRationalVariables++; + } else if (variableType.isArrayType()) { + offset = numberOfArrayVariables++; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Trying to declare a variable of unsupported type: '" << variableType.getStringRepresentation() << "'."); } } else { if (variableType.isBooleanType()) { @@ -178,8 +191,12 @@ namespace storm { offset = numberOfIntegerVariables++ + numberOfBitVectorVariables; } else if (variableType.isBitVectorType()) { offset = numberOfBitVectorVariables++ + numberOfIntegerVariables; - } else { + } else if (variableType.isRationalType()) { offset = numberOfRationalVariables++; + } else if (variableType.isArrayType()) { + offset = numberOfArrayVariables++; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Trying to declare a variable of unsupported type: '" << variableType.getStringRepresentation() << "'."); } } @@ -240,12 +257,14 @@ namespace storm { return numberOfBitVectorVariables; } else if (variableType.isRationalType()) { return numberOfRationalVariables; + } else if (variableType.isArrayType()) { + return numberOfArrayVariables; } return 0; } uint_fast64_t ExpressionManager::getNumberOfVariables() const { - return numberOfBooleanVariables + numberOfIntegerVariables + numberOfBitVectorVariables + numberOfRationalVariables; + return numberOfBooleanVariables + numberOfIntegerVariables + numberOfBitVectorVariables + numberOfRationalVariables + numberOfArrayVariables; } uint_fast64_t ExpressionManager::getNumberOfBooleanVariables() const { @@ -264,6 +283,10 @@ namespace storm { return numberOfRationalVariables; } + uint_fast64_t ExpressionManager::getNumberOfArrayVariables() const { + return numberOfRationalVariables; + } + std::string const& ExpressionManager::getVariableName(uint_fast64_t index) const { auto indexTypeNamePair = indexToNameMapping.find(index); STORM_LOG_THROW(indexTypeNamePair != indexToNameMapping.end(), storm::exceptions::InvalidArgumentException, "Unknown variable index '" << index << "'."); @@ -300,7 +323,7 @@ namespace storm { out << "manager {" << std::endl; for (auto const& variableTypePair : manager) { - std::cout << "\t" << variableTypePair.second << " " << variableTypePair.first.getName() << " [offset " << variableTypePair.first.getOffset() << "]" << std::endl; + out << "\t" << variableTypePair.second << " " << variableTypePair.first.getName() << " [offset " << variableTypePair.first.getOffset() << "]" << std::endl; } out << "}" << std::endl; diff --git a/src/storm/storage/expressions/ExpressionManager.h b/src/storm/storage/expressions/ExpressionManager.h index 3a80261b3..cf56d5670 100644 --- a/src/storm/storage/expressions/ExpressionManager.h +++ b/src/storm/storage/expressions/ExpressionManager.h @@ -149,6 +149,11 @@ namespace storm { * @return The rational type. */ Type const& getRationalType() const; + + /*! + * Retrieves the array type with the given element type + */ + Type const& getArrayType(Type elementType) const; /*! * Declares a variable that is a copy of the provided variable (i.e. has the same type). @@ -211,6 +216,11 @@ namespace storm { */ Variable declareRationalVariable(std::string const& name, bool auxiliary = false); + /*! + * Declares a new array variable with the given name and the given element type. + */ + Variable declareArrayVariable(std::string const& name, Type const& elementType, bool auxiliary = false); + /*! * Declares a variable with the given name if it does not yet exist. * @@ -321,6 +331,11 @@ namespace storm { */ uint_fast64_t getNumberOfRationalVariables() const; + /*! + * Retrieves the number of array variables. + */ + uint_fast64_t getNumberOfArrayVariables() const; + /*! * Retrieves the name of the variable with the given index. * @@ -443,6 +458,7 @@ namespace storm { uint_fast64_t numberOfIntegerVariables; uint_fast64_t numberOfBitVectorVariables; uint_fast64_t numberOfRationalVariables; + uint_fast64_t numberOfArrayVariables; // The number of declared auxiliary variables. uint_fast64_t numberOfAuxiliaryVariables; @@ -452,6 +468,7 @@ namespace storm { uint_fast64_t numberOfAuxiliaryIntegerVariables; uint_fast64_t numberOfAuxiliaryBitVectorVariables; uint_fast64_t numberOfAuxiliaryRationalVariables; + uint_fast64_t numberOfAuxiliaryArrayVariables; // A counter used to create fresh variables. uint_fast64_t freshVariableCounter; @@ -461,6 +478,7 @@ namespace storm { mutable boost::optional integerType; mutable std::unordered_set bitvectorTypes; mutable boost::optional rationalType; + mutable std::unordered_set arrayTypes; // A mask that can be used to query whether a variable is an auxiliary variable. static const uint64_t auxiliaryMask = (1ull << 50); diff --git a/src/storm/storage/expressions/Type.cpp b/src/storm/storage/expressions/Type.cpp index b51ac812a..b585b8eae 100644 --- a/src/storm/storage/expressions/Type.cpp +++ b/src/storm/storage/expressions/Type.cpp @@ -57,6 +57,14 @@ namespace storm { bool RationalType::isRationalType() const { return true; } + + bool BaseType::isArrayType() const { + return false; + } + + bool ArrayType::isArrayType() const { + return true; + } uint64_t BooleanType::getMask() const { return BooleanType::mask; @@ -102,6 +110,26 @@ namespace storm { return "rational"; } + ArrayType::ArrayType(Type elementType) : elementType(elementType) { + // Intentionally left empty + } + + Type ArrayType::getElementType() const { + return elementType; + } + + bool ArrayType::operator==(BaseType const& other) const { + return BaseType::operator==(other) && this->elementType == static_cast(other).getElementType(); + } + + uint64_t ArrayType::getMask() const { + return ArrayType::mask; + } + + std::string ArrayType::getStringRepresentation() const { + return "array[" + elementType.getStringRepresentation() + "]"; + } + bool operator<(BaseType const& first, BaseType const& second) { if (first.getMask() < second.getMask()) { return true; @@ -109,8 +137,11 @@ namespace storm { if (first.isBitVectorType() && second.isBitVectorType()) { return static_cast(first).getWidth() < static_cast(second).getWidth(); } + if (first.isArrayType() && second.isArrayType()) { + return static_cast(first).getElementType() < static_cast(second).getElementType(); + } return false; - } + } Type::Type() : manager(nullptr), innerType(nullptr) { // Intentionally left empty. @@ -144,6 +175,10 @@ namespace storm { return this->isIntegerType() || this->isRationalType(); } + bool Type::isArrayType() const { + return this->innerType->isArrayType(); + } + std::string Type::getStringRepresentation() const { return this->innerType->getStringRepresentation(); } @@ -151,6 +186,10 @@ namespace storm { std::size_t Type::getWidth() const { return static_cast(*this->innerType).getWidth(); } + + Type Type::getElementType() const { + return static_cast(*this->innerType).getElementType(); + } bool Type::isRationalType() const { return this->innerType->isRationalType(); diff --git a/src/storm/storage/expressions/Type.h b/src/storm/storage/expressions/Type.h index b173d5d53..ed5e60679 100644 --- a/src/storm/storage/expressions/Type.h +++ b/src/storm/storage/expressions/Type.h @@ -9,113 +9,8 @@ namespace storm { namespace expressions { - // Forward-declare expression manager class. class ExpressionManager; - - class BaseType { - public: - BaseType(); - virtual ~BaseType() = default; - - /*! - * Retrieves the mask that is associated with this type. - * - * @return The mask associated with this type. - */ - virtual uint64_t getMask() const = 0; - - /*! - * Checks whether two types are actually the same. - * - * @param other The type to compare with. - * @return True iff the types are the same. - */ - virtual bool operator==(BaseType const& other) const; - - /*! - * Returns a string representation of the type. - * - * @return A string representation of the type. - */ - virtual std::string getStringRepresentation() const = 0; - - virtual bool isErrorType() const; - virtual bool isBooleanType() const; - virtual bool isIntegerType() const; - virtual bool isBitVectorType() const; - virtual bool isRationalType() const; - }; - - class BooleanType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isBooleanType() const override; - - private: - static const uint64_t mask = (1ull << 60); - }; - - class IntegerType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isIntegerType() const override; - - private: - static const uint64_t mask = (1ull << 62); - }; - - class BitVectorType : public BaseType { - public: - /*! - * Creates a new bounded bitvector type with the given bit width. - * - * @param width The bit width of the type. - */ - BitVectorType(std::size_t width); - - /*! - * Retrieves the bit width of the bounded type. - * - * @return The bit width of the bounded type. - */ - std::size_t getWidth() const; - - virtual bool operator==(BaseType const& other) const override; - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isIntegerType() const override; - virtual bool isBitVectorType() const override; - - private: - static const uint64_t mask = (1ull << 61); - - // The bit width of the type. - std::size_t width; - }; - - class RationalType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isRationalType() const override; - - private: - static const uint64_t mask = (1ull << 63); - }; - - class ErrorType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isErrorType() const override; - - private: - static const uint64_t mask = 0; - }; - - bool operator<(BaseType const& first, BaseType const& second); + class BaseType; class Type { public: @@ -187,6 +82,13 @@ namespace storm { * @return True iff the type is a numerical one. */ bool isNumericalType() const; + + /*! + * Checks whether this type is an array type. + * + * @return True iff the type is an array. + */ + bool isArrayType() const; /*! * Retrieves the bit width of the type, provided that it is a bitvector type. @@ -195,6 +97,13 @@ namespace storm { */ std::size_t getWidth() const; + /*! + * Retrieves the element type of the type, provided that it is an Array type. + * + * @return The bit width of the bitvector type. + */ + Type getElementType() const; + /*! * Retrieves the manager of the type. * @@ -225,6 +134,130 @@ namespace storm { std::ostream& operator<<(std::ostream& stream, Type const& type); bool operator<(storm::expressions::Type const& type1, storm::expressions::Type const& type2); + + class BaseType { + public: + BaseType(); + virtual ~BaseType() = default; + + /*! + * Retrieves the mask that is associated with this type. + * + * @return The mask associated with this type. + */ + virtual uint64_t getMask() const = 0; + + /*! + * Checks whether two types are actually the same. + * + * @param other The type to compare with. + * @return True iff the types are the same. + */ + virtual bool operator==(BaseType const& other) const; + + /*! + * Returns a string representation of the type. + * + * @return A string representation of the type. + */ + virtual std::string getStringRepresentation() const = 0; + + virtual bool isErrorType() const; + virtual bool isBooleanType() const; + virtual bool isIntegerType() const; + virtual bool isBitVectorType() const; + virtual bool isRationalType() const; + virtual bool isArrayType() const; + }; + + class BooleanType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isBooleanType() const override; + + private: + static const uint64_t mask = (1ull << 60); + }; + + class IntegerType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isIntegerType() const override; + + private: + static const uint64_t mask = (1ull << 62); + }; + + class BitVectorType : public BaseType { + public: + /*! + * Creates a new bounded bitvector type with the given bit width. + * + * @param width The bit width of the type. + */ + BitVectorType(std::size_t width); + + /*! + * Retrieves the bit width of the bounded type. + * + * @return The bit width of the bounded type. + */ + std::size_t getWidth() const; + + virtual bool operator==(BaseType const& other) const override; + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isIntegerType() const override; + virtual bool isBitVectorType() const override; + + private: + static const uint64_t mask = (1ull << 61); + + // The bit width of the type. + std::size_t width; + }; + + class RationalType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isRationalType() const override; + + private: + static const uint64_t mask = (1ull << 63); + }; + + class ArrayType : public BaseType { + public: + ArrayType(Type elementType); + + Type getElementType() const; + + virtual bool operator==(BaseType const& other) const override; + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isArrayType() const override; + + private: + static const uint64_t mask = (1ull << 60); + + // The type of the array elements (can again be of type array). + Type elementType; + }; + + class ErrorType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isErrorType() const override; + + private: + static const uint64_t mask = 0; + }; + + bool operator<(BaseType const& first, BaseType const& second); } } diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp new file mode 100644 index 000000000..d143fc10c --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp @@ -0,0 +1,36 @@ +#include "storm/storage/jani/expressions/ArrayAccessExpression.h" + +namespace storm { + namespace expressions { + + ArrayAccessExpression::ArrayAccessExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& arrayExpression, std::shared_ptr const& indexExpression) : BinaryExpression(manager, type, arrayExpression, indexExpression) { + // Assert correct types + STORM_LOG_ASSERT(getFirstOperand()->getType().isArrayType(), "ArrayAccessExpression for an expression of type " << getFirstOperand()->getType() << "."); + STORM_LOG_ASSERT(type == getFirstOperand()->getType().getElementType(), "The ArrayAccessExpression should have type " << getFirstOperand()->getType().getElementType() << " but has " << type << " instead."); + STORM_LOG_ASSERT(getSecondOperand()->getType().isIntegerType(), "The index expression does not have an integer type."); + } + + std::shared_ptr ArrayAccessExpression::simplify() const { + return std::shared_ptr(new ArrayAccessExpression(manager, type, getFirstOperand()->simplify(), getSecondOperand()->simplify())); + } + + boost::any ArrayAccessExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ArrayAccessExpression::printToStream(std::ostream& stream) const { + if (firstOperand->isVariable()) { + getFirstOperand()->printToStream(stream); + } else { + stream << "("; + getFirstOperand()->printToStream(stream); + stream << ")"; + } + stream << "["; + getSecondOperand()->printToStream(stream); + stream << "]"; + } + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.h b/src/storm/storage/jani/expressions/ArrayAccessExpression.h new file mode 100644 index 000000000..0068b1b47 --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.h @@ -0,0 +1,33 @@ +#pragma once + +#include "storm/storage/expressions/BaseExpression.h" +#include "storm/storage/jani/expressions/ExpressionManager.h" + +namespace storm { + namespace expressions { + /*! + * Represents an access to an array. + */ + class ArrayAccessExpression : public BinaryExpression { + public: + + ArrayAccessExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& arrayExpression, std::shared_ptr const& indexExpression); + + // Instantiate constructors and assignments with their default implementations. + ArrayAccessExpression(ArrayAccessExpression const& other) = default; + ArrayAccessExpression& operator=(ArrayAccessExpression const& other) = delete; + ArrayAccessExpression(ArrayAccessExpression&&) = default; + ArrayAccessExpression& operator=(ArrayAccessExpression&&) = delete; + + virtual ~ArrayAccessExpression() = default; + + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + protected: + virtual void printToStream(std::ostream& stream) const override; + + + }; + } +} diff --git a/src/storm/storage/jani/expressions/ArrayExpression.cpp b/src/storm/storage/jani/expressions/ArrayExpression.cpp new file mode 100644 index 000000000..1f6aa0e49 --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayExpression.cpp @@ -0,0 +1,11 @@ +#include "storm/storage/jani/expressions/ArrayExpression.h" + +namespace storm { + namespace expressions { + + ArrayExpression::ArrayExpression(ExpressionManager const& manager, Type const& type) : BaseExpression(manager, type) { + // Intentionally left empty + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ArrayExpression.h b/src/storm/storage/jani/expressions/ArrayExpression.h new file mode 100644 index 000000000..63b1bae8e --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayExpression.h @@ -0,0 +1,33 @@ +#pragma once + +#include "storm/storage/expressions/BaseExpression.h" +#include "storm/storage/jani/expressions/ExpressionManager.h" + +namespace storm { + namespace expressions { + /*! + * The base class of all array expressions. + */ + class ArrayExpression : public BaseExpression { + public: + + ArrayExpression(ExpressionManager const& manager, Type const& type); + + // Instantiate constructors and assignments with their default implementations. + ArrayExpression(ArrayExpression const& other) = default; + ArrayExpression& operator=(ArrayExpression const& other) = delete; + ArrayExpression(ArrayExpression&&) = default; + ArrayExpression& operator=(ArrayExpression&&) = delete; + + virtual ~ArrayExpression() = default; + + // Returns the size of the array + virtual std::shared_ptr size() const = 0; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const = 0; + + + }; + } +} diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp new file mode 100644 index 000000000..d643c527e --- /dev/null +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp @@ -0,0 +1,72 @@ +#include "storm/storage/jani/expressions/ConstructorArrayExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + ConstructorArrayExpression::ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression) : ArrayExpression(manager, type), size(size), indexVar(indexVar), elementExpression(elementExpression) { + // Intentionally left empty + } + + void ConstructorArrayExpression::gatherVariables(std::set& variables) const { + // The indexVar should not be gathered (unless it is already contained). + bool indexVarContained = variables.find(indexVar) != variables.end(); + size->gatherVariables(variables); + elementExpression->gatherVariables(variables); + if (!indexVarContained) { + variables.erase(indexVar); + } + } + + bool ConstructorArrayExpression::containsVariables() const { + if (size->containsVariables()) { + return true; + } + // The index variable should not count + std::set variables; + elementExpression->gatherVariables(variables); + variables.erase(indexVar); + return !variables.empty(); + } + + std::shared_ptr ConstructorArrayExpression::simplify() const { + return std::shared_ptr(new ConstructorArrayExpression(manager, type, size->simplify(), indexVar, elementExpression->simplify())); + } + + boost::any ConstructorArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ConstructorArrayExpression::printToStream(std::ostream& stream) const { + stream << "array[ "; + elementExpression->printToStream(stream); + stream << " | " << indexVar << "<"; + size->printToStream(stream); + stream << " ]"; + } + + std::shared_ptr ConstructorArrayExpression::size() const { + return size; + } + + std::shared_ptr ConstructorArrayExpression::at(uint64_t i) const { + STORM_LOG_THROW(i < elements.size(), storm::exceptions::InvalidArgumentException, "Tried to access the element with index " << i << " of an array of size " << elements.size() << "."); + return elements[i]; + } + + std::shared_ptr const& ConstructorArrayExpression::getElementExpression() const { + return elementExpression; + } + + storm::expressions::Variable const& ConstructorArrayExpression::getIndexVar() const { + return indexVar; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h new file mode 100644 index 000000000..07d52b570 --- /dev/null +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h @@ -0,0 +1,46 @@ +#pragma once + +#include "storm/storage/jani/expressions/ArrayExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array of the given size, where the i'th entry is determined by the elementExpression, where occurrences of indexVar will be substituted by i + */ + class ConstructorArrayExpression : public ArrayExpression { + public: + + ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression); + + + // Instantiate constructors and assignments with their default implementations. + ConstructorArrayExpression(ConstructorArrayExpression const& other) = default; + ConstructorArrayExpression& operator=(ConstructorArrayExpression const& other) = delete; + ConstructorArrayExpression(ConstructorArrayExpression&&) = default; + ConstructorArrayExpression& operator=(ConstructorArrayExpression&&) = delete; + + virtual ~ConstructorArrayExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + // Returns the size of the array + virtual std::shared_ptr size() const override; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const override; + + std::shared_ptr const& getElementExpression() const; + storm::expressions::Variable const& getIndexVar() const; + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::shared_ptr size; + storm::expressions::Variable indexVar; + std::shared_ptr const& elementExpression; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp new file mode 100644 index 000000000..0a449d3d5 --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -0,0 +1,51 @@ +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace expressions { + template + boost::any JaniExpressionSubstitutionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { + uint64_t size = expression.getSize()->evaluateAsInt(); + std::vector> newElements; + newElements.reserve(size); + for (uint64_t i = 0; i < size; ++i) { + newElements.push_back(boost::any_cast>(expression.at(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new ValueArrayExpression(expression.getManager(), expression.getType(), newElements))); + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(ConstructorArrayExpression const& expression, boost::any const& data) { + std::shared_ptr newSize = boost::any_cast>(expression.getSize()->accept(*this, data)); + std::shared_ptr elementExpression = boost::any_cast>(expression.getElementExpression()->accept(*this, data)); + STORM_LOG_THROW(this->variableToExpressionMapping.find(expression.getIndexVar()) == this->variableToExpressionMapping.end(), storm::exceptions::InvalidArgumentException, "substitution of the index variable of a constructorArrayExpression is not possible."); + + // If the arguments did not change, we simply push the expression itself. + if (newSize.get() == expression.getSize().get() && elementExpression.get() == expression.getElementExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ConstructorArrayExpression(expression.getManager(), expression.getType(), newSize, expression.getIndexVar(), elementExpression))); + } + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(ArrayAccessExpression const& expression, boost::any const& data) { + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ArrayAccessExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression))); + } + } + + + // Explicitly instantiate the class with map and unordered_map. + template class JaniExpressionSubstitutionVisitor>; + template class JaniExpressionSubstitutionVisitor>; + + } +} diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h new file mode 100644 index 000000000..131c2f8ac --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/expressions/SubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" + + +namespace storm { + namespace expressions { + template + class JaniExpressionSubstitutionVisitor : public SubstitutionVisitor, public ExpressionManager { + public: + /*! + * Creates a new substitution visitor that uses the given map to replace variables. + * + * @param variableToExpressionMapping A mapping from variables to expressions. + */ + JaniExpressionSubstitutionVisitor(MapType const& variableToExpressionMapping); + + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override; + }; + } +} + +#endif /* STORM_STORAGE_EXPRESSIONS_SUBSTITUTIONVISITOR_H_ */ diff --git a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h new file mode 100644 index 000000000..d9c86e9af --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "storm/storage/expressions/SubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" + + +namespace storm { + namespace expressions { + template + class JaniExpressionVisitor{ + public: + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) = 0; + }; + } +} + +#endif /* STORM_STORAGE_EXPRESSIONS_SUBSTITUTIONVISITOR_H_ */ diff --git a/src/storm/storage/jani/expressions/JaniExpressions.h b/src/storm/storage/jani/expressions/JaniExpressions.h new file mode 100644 index 000000000..a48ec5119 --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressions.h @@ -0,0 +1,4 @@ +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/jani/expressions/ArrayAccessExpression.h" +#include "storm/storage/jani/expressions/ConstructorArrayExpression.h" +#include "storm/storage/jani/expressions/ValueArrayExpression.h" diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.cpp b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp new file mode 100644 index 000000000..feaf5a395 --- /dev/null +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp @@ -0,0 +1,68 @@ +#include "storm/storage/jani/expressions/ValueArrayExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + ValueArrayExpression::ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> const& elements) : ArrayExpression(manager, type), elements(elements) { + // Intentionally left empty + } + + void ValueArrayExpression::gatherVariables(std::set& variables) const { + for (auto const& e : elements) { + e->gatherVariables(variables); + } + } + + bool ValueArrayExpression::containsVariables() const { + for (auto const& e : elements) { + if (e->containsVariables()) { + return true; + } + } + return false; + } + + std::shared_ptr ValueArrayExpression::simplify() const { + std::vector> simplifiedElements; + simplifiedElements.reserve(elements.size()); + for (auto const& e : elements) { + simplifiedElements.push_back(e->simplify()); + } + return std::shared_ptr(new ValueArrayExpression(manager, type, simplifiedElements)); + } + + boost::any ValueArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ValueArrayExpression::printToStream(std::ostream& stream) const { + stream << "array[ "; + bool first = true; + for (auto const& e : elements) { + e->printToStream(stream); + if (!first) { + stream << " , "; + } + first = false; + } + stream << " ]"; + } + + std::shared_ptr ValueArrayExpression::size() const { + return this->manager.integer(elements.size()).getBaseExpressionPointer(); + } + + std::shared_ptr ValueArrayExpression::at(uint64_t i) const { + STORM_LOG_THROW(i < elements.size(), storm::exceptions::InvalidArgumentException, "Tried to access the element with index " << i << " of an array of size " << elements.size() << "."); + return elements[i]; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.h b/src/storm/storage/jani/expressions/ValueArrayExpression.h new file mode 100644 index 000000000..641330387 --- /dev/null +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.h @@ -0,0 +1,42 @@ +#pragma once + +#include "storm/storage/jani/expressions/ArrayExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array with a given list of elements. + */ + class ValueArrayExpression : public ArrayExpression { + public: + + ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> elements); + + + // Instantiate constructors and assignments with their default implementations. + ValueArrayExpression(ValueArrayExpression const& other) = default; + ValueArrayExpression& operator=(ValueArrayExpression const& other) = delete; + ValueArrayExpression(ValueArrayExpression&&) = default; + ValueArrayExpression& operator=(ValueArrayExpression&&) = delete; + + virtual ~ValueArrayExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + // Returns the size of the array + virtual std::shared_ptr size() const override; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const override; + + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::vector> elements; + }; + } +} \ No newline at end of file From 4b3e7849ed9c97dbb557ed469a2ebcb0bd031275 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 17 Aug 2018 17:18:08 +0200 Subject: [PATCH 487/647] jani parser parses array variables --- src/storm-parsers/parser/JaniParser.cpp | 208 ++++++++++++++--------- src/storm-parsers/parser/JaniParser.h | 10 +- src/storm/storage/jani/ArrayVariable.cpp | 57 +++++++ src/storm/storage/jani/ArrayVariable.h | 52 ++++++ src/storm/storage/jani/Model.cpp | 3 +- src/storm/storage/jani/Variable.cpp | 13 ++ src/storm/storage/jani/Variable.h | 4 + 7 files changed, 266 insertions(+), 81 deletions(-) create mode 100644 src/storm/storage/jani/ArrayVariable.cpp create mode 100644 src/storm/storage/jani/ArrayVariable.h diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 0d415d388..6d2df8e36 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -10,6 +10,7 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/InvalidJaniException.h" @@ -23,6 +24,7 @@ #include #include #include +#include #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -109,8 +111,9 @@ namespace storm { STORM_LOG_THROW(variablesCount < 2, storm::exceptions::InvalidJaniException, "Variable-declarations can be given at most once for global variables."); std::unordered_map> globalVars; if (variablesCount == 1) { + bool requireInitialValues = parsedStructure.count("restrict-initial") == 0; for (auto const& varStructure : parsedStructure.at("variables")) { - std::shared_ptr variable = parseVariable(varStructure, "global", globalVars, constants); + std::shared_ptr variable = parseVariable(varStructure, requireInitialValues, "global", globalVars, constants); globalVars.emplace(variable->getName(), variable); model.addVariable(*variable); } @@ -626,8 +629,52 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scopeDescription << ")"); } - - std::shared_ptr JaniParser::parseVariable(json const& variableStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool prefWithScope) { + + void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { + if (typeStructure.is_string()) { + if (typeStructure == "real") { + result.basicType = ParsedType::BasicType::Real; + } else if (typeStructure == "bool") { + result.basicType = ParsedType::BasicType::Bool; + } else if (typeStructure == "int") { + result.basicType = ParsedType::BasicType::Int; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); + } + } else if (typeStructure.is_object()) { + STORM_LOG_THROW(typeStructure.count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << variableName << "(scope: " << scopeDescription << ") kind must be given"); + std::string kind = getString(typeStructure.at("kind"), "kind for complex type as in variable " + variableName + "(scope: " + scopeDescription + ") "); + if (kind == "bounded") { + STORM_LOG_THROW(typeStructure.count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") lower-bound must be given"); + storm::expressions::Expression lowerboundExpr = parseExpression(typeStructure.at("lower-bound"), "Lower bound for variable " + variableName + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + assert(lowerboundExpr.isInitialized()); + STORM_LOG_THROW(typeStructure.count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") upper-bound must be given"); + storm::expressions::Expression upperboundExpr = parseExpression(typeStructure.at("upper-bound"), "Upper bound for variable "+ variableName + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + assert(upperboundExpr.isInitialized()); + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") base must be given"); + std::string basictype = getString(typeStructure.at("base"), "base for bounded type as in variable " + variableName + "(scope: " + scopeDescription + ") "); + if (basictype == "int") { + STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ") must be integer-typed"); + STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ") must be integer-typed"); + if (!lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { + STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ")"); + } + result.basicType = ParsedType::BasicType::Int; + result.bounds = std::make_pair(lowerboundExpr, upperboundExpr); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << variableName << "(scope: " << scopeDescription << ") "); + } + } else if (kind == "array") { + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For array type as in variable " << variableName << "(scope: " << scopeDescription << ") base must be given"); + result.arrayBase = ParsedType(); + parseType(result.arrayBase.get(), typeStructure.at("base"), variableName, scopeDescription, globalVars, constants, localVars); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); + } + } + } + + std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool prefWithScope) { STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); std::string pref = prefWithScope ? scopeDescription + VARIABLE_AUTOMATON_DELIMITER : ""; std::string name = getString(variableStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); @@ -640,101 +687,103 @@ namespace storm { if(tvarcount == 1) { transientVar = getBoolean(variableStructure.at("transient"), "transient-attribute in variable '" + name + "' (scope: " + scopeDescription + ") "); } + STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); + ParsedType type; + parseType(type, variableStructure.at("type"), name, scopeDescription, globalVars, constants, localVars); + size_t initvalcount = variableStructure.count("initial-value"); if(transientVar) { STORM_LOG_THROW(initvalcount == 1, storm::exceptions::InvalidJaniException, "Initial value must be given once for transient variable '" + name + "' (scope: " + scopeDescription + ") "+ name + "' (scope: " + scopeDescription + ") "); } else { STORM_LOG_THROW(initvalcount <= 1, storm::exceptions::InvalidJaniException, "Initial value can be given at most one for variable " + name + "' (scope: " + scopeDescription + ")"); } - STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); boost::optional initVal; - if(variableStructure.at("type").is_string()) { - if(variableStructure.at("type") == "real") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { + if (initvalcount == 1 && !variableStructure.at("initial-value").is_null()) { + initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); + } else { + assert(!transientVar); + } + + bool setInitValFromDefault = !initVal.is_initialized() && requireInitialValues; + if (type.basicType) { + switch (type.basicType.get()) { + case ParsedType::BasicType::Real: + if (setInitValFromDefault) { initVal = expressionManager->rational(defaultRationalInitialValue); - } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scopeDescription + ") should be a rational"); } - return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar); - - } - assert(!transientVar); - return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName)); - } else if(variableStructure.at("type") == "bool") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = expressionManager->boolean(defaultBooleanInitialValue); + if (initVal) { + STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scopeDescription + ") should be a rational"); + return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar); } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scopeDescription + ") should be a Boolean"); + return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName)); } - if(transientVar) { - labels.insert(name); + case ParsedType::BasicType::Int: + if (setInitValFromDefault) { + if (type.bounds) { + initVal = storm::expressions::ite(type.bounds->first < 0 && type.bounds->second > 0, expressionManager->integer(defaultIntegerInitialValue), type.bounds->first); + // TODO as soon as we support half-open intervals, we have to change this. + } else { + initVal = expressionManager->integer(defaultIntegerInitialValue); + } } - return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName), initVal.get(), transientVar); - } - assert(!transientVar); - return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName)); - } else if(variableStructure.at("type") == "int") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = expressionManager->integer(defaultIntegerInitialValue); - } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); + if (initVal) { STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); - } - return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); - } - assert(!transientVar); // Checked earlier. - return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName)); - } else if(variableStructure.at("type") == "clock") { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'clock' for variable '" << name << "' (scope: " << scopeDescription << ")"); - } else if(variableStructure.at("type") == "continuous") { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'continuous' for variable ''" << name << "' (scope: " << scopeDescription << ")"); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); - } - } else if(variableStructure.at("type").is_object()) { - STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scopeDescription << ") kind must be given"); - std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scopeDescription + ") "); - if(kind == "bounded") { - // First do the bounds, that makes the code a bit more streamlined - STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound must be given"); - storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable " + name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(lowerboundExpr.isInitialized()); - STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") upper-bound must be given"); - storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(upperboundExpr.isInitialized()); - STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") base must be given"); - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = storm::expressions::ite(lowerboundExpr < 0 && upperboundExpr > 0, expressionManager->integer(0), lowerboundExpr); - // TODO as soon as we support half-open intervals, we have to change this. + if (type.bounds) { + return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, type.bounds->first, type.bounds->second); + } else { + return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); + } } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); + if (type.bounds) { + return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); + } else { + return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), boost::none, false, type.bounds->first, type.bounds->second); + } } - } - std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scopeDescription + ") "); - if(basictype == "int") { - if(initVal) { - STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); + break; + case ParsedType::BasicType::Bool: + if (setInitValFromDefault) { + initVal = expressionManager->boolean(defaultBooleanInitialValue); } - STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - if(!lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { - STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ")"); + if (initVal) { + STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scopeDescription + ") should be a Boolean"); + if (transientVar) { + labels.insert(name); + } + return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName), initVal.get(), transientVar); + } else { + return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName)); } - return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, lowerboundExpr, upperboundExpr); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scopeDescription << ") "); - } + } + } else if (type.arrayBase) { + STORM_LOG_THROW(type.arrayBase->basicType, storm::exceptions::InvalidJaniException, "Array base type for variable " + name + "(scope " + scopeDescription + ") should be a BasicType or a BoundedType."); + storm::jani::ArrayVariable::ElementType elementType; + storm::expressions::Type* exprVariableType; + switch (type.arrayBase->basicType.get()) { + case ParsedType::BasicType::Real: + elementType = storm::jani::ArrayVariable::ElementType::Real; + exprVariableType = &expressionManager->getArrayType(expressionManager->getRationalType()); + break; + case ParsedType::BasicType::Bool: + elementType = storm::jani::ArrayVariable::ElementType::Bool; + exprVariableType = &expressionManager->getArrayType(expressionManager->getBooleanType()); + break; + case ParsedType::BasicType::Int: + elementType = storm::jani::ArrayVariable::ElementType::Int; + exprVariableType = &expressionManager->getArrayType(expressionManager->getIntegerType()); + break; + } + if (setInitValFromDefault) { + initVal = storm::expressions::ValueArrayExpression(expressionManager, *exprVariableType, {}); + } + if (initVal) { + STORM_LOG_THROW(initVal.get().hasArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scopeDescription + ") should be an Array"); + return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType->getElementType()), elementType, initVal.get(), transientVar); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); + return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType->getElementType()), elementType); } } - + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); } @@ -1050,8 +1099,9 @@ namespace storm { STORM_LOG_THROW(varDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of variables"); std::unordered_map> localVars; if(varDeclCount > 0) { + bool requireInitialValues = automatonStructure.count("restrict-initial") == 0; for(auto const& varStructure : automatonStructure.at("variables")) { - std::shared_ptr var = parseVariable(varStructure, name, globalVars, constants, localVars, true); + std::shared_ptr var = parseVariable(varStructure, requireInitialValues, name, globalVars, constants, localVars, true); assert(localVars.count(var->getName()) == 0); automaton.addVariable(*var); localVars.emplace(var->getName(), var); diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index 1ac4a514f..a6141c37c 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -48,7 +48,15 @@ namespace storm { std::pair> parseModel(bool parseProperties = true); storm::jani::Property parseProperty(json const& propertyStructure, std::unordered_map> const& globalVars, std::unordered_map> const& constants); storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants); - std::shared_ptr parseVariable(json const& variableStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool prefWithScope = false); + struct ParsedType { + enum class BasicType {Bool, Int, Real}; + + boost::optional basicType; + boost::optional> bounds; + boost::optional arrayBase; + }; + void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars); + std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool prefWithScope = false); storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false); private: diff --git a/src/storm/storage/jani/ArrayVariable.cpp b/src/storm/storage/jani/ArrayVariable.cpp new file mode 100644 index 000000000..95e146d91 --- /dev/null +++ b/src/storm/storage/jani/ArrayVariable.cpp @@ -0,0 +1,57 @@ +#include "storm/storage/jani/ArrayVariable.h" + +namespace storm { + namespace jani { + + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable) : Variable(name, variable) { + // Intentionally left empty. + } + + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& initValue) : Variable(name, variable, initValue, transient) { + // Intentionally left empty. + } + + void ArrayVariable::setElementTypeBounds(storm::expressions::Expression lowerBound, storm::expressions::Expression upperBound) { + elementTypeBounds = std::make_pair(lowerBound, upperBound); + } + + bool ArrayVariable::hasElementTypeBounds() const { + return elementTypeBounds.is_initialized(); + } + + std::pair const& ArrayVariable::getElementTypeBounds() const { + return elementTypeBounds.get(); + } + + void ArrayVariable::setMaxSize(uint64_t size) { + maxSize = size; + } + + bool ArrayVariable::hasMaxSize() const { + return maxSize.is_initialized(); + } + + uint64_t ArrayVariable::getMaxSize() const { + return maxSize.get(); + } + + ElementType ArrayVariable::getElementType() const { + return elementType; + } + + std::unique_ptr ArrayVariable::clone() const { + return std::make_unique(*this); + } + + bool ArrayVariable::isArrayVariable() const { + return true; + } + + void ArrayVariable::substitute(std::map const& substitution) { + Variable::substitute(substitution); + if (hasElementTypeBounds()) { + setElementTypeBounds(elementTypeBounds->first.substitute(substitution), elementTypeBounds->second.substitute(substitution)); + } + } + } +} diff --git a/src/storm/storage/jani/ArrayVariable.h b/src/storm/storage/jani/ArrayVariable.h new file mode 100644 index 000000000..f8aca2397 --- /dev/null +++ b/src/storm/storage/jani/ArrayVariable.h @@ -0,0 +1,52 @@ +#pragma once + +#include "storm/storage/jani/Variable.h" + +namespace storm { + namespace jani { + + class ArrayVariable : public Variable { + public: + + enum class ElementType {Bool, Int, Real}; + + /*! + * Creates an Array variable + */ + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType elementType); + + /*! + * Creates an Array variable with initial value + */ + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType elementType, storm::expressions::Expression const& initialValue, bool transient); + + /*! + * Sets/Gets bounds to the values stored in this array + */ + void setElementTypeBounds(storm::expressions::Expression lowerBound, storm::expressions::Expression upperBound); + bool hasElementTypeBounds() const; + std::pair const& getElementTypeBounds() const; + + /*! + * Sets/Gets the maximum size of the array + */ + void setMaxSize(uint64_t size); + bool hasMaxSize() const; + uint64_t getMaxSize() const; + + ElementType getElementType() const; + + virtual std::unique_ptr clone() const override; + virtual bool isArrayVariable() const override; + virtual void substitute(std::map const& substitution) override; + + + private: + ElementType elementType; + boost::optional> elementTypeBounds; + boost::optional maxSize; + }; + + + } +} diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 040f73eba..bd6e59c0c 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -924,10 +924,11 @@ namespace storm { } bool Model::hasArrayVariables() const { - return true; + return getExpressionManager().getNumberOfArrayVariables() != 0; } Model Model::convertArrays() const { + std::cout << "TODO"; return *this; } diff --git a/src/storm/storage/jani/Variable.cpp b/src/storm/storage/jani/Variable.cpp index 00f867ac2..d6a67996c 100644 --- a/src/storm/storage/jani/Variable.cpp +++ b/src/storm/storage/jani/Variable.cpp @@ -4,6 +4,7 @@ #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/storage/jani/UnboundedIntegerVariable.h" #include "storm/storage/jani/RealVariable.h" +#include "storm/storage/jani/ArrayVariable.h" namespace storm { namespace jani { @@ -48,6 +49,10 @@ namespace storm { return false; } + bool Variable::isArrayVariable() const { + return false; + } + bool Variable::isTransient() const { return transient; } @@ -96,6 +101,14 @@ namespace storm { return static_cast(*this); } + ArrayVariable& Variable::asArrayVariable() { + return static_cast(*this); + } + + ArrayVariable const& Variable::asArrayVariable() const { + return static_cast(*this); + } + void Variable::substitute(std::map const& substitution) { if (this->hasInitExpression()) { this->setInitExpression(this->getInitExpression().substitute(substitution)); diff --git a/src/storm/storage/jani/Variable.h b/src/storm/storage/jani/Variable.h index 010b37449..8d5884a12 100644 --- a/src/storm/storage/jani/Variable.h +++ b/src/storm/storage/jani/Variable.h @@ -14,6 +14,7 @@ namespace storm { class BoundedIntegerVariable; class UnboundedIntegerVariable; class RealVariable; + class ArrayVariable; class Variable { public: @@ -72,6 +73,7 @@ namespace storm { virtual bool isBoundedIntegerVariable() const; virtual bool isUnboundedIntegerVariable() const; virtual bool isRealVariable() const; + virtual bool isArrayVariable() const; virtual bool isTransient() const; @@ -84,6 +86,8 @@ namespace storm { UnboundedIntegerVariable const& asUnboundedIntegerVariable() const; RealVariable& asRealVariable(); RealVariable const& asRealVariable() const; + RealVariable& asArrayVariable(); + RealVariable const& asArrayVariable() const; /*! * Substitutes all variables in all expressions according to the given substitution. From f9f6b90cc2869111d67c9be9b9739c0d5ea55db5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 20 Aug 2018 09:52:05 +0200 Subject: [PATCH 488/647] updated changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ad6718a..637e9e21b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ The releases of major and minor versions contain an overview of changes since th Version 1.2.x ------------- +### Version 1.2.4 (2018/08) +- New binary `storm-conv` that handles conversions between model files (currently: prism to jani) +- Added support for expected time properties for discrete time models +- Several bug fixes related to jani +- `storm-gspn`: Improved .pnpro parser +- `storm-gspn`: Added option to set a global capacity for all places +- `storm-gspn`: Added option to include a set of standard properties when converting GSPNs to jani + ### Version 1.2.3 (2018/07) - Fix in version parsing From 7f601058a11b5a1d0b556527080c8f49efdcdf38 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 20 Aug 2018 14:19:18 +0200 Subject: [PATCH 489/647] flatten option should not require module prefix --- src/storm-conv/settings/modules/JaniExportSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 588bde61a..da45fdf0f 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -24,7 +24,7 @@ namespace storm { JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, true, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); } From 49930ebc9e44da83d94686f936ff9e2ad675159d Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 20 Aug 2018 14:33:06 +0200 Subject: [PATCH 490/647] fixed help text --- src/storm-conv/settings/modules/JaniExportSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index da45fdf0f..5199a308d 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -22,7 +22,7 @@ namespace storm { JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { - this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list with local variables.").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list of automaton and local variable names seperated by a dot, e.g. A.x,B.y.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); From 3215af6fc00dc0f20e7e561526dc1f61d6ee950d Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 21 Aug 2018 10:39:11 +0200 Subject: [PATCH 491/647] Implemented single- infinite- and k- server semantics for timed gspn transitions --- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 26 +++++++++- .../parser/GreatSpnEditorProjectParser.cpp | 13 ++++- src/storm-gspn/storage/gspn/GSPN.cpp | 2 + src/storm-gspn/storage/gspn/GspnBuilder.cpp | 11 ++++- src/storm-gspn/storage/gspn/GspnBuilder.h | 11 ++++- .../storage/gspn/GspnJsonExporter.cpp | 11 ++++- src/storm-gspn/storage/gspn/TimedTransition.h | 47 ++++++++++++++++++- 7 files changed, 114 insertions(+), 7 deletions(-) diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index aa8c64a4f..d21ef5c21 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -3,6 +3,8 @@ #include #include "storm/logic/Formulas.h" + +#include "storm/exceptions/InvalidModelException.h" namespace storm { namespace builder { @@ -132,7 +134,7 @@ namespace storm { } for (auto const& trans : gspn.getTimedTransitions()) { storm::expressions::Expression guard = expressionManager->boolean(true); - + std::vector assignments; for (auto const& inPlaceEntry : trans.getInputPlaces()) { guard = guard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second); @@ -153,9 +155,29 @@ namespace storm { std::shared_ptr templateEdge = std::make_shared(guard); automaton.registerTemplateEdge(templateEdge); + + storm::expressions::Expression rate = expressionManager->rational(trans.getRate()); + if (trans.hasInfiniteServerSemantics() || (trans.hasKServerSemantics() && !trans.hasSingleServerSemantics())) { + STORM_LOG_THROW(trans.hasKServerSemantics() || !trans.getInputPlaces().empty(), storm::exceptions::InvalidModelException, "Unclear semantics: Found a transition with infinite-server semantics and without input place."); + storm::expressions::Expression enablingDegree; + bool firstArgumentOfMinExpression = true; + if (trans.hasKServerSemantics()) { + enablingDegree = expressionManager->integer(trans.getNumberOfServers()); + firstArgumentOfMinExpression = false; + } + for (auto const& inPlaceEntry : trans.getInputPlaces()) { + storm::expressions::Expression enablingDegreeInPlace = vars[inPlaceEntry.first]->getExpressionVariable() / expressionManager->integer(inPlaceEntry.second); // Integer division! + if (firstArgumentOfMinExpression == true) { + enablingDegree = enablingDegreeInPlace; + } else { + enablingDegree = storm::expressions::minimum(enablingDegree, enablingDegreeInPlace); + } + } + rate = rate * enablingDegree; + } templateEdge->addDestination(assignments); - storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, expressionManager->rational(trans.getRate()), templateEdge, {locId}, {expressionManager->integer(1)}); + storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, rate, templateEdge, {locId}, {expressionManager->integer(1)}); automaton.addEdge(e); } diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index f4b4418a2..17d49e6f1 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -297,6 +297,7 @@ namespace storm { std::string transitionName; bool immediateTransition; double rate = 1.0; // The default rate in GreatSPN. + boost::optional numServers; // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -314,6 +315,16 @@ namespace storm { } else if(name.compare("delay") == 0) { expressionParser.setAcceptDoubleLiterals(true); rate = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); + } else if (name.compare("nservers") == 0) { + std::string nservers = storm::adapters::XMLtoString(attr->getNodeValue()); + if (nservers == "Single") { + numServers = 1; + } else if (nservers == "Infinite") { + // Ignore this case as we assume infinite by default (similar to GreatSpn) + } else { + expressionParser.setAcceptDoubleLiterals(false); + numServers = expressionParser.parseFromString(nservers).evaluateAsInt(); + } } else if (ignoreTransitionAttribute(name)) { // ignore node } else { @@ -327,7 +338,7 @@ namespace storm { if (immediateTransition) { builder.addImmediateTransition(0, 0, transitionName); } else { - builder.addTimedTransition(0, rate, transitionName); + builder.addTimedTransition(0, rate, numServers, transitionName); } // traverse children diff --git a/src/storm-gspn/storage/gspn/GSPN.cpp b/src/storm-gspn/storage/gspn/GSPN.cpp index c622cc4fe..5278b3b30 100644 --- a/src/storm-gspn/storage/gspn/GSPN.cpp +++ b/src/storm-gspn/storage/gspn/GSPN.cpp @@ -168,6 +168,7 @@ namespace storm { for (auto& trans : this->getTimedTransitions()) { outStream << "\t" << trans.getName() << " [label=\"" << trans.getName(); outStream << "(" << trans.getRate() << ")\"];" << std::endl; + STORM_LOG_WARN_COND(trans.hasSingleServerSemantics(), "Unable to export non-trivial transition semantics"); // TODO } // print arcs @@ -555,6 +556,7 @@ namespace storm { // add timed transitions for (const auto &trans : timedTransitions) { + STORM_LOG_WARN_COND(trans.hasInfiniteServerSemantics(), "Unable to export non-trivial transition semantics"); // TODO stream << space2 << "" << std::endl; stream << space3 << "" << std::endl; stream << space4 << "" << trans.getRate() << "" << std::endl; diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.cpp b/src/storm-gspn/storage/gspn/GspnBuilder.cpp index e273768ea..6920680ed 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.cpp +++ b/src/storm-gspn/storage/gspn/GspnBuilder.cpp @@ -65,13 +65,22 @@ namespace storm { return newId; } - + uint_fast64_t GspnBuilder::addTimedTransition(uint_fast64_t const &priority, double const &rate, std::string const& name) { + return addTimedTransition(priority, rate, 1, name); + } + + uint_fast64_t GspnBuilder::addTimedTransition(uint_fast64_t const &priority, double const &rate, boost::optional numServers, std::string const& name) { auto trans = storm::gspn::TimedTransition(); auto newId = GSPN::timedTransitionIdToTransitionId(timedTransitions.size()); trans.setName(name); trans.setPriority(priority); trans.setRate(rate); + if (numServers) { + trans.setKServerSemantics(numServers.get()); + } else { + trans.setInfiniteServerSemantics(); + } trans.setID(newId); timedTransitions.push_back(trans); diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.h b/src/storm-gspn/storage/gspn/GspnBuilder.h index a9a99699f..35c5ed220 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.h +++ b/src/storm-gspn/storage/gspn/GspnBuilder.h @@ -39,11 +39,20 @@ namespace storm { /** * Adds an timed transition to the gspn. + * The transition is assumed to have Single-Server-Semantics * @param priority The priority for the transtion. - * @param weight The weight for the transition. + * @param rate The rate for the transition. */ uint_fast64_t addTimedTransition(uint_fast64_t const &priority, RateType const& rate, std::string const& name = ""); + /** + * Adds an timed transition to the gspn. + * @param priority The priority for the transtion. + * @param rate The rate for the transition. + * @param numServers The number of servers this transition has (in case of K-Server semantics) or boost::none (in case of Infinite-Server-Semantics). + */ + uint_fast64_t addTimedTransition(uint_fast64_t const &priority, RateType const& rate, boost::optional numServers, std::string const& name = ""); + void setTransitionLayoutInfo(uint64_t transitionId, LayoutInfo const& layoutInfo); diff --git a/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp b/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp index 4e451d094..f4e910b81 100644 --- a/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp +++ b/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp @@ -160,7 +160,16 @@ namespace storm { data["name"] = transition.getName(); data["rate"] = transition.getRate(); data["priority"] = transition.getPriority(); - + if (!transition.hasSingleServerSemantics()) { + if (transition.hasInfiniteServerSemantics()) { + data["server-semantics"] = "infinite"; + } else if (transition.hasKServerSemantics()) { + data["server-semantics"] = transition.getNumberOfServers(); + } else { + STORM_LOG_WARN("Unable to export transition semantics."); + } + } + modernjson::json position; position["x"] = x * scaleFactor; position["y"] = y * scaleFactor; diff --git a/src/storm-gspn/storage/gspn/TimedTransition.h b/src/storm-gspn/storage/gspn/TimedTransition.h index d8399319d..37b5476f6 100644 --- a/src/storm-gspn/storage/gspn/TimedTransition.h +++ b/src/storm-gspn/storage/gspn/TimedTransition.h @@ -1,12 +1,18 @@ #pragma once #include "storm-gspn/storage/gspn/Transition.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace gspn { template class TimedTransition : public storm::gspn::Transition { public: + + TimedTransition() { + setSingleServerSemantics(); + } + /*! * Sets the rate of this transition to the given value. * @@ -15,7 +21,43 @@ namespace storm { void setRate(RateType const& rate) { this->rate = rate; } - + + /*! + * Sets the semantics of this transition + */ + void setKServerSemantics(uint64_t k) { + STORM_LOG_THROW(k>0, storm::exceptions::InvalidArgumentException, "Invalid Parameter for server semantics: 0"); + nServers = k; + } + + void setSingleServerSemantics() { + nServers = 1; + } + + void setInfiniteServerSemantics() { + nServers = 0; + } + + /*! + * Retrieves the semantics of this transition + */ + bool hasKServerSemantics() const { + return nServers > 0; + } + + bool hasSingleServerSemantics() const { + return nServers == 1; + } + + bool hasInfiniteServerSemantics() const { + return nServers == 0; + } + + uint64_t getNumberOfServers() const { + STORM_LOG_ASSERT(hasKServerSemantics(), "Tried to get the number of servers of a timed transition although it does not have K-Server-Semantics."); + return nServers; + } + /*! * Retrieves the rate of this transition. * @@ -28,6 +70,9 @@ namespace storm { private: // the rate of the transition RateType rate; + + // the number of servers of this transition. 0 means infinite server semantics. + uint64_t nServers; }; } } \ No newline at end of file From a44eed65e8d5e8d7324ccc42df462c73cdf89c1f Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 21 Aug 2018 10:39:49 +0200 Subject: [PATCH 492/647] allowing constant definitions for gspns via cli --- src/storm-gspn-cli/storm-gspn.cpp | 7 ++++- .../parser/GreatSpnEditorProjectParser.cpp | 29 ++++++++++++++++--- .../parser/GreatSpnEditorProjectParser.h | 4 +-- src/storm-gspn/parser/GspnParser.cpp | 5 ++-- src/storm-gspn/parser/GspnParser.h | 2 +- .../settings/modules/GSPNSettings.cpp | 12 ++++++++ .../settings/modules/GSPNSettings.h | 13 ++++++++- 7 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 6b9c5e2ee..1dda8938e 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -94,8 +94,13 @@ int main(const int argc, const char **argv) { return -1; } + std::string constantDefinitionString = ""; + if (gspnSettings.isConstantsSet()) { + constantDefinitionString = gspnSettings.getConstantDefinitionString(); + } + auto parser = storm::parser::GspnParser(); - auto gspn = parser.parse(gspnSettings.getGspnFilename()); + auto gspn = parser.parse(gspnSettings.getGspnFilename(), constantDefinitionString); std::string formulaString = ""; if (storm::settings::getModule().isPropertySet()) { diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index 17d49e6f1..9bee3d085 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -23,8 +23,15 @@ namespace { namespace storm { namespace parser { - GreatSpnEditorProjectParser::GreatSpnEditorProjectParser() : manager(std::make_shared()), expressionParser(*manager) { - // Intentionally left empty + GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString) : manager(std::make_shared()), expressionParser(*manager) { + std::vector constDefs; + boost::split( constDefs, constantDefinitionString, boost::is_any_of(",")); + for (auto const& pair : constDefs) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of("=")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::WrongFormatException, "Expected a constant definition of the form N=42 but got " << pair); + constantDefinitions.emplace(keyvaluepair.at(0), keyvaluepair.at(1)); + } } storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) { @@ -168,6 +175,8 @@ namespace storm { } else if (name.compare("consttype") == 0) { if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("REAL") == 0) { type = manager->getRationalType(); + } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("INTEGER") == 0) { + type = manager->getIntegerType(); } else { STORM_PRINT_AND_LOG("Unknown consttype: " << storm::adapters::XMLtoString(attr->getNodeValue()) << std::endl); } @@ -182,10 +191,20 @@ namespace storm { } } + STORM_LOG_THROW(constantDefinitions.count(identifier) == 0, storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); + storm::expressions::Expression valueExpression; + if (valueStr == "") { + auto constDef = constantDefinitions.find(identifier); + STORM_LOG_THROW(constDef != constantDefinitions.end(), storm::exceptions::NotSupportedException, "Constant '" << identifier << "' has no value defined."); + valueStr = constDef->second; + } if (type.isRationalType()) { expressionParser.setAcceptDoubleLiterals(true); valueExpression = manager->rational(expressionParser.parseFromString(valueStr).evaluateAsRational()); + } else if (type.isIntegerType()) { + expressionParser.setAcceptDoubleLiterals(false); + valueExpression = manager->integer(expressionParser.parseFromString(valueStr).evaluateAsInt()); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unknown type of constant" << type << "."); } @@ -257,7 +276,8 @@ namespace storm { if (name.compare("name") == 0) { placeName = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("marking") == 0) { - initialTokens = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); + expressionParser.setAcceptDoubleLiterals(false); + initialTokens = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); } else if (ignorePlaceAttribute(name)) { // ignore node } else { @@ -388,7 +408,8 @@ namespace storm { } else if (name.compare("kind") == 0) { kind = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("mult") == 0) { - mult = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); + expressionParser.setAcceptDoubleLiterals(false); + mult = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); } else if (ignoreArcAttribute(name)) { // ignore node } else { diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h index ba6f67a6a..693422af7 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h @@ -20,7 +20,7 @@ namespace storm { public: - GreatSpnEditorProjectParser(); + GreatSpnEditorProjectParser(std::string const& constantDefinitionString); /*! * Parses the given file into the GSPN. @@ -46,7 +46,7 @@ namespace storm { storm::gspn::GspnBuilder builder; std::shared_ptr manager; storm::parser::ExpressionParser expressionParser; - + std::unordered_map constantDefinitions; }; } } diff --git a/src/storm-gspn/parser/GspnParser.cpp b/src/storm-gspn/parser/GspnParser.cpp index b92b6f006..89a2f57e9 100644 --- a/src/storm-gspn/parser/GspnParser.cpp +++ b/src/storm-gspn/parser/GspnParser.cpp @@ -12,7 +12,7 @@ namespace storm { namespace parser { - storm::gspn::GSPN* GspnParser::parse(std::string const& filename) { + storm::gspn::GSPN* GspnParser::parse(std::string const& filename, std::string const& constantDefinitions) { #ifdef STORM_HAVE_XERCES // initialize xercesc try { @@ -62,10 +62,11 @@ namespace storm { xercesc::DOMElement* elementRoot = parser->getDocument()->getDocumentElement(); if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "pnml") { + STORM_LOG_WARN_COND(constantDefinitions == "", "Constant definitions for pnml files are currently not supported."); PnmlParser p; return p.parse(elementRoot); } else if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { - GreatSpnEditorProjectParser p; + GreatSpnEditorProjectParser p(constantDefinitions); return p.parse(elementRoot); } else { // If the top-level node is not a "pnml" or "" node, then throw an exception. diff --git a/src/storm-gspn/parser/GspnParser.h b/src/storm-gspn/parser/GspnParser.h index 862dfc757..512f0ddd6 100644 --- a/src/storm-gspn/parser/GspnParser.h +++ b/src/storm-gspn/parser/GspnParser.h @@ -4,7 +4,7 @@ namespace storm { namespace parser { class GspnParser { public: - static storm::gspn::GSPN* parse(std::string const& filename); + static storm::gspn::GSPN* parse(std::string const& filename, std::string const& constantDefinitions = ""); }; } } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index fd274726f..b114559a5 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -19,12 +19,16 @@ namespace storm { const std::string GSPNSettings::capacitiesFileOptionName = "capacitiesfile"; const std::string GSPNSettings::capacitiesFileOptionShortName = "capacities"; const std::string GSPNSettings::capacityOptionName = "capacity"; + const std::string GSPNSettings::constantsOptionName = "constants"; + const std::string GSPNSettings::constantsOptionShortName = "const"; + GSPNSettings::GSPNSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, gspnFileOptionName, false, "Parses the GSPN.").setShortName(gspnFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacitiesFileOptionName, false, "Capacaties as invariants for places.").setShortName(capacitiesFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacityOptionName, false, "Global capacity as invariants for all places.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("value", "capacity").addValidatorUnsignedInteger(ArgumentValidatorFactory::createUnsignedGreaterValidator(0)).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use.").setShortName(constantsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); } bool GSPNSettings::isGspnFileSet() const { @@ -51,6 +55,14 @@ namespace storm { return this->getOption(capacityOptionName).getArgumentByName("value").getValueAsUnsignedInteger(); } + bool GSPNSettings::isConstantsSet() const { + return this->getOption(constantsOptionName).getHasOptionBeenSet(); + } + + std::string GSPNSettings::getConstantDefinitionString() const { + return this->getOption(constantsOptionName).getArgumentByName("values").getValueAsString(); + } + void GSPNSettings::finalize() { } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.h b/src/storm-gspn/settings/modules/GSPNSettings.h index 665e588fb..78586cf9c 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.h +++ b/src/storm-gspn/settings/modules/GSPNSettings.h @@ -44,6 +44,16 @@ namespace storm { */ uint64_t getCapacity() const; + /*! + * Retrieves whether the constants ption was set. + */ + bool isConstantsSet() const; + + /*! + * Retrieves the string that defines the constants of a gspn + */ + std::string getConstantDefinitionString() const; + bool check() const override; void finalize() override; @@ -56,7 +66,8 @@ namespace storm { static const std::string capacitiesFileOptionName; static const std::string capacitiesFileOptionShortName; static const std::string capacityOptionName; - + static const std::string constantsOptionName; + static const std::string constantsOptionShortName; }; } } From 1f40a56ed8a35d1afe271c43b1566d0794f50676 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 21 Aug 2018 10:41:35 +0200 Subject: [PATCH 493/647] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 637e9e21b..7dd207331 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Version 1.2.x - Added support for expected time properties for discrete time models - Several bug fixes related to jani - `storm-gspn`: Improved .pnpro parser +- `storm-gspn`: Added support for single/infinite/k-server semantics for GSPNs given in the .pnpro format - `storm-gspn`: Added option to set a global capacity for all places - `storm-gspn`: Added option to include a set of standard properties when converting GSPNs to jani From 5f201da6daf1a95945a17968476afadc42250731 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 21 Aug 2018 13:44:01 +0200 Subject: [PATCH 494/647] correctly parse templates, weights, priorities --- .../parser/GreatSpnEditorProjectParser.cpp | 45 ++++++++++++------- .../parser/GreatSpnEditorProjectParser.h | 2 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index 9bee3d085..44fcb8bf8 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -24,13 +24,15 @@ namespace storm { namespace parser { GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString) : manager(std::make_shared()), expressionParser(*manager) { - std::vector constDefs; - boost::split( constDefs, constantDefinitionString, boost::is_any_of(",")); - for (auto const& pair : constDefs) { - std::vector keyvaluepair; - boost::split( keyvaluepair, pair, boost::is_any_of("=")); - STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::WrongFormatException, "Expected a constant definition of the form N=42 but got " << pair); - constantDefinitions.emplace(keyvaluepair.at(0), keyvaluepair.at(1)); + if (constantDefinitionString != "") { + std::vector constDefs; + boost::split( constDefs, constantDefinitionString, boost::is_any_of(",")); + for (auto const& pair : constDefs) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of("=")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::WrongFormatException, "Expected a constant definition of the form N=42 but got " << pair); + constantDefinitions.emplace(keyvaluepair.at(0), keyvaluepair.at(1)); + } } } @@ -133,8 +135,8 @@ namespace storm { for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); - if (name.compare("constant") == 0) { - traverseConstantElement(child, identifierMapping); + if (name.compare("constant") == 0 || name.compare("template") == 0) { + traverseConstantOrTemplateElement(child, identifierMapping); } } expressionParser.setIdentifierMapping(identifierMapping); @@ -148,7 +150,7 @@ namespace storm { traversePlaceElement(child); } else if(name.compare("transition") == 0) { traverseTransitionElement(child); - } else if(name.compare("constant") == 0) { + } else if(name.compare("constant") == 0 || name.compare("template") == 0) { // Ignore constant def in second pass } else if (isOnlyWhitespace(name)) { // ignore node (contains only whitespace) @@ -160,7 +162,7 @@ namespace storm { } } - void GreatSpnEditorProjectParser::traverseConstantElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping) { + void GreatSpnEditorProjectParser::traverseConstantOrTemplateElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping) { std::string identifier; storm::expressions::Type type; std::string valueStr = ""; @@ -172,7 +174,7 @@ namespace storm { if (name.compare("name") == 0) { identifier = storm::adapters::XMLtoString(attr->getNodeValue()); - } else if (name.compare("consttype") == 0) { + } else if (name.compare("consttype") == 0 || name.compare("type") == 0) { if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("REAL") == 0) { type = manager->getRationalType(); } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("INTEGER") == 0) { @@ -191,8 +193,7 @@ namespace storm { } } - STORM_LOG_THROW(constantDefinitions.count(identifier) == 0, storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); - + STORM_LOG_THROW(identifierMapping.count(identifier) == 0, storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); storm::expressions::Expression valueExpression; if (valueStr == "") { auto constDef = constantDefinitions.find(identifier); @@ -317,6 +318,8 @@ namespace storm { std::string transitionName; bool immediateTransition; double rate = 1.0; // The default rate in GreatSPN. + double weight = 1.0; // The default weight in GreatSpn + uint64_t priority = 1; // The default priority in GreatSpn boost::optional numServers; // traverse attributes @@ -329,12 +332,20 @@ namespace storm { } else if (name.compare("type") == 0) { if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("EXP") == 0) { immediateTransition = false; - } else { + } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("IMM") == 0) { immediateTransition = true; + } else { + STORM_PRINT_AND_LOG("unknown transition type: " << storm::adapters::XMLtoString(attr->getNodeValue())); } } else if(name.compare("delay") == 0) { expressionParser.setAcceptDoubleLiterals(true); rate = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); + } else if(name.compare("weight") == 0) { + expressionParser.setAcceptDoubleLiterals(true); + weight = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); + } else if(name.compare("priority") == 0) { + expressionParser.setAcceptDoubleLiterals(false); + priority = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); } else if (name.compare("nservers") == 0) { std::string nservers = storm::adapters::XMLtoString(attr->getNodeValue()); if (nservers == "Single") { @@ -356,7 +367,7 @@ namespace storm { } if (immediateTransition) { - builder.addImmediateTransition(0, 0, transitionName); + builder.addImmediateTransition(priority, weight, transitionName); } else { builder.addTimedTransition(0, rate, numServers, transitionName); } @@ -405,7 +416,7 @@ namespace storm { head = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("tail") == 0) { tail = storm::adapters::XMLtoString(attr->getNodeValue()); - } else if (name.compare("kind") == 0) { + } else if (name.compare("kind") == 0 || name.compare("type") == 0) { kind = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("mult") == 0) { expressionParser.setAcceptDoubleLiterals(false); diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h index 693422af7..41606bd98 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h @@ -36,7 +36,7 @@ namespace storm { void traverseNodesElement(xercesc::DOMNode const* const node); void traverseEdgesElement(xercesc::DOMNode const* const node); - void traverseConstantElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping); + void traverseConstantOrTemplateElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping); void traversePlaceElement(xercesc::DOMNode const* const node); void traverseTransitionElement(xercesc::DOMNode const* const node); void traverseArcElement(xercesc::DOMNode const* const node); From c124ebcc932a0709814122405fd46e521b04bea2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 21 Aug 2018 15:44:54 +0200 Subject: [PATCH 495/647] Fixed a Jani-related issue when adding assignments to OrderedAssignments --- src/storm/storage/jani/OrderedAssignments.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 7d1967ff7..9c622fe2b 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -27,19 +27,17 @@ namespace storm { bool OrderedAssignments::add(Assignment const& assignment, bool addToExisting) { // If the element is contained in this set of assignment, nothing needs to be added. - if (this->contains(assignment)) { + if (!addToExisting && this->contains(assignment)) { return false; } // Otherwise, we find the spot to insert it. auto it = lowerBound(assignment, allAssignments); - - if (it != allAssignments.end()) { - if ((!addToExisting || !assignment.getExpressionVariable().hasNumericalType())) { - STORM_LOG_THROW(assignment.getExpressionVariable() != (*it)->getExpressionVariable(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); - } else if (addToExisting && assignment.getExpressionVariable().hasNumericalType()) { - (*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression()); - } + + // Check if an assignment to this variable is already present + if (it != allAssignments.end() && assignment.getExpressionVariable() == (*it)->getExpressionVariable()) { + STORM_LOG_THROW(addToExisting && assignment.getExpressionVariable().hasNumericalType(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); + (*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression()); } else { // Finally, insert the new element in the correct vectors. auto elementToInsert = std::make_shared(assignment); From 4861b8d4b4b7edc0f48073d78481aa2dd01f23f8 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 22 Aug 2018 12:56:08 +0200 Subject: [PATCH 496/647] More robust parsing of capacities and allowing constants in GSPN properties --- src/storm-gspn-cli/storm-gspn.cpp | 28 +------- src/storm-gspn/api/storm-gspn.cpp | 34 ++++++++- src/storm-gspn/api/storm-gspn.h | 6 +- .../parser/GreatSpnEditorProjectParser.cpp | 69 +++++++++++-------- .../parser/GreatSpnEditorProjectParser.h | 7 +- src/storm-gspn/storage/gspn/GSPN.cpp | 18 +++-- src/storm-gspn/storage/gspn/GSPN.h | 11 ++- src/storm-gspn/storage/gspn/GspnBuilder.cpp | 13 ++-- src/storm-gspn/storage/gspn/GspnBuilder.h | 4 +- 9 files changed, 119 insertions(+), 71 deletions(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 1dda8938e..4308a1de8 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -5,9 +5,6 @@ #include "storm-gspn/builder/JaniGSPNBuilder.h" #include "storm-gspn/api/storm-gspn.h" -#include "storm/exceptions/BaseException.h" -#include "storm/exceptions/WrongFormatException.h" - #include "storm/utility/macros.h" #include "storm/utility/initialize.h" @@ -57,25 +54,6 @@ void initializeSettings() { } -std::unordered_map parseCapacitiesList(std::string const& filename) { - std::unordered_map map; - - std::ifstream stream; - storm::utility::openFile(filename, stream); - - std::string line; - while ( std::getline(stream, line) ) { - std::vector strs; - boost::split(strs, line, boost::is_any_of("\t ")); - STORM_LOG_THROW(strs.size() == 2, storm::exceptions::WrongFormatException, "Expect key value pairs"); - std::cout << std::stoll(strs[1]) << std::endl; - map[strs[0]] = std::stoll(strs[1]); - } - storm::utility::closeFile(stream); - return map; -} - - int main(const int argc, const char **argv) { try { storm::utility::setUp(); @@ -109,13 +87,14 @@ int main(const int argc, const char **argv) { boost::optional> propertyFilter; storm::parser::FormulaParser formulaParser(gspn->getExpressionManager()); std::vector properties = storm::api::parseProperties(formulaParser, formulaString, propertyFilter); - + properties = storm::api::substituteConstantsInProperties(properties, gspn->getConstantsSubstitution()); + if (!gspn->isValid()) { STORM_LOG_ERROR("The gspn is not valid."); } if(gspnSettings.isCapacitiesFileSet()) { - auto capacities = parseCapacitiesList(gspnSettings.getCapacitiesFilename()); + auto capacities = storm::api::parseCapacitiesList(gspnSettings.getCapacitiesFilename(), *gspn); gspn->setCapacities(capacities); } else if (gspnSettings.isCapacitySet()) { uint64_t capacity = gspnSettings.getCapacity(); @@ -131,7 +110,6 @@ int main(const int argc, const char **argv) { delete gspn; return 0; -// // // construct ma // auto builder = storm::builder::ExplicitGspnModelBuilder<>(); // auto ma = builder.translateGspn(gspn, formula); diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index b972b474c..7b18bc010 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -5,7 +5,8 @@ #include "storm-gspn/settings/modules/GSPNExportSettings.h" #include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm-conv/api/storm-conv.h" - +#include "storm-parsers/parser/ExpressionParser.h" +#include "storm/exceptions/WrongFormatException.h" namespace storm { namespace api { @@ -75,5 +76,36 @@ namespace storm { delete model; } } + + std::unordered_map parseCapacitiesList(std::string const& filename, storm::gspn::GSPN const& gspn) { + storm::parser::ExpressionParser expressionParser(*gspn.getExpressionManager()); + std::unordered_map identifierMapping; + for (auto const& var : gspn.getExpressionManager()->getVariables()) { + identifierMapping.emplace(var.getName(), var.getExpression()); + } + expressionParser.setIdentifierMapping(identifierMapping); + expressionParser.setAcceptDoubleLiterals(false); + + std::unordered_map map; + + std::ifstream stream; + storm::utility::openFile(filename, stream); + + std::string line; + while ( std::getline(stream, line) ) { + std::vector strs; + boost::split(strs, line, boost::is_any_of("\t ")); + STORM_LOG_THROW(strs.size() == 2, storm::exceptions::WrongFormatException, "Expect key value pairs"); + storm::expressions::Expression expr = expressionParser.parseFromString(strs[1]); + if (!gspn.getConstantsSubstitution().empty()) { + expr = expr.substitute(gspn.getConstantsSubstitution()); + } + STORM_LOG_THROW(!expr.containsVariables(), storm::exceptions::WrongFormatException, "The capacity expression '" << strs[1] << "' still contains undefined constants."); + map[strs[0]] = expr.evaluateAsInt(); + } + storm::utility::closeFile(stream); + return map; + } } } + diff --git a/src/storm-gspn/api/storm-gspn.h b/src/storm-gspn/api/storm-gspn.h index 7d2360946..a54bd6e28 100644 --- a/src/storm-gspn/api/storm-gspn.h +++ b/src/storm-gspn/api/storm-gspn.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "storm/storage/jani/Model.h" #include "storm-gspn/storage/gspn/GSPN.h" #include "storm-gspn/builder/JaniGSPNBuilder.h" @@ -14,6 +16,8 @@ namespace storm { void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, std::function(storm::builder::JaniGSPNBuilder const&)> const& janiProperyGetter = [](storm::builder::JaniGSPNBuilder const&) { return std::vector(); }); - + + std::unordered_map parseCapacitiesList(std::string const& filename, storm::gspn::GSPN const& gspn); + } } diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index 44fcb8bf8..4c77bc3a2 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -23,7 +23,7 @@ namespace { namespace storm { namespace parser { - GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString) : manager(std::make_shared()), expressionParser(*manager) { + GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString) : manager(std::make_shared()) { if (constantDefinitionString != "") { std::vector constDefs; boost::split( constDefs, constantDefinitionString, boost::is_any_of(",")); @@ -39,7 +39,7 @@ namespace storm { storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) { if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { traverseProjectElement(elementRoot); - return builder.buildGspn(); + return builder.buildGspn(manager, constantsSubstitution); } else { // If the top-level node is not a "pnml" or "" node, then throw an exception. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n"); @@ -130,17 +130,23 @@ namespace storm { // traverse children // First pass: find constant definitions + constantsSubstitution.clear(); + expressionParser = std::make_shared(*manager); std::unordered_map identifierMapping; - expressionParser.setIdentifierMapping(identifierMapping); + expressionParser->setIdentifierMapping(identifierMapping); for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); if (name.compare("constant") == 0 || name.compare("template") == 0) { - traverseConstantOrTemplateElement(child, identifierMapping); + traverseConstantOrTemplateElement(child); } } - expressionParser.setIdentifierMapping(identifierMapping); - + // Update the expression parser to make the newly created variables known to it + expressionParser = std::make_shared(*manager); + for (auto const& var : manager->getVariables()) { + identifierMapping.emplace(var.getName(), var.getExpression()); + } + expressionParser->setIdentifierMapping(identifierMapping); // Second pass: traverse other children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); @@ -162,7 +168,7 @@ namespace storm { } } - void GreatSpnEditorProjectParser::traverseConstantOrTemplateElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping) { + void GreatSpnEditorProjectParser::traverseConstantOrTemplateElement(xercesc::DOMNode const* const node) { std::string identifier; storm::expressions::Type type; std::string valueStr = ""; @@ -193,24 +199,24 @@ namespace storm { } } - STORM_LOG_THROW(identifierMapping.count(identifier) == 0, storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); - storm::expressions::Expression valueExpression; + STORM_LOG_THROW(!manager->hasVariable(identifier), storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); if (valueStr == "") { auto constDef = constantDefinitions.find(identifier); STORM_LOG_THROW(constDef != constantDefinitions.end(), storm::exceptions::NotSupportedException, "Constant '" << identifier << "' has no value defined."); valueStr = constDef->second; } + storm::expressions::Variable var; if (type.isRationalType()) { - expressionParser.setAcceptDoubleLiterals(true); - valueExpression = manager->rational(expressionParser.parseFromString(valueStr).evaluateAsRational()); + var = manager->declareRationalVariable(identifier); + expressionParser->setAcceptDoubleLiterals(true); } else if (type.isIntegerType()) { - expressionParser.setAcceptDoubleLiterals(false); - valueExpression = manager->integer(expressionParser.parseFromString(valueStr).evaluateAsInt()); + var = manager->declareIntegerVariable(identifier); + expressionParser->setAcceptDoubleLiterals(false); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unknown type of constant" << type << "."); } - identifierMapping.emplace(identifier, valueExpression); - + constantsSubstitution.emplace(var, expressionParser->parseFromString(valueStr)); + // traverse children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); @@ -277,8 +283,7 @@ namespace storm { if (name.compare("name") == 0) { placeName = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("marking") == 0) { - expressionParser.setAcceptDoubleLiterals(false); - initialTokens = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); + initialTokens = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignorePlaceAttribute(name)) { // ignore node } else { @@ -338,14 +343,11 @@ namespace storm { STORM_PRINT_AND_LOG("unknown transition type: " << storm::adapters::XMLtoString(attr->getNodeValue())); } } else if(name.compare("delay") == 0) { - expressionParser.setAcceptDoubleLiterals(true); - rate = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); + rate = parseReal(storm::adapters::XMLtoString(attr->getNodeValue())); } else if(name.compare("weight") == 0) { - expressionParser.setAcceptDoubleLiterals(true); - weight = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsDouble(); + weight = parseReal(storm::adapters::XMLtoString(attr->getNodeValue())); } else if(name.compare("priority") == 0) { - expressionParser.setAcceptDoubleLiterals(false); - priority = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); + priority = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (name.compare("nservers") == 0) { std::string nservers = storm::adapters::XMLtoString(attr->getNodeValue()); if (nservers == "Single") { @@ -353,8 +355,7 @@ namespace storm { } else if (nservers == "Infinite") { // Ignore this case as we assume infinite by default (similar to GreatSpn) } else { - expressionParser.setAcceptDoubleLiterals(false); - numServers = expressionParser.parseFromString(nservers).evaluateAsInt(); + numServers = parseInt(nservers); } } else if (ignoreTransitionAttribute(name)) { // ignore node @@ -419,8 +420,7 @@ namespace storm { } else if (name.compare("kind") == 0 || name.compare("type") == 0) { kind = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("mult") == 0) { - expressionParser.setAcceptDoubleLiterals(false); - mult = expressionParser.parseFromString(storm::adapters::XMLtoString(attr->getNodeValue())).evaluateAsInt(); + mult = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignoreArcAttribute(name)) { // ignore node } else { @@ -463,6 +463,21 @@ namespace storm { } } + int64_t GreatSpnEditorProjectParser::parseInt(std::string str) { + expressionParser->setAcceptDoubleLiterals(false); + auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution); + STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables."); + return expr.evaluateAsInt(); + } + + double GreatSpnEditorProjectParser::parseReal(std::string str) { + expressionParser->setAcceptDoubleLiterals(true); + auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution); + STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables."); + return expr.evaluateAsDouble(); + } + + } } #endif diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h index 41606bd98..7663d2a23 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h @@ -36,17 +36,20 @@ namespace storm { void traverseNodesElement(xercesc::DOMNode const* const node); void traverseEdgesElement(xercesc::DOMNode const* const node); - void traverseConstantOrTemplateElement(xercesc::DOMNode const* const node, std::unordered_map& identifierMapping); + void traverseConstantOrTemplateElement(xercesc::DOMNode const* const node); void traversePlaceElement(xercesc::DOMNode const* const node); void traverseTransitionElement(xercesc::DOMNode const* const node); void traverseArcElement(xercesc::DOMNode const* const node); + int64_t parseInt(std::string str); + double parseReal(std::string str); // the constructed gspn storm::gspn::GspnBuilder builder; std::shared_ptr manager; - storm::parser::ExpressionParser expressionParser; + std::shared_ptr expressionParser; std::unordered_map constantDefinitions; + std::map constantsSubstitution; }; } } diff --git a/src/storm-gspn/storage/gspn/GSPN.cpp b/src/storm-gspn/storage/gspn/GSPN.cpp index 5278b3b30..903425735 100644 --- a/src/storm-gspn/storage/gspn/GSPN.cpp +++ b/src/storm-gspn/storage/gspn/GSPN.cpp @@ -26,8 +26,8 @@ namespace storm { return tId; } - GSPN::GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager) - : name(name), places(places), immediateTransitions(itransitions), timedTransitions(ttransitions), partitions(partitions), exprManager(exprManager) + GSPN::GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager, std::map const& constantsSubstitution) + : name(name), places(places), immediateTransitions(itransitions), timedTransitions(ttransitions), partitions(partitions), exprManager(exprManager), constantsSubstitution(constantsSubstitution) { } @@ -134,12 +134,16 @@ namespace storm { return getImmediateTransition(id); } + + std::shared_ptr const& GSPN::getExpressionManager() const { + return exprManager; + } + + std::map const& GSPN::getConstantsSubstitution() const { + return constantsSubstitution; + } - std::shared_ptr const& GSPN::getExpressionManager() const { - return exprManager; - } - - void GSPN::setCapacities(std::unordered_map const& mapping) { + void GSPN::setCapacities(std::unordered_map const& mapping) { for(auto const& entry : mapping) { storm::gspn::Place* place = getPlace(entry.first); STORM_LOG_THROW(place != nullptr, storm::exceptions::InvalidArgumentException, "No place with name " << entry.first); diff --git a/src/storm-gspn/storage/gspn/GSPN.h b/src/storm-gspn/storage/gspn/GSPN.h index 7b37ed5cb..343dcd887 100644 --- a/src/storm-gspn/storage/gspn/GSPN.h +++ b/src/storm-gspn/storage/gspn/GSPN.h @@ -32,7 +32,7 @@ namespace storm { GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, - std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager); + std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager, std::map const& constantsSubstitution = std::map()); /*! * Returns the number of places in this gspn. @@ -145,8 +145,13 @@ namespace storm { */ std::shared_ptr const& getExpressionManager() const; + /*! + * Gets an assignment of occurring constants of the GSPN to their value + */ + std::map const& getConstantsSubstitution() const; + /** - * Set Capacities according to name->capacity map. + * Set Capacities of places according to name->capacity map. */ void setCapacities(std::unordered_map const& mapping); @@ -217,6 +222,8 @@ namespace storm { std::vector partitions; std::shared_ptr exprManager; + + std::map constantsSubstitution; // Layout information mutable std::map placeLayout; diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.cpp b/src/storm-gspn/storage/gspn/GspnBuilder.cpp index 6920680ed..c39b5c0f7 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.cpp +++ b/src/storm-gspn/storage/gspn/GspnBuilder.cpp @@ -171,8 +171,13 @@ namespace storm { - storm::gspn::GSPN* GspnBuilder::buildGspn() const { - std::shared_ptr exprManager(new storm::expressions::ExpressionManager()); + storm::gspn::GSPN* GspnBuilder::buildGspn(std::shared_ptr const& exprManager, std::map const& constantsSubstitution) const { + std::shared_ptr actualExprManager; + if (exprManager) { + actualExprManager = exprManager; + } else { + actualExprManager = std::make_shared(); + } std::vector orderedPartitions; for(auto const& priorityPartitions : partitions) { @@ -188,10 +193,10 @@ namespace storm { } std::reverse(orderedPartitions.begin(), orderedPartitions.end()); for(auto const& placeEntry : placeNames) { - exprManager->declareIntegerVariable(placeEntry.first, false); + actualExprManager->declareIntegerVariable(placeEntry.first, false); } - GSPN* result = new GSPN(gspnName, places, immediateTransitions, timedTransitions, orderedPartitions, exprManager); + GSPN* result = new GSPN(gspnName, places, immediateTransitions, timedTransitions, orderedPartitions, actualExprManager, constantsSubstitution); result->setTransitionLayoutInfo(transitionLayout); result->setPlaceLayoutInfo(placeLayout); return result; diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.h b/src/storm-gspn/storage/gspn/GspnBuilder.h index 35c5ed220..5e4db4a34 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.h +++ b/src/storm-gspn/storage/gspn/GspnBuilder.h @@ -100,10 +100,10 @@ namespace storm { /** - * + * @param exprManager The expression manager that will be associated with the new gspn. If this is nullptr, a new expressionmanager will be created. * @return The gspn which is constructed by the builder. */ - storm::gspn::GSPN* buildGspn() const; + storm::gspn::GSPN* buildGspn(std::shared_ptr const& exprManager = nullptr, std::map const& constantsSubstitution = std::map()) const; private: bool isImmediateTransitionId(uint64_t) const; bool isTimedTransitionId(uint64_t) const; From 0f97eb89db5e34e7fdeea61b54db48a08b5a71b5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 22 Aug 2018 14:16:44 +0200 Subject: [PATCH 497/647] binary storm-gspn now exits with 0 if no gspnfile is given --- src/storm-gspn-cli/storm-gspn.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index 4308a1de8..9d6924297 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -69,7 +69,8 @@ int main(const int argc, const char **argv) { // parse gspn from file if (!gspnSettings.isGspnFileSet()) { - return -1; + // If no gspn file is given, nothing needs to be done. + return 0; } std::string constantDefinitionString = ""; From e038fb64bea7665564ec210e9dfa5d1af76fbd09 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 22 Aug 2018 18:31:52 +0200 Subject: [PATCH 498/647] Jani: export the correct accumulation parameters for expected reward properties --- src/storm-parsers/parser/JaniParser.cpp | 6 +++--- src/storm/storage/jani/JSONExporter.cpp | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 0d415d388..f6d6251dd 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -243,8 +243,7 @@ namespace storm { } } } - STORM_LOG_THROW(!(accTime && accSteps), storm::exceptions::NotSupportedException, "Storm does not allow to accumulate over both time and steps"); - + // TODO: handle accumulation parameters! if (propertyStructure.count("step-instant") > 0) { STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + context); @@ -303,7 +302,8 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time', got " << accEntry.dump() << " in " << context); } } - STORM_LOG_THROW((rewInstAccTime && !rewInstAccSteps) || (!rewInstAccTime && rewInstAccSteps), storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); + STORM_LOG_THROW(rewInstAccSteps || rewInstAccTime, storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); + // TODO: handle accumulation parameters storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); bounds.emplace_back(false, rewInstantExpr); } diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 42bc15d62..deb831ed1 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -209,10 +209,8 @@ namespace storm { } else if(tbr.isRewardBound()) { modernjson::json rewbound; rewbound["exp"] = tbr.getRewardName(); - std::vector accvec; - if (model.isDiscreteTimeModel()) { - accvec.push_back("steps"); - } else { + std::vector accvec = {"steps"}; + if (!model.isDiscreteTimeModel()) { accvec.push_back("time"); } rewbound["accumulate"] = modernjson::json(accvec); @@ -403,10 +401,9 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector accvec; + std::vector accvec = {"steps"}; std::string instantName; if (model.isDiscreteTimeModel()) { - accvec.push_back("steps"); instantName = "step-instant"; } else { accvec.push_back("time"); From 251c9e2141a0220ea06461ea94edcaa95e5b2dbb Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 23 Aug 2018 09:25:18 +0200 Subject: [PATCH 499/647] added option to make the json export more compact --- src/storm-conv-cli/storm-conv.cpp | 4 ++-- src/storm-conv/api/storm-conv.cpp | 8 ++++---- src/storm-conv/api/storm-conv.h | 4 ++-- .../settings/modules/JaniExportSettings.cpp | 6 ++++++ .../settings/modules/JaniExportSettings.h | 3 +++ src/storm-gspn/api/storm-gspn.cpp | 2 +- src/storm-pgcl-cli/storm-pgcl.cpp | 2 +- src/storm/storage/jani/JSONExporter.cpp | 16 +++++++++++----- src/storm/storage/jani/JSONExporter.h | 4 ++-- 9 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 294beea6b..a499fccf2 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -86,11 +86,11 @@ namespace storm { auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); if (outputFilename != "") { - storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename); + storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename, jani.isCompactJsonSet()); } if (output.isStdOutOutputEnabled()) { - storm::api::printJaniToStream(janiModelProperties.first, janiModelProperties.second, std::cout); + storm::api::printJaniToStream(janiModelProperties.first, janiModelProperties.second, std::cout, jani.isCompactJsonSet()); } } diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index a8d88a502..aa37dd191 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -58,12 +58,12 @@ namespace storm { return res; } - void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { - storm::jani::JsonExporter::toFile(model, properties, filename); + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename, bool compact) { + storm::jani::JsonExporter::toFile(model, properties, filename, true, compact); } - void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream) { - storm::jani::JsonExporter::toStream(model, properties, ostream); + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream, bool compact) { + storm::jani::JsonExporter::toStream(model, properties, ostream, true, compact); } diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h index ec8a306df..42cbf804d 100644 --- a/src/storm-conv/api/storm-conv.h +++ b/src/storm-conv/api/storm-conv.h @@ -19,9 +19,9 @@ namespace storm { std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()); - void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename); + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename, bool compact = false); - void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream); + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream, bool compact = false); } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 5199a308d..707e91dac 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -19,6 +19,7 @@ namespace storm { const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; const std::string JaniExportSettings::locationVariablesOptionName = "location-variables"; const std::string JaniExportSettings::globalVariablesOptionName = "globalvars"; + const std::string JaniExportSettings::compactJsonOptionName = "compactjson"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { @@ -26,6 +27,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, compactJsonOptionName, false, "If set, the size of the resulting jani file will be reduced at the cost of (human-)readability.").build()); } bool JaniExportSettings::isExportAsStandardJaniSet() const { @@ -59,6 +61,10 @@ namespace storm { bool JaniExportSettings::isGlobalVarsSet() const { return this->getOption(globalVariablesOptionName).getHasOptionBeenSet(); } + + bool JaniExportSettings::isCompactJsonSet() const { + return this->getOption(compactJsonOptionName).getHasOptionBeenSet(); + } void JaniExportSettings::finalize() { diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h index 90dc532f0..2b2d6de7a 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.h +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -31,6 +31,8 @@ namespace storm { bool isLocationVariablesSet() const; bool isGlobalVarsSet() const; + + bool isCompactJsonSet() const; std::vector> getLocationVariables() const; @@ -47,6 +49,7 @@ namespace storm { static const std::string exportFlattenOptionName; static const std::string locationVariablesOptionName; static const std::string globalVariablesOptionName; + static const std::string compactJsonOptionName; }; } diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index 7b18bc010..63da78250 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -72,7 +72,7 @@ namespace storm { if (exportSettings.isAddJaniPropertiesSet()) { properties.insert(properties.end(), builder.getStandardProperties().begin(), builder.getStandardProperties().end()); } - storm::api::exportJaniToFile(*model, properties, exportSettings.getWriteToJaniFilename()); + storm::api::exportJaniToFile(*model, properties, exportSettings.getWriteToJaniFilename(), jani.isCompactJsonSet()); delete model; } } diff --git a/src/storm-pgcl-cli/storm-pgcl.cpp b/src/storm-pgcl-cli/storm-pgcl.cpp index 5ae5248b3..fe4585023 100644 --- a/src/storm-pgcl-cli/storm-pgcl.cpp +++ b/src/storm-pgcl-cli/storm-pgcl.cpp @@ -43,7 +43,7 @@ void handleJani(storm::jani::Model& model) { storm::converter::JaniConversionOptions options(jani); storm::api::postprocessJani(model, options); if (storm::settings::getModule().isToJaniSet()) { - storm::api::exportJaniToFile(model, {}, storm::settings::getModule().getWriteToJaniFilename()); + storm::api::exportJaniToFile(model, {}, storm::settings::getModule().getWriteToJaniFilename(), jani.isCompactJsonSet()); } else { storm::api::printJaniToStream(model, {}, std::cout); } diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index deb831ed1..c957cd29b 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -625,21 +625,27 @@ namespace storm { return modernjson::json(expression.getValueAsDouble()); } - void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid) { + void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid, bool compact) { std::ofstream stream; storm::utility::openFile(filepath, stream); - toStream(janiModel, formulas, stream, checkValid); + toStream(janiModel, formulas, stream, checkValid, compact); storm::utility::closeFile(stream); } - void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& os, bool checkValid) { + void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& os, bool checkValid, bool compact) { if(checkValid) { janiModel.checkValid(); } JsonExporter exporter; - exporter.convertModel(janiModel); + exporter.convertModel(janiModel, !compact); exporter.convertProperties(formulas, janiModel); - os << exporter.finalize().dump(4) << std::endl; + if (compact) { + // Dump without line breaks/indents + os << exporter.finalize().dump() << std::endl; + } else { + // Dump with line breaks and indention with 4 spaces + os << exporter.finalize().dump(4) << std::endl; + } } modernjson::json buildActionArray(std::vector const& actions) { diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 1bf098bca..f88bb7330 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -75,8 +75,8 @@ namespace storm { JsonExporter() = default; public: - static void toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid = true); - static void toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& ostream, bool checkValid = false); + static void toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid = true, bool compact = false); + static void toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& ostream, bool checkValid = false, bool compact = false); private: From ad88992ba2e2ee6315545508406a94d6a63f882b Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 23 Aug 2018 13:44:09 +0200 Subject: [PATCH 500/647] export gspns to ctmcs/mdps if no intermediate/timed transitions occur. --- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index d21ef5c21..744b76eb4 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -9,7 +9,13 @@ namespace storm { namespace builder { storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName, bool buildStandardProperties) { - storm::jani::Model* model = new storm::jani::Model(gspn.getName(), storm::jani::ModelType::MA, janiVersion, expressionManager); + storm::jani::ModelType modelType = storm::jani::ModelType::MA; + if (gspn.getNumberOfTimedTransitions() == 0) { + storm::jani::ModelType modelType = storm::jani::ModelType::MDP; + } else if (gspn.getNumberOfImmediateTransitions() == 0) { + storm::jani::ModelType modelType = storm::jani::ModelType::CTMC; + } + storm::jani::Model* model = new storm::jani::Model(gspn.getName(), modelType, janiVersion, expressionManager); storm::jani::Automaton mainAutomaton(automatonName, expressionManager->declareIntegerVariable("loc")); addVariables(model); uint64_t locId = addLocation(mainAutomaton); From c136b9c628b6f3e49cd340a4f3d06c28deb54c82 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 23 Aug 2018 17:15:16 +0200 Subject: [PATCH 501/647] Removed old jani file settings --- src/storm-conv/settings/modules/JaniExportSettings.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h index 2b2d6de7a..99e00ea9b 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.h +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -14,16 +14,6 @@ namespace storm { */ JaniExportSettings(); - /** - * Retrievew whether the pgcl file option was set - */ - bool isJaniFileSet() const; - - /** - * Retrieves the pgcl file name - */ - std::string getJaniFilename() const; - bool isExportAsStandardJaniSet() const; bool isExportFlattenedSet() const; @@ -42,8 +32,6 @@ namespace storm { static const std::string moduleName; private: - static const std::string janiFileOptionName; - static const std::string janiFileOptionShortName; static const std::string standardCompliantOptionName; static const std::string standardCompliantOptionShortName; static const std::string exportFlattenOptionName; From 953d570ff0bf60b3e51ffb573391ca046867afa4 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 24 Aug 2018 11:00:17 +0200 Subject: [PATCH 502/647] fix in syntacticalEquality checker --- .../storage/expressions/SyntacticalEqualityCheckVisitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp b/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp index 7f45240d7..d49b864dd 100644 --- a/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp +++ b/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp @@ -93,7 +93,7 @@ namespace storm { boost::any SyntacticalEqualityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { BaseExpression const& otherBaseExpression = boost::any_cast>(data).get(); - if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + if (otherBaseExpression.isUnaryBooleanFunctionExpression()) { UnaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asUnaryBooleanFunctionExpression(); bool result = expression.getOperatorType() == otherExpression.getOperatorType(); @@ -108,7 +108,7 @@ namespace storm { boost::any SyntacticalEqualityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { BaseExpression const& otherBaseExpression = boost::any_cast>(data).get(); - if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + if (otherBaseExpression.isUnaryNumericalFunctionExpression()) { UnaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asUnaryNumericalFunctionExpression(); bool result = expression.getOperatorType() == otherExpression.getOperatorType(); From a0125393239a876bede69efb46c3504b5eeafc2d Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 27 Aug 2018 12:06:19 +0200 Subject: [PATCH 503/647] cleared some TODOs in the Jani Parser --- src/storm-parsers/parser/JaniParser.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index f6d6251dd..80bb6c8c2 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -90,6 +90,14 @@ namespace storm { storm::jani::ModelType type = storm::jani::getModelType(modeltypestring); STORM_LOG_THROW(type != storm::jani::ModelType::UNDEFINED, storm::exceptions::InvalidJaniException, "model type " + modeltypestring + " not recognized"); storm::jani::Model model(name, type, version, expressionManager); + size_t featuresCount = parsedStructure.count("features"); + STORM_LOG_THROW(featuresCount < 2, storm::exceptions::InvalidJaniException, "features-declarations can be given at most once."); + if (featuresCount == 1) { + std::unordered_set supportedFeatures = {"derived-operators", "state-exit-rewards"}; + for (auto const& feature : parsedStructure.at("features")) { + STORM_LOG_WARN_COND(supportedFeatures.find(getString(feature)) != supportedFeatures.end(), "Storm does not support the model feature " << getString(feature) << "."); + } + } size_t actionCount = parsedStructure.count("actions"); STORM_LOG_THROW(actionCount < 2, storm::exceptions::InvalidJaniException, "Action-declarations can be given at most once."); if (actionCount > 0) { @@ -478,8 +486,6 @@ namespace storm { } else if(propertyStructure.at("right").count("op") > 0 && (propertyStructure.at("right").at("op") == "Pmin" || propertyStructure.at("right").at("op") == "Pmax" || propertyStructure.at("right").at("op") == "Emin" || propertyStructure.at("right").at("op") == "Emax" || propertyStructure.at("right").at("op") == "Smin" || propertyStructure.at("right").at("op") == "Smax")) { auto expr = parseExpression(propertyStructure.at("left"), "Threshold for operator " + propertyStructure.at("right").at("op").get(),{},{}); - STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported"); - // TODO evaluate this expression directly as rational number return parseFormula(propertyStructure.at("right"),formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons are allowed."); @@ -950,8 +956,7 @@ namespace storm { assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); - // TODO implement - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "modulo operation is not yet implemented"); + return arguments[0] % arguments[1]; } else if (opstring == "max") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 2); @@ -988,14 +993,13 @@ namespace storm { arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - return storm::expressions::abs(arguments[0]); + return storm::expressions::truncate(arguments[0]); } else if (opstring == "pow") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); - // TODO implement - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "pow operation is not yet implemented"); + return arguments[0]^arguments[1]; } else if (opstring == "exp") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); assert(arguments.size() == 2); From 234ddb7cff1f968ed32f593865ff98e9f2ae961c Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 27 Aug 2018 14:17:07 +0200 Subject: [PATCH 504/647] fixed compilation of JaniParser --- src/storm-parsers/parser/JaniParser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 80bb6c8c2..0fecbe87a 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -95,7 +95,8 @@ namespace storm { if (featuresCount == 1) { std::unordered_set supportedFeatures = {"derived-operators", "state-exit-rewards"}; for (auto const& feature : parsedStructure.at("features")) { - STORM_LOG_WARN_COND(supportedFeatures.find(getString(feature)) != supportedFeatures.end(), "Storm does not support the model feature " << getString(feature) << "."); + std::string featureStr = getString(feature, "Model feature"); + STORM_LOG_WARN_COND(supportedFeatures.find(featureStr) != supportedFeatures.end(), "Storm does not support the model feature " << featureStr << "."); } } size_t actionCount = parsedStructure.count("actions"); From 76b2eb2ee9e3ca3b3be2ccd43996eb438c2352fa Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 27 Aug 2018 16:36:54 +0200 Subject: [PATCH 505/647] added reward accumulation to formulas --- src/storm/logic/BoundedUntilFormula.cpp | 6 ++- src/storm/logic/CloneVisitor.cpp | 6 ++- src/storm/logic/CumulativeRewardFormula.cpp | 22 ++++++++-- src/storm/logic/CumulativeRewardFormula.h | 9 +++- src/storm/logic/EventuallyFormula.cpp | 13 +++++- src/storm/logic/EventuallyFormula.h | 8 +++- src/storm/logic/RewardAccumulation.cpp | 47 +++++++++++++++++++++ src/storm/logic/RewardAccumulation.h | 24 +++++++++++ src/storm/logic/TimeBoundType.h | 20 ++++++++- src/storm/logic/TotalRewardFormula.cpp | 10 ++++- src/storm/logic/TotalRewardFormula.h | 13 ++++-- 11 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 src/storm/logic/RewardAccumulation.cpp create mode 100644 src/storm/logic/RewardAccumulation.h diff --git a/src/storm/logic/BoundedUntilFormula.cpp b/src/storm/logic/BoundedUntilFormula.cpp index 97c768944..6054e7cd3 100644 --- a/src/storm/logic/BoundedUntilFormula.cpp +++ b/src/storm/logic/BoundedUntilFormula.cpp @@ -285,7 +285,11 @@ namespace storm { out << ", "; } if (this->getTimeBoundReference(i).isRewardBound()) { - out << "rew{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; + out << "rew"; + if (this->getTimeBoundReference(i).hasRewardAccumulation()) { + out << "[" << this->getTimeBoundReference(i).getRewardAccumulation() << "]"; + } + out << "{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; } else if (this->getTimeBoundReference(i).isStepBound()) { out << "steps"; //} else if (this->getTimeBoundReference(i).isStepBound()) diff --git a/src/storm/logic/CloneVisitor.cpp b/src/storm/logic/CloneVisitor.cpp index d97dd41d6..3e24d92c0 100644 --- a/src/storm/logic/CloneVisitor.cpp +++ b/src/storm/logic/CloneVisitor.cpp @@ -70,7 +70,11 @@ namespace storm { boost::any CloneVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + if (f.hasRewardAccumulation()) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } else { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + } } boost::any CloneVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { diff --git a/src/storm/logic/CumulativeRewardFormula.cpp b/src/storm/logic/CumulativeRewardFormula.cpp index 19a60a623..bbf21cbf0 100644 --- a/src/storm/logic/CumulativeRewardFormula.cpp +++ b/src/storm/logic/CumulativeRewardFormula.cpp @@ -9,11 +9,11 @@ namespace storm { namespace logic { - CumulativeRewardFormula::CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference) : timeBoundReferences({timeBoundReference}), bounds({bound}) { + CumulativeRewardFormula::CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference, boost::optional rewardAccumulation) : timeBoundReferences({timeBoundReference}), bounds({bound}), rewardAccumulation(rewardAccumulation) { // Intentionally left empty. } - CumulativeRewardFormula::CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences) : timeBoundReferences(timeBoundReferences), bounds(bounds) { + CumulativeRewardFormula::CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences, boost::optional rewardAccumulation) : timeBoundReferences(timeBoundReferences), bounds(bounds), rewardAccumulation(rewardAccumulation) { STORM_LOG_ASSERT(this->timeBoundReferences.size() == this->bounds.size(), "Number of time bounds and number of time bound references does not match."); STORM_LOG_ASSERT(!this->timeBoundReferences.empty(), "No time bounds given."); @@ -137,12 +137,24 @@ namespace storm { STORM_LOG_THROW(!bound.containsVariables(), storm::exceptions::InvalidOperationException, "Cannot evaluate time-bound '" << bound << "' as it contains undefined constants."); } + bool CumulativeRewardFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& CumulativeRewardFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + + std::shared_ptr CumulativeRewardFormula::restrictToDimension(unsigned i) const { return std::make_shared(bounds.at(i), getTimeBoundReference(i)); } std::ostream& CumulativeRewardFormula::writeToStream(std::ostream& out) const { out << "C"; + if (hasRewardAccumulation()) { + out << "[" << getRewardAccumulation() << "]"; + } if (this->isMultiDimensional()) { out << "^{"; } @@ -151,7 +163,11 @@ namespace storm { out << ", "; } if (this->getTimeBoundReference(i).isRewardBound()) { - out << "rew{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; + out << "rew"; + if (this->getTimeBoundReference(i).hasRewardAccumulation()) { + out << "[" << this->getTimeBoundReference(i).getRewardAccumulation() << "]"; + } + out << "{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; } else if (this->getTimeBoundReference(i).isStepBound()) { out << "steps"; //} else if (this->getTimeBoundReference(i).isStepBound()) diff --git a/src/storm/logic/CumulativeRewardFormula.h b/src/storm/logic/CumulativeRewardFormula.h index e40370b07..4c436037e 100644 --- a/src/storm/logic/CumulativeRewardFormula.h +++ b/src/storm/logic/CumulativeRewardFormula.h @@ -10,8 +10,8 @@ namespace storm { namespace logic { class CumulativeRewardFormula : public PathFormula { public: - CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference = TimeBoundReference(TimeBoundType::Time)); - CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences); + CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference = TimeBoundReference(TimeBoundType::Time), boost::optional rewardAccumulation = boost::none); + CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences, boost::optional rewardAccumulation = boost::none); virtual ~CumulativeRewardFormula() = default; @@ -47,6 +47,9 @@ namespace storm { template ValueType getNonStrictBound() const; + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; + std::shared_ptr restrictToDimension(unsigned i) const; private: @@ -54,6 +57,8 @@ namespace storm { std::vector timeBoundReferences; std::vector bounds; + boost::optional rewardAccumulation; + }; } } diff --git a/src/storm/logic/EventuallyFormula.cpp b/src/storm/logic/EventuallyFormula.cpp index 2f1243f8a..863b977fd 100644 --- a/src/storm/logic/EventuallyFormula.cpp +++ b/src/storm/logic/EventuallyFormula.cpp @@ -6,7 +6,7 @@ namespace storm { namespace logic { - EventuallyFormula::EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context) : UnaryPathFormula(subformula), context(context) { + EventuallyFormula::EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context, boost::optional rewardAccumulation) : UnaryPathFormula(subformula), context(context), rewardAccumulation(rewardAccumulation) { STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::Time, storm::exceptions::InvalidPropertyException, "Invalid context for formula."); } @@ -42,6 +42,14 @@ namespace storm { return this->isReachabilityTimeFormula(); } + bool EventuallyFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& EventuallyFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + boost::any EventuallyFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } @@ -49,6 +57,9 @@ namespace storm { std::ostream& EventuallyFormula::writeToStream(std::ostream& out) const { out << "F "; this->getSubformula().writeToStream(out); + if (hasRewardAccumulation()) { + out << "[" << getRewardAccumulation() << "]"; + } return out; } } diff --git a/src/storm/logic/EventuallyFormula.h b/src/storm/logic/EventuallyFormula.h index 9cc4d853d..5fa30da6d 100644 --- a/src/storm/logic/EventuallyFormula.h +++ b/src/storm/logic/EventuallyFormula.h @@ -1,14 +1,17 @@ #ifndef STORM_LOGIC_EVENTUALLYFORMULA_H_ #define STORM_LOGIC_EVENTUALLYFORMULA_H_ +#include + #include "storm/logic/UnaryPathFormula.h" #include "storm/logic/FormulaContext.h" +#include "storm/logic/RewardAccumulation.h" namespace storm { namespace logic { class EventuallyFormula : public UnaryPathFormula { public: - EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context = FormulaContext::Probability); + EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context = FormulaContext::Probability, boost::optional rewardAccumulation = boost::none); virtual ~EventuallyFormula() { // Intentionally left empty. @@ -27,9 +30,12 @@ namespace storm { virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual std::ostream& writeToStream(std::ostream& out) const override; + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; private: FormulaContext context; + boost::optional rewardAccumulation; }; } } diff --git a/src/storm/logic/RewardAccumulation.cpp b/src/storm/logic/RewardAccumulation.cpp new file mode 100644 index 000000000..e7996f0e0 --- /dev/null +++ b/src/storm/logic/RewardAccumulation.cpp @@ -0,0 +1,47 @@ +#include "storm/logic/RewardAccumulation.h" + +namespace storm { + namespace logic { + + RewardAccumulation::RewardAccumulation(bool steps, bool time, bool exit) : steps(steps), time(time), exit(exit){ + // Intentionally left empty + } + + bool RewardAccumulation::isStepsSet() const { + return steps; + } + + bool RewardAccumulation::isTimeSet() const { + return time; + } + + bool RewardAccumulation::isExitSet() const { + return exit; + } + + std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc) { + bool hasEntry = false; + if (acc.isStepsSet()) { + out << "steps"; + hasEntry = true; + } + if (acc.isTimeSet()) { + if (hasEntry) { + out << ", "; + } + out << "time"; + hasEntry = true; + } + if (acc.isExitSet()) { + if (hasEntry) { + out << ", "; + } + out << "exit"; + hasEntry = true; + } + + return out; + } + + } +} diff --git a/src/storm/logic/RewardAccumulation.h b/src/storm/logic/RewardAccumulation.h new file mode 100644 index 000000000..89c18b017 --- /dev/null +++ b/src/storm/logic/RewardAccumulation.h @@ -0,0 +1,24 @@ +#pragma once +#include + +namespace storm { + namespace logic { + + class RewardAccumulation { + public: + RewardAccumulation(bool steps, bool time, bool exit); + RewardAccumulation(RewardAccumulation const& other) = default; + + bool isStepsSet() const; // If set, choice rewards and transition rewards are accumulated upon taking the transition + bool isTimeSet() const; // If set, state rewards are accumulated over time (assuming 0 time passes in discrete-time model states) + bool isExitSet() const; // If set, state rewards are accumulated upon exiting the state + + private: + bool time, steps, exit; + }; + + std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc); + + } +} + diff --git a/src/storm/logic/TimeBoundType.h b/src/storm/logic/TimeBoundType.h index 0bd6aba0c..23f850105 100644 --- a/src/storm/logic/TimeBoundType.h +++ b/src/storm/logic/TimeBoundType.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "storm/logic/RewardAccumulation.h" + namespace storm { namespace logic { @@ -13,14 +17,15 @@ namespace storm { class TimeBoundReference { TimeBoundType type; std::string rewardName; - + boost::optional rewardAccumulation; + public: explicit TimeBoundReference(TimeBoundType t) : type(t) { // For rewards, use the other constructor. assert(t != TimeBoundType::Reward); } - explicit TimeBoundReference(std::string const& rewardName) : type(TimeBoundType::Reward), rewardName(rewardName) { + explicit TimeBoundReference(std::string const& rewardName, boost::optional rewardAccumulation = boost::none) : type(TimeBoundType::Reward), rewardName(rewardName), rewardAccumulation(rewardAccumulation) { assert(rewardName != ""); // Empty reward name is reserved. } @@ -44,6 +49,17 @@ namespace storm { assert(isRewardBound()); return rewardName; } + + bool hasRewardAccumulation() const { + assert(isRewardBound()); + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& getRewardAccumulation() const { + assert(isRewardBound()); + return rewardAccumulation.get(); + } + }; diff --git a/src/storm/logic/TotalRewardFormula.cpp b/src/storm/logic/TotalRewardFormula.cpp index 18c79cd67..6136581a3 100644 --- a/src/storm/logic/TotalRewardFormula.cpp +++ b/src/storm/logic/TotalRewardFormula.cpp @@ -4,7 +4,7 @@ namespace storm { namespace logic { - TotalRewardFormula::TotalRewardFormula() { + TotalRewardFormula::TotalRewardFormula(boost::optional rewardAccumulation) : rewardAccumulation(rewardAccumulation) { // Intentionally left empty. } @@ -16,6 +16,14 @@ namespace storm { return true; } + bool TotalRewardFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& TotalRewardFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + boost::any TotalRewardFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } diff --git a/src/storm/logic/TotalRewardFormula.h b/src/storm/logic/TotalRewardFormula.h index 90caee9e7..a11fb3b03 100644 --- a/src/storm/logic/TotalRewardFormula.h +++ b/src/storm/logic/TotalRewardFormula.h @@ -1,15 +1,16 @@ #ifndef STORM_LOGIC_TOTALREWARDFORMULA_H_ #define STORM_LOGIC_TOTALREWARDFORMULA_H_ -#include +#include +#include "storm/logic/RewardAccumulation.h" #include "storm/logic/PathFormula.h" namespace storm { namespace logic { class TotalRewardFormula : public PathFormula { public: - TotalRewardFormula(); + TotalRewardFormula(boost::optional rewardAccumulation = boost::none); virtual ~TotalRewardFormula() { // Intentionally left empty. @@ -17,11 +18,15 @@ namespace storm { virtual bool isTotalRewardFormula() const override; virtual bool isRewardPathFormula() const override; - + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; + virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual std::ostream& writeToStream(std::ostream& out) const override; - + + private: + boost::optional rewardAccumulation; }; } } From 4302aa0be006f7775b94ec0bcfae67d2f5e899ec Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 27 Aug 2018 18:41:43 +0200 Subject: [PATCH 506/647] added missing include --- src/storm/builder/DdPrismModelBuilder.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm/builder/DdPrismModelBuilder.h b/src/storm/builder/DdPrismModelBuilder.h index 57d990b23..fb357a6c8 100644 --- a/src/storm/builder/DdPrismModelBuilder.h +++ b/src/storm/builder/DdPrismModelBuilder.h @@ -3,6 +3,7 @@ #include #include +#include #include "storm/storage/prism/Program.h" From ee1dcbd483f258fefdb9e2402aa624518e75864a Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 27 Aug 2018 18:42:28 +0200 Subject: [PATCH 507/647] fragment checker checks reward accumulations --- src/storm/logic/FragmentChecker.cpp | 17 +++++++++++++++-- src/storm/logic/FragmentSpecification.cpp | 13 +++++++++++++ src/storm/logic/FragmentSpecification.h | 12 ++++++++++++ src/storm/logic/RewardAccumulation.cpp | 4 ++++ src/storm/logic/RewardAccumulation.h | 2 ++ 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/storm/logic/FragmentChecker.cpp b/src/storm/logic/FragmentChecker.cpp index 24ad016c8..adc96728b 100644 --- a/src/storm/logic/FragmentChecker.cpp +++ b/src/storm/logic/FragmentChecker.cpp @@ -70,6 +70,9 @@ namespace storm { } else { assert(tbr.isRewardBound()); result = result && inherited.getSpecification().areRewardBoundedUntilFormulasAllowed(); + if (tbr.hasRewardAccumulation()) { + result = result && inherited.getSpecification().isRewardAccumulationAllowed(); + } } } @@ -118,6 +121,7 @@ namespace storm { bool result = inherited.getSpecification().areCumulativeRewardFormulasAllowed(); result = result && (!f.isMultiDimensional() || inherited.getSpecification().areMultiDimensionalCumulativeRewardFormulasAllowed()); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); for (uint64_t i = 0; i < f.getDimension(); ++i) { auto tbr = f.getTimeBoundReference(i); if (tbr.isStepBound()) { @@ -127,6 +131,9 @@ namespace storm { } else { assert(tbr.isRewardBound()); result = result && inherited.getSpecification().areRewardBoundedCumulativeRewardFormulasAllowed(); + if (tbr.hasRewardAccumulation()) { + result = result && inherited.getSpecification().isRewardAccumulationAllowed(); + } } } return result; @@ -140,12 +147,15 @@ namespace storm { if (!inherited.getSpecification().areNestedPathFormulasAllowed()) { result = result && !f.getSubformula().isPathFormula(); } + result = result && !f.hasRewardAccumulation(); } else if (f.isReachabilityRewardFormula()) { result = result && inherited.getSpecification().areReachabilityRewardFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); } else if (f.isReachabilityTimeFormula()) { result = result && inherited.getSpecification().areReachbilityTimeFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); } result = result && boost::any_cast(f.getSubformula().accept(*this, data)); return result; @@ -250,6 +260,7 @@ namespace storm { result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula()); result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation); + if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { @@ -258,9 +269,11 @@ namespace storm { return result; } - boost::any FragmentChecker::visit(TotalRewardFormula const&, boost::any const& data) const { + boost::any FragmentChecker::visit(TotalRewardFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast(data); - return inherited.getSpecification().areTotalRewardFormulasAllowed(); + bool result = (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); + result = result && inherited.getSpecification().areTotalRewardFormulasAllowed(); + return result; } boost::any FragmentChecker::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const { diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index cdcfc6ecd..9b5b8b17e 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -1,6 +1,7 @@ #include "storm/logic/FragmentSpecification.h" #include +#include "storm/logic/RewardAccumulation.h" namespace storm { namespace logic { @@ -161,6 +162,8 @@ namespace storm { operatorAtTopLevelRequired = false; multiObjectiveFormulaAtTopLevelRequired = false; operatorsAtTopLevelOfMultiObjectiveFormulasRequired = false; + + rewardAccumulation = false; } FragmentSpecification FragmentSpecification::copy() const { @@ -564,5 +567,15 @@ namespace storm { return *this; } + bool FragmentSpecification::isRewardAccumulationAllowed() const { + return rewardAccumulation; + } + + FragmentSpecification& FragmentSpecification::setRewardAccumulationAllowed(bool newValue) { + rewardAccumulation = newValue; + return *this; + } + + } } diff --git a/src/storm/logic/FragmentSpecification.h b/src/storm/logic/FragmentSpecification.h index d90ebd5fb..012716c78 100644 --- a/src/storm/logic/FragmentSpecification.h +++ b/src/storm/logic/FragmentSpecification.h @@ -1,8 +1,14 @@ #ifndef STORM_LOGIC_FRAGMENTSPECIFICATION_H_ #define STORM_LOGIC_FRAGMENTSPECIFICATION_H_ +#include +#include + namespace storm { namespace logic { + + class RewardAccumulation; + class FragmentSpecification { public: FragmentSpecification(); @@ -139,6 +145,10 @@ namespace storm { bool areOperatorsAtTopLevelOfMultiObjectiveFormulasRequired() const; FragmentSpecification& setOperatorsAtTopLevelOfMultiObjectiveFormulasRequired(bool newValue); + bool isRewardAccumulationAllowed() const; + FragmentSpecification& setRewardAccumulationAllowed(bool newValue); + + FragmentSpecification& setOperatorsAllowed(bool newValue); FragmentSpecification& setTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); @@ -195,6 +205,8 @@ namespace storm { bool operatorAtTopLevelRequired; bool multiObjectiveFormulaAtTopLevelRequired; bool operatorsAtTopLevelOfMultiObjectiveFormulasRequired; + + bool rewardAccumulation; }; // Propositional. diff --git a/src/storm/logic/RewardAccumulation.cpp b/src/storm/logic/RewardAccumulation.cpp index e7996f0e0..ed99baaa0 100644 --- a/src/storm/logic/RewardAccumulation.cpp +++ b/src/storm/logic/RewardAccumulation.cpp @@ -19,6 +19,10 @@ namespace storm { return exit; } + bool RewardAccumulation::implies(RewardAccumulation const& other) const { + return (!isStepsSet() || other.isStepsSet()) && (!isTimeSet() || other.isTimeSet()) && (!isExitSet() || other.isExitSet()); + } + std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc) { bool hasEntry = false; if (acc.isStepsSet()) { diff --git a/src/storm/logic/RewardAccumulation.h b/src/storm/logic/RewardAccumulation.h index 89c18b017..6350c2d00 100644 --- a/src/storm/logic/RewardAccumulation.h +++ b/src/storm/logic/RewardAccumulation.h @@ -13,6 +13,8 @@ namespace storm { bool isTimeSet() const; // If set, state rewards are accumulated over time (assuming 0 time passes in discrete-time model states) bool isExitSet() const; // If set, state rewards are accumulated upon exiting the state + // Returns true, if every reward-type set in this RewardAccumulation is also set for the other RewardAccumulation + bool implies(RewardAccumulation const& other) const; private: bool time, steps, exit; }; From 701f3832b163bc19771f7b0ba1dbee7d330953dc Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 28 Aug 2018 10:19:58 +0200 Subject: [PATCH 508/647] parsing reward accumulations --- src/storm-parsers/parser/JaniParser.cpp | 64 ++++++++++++------------- src/storm-parsers/parser/JaniParser.h | 4 +- src/storm/logic/EventuallyFormula.cpp | 1 + 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 0fecbe87a..65cd53ad4 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -196,6 +196,24 @@ namespace storm { } + storm::logic::RewardAccumulation JaniParser::parseRewardAccumulation(json const& accStructure, std::string const& context) { + bool accTime = false; + bool accSteps = false; + bool accExit = false; + STORM_LOG_THROW(accStructure.is_array(), storm::exceptions::InvalidJaniException, "Accumulate should be an array"); + for (auto const& accEntry : accStructure) { + if (accEntry == "steps") { + accSteps = true; + } else if (accEntry == "time") { + accTime = true; + } else if (accEntry == "exit") { + accExit = true; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time' or 'exit', got " << accEntry.dump() << " in " << context); + } + } + return storm::logic::RewardAccumulation(accSteps, accTime, accExit); + } std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext,std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound) { if (propertyStructure.is_boolean()) { @@ -238,28 +256,17 @@ namespace storm { opInfo.optimalityType = opString == "Emin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; opInfo.bound = bound; - bool accTime = false; - bool accSteps = false; + storm::logic::RewardAccumulation rewardAccumulation(false, false, false); if (propertyStructure.count("accumulate") > 0) { - STORM_LOG_THROW(propertyStructure.at("accumulate").is_array(), storm::exceptions::InvalidJaniException, "Accumulate should be an array"); - for(auto const& accEntry : propertyStructure.at("accumulate")) { - if (accEntry == "steps") { - accSteps = true; - } else if (accEntry == "time") { - accTime = true; - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time', got " << accEntry.dump() << " in " << context); - } - } + rewardAccumulation = parseRewardAccumulation(propertyStructure.at("accumulate"), context); } - // TODO: handle accumulation parameters! if (propertyStructure.count("step-instant") > 0) { STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + context); STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + context); storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), "Step instant in " + context, globalVars, constants); - if(!accTime && !accSteps) { + if(rewardAccumulation.isEmpty()) { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); return std::make_shared(std::make_shared(stepInstantExpr, storm::logic::TimeBoundType::Steps), rewardName, opInfo); @@ -269,7 +276,7 @@ namespace storm { } else { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(storm::logic::TimeBound(false, stepInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)), rewardName, opInfo); + return std::make_shared(std::make_shared(storm::logic::TimeBound(false, stepInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps), rewardAccumulation), rewardName, opInfo); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); } @@ -279,7 +286,7 @@ namespace storm { storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); - if(!accTime && !accSteps) { + if(rewardAccumulation.isEmpty()) { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); return std::make_shared(std::make_shared(timeInstantExpr, storm::logic::TimeBoundType::Time), rewardName, opInfo); @@ -289,7 +296,7 @@ namespace storm { } else { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(storm::logic::TimeBound(false, timeInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)), rewardName, opInfo); + return std::make_shared(std::make_shared(storm::logic::TimeBound(false, timeInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time), rewardAccumulation), rewardName, opInfo); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); } @@ -300,25 +307,14 @@ namespace storm { for (auto const& rewInst : propertyStructure.at("reward-instants")) { storm::expressions::Expression rewInstExpression = parseExpression(rewInst.at("exp"), "Reward expression in " + context, globalVars, constants); STORM_LOG_THROW(!rewInstExpression.isVariable(), storm::exceptions::NotSupportedException, "Reward bounded cumulative reward formulas should only argue over reward expressions."); - boundReferences.emplace_back(rewInstExpression.getVariables().begin()->getName()); - bool rewInstAccSteps(false), rewInstAccTime(false); - for (auto const& accEntry : rewInst.at("accumulate")) { - if (accEntry == "steps") { - rewInstAccSteps = true; - } else if (accEntry == "time") { - rewInstAccTime = true; - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time', got " << accEntry.dump() << " in " << context); - } - } - STORM_LOG_THROW(rewInstAccSteps || rewInstAccTime, storm::exceptions::NotSupportedException, "Storm only allows to accumulate either over time or over steps in " + context); - // TODO: handle accumulation parameters + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rewInst.at("accumulate"), context); + boundReferences.emplace_back(rewInstExpression.getVariables().begin()->getName(), boundRewardAccumulation); storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); bounds.emplace_back(false, rewInstantExpr); } if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(bounds, boundReferences), rewardName, opInfo); + return std::make_shared(std::make_shared(bounds, boundReferences, rewardAccumulation), rewardName, opInfo); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); } @@ -326,9 +322,9 @@ namespace storm { std::shared_ptr subformula; if (propertyStructure.count("reach") > 0) { auto context = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; - subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context); + subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context, rewardAccumulation); } else { - subformula = std::make_shared(); + subformula = std::make_shared(rewardAccumulation); } if (rewExpr.isVariable()) { assert(!time); @@ -410,6 +406,8 @@ namespace storm { STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), "Reward expression in " + context, globalVars, constants); STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rbStructure.at("accumulate"), context); + tbReferences.emplace_back(rewExpr.getVariables().begin()->getName(), boundRewardAccumulation); std::string rewardName = rewExpr.getVariables().begin()->getName(); STORM_LOG_WARN("Reward-type (steps, time) is deduced from model type."); if (pi.hasLowerBound()) { diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index 1ac4a514f..f56984c25 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -2,6 +2,7 @@ #include "storm/storage/jani/Constant.h" #include "storm/logic/Formula.h" #include "storm/logic/Bound.h" +#include "storm/logic/RewardAccumulation.h" #include "storm/exceptions/FileIoException.h" #include "storm/storage/expressions/ExpressionManager.h" @@ -66,7 +67,8 @@ namespace storm { std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, std::unordered_map> const& constants); - + storm::logic::RewardAccumulation parseRewardAccumulation(json const& accStructure, std::string const& context); + std::shared_ptr parseComposition(json const& compositionStructure); storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}); diff --git a/src/storm/logic/EventuallyFormula.cpp b/src/storm/logic/EventuallyFormula.cpp index 863b977fd..c8ed335e5 100644 --- a/src/storm/logic/EventuallyFormula.cpp +++ b/src/storm/logic/EventuallyFormula.cpp @@ -8,6 +8,7 @@ namespace storm { namespace logic { EventuallyFormula::EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context, boost::optional rewardAccumulation) : UnaryPathFormula(subformula), context(context), rewardAccumulation(rewardAccumulation) { STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::Time, storm::exceptions::InvalidPropertyException, "Invalid context for formula."); + STORM_LOG_THROW(context != FormulaContext::Probability || !rewardAccumulation.is_initialized(), storm::exceptions::InvalidPropertyException, "Reward accumulations should only be given for time- and reward formulas"); } FormulaContext const& EventuallyFormula::getContext() const { From 831f07e867d73649c63f22a36215bb35f62e8120 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 28 Aug 2018 15:03:45 +0200 Subject: [PATCH 509/647] eliminate reward accumulations whenever possible --- src/storm-cli-utilities/model-handling.h | 38 +++- src/storm/logic/CloneVisitor.cpp | 4 +- src/storm/logic/RewardAccumulation.cpp | 6 +- src/storm/logic/RewardAccumulation.h | 5 +- .../RewardAccumulationEliminationVisitor.cpp | 173 ++++++++++++++++++ .../RewardAccumulationEliminationVisitor.h | 39 ++++ 6 files changed, 254 insertions(+), 11 deletions(-) create mode 100644 src/storm/logic/RewardAccumulationEliminationVisitor.cpp create mode 100644 src/storm/logic/RewardAccumulationEliminationVisitor.h diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index f60a3ffb5..257453e92 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -18,10 +18,12 @@ #include "storm/storage/SymbolicModelDescription.h" #include "storm/storage/jani/Property.h" +#include "storm/logic/RewardAccumulationEliminationVisitor.h" #include "storm/models/ModelBase.h" #include "storm/exceptions/OptionParserException.h" +#include "storm/exceptions/UnexpectedException.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -382,6 +384,7 @@ namespace storm { std::pair, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { + STORM_LOG_THROW((std::is_same::value), storm::exceptions::UnexpectedException, "Build-Value Type and ExportValueType should be the same in the sparse engine."); result = preprocessSparseModel(result.first->as>(), input); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); @@ -396,6 +399,29 @@ namespace storm { return result; } + template + storm::jani::Property preprocessProperty(std::shared_ptr const& model, storm::jani::Property const& property) { + storm::logic::RewardAccumulationEliminationVisitor v(model->getRewardModels(), model->getType()); + auto formula = v.eliminateRewardAccumulations(*property.getFilter().getFormula()); + auto states = v.eliminateRewardAccumulations(*property.getFilter().getStatesFormula()); + storm::jani::FilterExpression fe(formula, property.getFilter().getFilterType(), states); + return storm::jani::Property(property.getName(), fe, property.getComment()); + } + + template + std::vector preprocessProperties(std::shared_ptr const& model, SymbolicInput const& input) { + std::vector resultProperties; + for (auto const& property : input.properties) { + if (model->isSparseModel()) { + resultProperties.push_back(preprocessProperty(model->as>(), property)); + } else { + STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); + resultProperties.push_back(preprocessProperty(model->as>(), property)); + } + } + return resultProperties; + } + void printComputingCounterexample(storm::jani::Property const& property) { STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ..." << std::endl); } @@ -670,7 +696,7 @@ namespace storm { } template - std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { + std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput& input, storm::settings::modules::CoreSettings::Engine engine) { auto ioSettings = storm::settings::getModule(); auto buildSettings = storm::settings::getModule(); std::shared_ptr model; @@ -690,6 +716,9 @@ namespace storm { model = preprocessingResult.first; model->printModelInformationToStream(std::cout); } + if (!input.properties.empty()) { + input.properties = preprocessProperties(model, input); + } exportModel(model, input); } return model; @@ -708,15 +737,16 @@ namespace storm { } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { verifyWithExplorationEngine(input); } else { - std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); + SymbolicInput preprocessedInput = input; + std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(preprocessedInput, engine); if (model) { if (coreSettings.isCounterexampleSet()) { auto ioSettings = storm::settings::getModule(); - generateCounterexamples(model, input); + generateCounterexamples(model, preprocessedInput); } else { auto ioSettings = storm::settings::getModule(); - verifyModel(model, input, coreSettings); + verifyModel(model, preprocessedInput, coreSettings); } } } diff --git a/src/storm/logic/CloneVisitor.cpp b/src/storm/logic/CloneVisitor.cpp index 3e24d92c0..4b427b1dc 100644 --- a/src/storm/logic/CloneVisitor.cpp +++ b/src/storm/logic/CloneVisitor.cpp @@ -123,8 +123,8 @@ namespace storm { return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation())); } - boost::any CloneVisitor::visit(TotalRewardFormula const&, boost::any const&) const { - return std::static_pointer_cast(std::make_shared()); + boost::any CloneVisitor::visit(TotalRewardFormula const& f, boost::any const&) const { + return std::static_pointer_cast(std::make_shared(f)); } boost::any CloneVisitor::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const { diff --git a/src/storm/logic/RewardAccumulation.cpp b/src/storm/logic/RewardAccumulation.cpp index ed99baaa0..32065268a 100644 --- a/src/storm/logic/RewardAccumulation.cpp +++ b/src/storm/logic/RewardAccumulation.cpp @@ -18,9 +18,9 @@ namespace storm { bool RewardAccumulation::isExitSet() const { return exit; } - - bool RewardAccumulation::implies(RewardAccumulation const& other) const { - return (!isStepsSet() || other.isStepsSet()) && (!isTimeSet() || other.isTimeSet()) && (!isExitSet() || other.isExitSet()); + + bool RewardAccumulation::isEmpty() const { + return !isStepsSet() && !isTimeSet() && !isExitSet(); } std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc) { diff --git a/src/storm/logic/RewardAccumulation.h b/src/storm/logic/RewardAccumulation.h index 6350c2d00..4f8a50b29 100644 --- a/src/storm/logic/RewardAccumulation.h +++ b/src/storm/logic/RewardAccumulation.h @@ -13,8 +13,9 @@ namespace storm { bool isTimeSet() const; // If set, state rewards are accumulated over time (assuming 0 time passes in discrete-time model states) bool isExitSet() const; // If set, state rewards are accumulated upon exiting the state - // Returns true, if every reward-type set in this RewardAccumulation is also set for the other RewardAccumulation - bool implies(RewardAccumulation const& other) const; + // Returns true iff accumulation for all types of reward is disabled. + bool isEmpty() const; + private: bool time, steps, exit; }; diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp new file mode 100644 index 000000000..0cefa9a7d --- /dev/null +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp @@ -0,0 +1,173 @@ +#include "storm/logic/RewardAccumulationEliminationVisitor.h" +#include "storm/logic/Formulas.h" + +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/InvalidPropertyException.h" +#include "storm/storage/dd/DdManager.h" +#include "storm/storage/dd/Add.h" +#include "storm/storage/dd/Bdd.h" + +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/models/symbolic/StandardRewardModel.h" + +namespace storm { + namespace logic { + + template + RewardAccumulationEliminationVisitor::RewardAccumulationEliminationVisitor(std::unordered_map const& rewardModels, storm::models::ModelType const& modelType) : rewardModels(rewardModels) { + if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::S2pg) { + isDiscreteTimeModel = true; + } else if (modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::MarkovAutomaton) { + isDiscreteTimeModel = false; + } else { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled model type " << modelType << "."); + } + } + + template + std::shared_ptr RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(Formula const& f) const { + boost::any result = f.accept(*this, boost::any()); + return boost::any_cast>(result); + } + + template + boost::any RewardAccumulationEliminationVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + std::vector> lowerBounds, upperBounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + if (f.hasLowerBound(i)) { + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), f.getLowerBound(i))); + } else { + lowerBounds.emplace_back(); + } + if (f.hasUpperBound(i)) { + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), f.getUpperBound(i))); + } else { + upperBounds.emplace_back(); + } + storm::logic::TimeBoundReference tbr = f.getTimeBoundReference(i); + if (tbr.hasRewardAccumulation() && canEliminate(tbr.getRewardAccumulation(), tbr.getRewardName())) { + // Eliminate accumulation + tbr = storm::logic::TimeBoundReference(tbr.getRewardName(), boost::none); + } + timeBoundReferences.push_back(std::move(tbr)); + } + if (f.hasMultiDimensionalSubformulas()) { + std::vector> leftSubformulas, rightSubformulas; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + leftSubformulas.push_back(boost::any_cast>(f.getLeftSubformula(i).accept(*this, data))); + rightSubformulas.push_back(boost::any_cast>(f.getRightSubformula(i).accept(*this, data))); + } + return std::static_pointer_cast(std::make_shared(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences)); + } else { + std::shared_ptr left = boost::any_cast>(f.getLeftSubformula().accept(*this, data)); + std::shared_ptr right = boost::any_cast>(f.getRightSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(left, right, lowerBounds, upperBounds, timeBoundReferences)); + } + } + + template + boost::any RewardAccumulationEliminationVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + boost::optional rewAcc; + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (f.hasRewardAccumulation() && !canEliminate(f.getRewardAccumulation(), rewName)) { + rewAcc = f.getRewardAccumulation(); + } + + std::vector bounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + bounds.emplace_back(TimeBound(f.isBoundStrict(i), f.getBound(i))); + storm::logic::TimeBoundReference tbr = f.getTimeBoundReference(i); + if (tbr.hasRewardAccumulation() && canEliminate(tbr.getRewardAccumulation(), tbr.getRewardName())) { + // Eliminate accumulation + tbr = storm::logic::TimeBoundReference(tbr.getRewardName(), boost::none); + } + timeBoundReferences.push_back(std::move(tbr)); + } + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences, rewAcc)); + } + + template + boost::any RewardAccumulationEliminationVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + if (f.hasRewardAccumulation()) { + if (f.isTimePathFormula()) { + if (isDiscreteTimeModel && ((!f.getRewardAccumulation().isExitSet() && !f.getRewardAccumulation().isStepsSet()) || (f.getRewardAccumulation().isStepsSet() && f.getRewardAccumulation().isExitSet()))) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } else if (!isDiscreteTimeModel && (!f.getRewardAccumulation().isTimeSet() || f.getRewardAccumulation().isExitSet() || f.getRewardAccumulation().isStepsSet())) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } + } else if (f.isRewardPathFormula()) { + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (!canEliminate(f.getRewardAccumulation(), rewName)) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } + } + } + return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + } + + template + boost::any RewardAccumulationEliminationVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, f.getOptionalRewardModelName())); + return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation())); + } + + template + boost::any RewardAccumulationEliminationVisitor::visit(TotalRewardFormula const& f, boost::any const& data) const { + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (f.hasRewardAccumulation() || canEliminate(f.getRewardAccumulation(), rewName)) { + return std::static_pointer_cast(std::make_shared()); + } else { + return std::static_pointer_cast(std::make_shared(f.getRewardAccumulation())); + } + } + + template + bool RewardAccumulationEliminationVisitor::canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const { + auto rewModelIt = rewardModels.end(); + if (rewardModelName.is_initialized()){ + rewModelIt = rewardModels.find(rewardModelName.get()); + STORM_LOG_THROW(rewModelIt != rewardModels.end(), storm::exceptions::InvalidPropertyException, "Unable to find reward model with name " << rewardModelName.get()); + } else if (rewardModels.size() == 1) { + rewModelIt = rewardModels.begin(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Multiple reward models were defined but no reward model name was given for at least one property."); + } + RewardModelType const& rewardModel = rewModelIt->second; + if ((rewardModel.hasStateActionRewards() || rewardModel.hasTransitionRewards()) && !accumulation.isStepsSet()) { + return false; + } + if (rewardModel.hasStateRewards()) { + if (isDiscreteTimeModel) { + if (!accumulation.isExitSet()) { + return false; + } + // accumulating over time in discrete time models has no effect, i.e., the value of accumulation.isTimeSet() does not matter here. + } else { + if (accumulation.isExitSet() || !accumulation.isTimeSet()) { + return false; + } + } + } + return true; + } + + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + template class RewardAccumulationEliminationVisitor>; + + } +} diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.h b/src/storm/logic/RewardAccumulationEliminationVisitor.h new file mode 100644 index 000000000..80915b8e9 --- /dev/null +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "storm/logic/CloneVisitor.h" +#include "storm/logic/RewardAccumulation.h" +#include "storm/models/ModelType.h" + + +namespace storm { + namespace logic { + + template + class RewardAccumulationEliminationVisitor : public CloneVisitor { + public: + RewardAccumulationEliminationVisitor(std::unordered_map const& rewardModels, storm::models::ModelType const& modelType); + + /*! + * Eliminates any reward accumulations of the formula, where the presence of the reward accumulation does not change the result of the formula + */ + std::shared_ptr eliminateRewardAccumulations(Formula const& f) const; + + virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; + virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(TotalRewardFormula const& f, boost::any const& data) const override; + + + private: + bool canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const; + + std::unordered_map const& rewardModels; + bool isDiscreteTimeModel; + }; + + } +} From a739ce38f105e7dcc7671d73d7a1858bc6a4c742 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 28 Aug 2018 15:18:03 +0200 Subject: [PATCH 510/647] export of reward accumulations --- src/storm/storage/jani/JSONExporter.cpp | 108 ++++++++++++++++-------- src/storm/storage/jani/JSONExporter.h | 13 ++- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index c957cd29b..d0d1fb8e6 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -153,9 +153,40 @@ namespace storm { return iDecl; } - modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model) { + modernjson::json FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const { + std::vector res; + if (rewardAccumulation.isStepsSet()) { + res.push_back("steps"); + } + if (rewardAccumulation.isTimeSet()) { + res.push_back("time"); + } + if (rewardAccumulation.isExitSet()) { + stateExitRewards = true; + res.push_back("exit"); + } + return res; + } + + modernjson::json FormulaToJaniJson::constructStandardRewardAccumulation() const { + if (model.isDiscreteTimeModel()) { + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, false, true)); + } else { + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false)); + } + } + + modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model, std::set& modelFeatures) { FormulaToJaniJson translator(model); - return boost::any_cast(formula.accept(translator)); + auto result = boost::any_cast(formula.accept(translator)); + if (translator.containsStateExitRewards()) { + modelFeatures.insert("state-exit-rewards"); + } + return result; + } + + bool FormulaToJaniJson::containsStateExitRewards() const { + return stateExitRewards; } boost::any FormulaToJaniJson::visit(storm::logic::AtomicExpressionFormula const& f, boost::any const&) const { @@ -209,11 +240,11 @@ namespace storm { } else if(tbr.isRewardBound()) { modernjson::json rewbound; rewbound["exp"] = tbr.getRewardName(); - std::vector accvec = {"steps"}; - if (!model.isDiscreteTimeModel()) { - accvec.push_back("time"); + if (tbr.hasRewardAccumulation()) { + rewbound["accumulate"] = constructRewardAccumulation(tbr.getRewardAccumulation()); + } else { + rewbound["accumulate"] = constructStandardRewardAccumulation(); } - rewbound["accumulate"] = modernjson::json(accvec); rewbound["bounds"] = propertyInterval; rewardBounds.push_back(std::move(rewbound)); } else { @@ -247,12 +278,14 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector accvec; - if (model.isDiscreteTimeModel()) { - accvec.push_back("steps"); - } else { - accvec.push_back("time"); + + // Create standard reward accumulation for time operator formulas. + storm::logic::RewardAccumulation rewAcc(model.isDiscreteTimeModel(), !model.isDiscreteTimeModel(), false); + if (f.getSubformula().isEventuallyFormula() && f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + rewAcc = f.getSubformula().asEventuallyFormula().getRewardAccumulation(); } + auto rewAccJson = constructRewardAccumulation(rewAcc); + if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); @@ -268,7 +301,7 @@ namespace storm { opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["left"]["exp"] = modernjson::json(1); - opDecl["left"]["accumulate"] = modernjson::json(accvec); + opDecl["left"]["accumulate"] = rewAccJson; opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if(f.hasOptimalityType()) { @@ -284,7 +317,7 @@ namespace storm { opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["exp"] = modernjson::json(1); - opDecl["accumulate"] = modernjson::json(accvec); + opDecl["accumulate"] = rewAccJson; } return opDecl; } @@ -401,12 +434,11 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector accvec = {"steps"}; + std::string instantName; if (model.isDiscreteTimeModel()) { instantName = "step-instant"; } else { - accvec.push_back("time"); instantName = "time-instant"; } @@ -436,21 +468,29 @@ namespace storm { } if (f.getSubformula().isEventuallyFormula()) { opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation()); + } else { + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(); + } } else if (f.getSubformula().isCumulativeRewardFormula()) { + // TODO: support for reward bounded formulas + STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation()); + } else { + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(); + } } else if (f.getSubformula().isInstantaneousRewardFormula()) { opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } STORM_LOG_THROW(f.hasRewardModelName(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); opDecl["left"]["exp"] = rewardModelName; - if (f.getSubformula().isReachabilityRewardFormula() || f.getSubformula().isCumulativeRewardFormula()) { - opDecl["left"]["accumulate"] = modernjson::json(accvec); - } opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if (f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - } else { // TODO add checks opDecl["op"] = "Emin"; @@ -458,16 +498,24 @@ namespace storm { if (f.getSubformula().isEventuallyFormula()) { opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation()); + } else { + opDecl["accumulate"] = constructStandardRewardAccumulation(); + } } else if (f.getSubformula().isCumulativeRewardFormula()) { + // TODO: support for reward bounded formulas + STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); opDecl[instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation()); + } else { + opDecl["accumulate"] = constructStandardRewardAccumulation(); + } } else if (f.getSubformula().isInstantaneousRewardFormula()) { opDecl[instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } - opDecl["exp"] = rewardModelName; - if (f.getSubformula().isReachabilityRewardFormula() || f.getSubformula().isCumulativeRewardFormula()) { - opDecl["accumulate"] = modernjson::json(accvec); - } } return opDecl; } @@ -841,8 +889,8 @@ namespace storm { return modernjson::json(automataDeclarations); } - void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) { + modelFeatures = {"derived-operators"}; jsonStruct["jani-version"] = janiModel.getJaniVersion(); jsonStruct["name"] = janiModel.getName(); jsonStruct["type"] = to_string(janiModel.getModelType()); @@ -852,14 +900,8 @@ namespace storm { jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction(), janiModel.getConstants(), janiModel.getGlobalVariables()); jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables(), commentExpressions); jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition()); - std::vector standardFeatureVector = {"derived-operators"}; - jsonStruct["features"] = standardFeatureVector; - } - - - std::string janiFilterTypeString(storm::modelchecker::FilterType const& ft) { switch(ft) { case storm::modelchecker::FilterType::MIN: @@ -888,12 +930,12 @@ namespace storm { } } - modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model) { + modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model, std::set& modelFeatures) { modernjson::json propDecl; propDecl["states"]["op"] = "initial"; propDecl["op"] = "filter"; propDecl["fun"] = janiFilterTypeString(fe.getFilterType()); - propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model); + propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model, modelFeatures); return propDecl; } @@ -904,7 +946,7 @@ namespace storm { for(auto const& f : formulas) { modernjson::json propDecl; propDecl["name"] = f.getName(); - propDecl["expression"] = convertFilterExpression(f.getFilter(), model); + propDecl["expression"] = convertFilterExpression(f.getFilter(), model, modelFeatures); ++index; properties.push_back(propDecl); } diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index f88bb7330..63bc24826 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -41,7 +41,8 @@ namespace storm { class FormulaToJaniJson : public storm::logic::FormulaVisitor { public: - static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& modeln); + static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& model, std::set& modelFeatures); + bool containsStateExitRewards() const; // Returns true iff the previously translated formula contained state exit rewards virtual boost::any visit(storm::logic::AtomicExpressionFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::AtomicLabelFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::BinaryBooleanStateFormula const& f, boost::any const& data) const; @@ -64,11 +65,15 @@ namespace storm { virtual boost::any visit(storm::logic::UntilFormula const& f, boost::any const& data) const; private: - FormulaToJaniJson(storm::jani::Model const& model) : model(model) { } + FormulaToJaniJson(storm::jani::Model const& model) : model(model), stateExitRewards(false) { } modernjson::json constructPropertyInterval(boost::optional const& lower, boost::optional const& lowerExclusive, boost::optional const& upper, boost::optional const& upperExclusive) const; + + modernjson::json constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const; + modernjson::json constructStandardRewardAccumulation() const; storm::jani::Model const& model; + mutable bool stateExitRewards; }; class JsonExporter { @@ -85,11 +90,13 @@ namespace storm { void appendVariableDeclaration(storm::jani::Variable const& variable); modernjson::json finalize() { + std::vector featureVector(modelFeatures.begin(), modelFeatures.end()); + jsonStruct["features"] = featureVector; return jsonStruct; } modernjson::json jsonStruct; - + std::set modelFeatures; }; } From 1714126a6fe3ed668ae92d83ab6cca45614fab8a Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 28 Aug 2018 16:43:16 +0200 Subject: [PATCH 511/647] traverser for jani models --- src/storm/storage/jani/Automaton.cpp | 4 + src/storm/storage/jani/Automaton.h | 2 + src/storm/storage/jani/EdgeContainer.cpp | 6 +- src/storm/storage/jani/EdgeContainer.h | 2 + .../storage/jani/traverser/JaniTraverser.cpp | 130 ++++++++++++++++++ .../storage/jani/traverser/JaniTraverser.h | 36 +++++ 6 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 src/storm/storage/jani/traverser/JaniTraverser.cpp create mode 100644 src/storm/storage/jani/traverser/JaniTraverser.h diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index cc75d080e..62d2576cf 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -270,6 +270,10 @@ namespace storm { return ConstEdges(it1, it2); } + EdgeContainer const& Automaton::getEdgeContainer() const { + return edges; + } + void Automaton::addEdge(Edge const& edge) { STORM_LOG_THROW(edge.getSourceLocationIndex() < locations.size(), storm::exceptions::InvalidArgumentException, "Cannot add edge with unknown source location index '" << edge.getSourceLocationIndex() << "'."); assert(validate()); diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index eb1362741..869f5cd09 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -192,6 +192,8 @@ namespace storm { */ ConstEdges getEdgesFromLocation(uint64_t locationIndex, uint64_t actionIndex) const; + EdgeContainer const& getEdgeContainer() const; + /*! * Adds the template edge to the list of edges */ diff --git a/src/storm/storage/jani/EdgeContainer.cpp b/src/storm/storage/jani/EdgeContainer.cpp index b7a9ca1ec..d735bc80d 100644 --- a/src/storm/storage/jani/EdgeContainer.cpp +++ b/src/storm/storage/jani/EdgeContainer.cpp @@ -121,8 +121,6 @@ namespace storm { } - - std::vector & EdgeContainer::getConcreteEdges() { return edges; } @@ -130,6 +128,10 @@ namespace storm { std::vector const& EdgeContainer::getConcreteEdges() const { return edges; } + + TemplateEdgeContainer const& EdgeContainer::getTemplateEdges() const { + return templates; + } std::set EdgeContainer::getActionIndices() const { std::set result; diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h index f4738e1e0..faa33a418 100644 --- a/src/storm/storage/jani/EdgeContainer.h +++ b/src/storm/storage/jani/EdgeContainer.h @@ -95,6 +95,8 @@ namespace storm { void clearConcreteEdges(); std::vector const& getConcreteEdges() const; std::vector & getConcreteEdges(); + TemplateEdgeContainer const& getTemplateEdges const; + size_t size() const; iterator begin(); diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp new file mode 100644 index 000000000..3c695d0c1 --- /dev/null +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -0,0 +1,130 @@ +#include "storm/storage/jani/traverser/JaniTraverser.h" + + +namespace storm { + namespace jani { + void JaniTraverser::traverse(Model const& model, boost::any& data) const { + for (auto const& act : model.getActions()) { + traverse(act, data); + } + for (auto const& c : model.getConstants()) { + traverse(c, data); + } + traverse(model.getGlobalVariables(), data); + for (auto const& aut : model.getAutomata()) { + traverse(aut, data); + } + traverse(model.getInitialStatesRestriction(), data); + } + + void JaniTraverser::traverse(Action const& action, boost::any& data) const { + // Intentionally left empty. + } + + void JaniTraverser::traverse(Automaton const& automaton, boost::any& data) const { + traverse(automaton.getVariables(), data); + for (auto const& loc : automaton.getLocations()) { + traverse(loc, data); + } + traverse(automaton.getEdgeContainer(), data); + traverse(automaton.getInitialStatesRestriction(), data); + } + + void JaniTraverser::traverse(Constant const& constant, boost::any& data) const { + traverse(constant.getExpression(), data); + } + + void JaniTraverser::traverse(VariableSet const& variableSet, boost::any& data) const { + for (auto const& v : variableSet.getBooleanVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getBoundedIntegerVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getUnboundedIntegerVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getRealVariables()) { + traverse(v, data); + } + } + + void JaniTraverser::traverse(Location const& location, boost::any& data) const { + traverse(location.getAssignments(), data) + } + + void JaniTraverser::traverse(BooleanVariable const& variable, boost::any& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression()); + } + } + + void JaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression()); + } + traverse(variable.getLowerBound()); + traverse(variable.getUpperBound()); + } + + void JaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression()); + } + } + + void JaniTraverser::traverse(RealVariable const& variable, boost::any& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression()); + } + } + + void JaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any& data) const { + for (auto const& templateEdge : edgeContainer.getTemplateEdges()) { + traverse(templateEdge, data); + } + for (auto const& concreteEdge : edgeContainer.getConcreteEdges()) { + traverse(concreteEdge, data); + } + } + + void JaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any& data) const { + traverse(templateEdge.getGuard(), data); + for (auto const& dest : templateEdge.getDestinations()) { + traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + void JaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any& data) const { + traverse(templateEdgeDestination.getOrderedAssignments(), data); + } + + void JaniTraverser::traverse(Edge const& edge, boost::any& data) const { + traverse(edge.getRate(), data); + for (auto const& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void JaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any& data) const { + traverse(edgeDestination.getProbability()); + } + + void JaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any& data) const { + for (auto const& assignment : orderedAssignments) { + traverse(assignment, data); + } + } + + void JaniTraverser::traverse(Assignment const& assignment, boost::any& data) const { + traverse(assignment.getAssignedExpression(), data); + } + + void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any& data) const { + // intentionally left empty. + } + + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h new file mode 100644 index 000000000..24b619c1f --- /dev/null +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -0,0 +1,36 @@ +#pragma once + + +#include + +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + class JaniTraverser { + public: + virtual ~JaniTraverser() = default; + + virtual void traverse(Model const& model, boost::any& data) const; + + virtual void traverse(Action const& action, boost::any& data) const; + virtual void traverse(Automaton const& automaton, boost::any& data) const; + virtual void traverse(Constant const& constant, boost::any& data) const; + virtual void traverse(VariableSet const& variableSet, boost::any& data) const; + virtual void traverse(Location const& location, boost::any& data) const; + virtual void traverse(BooleanVariable const& variable, boost::any& data) const; + virtual void traverse(BoundedIntegerVariable const& variable, boost::any& data) const; + virtual void traverse(UnboundedIntegerVariable const& variable, boost::any& data) const; + virtual void traverse(RealVariable const& variable, boost::any& data) const; + virtual void traverse(EdgeContainer const& edgeContainer, boost::any& data) const; + virtual void traverse(TemplateEdge const& templateEdge, boost::any& data) const; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any& data) const; + virtual void traverse(Edge const& edge, boost::any& data) const; + virtual void traverse(EdgeDestination const& edgeDestination, boost::any& data) const; + virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any& data) const; + virtual void traverse(Assignment const& assignment, boost::any& data) const; + virtual void traverse(storm::expressions::Expression const& expression, boost::any& data) const; + }; + } +} + From 6cc0369a1c74121b3f5a3e61787188d271ff1d13 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 29 Aug 2018 08:53:37 +0200 Subject: [PATCH 512/647] added JaniTraverser to conveniently traverse all components of a jani model. --- .../jani/traverser/AssignmentsFinder.cpp | 47 +++++++++++++ .../jani/traverser/AssignmentsFinder.h | 29 ++++++++ .../storage/jani/traverser/JaniTraverser.cpp | 70 +++++++++++-------- .../storage/jani/traverser/JaniTraverser.h | 36 +++++----- 4 files changed, 133 insertions(+), 49 deletions(-) create mode 100644 src/storm/storage/jani/traverser/AssignmentsFinder.cpp create mode 100644 src/storm/storage/jani/traverser/AssignmentsFinder.h diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp new file mode 100644 index 000000000..f1450d004 --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp @@ -0,0 +1,47 @@ +#include "storm/storage/jani/traverser/AssignmentsFinder.h" + + +namespace storm { + namespace jani { + + AssignmentsFinder::ResultType AssignmentsFinder::find(Model const& model, Variable const& variable) { + ResultType res; + res.hasLocationAssignment = false; + res.hasEdgeAssignment = false; + res.hasEdgeDestinationAssignment = false; + JaniTraverser::traverse(model, std::make_pair(&variable, &res)); + return res; + } + + void AssignmentsFinder::traverse(Location const& location, boost::any const& data) const { + auto resVar = boost::any_cast>(data); + for (auto const& assignment : location.getAssignments()) { + if (assignment.getVariable() == *resVar.first) { + resVar.second->hasLocationAssignment = true; + } + } + JaniTraverser::traverse(location, data); + } + + void AssignmentsFinder::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { + auto resVar = boost::any_cast>(data); + for (auto const& assignment : templateEdge.getAssignments()) { + if (assignment.getVariable() == *resVar.first) { + resVar.second->hasEdgeAssignment = true; + } + } + JaniTraverser::traverse(templateEdge, data); + } + + void AssignmentsFinder::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { + auto resVar = boost::any_cast>(data); + for (auto const& assignment : templateEdgeDestination.getOrderedAssignments()) { + if (assignment.getVariable() == *resVar.first) { + resVar.second->hasEdgeDestinationAssignment = true; + } + } + JaniTraverser::traverse(templateEdgeDestination, data); + } + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.h b/src/storm/storage/jani/traverser/AssignmentsFinder.h new file mode 100644 index 000000000..2a2d2cdd0 --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.h @@ -0,0 +1,29 @@ +#pragma once + + +#include + +#include "storm/storage/jani/traverser/JaniTraverser.h" + +namespace storm { + namespace jani { + class AssignmentsFinder : public JaniTraverser { + public: + + struct ResultType { + bool hasLocationAssignment, hasEdgeAssignment, hasEdgeDestinationAssignment; + }; + + AssignmentsFinder() = default; + + ResultType find(Model const& model, Variable const& variable); + + virtual ~AssignmentsFinder() = default; + + virtual void traverse(Location const& location, boost::any const& data) const override; + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const override; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const override; + }; + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp index 3c695d0c1..2461792b5 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.cpp +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -3,7 +3,7 @@ namespace storm { namespace jani { - void JaniTraverser::traverse(Model const& model, boost::any& data) const { + void JaniTraverser::traverse(Model const& model, boost::any const& data) const { for (auto const& act : model.getActions()) { traverse(act, data); } @@ -14,27 +14,33 @@ namespace storm { for (auto const& aut : model.getAutomata()) { traverse(aut, data); } - traverse(model.getInitialStatesRestriction(), data); + if (model.hasInitialStatesRestriction()) { + traverse(model.getInitialStatesRestriction(), data); + } } - void JaniTraverser::traverse(Action const& action, boost::any& data) const { + void JaniTraverser::traverse(Action const& action, boost::any const& data) const { // Intentionally left empty. } - void JaniTraverser::traverse(Automaton const& automaton, boost::any& data) const { + void JaniTraverser::traverse(Automaton const& automaton, boost::any const& data) const { traverse(automaton.getVariables(), data); for (auto const& loc : automaton.getLocations()) { traverse(loc, data); } traverse(automaton.getEdgeContainer(), data); - traverse(automaton.getInitialStatesRestriction(), data); + if (automaton.hasInitialStatesRestriction()) { + traverse(automaton.getInitialStatesRestriction(), data); + } } - void JaniTraverser::traverse(Constant const& constant, boost::any& data) const { - traverse(constant.getExpression(), data); + void JaniTraverser::traverse(Constant const& constant, boost::any const& data) const { + if (constant.isDefined()) { + traverse(constant.getExpression(), data); + } } - void JaniTraverser::traverse(VariableSet const& variableSet, boost::any& data) const { + void JaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) const { for (auto const& v : variableSet.getBooleanVariables()) { traverse(v, data); } @@ -49,46 +55,46 @@ namespace storm { } } - void JaniTraverser::traverse(Location const& location, boost::any& data) const { - traverse(location.getAssignments(), data) + void JaniTraverser::traverse(Location const& location, boost::any const& data) const { + traverse(location.getAssignments(), data); } - void JaniTraverser::traverse(BooleanVariable const& variable, boost::any& data) const { + void JaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { - traverse(variable.getInitExpression()); + traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any& data) const { + void JaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { - traverse(variable.getInitExpression()); + traverse(variable.getInitExpression(), data); } - traverse(variable.getLowerBound()); - traverse(variable.getUpperBound()); + traverse(variable.getLowerBound(), data); + traverse(variable.getUpperBound(), data); } - void JaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any& data) const { + void JaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { - traverse(variable.getInitExpression()); + traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(RealVariable const& variable, boost::any& data) const { + void JaniTraverser::traverse(RealVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { - traverse(variable.getInitExpression()); + traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any& data) const { + void JaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) const { for (auto const& templateEdge : edgeContainer.getTemplateEdges()) { - traverse(templateEdge, data); + traverse(*templateEdge, data); } for (auto const& concreteEdge : edgeContainer.getConcreteEdges()) { traverse(concreteEdge, data); } } - void JaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any& data) const { + void JaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { traverse(templateEdge.getGuard(), data); for (auto const& dest : templateEdge.getDestinations()) { traverse(dest, data); @@ -96,32 +102,34 @@ namespace storm { traverse(templateEdge.getAssignments(), data); } - void JaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any& data) const { + void JaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { traverse(templateEdgeDestination.getOrderedAssignments(), data); } - void JaniTraverser::traverse(Edge const& edge, boost::any& data) const { - traverse(edge.getRate(), data); + void JaniTraverser::traverse(Edge const& edge, boost::any const& data) const { + if (edge.hasRate()) { + traverse(edge.getRate(), data); + } for (auto const& dest : edge.getDestinations()) { traverse(dest, data); } } - void JaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any& data) const { - traverse(edgeDestination.getProbability()); + void JaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) const { + traverse(edgeDestination.getProbability(), data); } - void JaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any& data) const { + void JaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const { for (auto const& assignment : orderedAssignments) { traverse(assignment, data); } } - void JaniTraverser::traverse(Assignment const& assignment, boost::any& data) const { + void JaniTraverser::traverse(Assignment const& assignment, boost::any const& data) const { traverse(assignment.getAssignedExpression(), data); } - void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any& data) const { + void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { // intentionally left empty. } diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h index 24b619c1f..905ad0208 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.h +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -11,25 +11,25 @@ namespace storm { public: virtual ~JaniTraverser() = default; - virtual void traverse(Model const& model, boost::any& data) const; + virtual void traverse(Model const& model, boost::any const& data) const; - virtual void traverse(Action const& action, boost::any& data) const; - virtual void traverse(Automaton const& automaton, boost::any& data) const; - virtual void traverse(Constant const& constant, boost::any& data) const; - virtual void traverse(VariableSet const& variableSet, boost::any& data) const; - virtual void traverse(Location const& location, boost::any& data) const; - virtual void traverse(BooleanVariable const& variable, boost::any& data) const; - virtual void traverse(BoundedIntegerVariable const& variable, boost::any& data) const; - virtual void traverse(UnboundedIntegerVariable const& variable, boost::any& data) const; - virtual void traverse(RealVariable const& variable, boost::any& data) const; - virtual void traverse(EdgeContainer const& edgeContainer, boost::any& data) const; - virtual void traverse(TemplateEdge const& templateEdge, boost::any& data) const; - virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any& data) const; - virtual void traverse(Edge const& edge, boost::any& data) const; - virtual void traverse(EdgeDestination const& edgeDestination, boost::any& data) const; - virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any& data) const; - virtual void traverse(Assignment const& assignment, boost::any& data) const; - virtual void traverse(storm::expressions::Expression const& expression, boost::any& data) const; + virtual void traverse(Action const& action, boost::any const& data) const; + virtual void traverse(Automaton const& automaton, boost::any const& data) const; + virtual void traverse(Constant const& constant, boost::any const& data) const; + virtual void traverse(VariableSet const& variableSet, boost::any const& data) const; + virtual void traverse(Location const& location, boost::any const& data) const; + virtual void traverse(BooleanVariable const& variable, boost::any const& data) const; + virtual void traverse(BoundedIntegerVariable const& variable, boost::any const& data) const; + virtual void traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const; + virtual void traverse(RealVariable const& variable, boost::any const& data) const; + virtual void traverse(EdgeContainer const& edgeContainer, boost::any const& data) const; + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const; + virtual void traverse(Edge const& edge, boost::any const& data) const; + virtual void traverse(EdgeDestination const& edgeDestination, boost::any const& data) const; + virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const; + virtual void traverse(Assignment const& assignment, boost::any const& data) const; + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) const; }; } } From 8050f8fc67926d61ddd9831789ac68e2f66b5a8a Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 29 Aug 2018 08:54:28 +0200 Subject: [PATCH 513/647] eliminate reward accumulations on jani level --- src/storm-cli-utilities/model-handling.h | 41 ++------- .../RewardAccumulationEliminationVisitor.cpp | 88 +++++++------------ .../RewardAccumulationEliminationVisitor.h | 12 +-- src/storm/logic/TimeBoundType.h | 1 - src/storm/storage/jani/EdgeContainer.h | 2 +- 5 files changed, 49 insertions(+), 95 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 257453e92..524d772be 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -23,7 +23,6 @@ #include "storm/models/ModelBase.h" #include "storm/exceptions/OptionParserException.h" -#include "storm/exceptions/UnexpectedException.h" #include "storm/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -126,6 +125,10 @@ namespace storm { } if (!output.properties.empty()) { output.properties = storm::api::substituteConstantsInProperties(output.properties, constantDefinitions); + if (output.model.is_initialized() && output.model->isJaniModel()) { + storm::logic::RewardAccumulationEliminationVisitor v(output.model->asJaniModel()); + v.eliminateRewardAccumulations(output.properties); + } } // Check whether conversion for PRISM to JANI is requested or necessary. @@ -384,7 +387,6 @@ namespace storm { std::pair, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { - STORM_LOG_THROW((std::is_same::value), storm::exceptions::UnexpectedException, "Build-Value Type and ExportValueType should be the same in the sparse engine."); result = preprocessSparseModel(result.first->as>(), input); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); @@ -399,29 +401,6 @@ namespace storm { return result; } - template - storm::jani::Property preprocessProperty(std::shared_ptr const& model, storm::jani::Property const& property) { - storm::logic::RewardAccumulationEliminationVisitor v(model->getRewardModels(), model->getType()); - auto formula = v.eliminateRewardAccumulations(*property.getFilter().getFormula()); - auto states = v.eliminateRewardAccumulations(*property.getFilter().getStatesFormula()); - storm::jani::FilterExpression fe(formula, property.getFilter().getFilterType(), states); - return storm::jani::Property(property.getName(), fe, property.getComment()); - } - - template - std::vector preprocessProperties(std::shared_ptr const& model, SymbolicInput const& input) { - std::vector resultProperties; - for (auto const& property : input.properties) { - if (model->isSparseModel()) { - resultProperties.push_back(preprocessProperty(model->as>(), property)); - } else { - STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - resultProperties.push_back(preprocessProperty(model->as>(), property)); - } - } - return resultProperties; - } - void printComputingCounterexample(storm::jani::Property const& property) { STORM_PRINT("Computing counterexample for property " << *property.getRawFormula() << " ..." << std::endl); } @@ -696,7 +675,7 @@ namespace storm { } template - std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput& input, storm::settings::modules::CoreSettings::Engine engine) { + std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { auto ioSettings = storm::settings::getModule(); auto buildSettings = storm::settings::getModule(); std::shared_ptr model; @@ -716,9 +695,6 @@ namespace storm { model = preprocessingResult.first; model->printModelInformationToStream(std::cout); } - if (!input.properties.empty()) { - input.properties = preprocessProperties(model, input); - } exportModel(model, input); } return model; @@ -737,16 +713,15 @@ namespace storm { } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { verifyWithExplorationEngine(input); } else { - SymbolicInput preprocessedInput = input; - std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(preprocessedInput, engine); + std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); if (model) { if (coreSettings.isCounterexampleSet()) { auto ioSettings = storm::settings::getModule(); - generateCounterexamples(model, preprocessedInput); + generateCounterexamples(model, input); } else { auto ioSettings = storm::settings::getModule(); - verifyModel(model, preprocessedInput, coreSettings); + verifyModel(model, input, coreSettings); } } } diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp index 0cefa9a7d..710f959f1 100644 --- a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp @@ -1,39 +1,35 @@ #include "storm/logic/RewardAccumulationEliminationVisitor.h" #include "storm/logic/Formulas.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" #include "storm/utility/macros.h" #include "storm/exceptions/UnexpectedException.h" #include "storm/exceptions/InvalidPropertyException.h" -#include "storm/storage/dd/DdManager.h" -#include "storm/storage/dd/Add.h" -#include "storm/storage/dd/Bdd.h" - -#include "storm/models/sparse/StandardRewardModel.h" -#include "storm/models/symbolic/StandardRewardModel.h" namespace storm { namespace logic { - template - RewardAccumulationEliminationVisitor::RewardAccumulationEliminationVisitor(std::unordered_map const& rewardModels, storm::models::ModelType const& modelType) : rewardModels(rewardModels) { - if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::S2pg) { - isDiscreteTimeModel = true; - } else if (modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::MarkovAutomaton) { - isDiscreteTimeModel = false; - } else { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled model type " << modelType << "."); - } + RewardAccumulationEliminationVisitor::RewardAccumulationEliminationVisitor(storm::jani::Model const& model) : model(model) { + // Intentionally left empty } - template - std::shared_ptr RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(Formula const& f) const { + std::shared_ptr RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(Formula const& f) const { boost::any result = f.accept(*this, boost::any()); return boost::any_cast>(result); } - template - boost::any RewardAccumulationEliminationVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + void RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(std::vector& properties) const { + for (auto& p : properties) { + auto formula = eliminateRewardAccumulations(*p.getFilter().getFormula()); + auto states = eliminateRewardAccumulations(*p.getFilter().getStatesFormula()); + storm::jani::FilterExpression fe(formula, p.getFilter().getFilterType(), states); + p = storm::jani::Property(p.getName(), storm::jani::FilterExpression(formula, p.getFilter().getFilterType(), states), p.getComment()); + } + } + + boost::any RewardAccumulationEliminationVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { std::vector> lowerBounds, upperBounds; std::vector timeBoundReferences; for (uint64_t i = 0; i < f.getDimension(); ++i) { @@ -68,8 +64,7 @@ namespace storm { } } - template - boost::any RewardAccumulationEliminationVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + boost::any RewardAccumulationEliminationVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { boost::optional rewAcc; STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); auto rewName = boost::any_cast>(data); @@ -91,14 +86,13 @@ namespace storm { return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences, rewAcc)); } - template - boost::any RewardAccumulationEliminationVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { + boost::any RewardAccumulationEliminationVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); if (f.hasRewardAccumulation()) { if (f.isTimePathFormula()) { - if (isDiscreteTimeModel && ((!f.getRewardAccumulation().isExitSet() && !f.getRewardAccumulation().isStepsSet()) || (f.getRewardAccumulation().isStepsSet() && f.getRewardAccumulation().isExitSet()))) { + if (model.isDiscreteTimeModel() && ((!f.getRewardAccumulation().isExitSet() && !f.getRewardAccumulation().isStepsSet()) || (f.getRewardAccumulation().isStepsSet() && f.getRewardAccumulation().isExitSet()))) { return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); - } else if (!isDiscreteTimeModel && (!f.getRewardAccumulation().isTimeSet() || f.getRewardAccumulation().isExitSet() || f.getRewardAccumulation().isStepsSet())) { + } else if (!model.isDiscreteTimeModel() && (!f.getRewardAccumulation().isTimeSet() || f.getRewardAccumulation().isExitSet() || f.getRewardAccumulation().isStepsSet())) { return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); } } else if (f.isRewardPathFormula()) { @@ -112,14 +106,12 @@ namespace storm { return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); } - template - boost::any RewardAccumulationEliminationVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + boost::any RewardAccumulationEliminationVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, f.getOptionalRewardModelName())); return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation())); } - template - boost::any RewardAccumulationEliminationVisitor::visit(TotalRewardFormula const& f, boost::any const& data) const { + boost::any RewardAccumulationEliminationVisitor::visit(TotalRewardFormula const& f, boost::any const& data) const { STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); auto rewName = boost::any_cast>(data); if (f.hasRewardAccumulation() || canEliminate(f.getRewardAccumulation(), rewName)) { @@ -129,23 +121,22 @@ namespace storm { } } - template - bool RewardAccumulationEliminationVisitor::canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const { - auto rewModelIt = rewardModels.end(); - if (rewardModelName.is_initialized()){ - rewModelIt = rewardModels.find(rewardModelName.get()); - STORM_LOG_THROW(rewModelIt != rewardModels.end(), storm::exceptions::InvalidPropertyException, "Unable to find reward model with name " << rewardModelName.get()); - } else if (rewardModels.size() == 1) { - rewModelIt = rewardModels.begin(); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Multiple reward models were defined but no reward model name was given for at least one property."); + bool RewardAccumulationEliminationVisitor::canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const { + STORM_LOG_THROW(rewardModelName.is_initialized(), storm::exceptions::InvalidPropertyException, "Unable to find transient variable with for unique reward model."); + storm::jani::AssignmentsFinder::ResultType assignmentKinds; + STORM_LOG_THROW(model.hasGlobalVariable(rewardModelName.get()), storm::exceptions::InvalidPropertyException, "Unable to find transient variable with name " << rewardModelName.get() << "."); + storm::jani::Variable const& transientVar = model.getGlobalVariable(rewardModelName.get()); + if (transientVar.getInitExpression().containsVariables() || !storm::utility::isZero(transientVar.getInitExpression().evaluateAsRational())) { + assignmentKinds.hasLocationAssignment = true; + assignmentKinds.hasEdgeAssignment = true; + assignmentKinds.hasEdgeDestinationAssignment = true; } - RewardModelType const& rewardModel = rewModelIt->second; - if ((rewardModel.hasStateActionRewards() || rewardModel.hasTransitionRewards()) && !accumulation.isStepsSet()) { + assignmentKinds = storm::jani::AssignmentsFinder().find(model, transientVar); + if ((assignmentKinds.hasEdgeAssignment || assignmentKinds.hasEdgeDestinationAssignment) && !accumulation.isStepsSet()) { return false; } - if (rewardModel.hasStateRewards()) { - if (isDiscreteTimeModel) { + if (assignmentKinds.hasLocationAssignment) { + if (model.isDiscreteTimeModel()) { if (!accumulation.isExitSet()) { return false; } @@ -158,16 +149,5 @@ namespace storm { } return true; } - - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - template class RewardAccumulationEliminationVisitor>; - } } diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.h b/src/storm/logic/RewardAccumulationEliminationVisitor.h index 80915b8e9..0b77901d9 100644 --- a/src/storm/logic/RewardAccumulationEliminationVisitor.h +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.h @@ -5,21 +5,22 @@ #include "storm/logic/CloneVisitor.h" #include "storm/logic/RewardAccumulation.h" -#include "storm/models/ModelType.h" - +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" namespace storm { namespace logic { - template class RewardAccumulationEliminationVisitor : public CloneVisitor { public: - RewardAccumulationEliminationVisitor(std::unordered_map const& rewardModels, storm::models::ModelType const& modelType); + RewardAccumulationEliminationVisitor(storm::jani::Model const& model); /*! * Eliminates any reward accumulations of the formula, where the presence of the reward accumulation does not change the result of the formula */ std::shared_ptr eliminateRewardAccumulations(Formula const& f) const; + + void eliminateRewardAccumulations(std::vector& properties) const; virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; @@ -31,8 +32,7 @@ namespace storm { private: bool canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const; - std::unordered_map const& rewardModels; - bool isDiscreteTimeModel; + storm::jani::Model const& model; }; } diff --git a/src/storm/logic/TimeBoundType.h b/src/storm/logic/TimeBoundType.h index 23f850105..ec9a753b0 100644 --- a/src/storm/logic/TimeBoundType.h +++ b/src/storm/logic/TimeBoundType.h @@ -51,7 +51,6 @@ namespace storm { } bool hasRewardAccumulation() const { - assert(isRewardBound()); return rewardAccumulation.is_initialized(); } diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h index faa33a418..c2bdfe80c 100644 --- a/src/storm/storage/jani/EdgeContainer.h +++ b/src/storm/storage/jani/EdgeContainer.h @@ -95,7 +95,7 @@ namespace storm { void clearConcreteEdges(); std::vector const& getConcreteEdges() const; std::vector & getConcreteEdges(); - TemplateEdgeContainer const& getTemplateEdges const; + TemplateEdgeContainer const& getTemplateEdges() const; size_t size() const; From 539b3230eb46d8e9ab45bd23797b43311a6479df Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 29 Aug 2018 08:56:57 +0200 Subject: [PATCH 514/647] when exporting jani, eliminate reward accumulation kinds whenever they do not have any effect --- src/storm/storage/jani/JSONExporter.cpp | 46 ++++++++++++++++++------- src/storm/storage/jani/JSONExporter.h | 3 +- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index d0d1fb8e6..cc45468c0 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -11,6 +11,7 @@ #include "storm/exceptions/InvalidJaniException.h" #include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/InvalidPropertyException.h" #include "storm/storage/expressions/RationalLiteralExpression.h" #include "storm/storage/expressions/IntegerLiteralExpression.h" @@ -29,6 +30,7 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/Property.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" namespace storm { namespace jani { @@ -153,6 +155,24 @@ namespace storm { return iDecl; } + modernjson::json FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation, std::string const& rewardModelName) const { + + storm::jani::Variable const& transientVar = model.getGlobalVariable(rewardModelName); + storm::jani::AssignmentsFinder::ResultType assignmentKinds; + STORM_LOG_THROW(model.hasGlobalVariable(rewardModelName), storm::exceptions::InvalidPropertyException, "Unable to find transient variable with name " << rewardModelName << "."); + if (transientVar.getInitExpression().containsVariables() || !storm::utility::isZero(transientVar.getInitExpression().evaluateAsRational())) { + assignmentKinds.hasLocationAssignment = true; + assignmentKinds.hasEdgeAssignment = true; + assignmentKinds.hasEdgeDestinationAssignment = true; + } + assignmentKinds = storm::jani::AssignmentsFinder().find(model, transientVar); + + bool steps = rewardAccumulation.isStepsSet() && (assignmentKinds.hasEdgeAssignment || assignmentKinds.hasEdgeDestinationAssignment); + bool time = rewardAccumulation.isTimeSet() && !model.isDiscreteTimeModel() && assignmentKinds.hasLocationAssignment; + bool exit = rewardAccumulation.isExitSet() && assignmentKinds.hasLocationAssignment; + return constructRewardAccumulation(storm::logic::RewardAccumulation(steps, time, exit)); + } + modernjson::json FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const { std::vector res; if (rewardAccumulation.isStepsSet()) { @@ -168,11 +188,11 @@ namespace storm { return res; } - modernjson::json FormulaToJaniJson::constructStandardRewardAccumulation() const { + modernjson::json FormulaToJaniJson::constructStandardRewardAccumulation(std::string const& rewardModelName) const { if (model.isDiscreteTimeModel()) { - return constructRewardAccumulation(storm::logic::RewardAccumulation(true, false, true)); + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, false, true), rewardModelName); } else { - return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false)); + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false), rewardModelName); } } @@ -241,9 +261,9 @@ namespace storm { modernjson::json rewbound; rewbound["exp"] = tbr.getRewardName(); if (tbr.hasRewardAccumulation()) { - rewbound["accumulate"] = constructRewardAccumulation(tbr.getRewardAccumulation()); + rewbound["accumulate"] = constructRewardAccumulation(tbr.getRewardAccumulation(), tbr.getRewardName()); } else { - rewbound["accumulate"] = constructStandardRewardAccumulation(); + rewbound["accumulate"] = constructStandardRewardAccumulation(tbr.getRewardName()); } rewbound["bounds"] = propertyInterval; rewardBounds.push_back(std::move(rewbound)); @@ -469,18 +489,18 @@ namespace storm { if (f.getSubformula().isEventuallyFormula()) { opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { - opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation()); + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation(), rewardModelName); } else { - opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(); + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(rewardModelName); } } else if (f.getSubformula().isCumulativeRewardFormula()) { // TODO: support for reward bounded formulas STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { - opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation()); + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation(), rewardModelName); } else { - opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(); + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(rewardModelName); } } else if (f.getSubformula().isInstantaneousRewardFormula()) { opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); @@ -499,18 +519,18 @@ namespace storm { if (f.getSubformula().isEventuallyFormula()) { opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { - opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation()); + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation(), rewardModelName); } else { - opDecl["accumulate"] = constructStandardRewardAccumulation(); + opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName); } } else if (f.getSubformula().isCumulativeRewardFormula()) { // TODO: support for reward bounded formulas STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); opDecl[instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { - opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation()); + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation(), rewardModelName); } else { - opDecl["accumulate"] = constructStandardRewardAccumulation(); + opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName); } } else if (f.getSubformula().isInstantaneousRewardFormula()) { opDecl[instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 63bc24826..1f1a49db8 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -70,7 +70,8 @@ namespace storm { modernjson::json constructPropertyInterval(boost::optional const& lower, boost::optional const& lowerExclusive, boost::optional const& upper, boost::optional const& upperExclusive) const; modernjson::json constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const; - modernjson::json constructStandardRewardAccumulation() const; + modernjson::json constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation, std::string const& rewardModelName) const; + modernjson::json constructStandardRewardAccumulation(std::string const& rewardModelName) const; storm::jani::Model const& model; mutable bool stateExitRewards; From 8ab3ea991da3f41b3b6e558cbdbb5ff25549c60a Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 30 Aug 2018 14:05:57 +0200 Subject: [PATCH 515/647] fix in drn parser --- CHANGELOG.md | 1 + src/storm-parsers/parser/DirectEncodingParser.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dd207331..eb2345e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Version 1.2.x ### Version 1.2.4 (2018/08) - New binary `storm-conv` that handles conversions between model files (currently: prism to jani) - Added support for expected time properties for discrete time models +- Bug fix in the parser for DRN (MDPs and MAs might have been affected). - Several bug fixes related to jani - `storm-gspn`: Improved .pnpro parser - `storm-gspn`: Added support for single/infinite/k-server semantics for GSPNs given in the .pnpro format diff --git a/src/storm-parsers/parser/DirectEncodingParser.cpp b/src/storm-parsers/parser/DirectEncodingParser.cpp index da4cd5228..13be6d62d 100644 --- a/src/storm-parsers/parser/DirectEncodingParser.cpp +++ b/src/storm-parsers/parser/DirectEncodingParser.cpp @@ -126,7 +126,7 @@ namespace storm { size_t row = 0; size_t state = 0; bool firstState = true; - bool firstAction = true; + bool firstActionForState = true; while (std::getline(file, line)) { STORM_LOG_TRACE("Parsing: " << line); if (boost::starts_with(line, "state ")) { @@ -135,7 +135,9 @@ namespace storm { firstState = false; } else { ++state; + ++row; } + firstActionForState = true; STORM_LOG_TRACE("New state " << state); // Parse state id @@ -209,8 +211,8 @@ namespace storm { } else if (boost::starts_with(line, "\taction ")) { // New action - if (firstAction) { - firstAction = false; + if (firstActionForState) { + firstActionForState = false; } else { ++row; } @@ -232,7 +234,7 @@ namespace storm { } else { // New transition size_t posColon = line.find(":"); - STORM_LOG_ASSERT(posColon != std::string::npos, "':' not found."); + STORM_LOG_THROW(posColon != std::string::npos, storm::exceptions::WrongFormatException, "':' not found."); size_t target = NumberParser::parse(line.substr(2, posColon-3)); std::string valueStr = line.substr(posColon+2); ValueType value = valueParser.parseValue(valueStr); From 53e9179722e610074d6b0e0652bdd0bf227c1ec8 Mon Sep 17 00:00:00 2001 From: Sebastian Junges Date: Thu, 30 Aug 2018 14:06:40 +0200 Subject: [PATCH 516/647] CMake more stable in case z3 version is not obtained --- resources/3rdparty/CMakeLists.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index 18a68a23f..f52ae7f3d 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -169,12 +169,17 @@ else() endif(Z3_FOUND) # split Z3 version into its components -string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) -list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) -list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) -list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) -if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") - set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) +if(Z3_VERSION) + string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) + list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) + list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) + list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) + if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") + set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) + endif() +else() + message(WARNING "Storm - Could not obtain Z3 version. Do you have the binary installed?. Building of Prism/JANI models will not be supported.") + set(Z3_FOUND FALSE) endif() ############################################################# From 5706831ad6070c28053ea4d657c1e56af098bee7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 30 Aug 2018 14:28:31 +0200 Subject: [PATCH 517/647] fixing settings/tests --- .../settings/modules/AbstractionSettings.cpp | 4 + .../settings/modules/AbstractionSettings.h | 7 + .../storm/abstraction/PrismMenuGameTest.cpp | 148 ++++++++++++------ 3 files changed, 109 insertions(+), 50 deletions(-) diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index ace89c635..682418169 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -180,6 +180,10 @@ namespace storm { this->getOption(addAllGuardsOptionName).getArgumentByName("value").setFromStringValue(value ? "on" : "off"); } + void AbstractionSettings::setAddAllInitialExpressions(bool value) { + this->getOption(addInitialExpressionsOptionName).getArgumentByName("value").setFromStringValue(value ? "on" : "off"); + } + bool AbstractionSettings::isUseInterpolationSet() const { return this->getOption(useInterpolationOptionName).getArgumentByName("value").getValueAsString() == "on"; } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 5e2e8fdbc..dbcaffd9d 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -76,6 +76,13 @@ namespace storm { */ void setAddAllGuards(bool value); + /*! + * Sets the option to add all initial expressions to the specified value. + * + * @param value The new value. + */ + void setAddAllInitialExpressions(bool value); + /*! * Retrieves whether the option to use interpolation was set. * diff --git a/src/test/storm/abstraction/PrismMenuGameTest.cpp b/src/test/storm/abstraction/PrismMenuGameTest.cpp index a200c1d68..5f9f86ddd 100644 --- a/src/test/storm/abstraction/PrismMenuGameTest.cpp +++ b/src/test/storm/abstraction/PrismMenuGameTest.cpp @@ -23,7 +23,9 @@ #include "storm/settings/modules/AbstractionSettings.h" TEST(PrismMenuGame, DieAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); @@ -47,8 +49,10 @@ TEST(PrismMenuGame, DieAbstractionTest_Cudd) { } TEST(PrismMenuGame, DieAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); std::vector initialPredicates; @@ -97,8 +101,10 @@ TEST(PrismMenuGame, DieAbstractionTest_Sylvan) { #endif TEST(PrismMenuGame, DieAbstractionAndRefinementTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); std::vector initialPredicates; @@ -124,8 +130,10 @@ TEST(PrismMenuGame, DieAbstractionAndRefinementTest_Cudd) { } TEST(PrismMenuGame, DieAbstractionAndRefinementTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); std::vector initialPredicates; @@ -151,8 +159,10 @@ TEST(PrismMenuGame, DieAbstractionAndRefinementTest_Sylvan) { } TEST(PrismMenuGame, DieFullAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); std::vector initialPredicates; @@ -191,8 +201,10 @@ TEST(PrismMenuGame, DieFullAbstractionTest_Cudd) { } TEST(PrismMenuGame, DieFullAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/die.pm"); std::vector initialPredicates; @@ -231,8 +243,10 @@ TEST(PrismMenuGame, DieFullAbstractionTest_Sylvan) { } TEST(PrismMenuGame, CrowdsAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -257,8 +271,10 @@ TEST(PrismMenuGame, CrowdsAbstractionTest_Cudd) { } TEST(PrismMenuGame, CrowdsAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -283,8 +299,10 @@ TEST(PrismMenuGame, CrowdsAbstractionTest_Sylvan) { } TEST(PrismMenuGame, CrowdsAbstractionAndRefinementTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -311,8 +329,10 @@ TEST(PrismMenuGame, CrowdsAbstractionAndRefinementTest_Cudd) { } TEST(PrismMenuGame, CrowdsAbstractionAndRefinementTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -339,8 +359,10 @@ TEST(PrismMenuGame, CrowdsAbstractionAndRefinementTest_Sylvan) { } TEST(PrismMenuGame, CrowdsFullAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -419,8 +441,10 @@ TEST(PrismMenuGame, CrowdsFullAbstractionTest_Cudd) { } TEST(PrismMenuGame, CrowdsFullAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/dtmc/crowds-5-5.pm"); program = program.substituteConstants(); @@ -499,8 +523,10 @@ TEST(PrismMenuGame, CrowdsFullAbstractionTest_Sylvan) { } TEST(PrismMenuGame, TwoDiceAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -527,8 +553,10 @@ TEST(PrismMenuGame, TwoDiceAbstractionTest_Cudd) { } TEST(PrismMenuGame, TwoDiceAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -555,8 +583,10 @@ TEST(PrismMenuGame, TwoDiceAbstractionTest_Sylvan) { } TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -585,8 +615,10 @@ TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Cudd) { } TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -615,8 +647,10 @@ TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Sylvan) { } TEST(PrismMenuGame, TwoDiceFullAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -674,8 +708,10 @@ TEST(PrismMenuGame, TwoDiceFullAbstractionTest_Cudd) { } TEST(PrismMenuGame, TwoDiceFullAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -733,8 +769,10 @@ TEST(PrismMenuGame, TwoDiceFullAbstractionTest_Sylvan) { } TEST(PrismMenuGame, WlanAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -754,7 +792,7 @@ TEST(PrismMenuGame, WlanAbstractionTest_Cudd) { storm::abstraction::MenuGame game = abstractor.abstract(); - EXPECT_EQ(915ull, game.getNumberOfTransitions()); + EXPECT_EQ(903ull, game.getNumberOfTransitions()); EXPECT_EQ(8ull, game.getNumberOfStates()); EXPECT_EQ(4ull, game.getBottomStates().getNonZeroCount()); @@ -762,8 +800,10 @@ TEST(PrismMenuGame, WlanAbstractionTest_Cudd) { } TEST(PrismMenuGame, WlanAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -783,7 +823,7 @@ TEST(PrismMenuGame, WlanAbstractionTest_Sylvan) { storm::abstraction::MenuGame game = abstractor.abstract(); - EXPECT_EQ(915ull, game.getNumberOfTransitions()); + EXPECT_EQ(903ull, game.getNumberOfTransitions()); EXPECT_EQ(8ull, game.getNumberOfStates()); EXPECT_EQ(4ull, game.getBottomStates().getNonZeroCount()); @@ -791,7 +831,9 @@ TEST(PrismMenuGame, WlanAbstractionTest_Sylvan) { } TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); @@ -814,7 +856,7 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Cudd) { storm::abstraction::MenuGame game = abstractor.abstract(); - EXPECT_EQ(1824ull, game.getNumberOfTransitions()); + EXPECT_EQ(1800ull, game.getNumberOfTransitions()); EXPECT_EQ(16ull, game.getNumberOfStates()); EXPECT_EQ(8ull, game.getBottomStates().getNonZeroCount()); @@ -822,8 +864,10 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Cudd) { } TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -845,7 +889,7 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Sylvan) { storm::abstraction::MenuGame game = abstractor.abstract(); - EXPECT_EQ(1824ull, game.getNumberOfTransitions()); + EXPECT_EQ(1800ull, game.getNumberOfTransitions()); EXPECT_EQ(16ull, game.getNumberOfStates()); EXPECT_EQ(8ull, game.getBottomStates().getNonZeroCount()); @@ -853,8 +897,10 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Sylvan) { } TEST(PrismMenuGame, WlanFullAbstractionTest_Cudd) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); @@ -980,8 +1026,10 @@ TEST(PrismMenuGame, WlanFullAbstractionTest_Cudd) { } TEST(PrismMenuGame, WlanFullAbstractionTest_Sylvan) { - storm::settings::mutableAbstractionSettings().setAddAllGuards(false); - + auto& settings = storm::settings::mutableAbstractionSettings(); + settings.setAddAllGuards(false); + settings.setAddAllInitialExpressions(false); + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/wlan0-2-4.nm"); program = program.substituteConstants(); program = program.flattenModules(std::make_shared()); From 943de2e17c328a2a1ca60080946821c5bad0fde7 Mon Sep 17 00:00:00 2001 From: dehnert Date: Thu, 30 Aug 2018 15:07:01 +0200 Subject: [PATCH 518/647] changing abstraction options slightly --- src/storm/settings/modules/AbstractionSettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 682418169..7300f8451 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -59,7 +59,7 @@ namespace storm { std::vector solveModes = {"dd", "sparse"}; this->addOption(storm::settings::OptionBuilder(moduleName, solveModeOptionName, true, "Sets how the abstractions are solved.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(solveModes)) - .setDefaultValueString("dd").build()) + .setDefaultValueString("sparse").build()) .build()); this->addOption(storm::settings::OptionBuilder(moduleName, addAllGuardsOptionName, true, "Sets whether all guards are added as initial predicates.") From 785dbbdcdbb5694e62c18e57c257cf89e7eb94a2 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 30 Aug 2018 18:30:23 +0200 Subject: [PATCH 519/647] CMake version parsing of z3 without z3 binary --- resources/3rdparty/CMakeLists.txt | 53 ++++++++++++------------ resources/3rdparty/z3/output_version.cpp | 9 ++++ 2 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 resources/3rdparty/z3/output_version.cpp diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index f52ae7f3d..472560abe 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -141,46 +141,45 @@ find_package(Z3 QUIET) # Z3 Defines set(STORM_HAVE_Z3 ${Z3_FOUND}) + if(Z3_FOUND) - # Check whether the version of z3 supports optimization - if (Z3_EXEC) - execute_process (COMMAND ${Z3_EXEC} -version - OUTPUT_VARIABLE z3_version_output - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) + # Get the z3 version by compiling and running a simple program + try_run(version_run_result version_compile_result "${STORM_3RDPARTY_BINARY_DIR}/z3/" "${PROJECT_SOURCE_DIR}/resources/3rdparty/z3/output_version.cpp" LINK_LIBRARIES "${Z3_LIBRARIES}" RUN_OUTPUT_VARIABLE z3_version_output) + if (version_compile_result AND version_run_result EQUAL 0) if (z3_version_output MATCHES "([0-9]*\\.[0-9]*\\.[0-9]*)") set(Z3_VERSION "${CMAKE_MATCH_1}") - if(NOT "${Z3_VERSION}" VERSION_LESS "4.5.0") - set(STORM_HAVE_Z3_OPTIMIZE ON) - endif() endif() endif() - if(STORM_HAVE_Z3_OPTIMIZE) - message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version supports optimization)") + if(Z3_VERSION) + # Split Z3 version into its components + string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) + list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) + list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) + list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) + + # Check whether the version of z3 supports optimization + if(NOT "${Z3_VERSION}" VERSION_LESS "4.5.0") + set(STORM_HAVE_Z3_OPTIMIZE ON) + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version supports optimization)") + else() + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version does not support optimization)") + endif() + if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") + set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) + endif() + + add_imported_library(z3 SHARED ${Z3_LIBRARIES} ${Z3_INCLUDE_DIRS}) + list(APPEND STORM_DEP_TARGETS z3_SHARED) else() - message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version does not support optimization)") + message(WARNING "Storm - Could not obtain Z3 version. Building of Prism/JANI models will not be supported.") + set(Z3_FOUND FALSE) endif() - add_imported_library(z3 SHARED ${Z3_LIBRARIES} ${Z3_INCLUDE_DIRS}) - list(APPEND STORM_DEP_TARGETS z3_SHARED) else() message (WARNING "Storm - Z3 not found. Building of Prism/JANI models will not be supported.") endif(Z3_FOUND) -# split Z3 version into its components -if(Z3_VERSION) - string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) - list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) - list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) - list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) - if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") - set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) - endif() -else() - message(WARNING "Storm - Could not obtain Z3 version. Do you have the binary installed?. Building of Prism/JANI models will not be supported.") - set(Z3_FOUND FALSE) -endif() ############################################################# ## diff --git a/resources/3rdparty/z3/output_version.cpp b/resources/3rdparty/z3/output_version.cpp new file mode 100644 index 000000000..3f631199e --- /dev/null +++ b/resources/3rdparty/z3/output_version.cpp @@ -0,0 +1,9 @@ +#include +#include + +int main() { + unsigned major, minor, build_number, revision_number; + Z3_get_version(&major, &minor, &build_number, &revision_number); + std::cout << major << "." << minor << "." << build_number << std::endl; + return 0; +} From 59a81831f3c44425d20ed8ad18a9760137115737 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 31 Aug 2018 10:21:47 +0200 Subject: [PATCH 520/647] fixing bug in relevant states computation of menu-game-based abstraction --- src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp | 2 +- src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index d233e3f5f..493b70e4b 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -201,7 +201,7 @@ namespace storm { storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); // In the presence of target states, we keep only states that can reach the target states. - reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index d25a51712..92b7e3bfb 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -193,7 +193,7 @@ namespace storm { storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); // In the presence of target states, we keep only states that can reach the target states. - reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates && !initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()) || initialStates; + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); // Include all successors of reachable states, because the backward search otherwise potentially // cuts probability 0 choices of these states. From dac431b263fe882dd4498f58215da42960b3672b Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 31 Aug 2018 17:28:36 +0200 Subject: [PATCH 521/647] parsing of jani-arrays --- src/storm-parsers/parser/JaniParser.cpp | 230 ++++++++++++------ src/storm-parsers/parser/JaniParser.h | 15 +- src/storm/storage/expressions/Expression.cpp | 3 - .../storage/expressions/SubstitutionVisitor.h | 2 +- src/storm/storage/jani/ArrayVariable.cpp | 6 +- src/storm/storage/jani/ArrayVariable.h | 4 +- src/storm/storage/jani/Assignment.cpp | 45 ++-- src/storm/storage/jani/Assignment.h | 41 +++- src/storm/storage/jani/LValue.cpp | 96 ++++++++ src/storm/storage/jani/LValue.h | 41 ++++ src/storm/storage/jani/OrderedAssignments.cpp | 4 +- src/storm/storage/jani/Variable.h | 4 +- .../expressions/ArrayAccessExpression.cpp | 17 +- .../jani/expressions/ArrayAccessExpression.h | 3 +- .../jani/expressions/ArrayExpression.h | 1 - .../ConstructorArrayExpression.cpp | 22 +- .../expressions/ConstructorArrayExpression.h | 5 +- .../JaniExpressionSubstitutionVisitor.cpp | 6 +- .../JaniExpressionSubstitutionVisitor.h | 8 +- .../jani/expressions/JaniExpressionVisitor.h | 3 - .../jani/expressions/ValueArrayExpression.cpp | 7 +- .../jani/expressions/ValueArrayExpression.h | 4 +- .../storage/jani/traverser/ArrayEliminator.h | 56 +++++ .../storage/jani/traverser/JaniTraverser.cpp | 8 +- .../storage/jani/traverser/JaniTraverser.h | 1 + src/storm/storage/prism/ToJaniConverter.cpp | 10 +- 26 files changed, 479 insertions(+), 163 deletions(-) create mode 100644 src/storm/storage/jani/LValue.cpp create mode 100644 src/storm/storage/jani/LValue.h create mode 100644 src/storm/storage/jani/traverser/ArrayEliminator.h diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index fc61bed31..97e7a80ad 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -644,7 +644,7 @@ namespace storm { } else if (typeStructure == "int") { result.basicType = ParsedType::BasicType::Int; } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << variableName << "' (scope: " << scopeDescription << ")"); } } else if (typeStructure.is_object()) { STORM_LOG_THROW(typeStructure.count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << variableName << "(scope: " << scopeDescription << ") kind must be given"); @@ -671,10 +671,10 @@ namespace storm { } } else if (kind == "array") { STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For array type as in variable " << variableName << "(scope: " << scopeDescription << ") base must be given"); - result.arrayBase = ParsedType(); - parseType(result.arrayBase.get(), typeStructure.at("base"), variableName, scopeDescription, globalVars, constants, localVars); + result.arrayBase = std::make_unique(); + parseType(*result.arrayBase, typeStructure.at("base"), variableName, scopeDescription, globalVars, constants, localVars); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << variableName << "(scope: " << scopeDescription << ") "); } } } @@ -763,29 +763,31 @@ namespace storm { } else if (type.arrayBase) { STORM_LOG_THROW(type.arrayBase->basicType, storm::exceptions::InvalidJaniException, "Array base type for variable " + name + "(scope " + scopeDescription + ") should be a BasicType or a BoundedType."); storm::jani::ArrayVariable::ElementType elementType; - storm::expressions::Type* exprVariableType; + storm::expressions::Type exprVariableType; switch (type.arrayBase->basicType.get()) { case ParsedType::BasicType::Real: elementType = storm::jani::ArrayVariable::ElementType::Real; - exprVariableType = &expressionManager->getArrayType(expressionManager->getRationalType()); + exprVariableType = expressionManager->getArrayType(expressionManager->getRationalType()); break; case ParsedType::BasicType::Bool: elementType = storm::jani::ArrayVariable::ElementType::Bool; - exprVariableType = &expressionManager->getArrayType(expressionManager->getBooleanType()); + exprVariableType = expressionManager->getArrayType(expressionManager->getBooleanType()); break; case ParsedType::BasicType::Int: elementType = storm::jani::ArrayVariable::ElementType::Int; - exprVariableType = &expressionManager->getArrayType(expressionManager->getIntegerType()); + exprVariableType = expressionManager->getArrayType(expressionManager->getIntegerType()); break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported type"); } if (setInitValFromDefault) { - initVal = storm::expressions::ValueArrayExpression(expressionManager, *exprVariableType, {}); + initVal = storm::expressions::ValueArrayExpression(*expressionManager, exprVariableType, {}).toExpression(); } if (initVal) { - STORM_LOG_THROW(initVal.get().hasArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scopeDescription + ") should be an Array"); - return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType->getElementType()), elementType, initVal.get(), transientVar); + STORM_LOG_THROW(initVal->getType().isArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scopeDescription + ") should be an Array"); + return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType, initVal.get(), transientVar); } else { - return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType->getElementType()), elementType); + return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType); } } @@ -799,14 +801,14 @@ namespace storm { STORM_LOG_THROW(expected == actual, storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects " << expected << " arguments, but got " << actual << " in " << errorInfo << "."); } - std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars,returnNoneInitializedOnUnknownOperator); + std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars,returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left}; } - std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); - storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left, right}; } /** @@ -823,29 +825,79 @@ namespace storm { STORM_LOG_THROW(expr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be numerical in " << errorInfo << "."); } - storm::jani::Variable const& getLValue(std::string const& ident, storm::jani::VariableSet const& globalVars, storm::jani::VariableSet const& localVars, std::string const& scopeDescription) { - if(localVars.hasVariable(ident)) { - return localVars.getVariable(ident); - } else if(globalVars.hasVariable(ident)) { - return globalVars.getVariable(ident); + /** + * Helper for parse expression. + */ + void ensureIntegerType(storm::expressions::Expression const& expr, std::string const& opstring, unsigned argNr, std::string const& errorInfo) { + STORM_LOG_THROW(expr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be numerical in " << errorInfo << "."); + } + + /** + * Helper for parse expression. + */ + void ensureArrayType(storm::expressions::Expression const& expr, std::string const& opstring, unsigned argNr, std::string const& errorInfo) { + STORM_LOG_THROW(expr.getType().isArrayType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be of type 'array' in " << errorInfo << "."); + } + + storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { + if (lValueStructure.is_string()) { + std::string ident = getString(lValueStructure, scopeDescription); + auto localVar = localVars.find(ident); + if (localVar != localVars.end()) { + return storm::jani::LValue(*localVar->second); + } + auto globalVar = globalVars.find(ident); + if (globalVar != globalVars.end()) { + return storm::jani::LValue(*globalVar->second); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + } + } else if (lValueStructure.count("op") == 1) { + std::string opstring = getString(lValueStructure.at("op"), scopeDescription); + STORM_LOG_THROW(opstring == "aa", storm::exceptions::InvalidJaniException, "Unknown operation '" << opstring << "' occurs in " << scopeDescription); + STORM_LOG_THROW(lValueStructure.count("exp"), storm::exceptions::InvalidJaniException, "Missing 'exp' in array access at " << scopeDescription); + storm::jani::LValue exp = parseLValue(lValueStructure.at("exp"), "LValue description of array expression in " + scopeDescription, globalVars, constants, localVars); + STORM_LOG_THROW(lValueStructure.count("index"), storm::exceptions::InvalidJaniException, "Missing 'index' in array access at " << scopeDescription); + storm::expressions::Expression index = parseExpression(lValueStructure.at("index"), "Index expression of array access at " + scopeDescription, globalVars, constants, localVars); + return storm::jani::LValue(exp, index); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown LValue '" << lValueStructure.dump() << "' occurs in " << scopeDescription); + // Silly warning suppression. + return storm::jani::LValue(*localVars.end()->second); } } - storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { - if(localVars.count(ident) == 1) { - return localVars.at(ident)->getExpressionVariable(); - } else if(globalVars.count(ident) == 1) { - return globalVars.at(ident)->getExpressionVariable(); - } else if(constants.count(ident) == 1) { - return constants.at(ident)->getExpressionVariable(); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, std::unordered_map const& auxiliaryVariables) { + { + auto it = auxiliaryVariables.find(ident); + if (it != auxiliaryVariables.end()) { + return it->second; + } + } + { + auto it = localVars.find(ident); + if (it != localVars.end()) { + return it->second->getExpressionVariable(); + } + } + { + auto it = globalVars.find(ident); + if (it != globalVars.end()) { + return it->second->getExpressionVariable(); + } + } + { + auto it = constants.find(ident); + if (it != constants.end()) { + return it->second->getExpressionVariable(); + } } + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + // Silly warning suppression. + return storm::expressions::Variable(); } - storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { + storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { if(expressionStructure.is_boolean()) { if(expressionStructure.get()) { return expressionManager->boolean(true); @@ -872,15 +924,15 @@ namespace storm { STORM_LOG_THROW(expressionStructure.count("if") == 1, storm::exceptions::InvalidJaniException, "If operator required"); STORM_LOG_THROW(expressionStructure.count("else") == 1, storm::exceptions::InvalidJaniException, "Else operator required"); STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "Then operator required"); - arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); - arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); - arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); + arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); ensureNumberOfArguments(3, arguments.size(), opstring, scopeDescription); assert(arguments.size() == 3); ensureBooleanType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::ite(arguments[0], arguments[1], arguments[2]); } else if (opstring == "∨") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -889,7 +941,7 @@ namespace storm { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return arguments[0] || arguments[1]; } else if (opstring == "∧") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -898,7 +950,7 @@ namespace storm { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return arguments[0] && arguments[1]; } else if (opstring == "⇒") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -907,7 +959,7 @@ namespace storm { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return (!arguments[0]) || arguments[1]; } else if (opstring == "¬") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); if(!arguments[0].isInitialized()) { return storm::expressions::Expression(); @@ -915,7 +967,7 @@ namespace storm { ensureBooleanType(arguments[0], opstring, 0, scopeDescription); return !arguments[0]; } else if (opstring == "=") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); @@ -925,7 +977,7 @@ namespace storm { return arguments[0] == arguments[1]; } } else if (opstring == "≠") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); @@ -935,7 +987,7 @@ namespace storm { return arguments[0] != arguments[1]; } } else if (opstring == "<") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -944,7 +996,7 @@ namespace storm { ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] < arguments[1]; } else if (opstring == "≤") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -953,7 +1005,7 @@ namespace storm { ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] <= arguments[1]; } else if (opstring == ">") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -962,7 +1014,7 @@ namespace storm { ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] > arguments[1]; } else if (opstring == "≥") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); @@ -971,97 +1023,137 @@ namespace storm { ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] >= arguments[1]; } else if (opstring == "+") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] + arguments[1]; } else if (opstring == "-") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] - arguments[1]; } else if (opstring == "-") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription,globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription,globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return -arguments[0]; } else if (opstring == "*") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] * arguments[1]; } else if (opstring == "/") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] / arguments[1]; } else if (opstring == "%") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0] % arguments[1]; } else if (opstring == "max") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::maximum(arguments[0],arguments[1]); } else if (opstring == "min") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::minimum(arguments[0],arguments[1]); } else if (opstring == "floor") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::floor(arguments[0]); } else if (opstring == "ceil") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::ceil(arguments[0]); } else if (opstring == "abs") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::abs(arguments[0]); } else if (opstring == "sgn") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::sign(arguments[0]); } else if (opstring == "trc") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); return storm::expressions::truncate(arguments[0]); } else if (opstring == "pow") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); return arguments[0]^arguments[1]; } else if (opstring == "exp") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "exp operation is not yet implemented"); } else if (opstring == "log") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); ensureNumericalType(arguments[0], opstring, 0, scopeDescription); ensureNumericalType(arguments[1], opstring, 1, scopeDescription); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "log operation is not yet implemented"); + } else if (opstring == "aa") { + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scopeDescription + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + STORM_LOG_THROW(expressionStructure.count("index") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one index (at " + scopeDescription + ")."); + storm::expressions::Expression index = parseExpression(expressionStructure.at("index"), "index in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureArrayType(exp, opstring, 0, scopeDescription); + ensureIntegerType(index, opstring, 1, scopeDescription); + return std::make_shared(exp.getManager(), exp.getType().getElementType(), exp.getBaseExpressionPointer(), index.getBaseExpressionPointer())->toExpression(); + } else if (opstring == "av") { + STORM_LOG_THROW(expressionStructure.count("elements") == 1, storm::exceptions::InvalidJaniException, "Array value operator requires exactly one 'elements' (at " + scopeDescription + ")."); + std::vector> elements; + storm::expressions::Type commonType; + bool first = true; + for (auto const& element : expressionStructure.at("elements")) { + elements.push_back(parseExpression(element, "element " + std::to_string(elements.size()) + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); + if (first) { + commonType = elements.back()->getType(); + first = false; + } else if (!(commonType == elements.back()->getType())) { + if (commonType.isIntegerType() && elements.back()->getType().isRationalType()) { + commonType = elements.back()->getType(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Incompatible element types " << commonType << " and " << elements.back()->getType() << " of array value expression at " << scopeDescription); + } + } + } + return std::make_shared(*expressionManager, expressionManager->getArrayType(commonType), elements)->toExpression(); + } else if (opstring == "ac") { + STORM_LOG_THROW(expressionStructure.count("length") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one length (at " + scopeDescription + ")."); + storm::expressions::Expression length = parseExpression(expressionStructure.at("length"), "index in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureIntegerType(length, opstring, 1, scopeDescription); + STORM_LOG_THROW(expressionStructure.count("var") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one var (at " + scopeDescription + ")."); + std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scopeDescription + ")."); + STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scopeDescription + ")."); + auto newAuxVars = auxiliaryVariables; + storm::expressions::Variable indexVar = expressionManager->declareIntegerVariable(indexVarName); + newAuxVars.emplace(indexVarName, indexVar); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scopeDescription + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); + return std::make_shared(*expressionManager, expressionManager->getArrayType(exp.getType()), length.getBaseExpressionPointer(), indexVar, exp.getBaseExpressionPointer())->toExpression(); } else if (unsupportedOpstrings.count(opstring) > 0){ STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm"); @@ -1080,8 +1172,6 @@ namespace storm { } - - void JaniParser::parseActions(json const& actionStructure, storm::jani::Model& parentModel) { std::set actionNames; for(auto const& actionEntry : actionStructure) { @@ -1125,10 +1215,10 @@ namespace storm { for(auto const& transientValueEntry : locEntry.at("transient-values")) { STORM_LOG_THROW(transientValueEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one ref that is assigned to"); STORM_LOG_THROW(transientValueEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one assigned value"); - storm::jani::Variable const& lhs = getLValue(transientValueEntry.at("ref"), parentModel.getGlobalVariables(), automaton.getVariables(), "LHS of assignment in location " + locName + " (automaton '" + name + "')"); - STORM_LOG_THROW(lhs.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')"); - storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')", globalVars, constants, localVars); - transientAssignments.emplace_back(lhs, rhs); + storm::jani::LValue lValue = parseLValue(transientValueEntry.at("ref"), "LHS of assignment in location " + locName + " (automaton '" + name + "')", globalVars, constants, localVars); + STORM_LOG_THROW(lValue.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " << lValue << " in location " + locName + " (automaton: '" + name + "')"); + storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of lValue in location " + locName + " (automaton: '" + name + "')", globalVars, constants, localVars); + transientAssignments.emplace_back(lValue, rhs); } } uint64_t id = automaton.addLocation(storm::jani::Location(locName, transientAssignments)); @@ -1210,7 +1300,7 @@ namespace storm { // ref STORM_LOG_THROW(assignmentEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one ref field"); std::string refstring = getString(assignmentEntry.at("ref"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); - storm::jani::Variable const& lhs = getLValue(refstring, parentModel.getGlobalVariables(), automaton.getVariables(), "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); + storm::jani::LValue lValue = parseLValue(refstring, "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); // value STORM_LOG_THROW(assignmentEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one value field"); storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); @@ -1220,7 +1310,7 @@ namespace storm { if(assignmentEntry.count("index") > 0) { assignmentIndex = getUnsignedInt(assignmentEntry.at("index"), "assignment index in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); } - assignments.emplace_back(lhs, assignmentExpr, assignmentIndex); + assignments.emplace_back(lValue, assignmentExpr, assignmentIndex); } } destinationLocationsAndProbabilities.emplace_back(locIds.at(targetLoc), probExpr); diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index d14b20259..ed5d9fe32 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -1,5 +1,6 @@ #pragma once #include "storm/storage/jani/Constant.h" +#include "storm/storage/jani/LValue.h" #include "storm/logic/Formula.h" #include "storm/logic/Bound.h" #include "storm/logic/RewardAccumulation.h" @@ -51,14 +52,14 @@ namespace storm { storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants); struct ParsedType { enum class BasicType {Bool, Int, Real}; - boost::optional basicType; boost::optional> bounds; - boost::optional arrayBase; + std::unique_ptr arrayBase; }; - void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars); + void parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars); + storm::jani::LValue parseLValue(json const& lValueStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}); std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool prefWithScope = false); - storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false); + storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); private: std::shared_ptr parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription = "global"); @@ -68,8 +69,8 @@ namespace storm { */ void parseActions(json const& actionStructure, storm::jani::Model& parentModel); std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound = boost::none); - std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars= {}, bool returnNoneOnUnknownOpString = false); - std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false); + std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars= {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); @@ -79,7 +80,7 @@ namespace storm { std::shared_ptr parseComposition(json const& compositionStructure); - storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}); + storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, std::unordered_map const& auxiliaryVariables = {}); diff --git a/src/storm/storage/expressions/Expression.cpp b/src/storm/storage/expressions/Expression.cpp index 1d31f4c6f..957acf978 100644 --- a/src/storm/storage/expressions/Expression.cpp +++ b/src/storm/storage/expressions/Expression.cpp @@ -451,8 +451,5 @@ namespace storm { return result; } - - - } } diff --git a/src/storm/storage/expressions/SubstitutionVisitor.h b/src/storm/storage/expressions/SubstitutionVisitor.h index c0885c0fe..99f0c2c18 100644 --- a/src/storm/storage/expressions/SubstitutionVisitor.h +++ b/src/storm/storage/expressions/SubstitutionVisitor.h @@ -39,7 +39,7 @@ namespace storm { virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; - private: + protected: // A mapping of variables to expressions with which they shall be replaced. MapType const& variableToExpressionMapping; }; diff --git a/src/storm/storage/jani/ArrayVariable.cpp b/src/storm/storage/jani/ArrayVariable.cpp index 95e146d91..9ae41fff7 100644 --- a/src/storm/storage/jani/ArrayVariable.cpp +++ b/src/storm/storage/jani/ArrayVariable.cpp @@ -3,11 +3,11 @@ namespace storm { namespace jani { - ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable) : Variable(name, variable) { + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType) : Variable(name, variable), elementType(elementType) { // Intentionally left empty. } - ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, storm::expressions::Expression const& initValue) : Variable(name, variable, initValue, transient) { + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType, storm::expressions::Expression const& initValue, bool transient) : Variable(name, variable, initValue, transient), elementType(elementType) { // Intentionally left empty. } @@ -35,7 +35,7 @@ namespace storm { return maxSize.get(); } - ElementType ArrayVariable::getElementType() const { + typename ArrayVariable::ElementType ArrayVariable::getElementType() const { return elementType; } diff --git a/src/storm/storage/jani/ArrayVariable.h b/src/storm/storage/jani/ArrayVariable.h index f8aca2397..4c68b1ca9 100644 --- a/src/storm/storage/jani/ArrayVariable.h +++ b/src/storm/storage/jani/ArrayVariable.h @@ -13,12 +13,12 @@ namespace storm { /*! * Creates an Array variable */ - ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType elementType); + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType); /*! * Creates an Array variable with initial value */ - ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType elementType, storm::expressions::Expression const& initialValue, bool transient); + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType, storm::expressions::Expression const& initValue, bool transient); /*! * Sets/Gets bounds to the values stored in this array diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 747679385..6830abb6f 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -1,5 +1,7 @@ #include "storm/storage/jani/Assignment.h" +#include "storm/storage/jani/LValue.h" + #include "storm/storage/expressions/LinearityCheckVisitor.h" #include "storm/utility/macros.h" @@ -8,20 +10,32 @@ namespace storm { namespace jani { - Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) { - + Assignment::Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, uint64_t level) : lValue(lValue), expression(expression), level(level) { + // Intentionally left empty } bool Assignment::operator==(Assignment const& other) const { return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()) && this->getLevel() == other.getLevel(); } + bool Assignment::lValueIsVariable() const { + return lValue.isVariable(); + } + + bool Assignment::lValueIsArrayAccess() const { + return lValue.isArrayAccess(); + } + + storm::jani::LValue const& Assignment::getLValue() const { + return lValue; + } + storm::jani::Variable const& Assignment::getVariable() const { - return variable.get(); + return lValue.getVariable(); } storm::expressions::Variable const& Assignment::getExpressionVariable() const { - return variable.get().getExpressionVariable(); + return getVariable().getExpressionVariable(); } storm::expressions::Expression const& Assignment::getAssignedExpression() const { @@ -33,11 +47,14 @@ namespace storm { } bool Assignment::isTransient() const { - return this->variable.get().isTransient(); + return lValue.isTransient(); } void Assignment::substitute(std::map const& substitution) { this->setAssignedExpression(this->getAssignedExpression().substitute(substitution).simplify()); + if (lValue.isArrayAccess()) { + lValue = LValue(LValue(lValue.getArray()), lValue.getArrayIndex().substitute(substitution).simplify()); + } } int64_t Assignment::getLevel() const { @@ -54,24 +71,24 @@ namespace storm { } std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) { - stream << assignment.getVariable().getName() << " := " << assignment.getAssignedExpression(); + stream << assignment.getLValue() << " := " << assignment.getAssignedExpression(); return stream; } - bool AssignmentPartialOrderByLevelAndVariable::operator()(Assignment const& left, Assignment const& right) const { - return left.getLevel() < right.getLevel() || (left.getLevel() == right.getLevel() && left.getExpressionVariable() < right.getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(Assignment const& left, Assignment const& right) const { + return left.getLevel() < right.getLevel() || (left.getLevel() == right.getLevel() && left.getLValue() < right.getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(Assignment const& left, std::shared_ptr const& right) const { - return left.getLevel() < right->getLevel() || (left.getLevel() == right->getLevel() && left.getExpressionVariable() < right->getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(Assignment const& left, std::shared_ptr const& right) const { + return left.getLevel() < right->getLevel() || (left.getLevel() == right->getLevel() && left.getLValue() < right->getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(std::shared_ptr const& left, std::shared_ptr const& right) const { - return left->getLevel() < right->getLevel() || (left->getLevel() == right->getLevel() && left->getExpressionVariable() < right->getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(std::shared_ptr const& left, std::shared_ptr const& right) const { + return left->getLevel() < right->getLevel() || (left->getLevel() == right->getLevel() && left->getLValue() < right->getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(std::shared_ptr const& left, Assignment const& right) const { - return left->getLevel() < right.getLevel() || (left->getLevel() == right.getLevel() && left->getExpressionVariable() < right.getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(std::shared_ptr const& left, Assignment const& right) const { + return left->getLevel() < right.getLevel() || (left->getLevel() == right.getLevel() && left->getLValue() < right.getLValue()); } } } diff --git a/src/storm/storage/jani/Assignment.h b/src/storm/storage/jani/Assignment.h index 3ab3b5581..5179215e7 100644 --- a/src/storm/storage/jani/Assignment.h +++ b/src/storm/storage/jani/Assignment.h @@ -2,7 +2,7 @@ #include -#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/LValue.h" #include "storm/storage/expressions/Expression.h" namespace storm { @@ -11,20 +11,39 @@ namespace storm { class Assignment { public: /*! - * Creates an assignment of the given expression to the given variable. + * Creates an assignment of the given expression to the given LValue. */ - Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0); + Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, uint64_t index = 0); Assignment(Assignment const&) = default; bool operator==(Assignment const& other) const; + /*! - * Retrieves the expression variable that is written in this assignment. + * Returns true if the lValue is a variable + */ + bool lValueIsVariable() const; + + /*! + * Returns true if the lValue is an array access + */ + bool lValueIsArrayAccess() const; + + /*! + * Retrieves the lValue that is written in this assignment. + * @return + */ + storm::jani::LValue const& getLValue() const; + + /*! + * Retrieves the Variable that is written in this assignment. + * This assumes that the lValue is a variable. */ storm::jani::Variable const& getVariable() const; - + /*! * Retrieves the expression variable that is written in this assignment. + * This assumes that the lValue is a variable. */ storm::expressions::Variable const& getExpressionVariable() const; @@ -34,7 +53,7 @@ namespace storm { storm::expressions::Expression const& getAssignedExpression() const; /*! - * Sets a new expression that is assigned to the target variable. + * Sets a new expression that is assigned to the target LValue. */ void setAssignedExpression(storm::expressions::Expression const& expression); @@ -66,10 +85,10 @@ namespace storm { friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment); private: - // The variable being assigned. - std::reference_wrapper variable; + // The lValue being assigned. + LValue lValue; - // The expression that is being assigned to the variable. + // The expression that is being assigned to the lValue. storm::expressions::Expression expression; // The level of the assignment. @@ -77,10 +96,10 @@ namespace storm { }; /*! - * This functor enables ordering the assignments first by the assignment level and then by variable. + * This functor enables ordering the assignments first by the assignment level and then by lValue. * Note that this is a partial order. */ - struct AssignmentPartialOrderByLevelAndVariable { + struct AssignmentPartialOrderByLevelAndLValue { bool operator()(Assignment const& left, Assignment const& right) const; bool operator()(Assignment const& left, std::shared_ptr const& right) const; bool operator()(std::shared_ptr const& left, std::shared_ptr const& right) const; diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp new file mode 100644 index 000000000..f8ba7eef4 --- /dev/null +++ b/src/storm/storage/jani/LValue.cpp @@ -0,0 +1,96 @@ +#include "storm/storage/jani/LValue.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace jani { + + LValue::LValue(storm::jani::Variable const& variable) : variable(&variable) { + // Intentionally left empty + } + + LValue::LValue(LValue const& array, storm::expressions::Expression const& index) : arrayIndex(index) { + STORM_LOG_THROW(array.isVariable(), storm::exceptions::NotSupportedException, "Nested arrays as LValues are currently not implemented."); + variable = &array.getVariable(); + } + + bool LValue::isVariable() const { + return !arrayIndex.isInitialized(); + } + + storm::jani::Variable const& LValue::getVariable() const { + STORM_LOG_ASSERT(isVariable(), "Tried to get the variable of an LValue, that actually is not a variable."); + return *variable; + } + + bool LValue::isArrayAccess() const { + return arrayIndex.isInitialized(); + } + + storm::jani::ArrayVariable const& LValue::getArray() const { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array variable of an LValue that is not an array access."); + STORM_LOG_ASSERT(variable->isArrayVariable(), "Tried to get the array variable of an array access LValue, but the variable is not of type array."); + return variable->asArrayVariable(); + } + + storm::expressions::Expression const& LValue::getArrayIndex() const { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array index of an LValue, that is not an array access."); + return arrayIndex; + } + + bool LValue::isTransient() const { + return variable->isTransient(); + } + + LValue LValue::changeAssignmentVariables(std::map> const& remapping) const { + if (isVariable()) { + return LValue(remapping.at(variable)); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + return LValue(LValue(remapping.at(variable)), arrayIndex); + } + } + + + bool LValue::operator<(LValue const& other) const { + if (isVariable()) { + return !other.isVariable() || variable->getExpressionVariable() < other.getVariable().getExpressionVariable(); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + if (other.isVariable()) { + return false; + } + STORM_LOG_ASSERT(other.isArrayAccess(), "Unhandled LValue."); + if (variable->getExpressionVariable() < other.getVariable().getExpressionVariable()) { + return true; + } else if (other.getVariable().getExpressionVariable() < variable->getExpressionVariable()) { + return false; + } else { + return std::less()(arrayIndex, other.getArrayIndex()); + } + } + } + + bool LValue::operator==(LValue const& other) const { + if (isVariable()) { + return other.isVariable() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable(); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + return other.isArrayAccess() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); + } + } + + std::ostream& operator<<(std::ostream& stream, LValue const& lValue) { + if (lValue.isVariable()) { + stream << lValue.getVariable().getName(); + } else { + STORM_LOG_ASSERT(lValue.isArrayAccess(), "Unhandled LValue."); + stream << lValue.getArray().getName() << "[" << lValue.getArrayIndex() << "]"; + } + return stream; + } + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/LValue.h b/src/storm/storage/jani/LValue.h new file mode 100644 index 000000000..0e8126bcd --- /dev/null +++ b/src/storm/storage/jani/LValue.h @@ -0,0 +1,41 @@ +#pragma once + +#include "storm/storage/jani/ArrayVariable.h" +#include "storm/storage/expressions/Expressions.h" + +namespace storm { + namespace jani { + + class LValue { + public: + explicit LValue(storm::jani::Variable const& variable); + LValue(LValue const& array, storm::expressions::Expression const& index); + + LValue(LValue const&) = default; + bool operator==(LValue const& other) const; + + bool isVariable() const; + storm::jani::Variable const& getVariable() const; + + bool isArrayAccess() const; + storm::jani::ArrayVariable const& getArray() const; + storm::expressions::Expression const& getArrayIndex() const; + + bool isTransient() const; + bool operator< (LValue const& other) const; + + LValue changeAssignmentVariables(std::map> const& remapping) const; + + friend std::ostream& operator<<(std::ostream& stream, LValue const& lvalue); + + private: + + // The variable being assigned. + storm::jani::Variable const* variable; + + + // In case of an array access LValue, this is the accessed index of the array. + storm::expressions::Expression arrayIndex; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 9c622fe2b..bce6a0fc8 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -221,13 +221,13 @@ namespace storm { void OrderedAssignments::changeAssignmentVariables(std::map> const& remapping) { std::vector newAssignments; for (auto& assignment : allAssignments) { - newAssignments.emplace_back(remapping.at(&assignment->getVariable()), assignment->getAssignedExpression(), assignment->getLevel()); + newAssignments.emplace_back(assignment->getLValue().changeAssignmentVariables(remapping), assignment->getAssignedExpression(), assignment->getLevel()); } *this = OrderedAssignments(newAssignments); } std::vector>::const_iterator OrderedAssignments::lowerBound(Assignment const& assignment, std::vector> const& assignments) { - return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndVariable()); + return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndLValue()); } uint64_t OrderedAssignments::isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start) const { diff --git a/src/storm/storage/jani/Variable.h b/src/storm/storage/jani/Variable.h index 8d5884a12..ab4bf80c1 100644 --- a/src/storm/storage/jani/Variable.h +++ b/src/storm/storage/jani/Variable.h @@ -86,8 +86,8 @@ namespace storm { UnboundedIntegerVariable const& asUnboundedIntegerVariable() const; RealVariable& asRealVariable(); RealVariable const& asRealVariable() const; - RealVariable& asArrayVariable(); - RealVariable const& asArrayVariable() const; + ArrayVariable& asArrayVariable(); + ArrayVariable const& asArrayVariable() const; /*! * Substitutes all variables in all expressions according to the given substitution. diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp index d143fc10c..1f3980fc9 100644 --- a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp @@ -1,5 +1,8 @@ #include "storm/storage/jani/expressions/ArrayAccessExpression.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/utility/macros.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace expressions { @@ -11,7 +14,7 @@ namespace storm { } std::shared_ptr ArrayAccessExpression::simplify() const { - return std::shared_ptr(new ArrayAccessExpression(manager, type, getFirstOperand()->simplify(), getSecondOperand()->simplify())); + return std::shared_ptr(new ArrayAccessExpression(getManager(), getType(), getFirstOperand()->simplify(), getSecondOperand()->simplify())); } boost::any ArrayAccessExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { @@ -21,16 +24,12 @@ namespace storm { } void ArrayAccessExpression::printToStream(std::ostream& stream) const { - if (firstOperand->isVariable()) { - getFirstOperand()->printToStream(stream); + if (getFirstOperand()->isVariable()) { + stream << *getFirstOperand(); } else { - stream << "("; - getFirstOperand()->printToStream(stream); - stream << ")"; + stream << "(" << *getFirstOperand() << ")"; } - stream << "["; - getSecondOperand()->printToStream(stream); - stream << "]"; + stream << "[" << getSecondOperand() << "]"; } } } \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.h b/src/storm/storage/jani/expressions/ArrayAccessExpression.h index 0068b1b47..a545e123e 100644 --- a/src/storm/storage/jani/expressions/ArrayAccessExpression.h +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.h @@ -1,7 +1,6 @@ #pragma once -#include "storm/storage/expressions/BaseExpression.h" -#include "storm/storage/jani/expressions/ExpressionManager.h" +#include "storm/storage/expressions/BinaryExpression.h" namespace storm { namespace expressions { diff --git a/src/storm/storage/jani/expressions/ArrayExpression.h b/src/storm/storage/jani/expressions/ArrayExpression.h index 63b1bae8e..3dbcf480d 100644 --- a/src/storm/storage/jani/expressions/ArrayExpression.h +++ b/src/storm/storage/jani/expressions/ArrayExpression.h @@ -1,7 +1,6 @@ #pragma once #include "storm/storage/expressions/BaseExpression.h" -#include "storm/storage/jani/expressions/ExpressionManager.h" namespace storm { namespace expressions { diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp index d643c527e..2eb778800 100644 --- a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/expressions/ConstructorArrayExpression.h" #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/UnexpectedException.h" @@ -8,14 +9,14 @@ namespace storm { namespace expressions { - ConstructorArrayExpression::ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression) : ArrayExpression(manager, type), size(size), indexVar(indexVar), elementExpression(elementExpression) { + ConstructorArrayExpression::ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression) : ArrayExpression(manager, type), sizeExpression(size), indexVar(indexVar), elementExpression(elementExpression) { // Intentionally left empty } void ConstructorArrayExpression::gatherVariables(std::set& variables) const { // The indexVar should not be gathered (unless it is already contained). bool indexVarContained = variables.find(indexVar) != variables.end(); - size->gatherVariables(variables); + sizeExpression->gatherVariables(variables); elementExpression->gatherVariables(variables); if (!indexVarContained) { variables.erase(indexVar); @@ -23,7 +24,7 @@ namespace storm { } bool ConstructorArrayExpression::containsVariables() const { - if (size->containsVariables()) { + if (sizeExpression->containsVariables()) { return true; } // The index variable should not count @@ -34,7 +35,7 @@ namespace storm { } std::shared_ptr ConstructorArrayExpression::simplify() const { - return std::shared_ptr(new ConstructorArrayExpression(manager, type, size->simplify(), indexVar, elementExpression->simplify())); + return std::shared_ptr(new ConstructorArrayExpression(getManager(), getType(), sizeExpression->simplify(), indexVar, elementExpression->simplify())); } boost::any ConstructorArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { @@ -44,20 +45,17 @@ namespace storm { } void ConstructorArrayExpression::printToStream(std::ostream& stream) const { - stream << "array[ "; - elementExpression->printToStream(stream); - stream << " | " << indexVar << "<"; - size->printToStream(stream); - stream << " ]"; + stream << "array[ " << *elementExpression << " | " << indexVar.getExpression() << " < " << *sizeExpression << " ]"; } std::shared_ptr ConstructorArrayExpression::size() const { - return size; + return sizeExpression; } std::shared_ptr ConstructorArrayExpression::at(uint64_t i) const { - STORM_LOG_THROW(i < elements.size(), storm::exceptions::InvalidArgumentException, "Tried to access the element with index " << i << " of an array of size " << elements.size() << "."); - return elements[i]; + std::map substitution; + substitution.emplace(indexVar, this->getManager().integer(i)); + return elementExpression->toExpression().substitute(substitution).getBaseExpressionPointer(); } std::shared_ptr const& ConstructorArrayExpression::getElementExpression() const { diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h index 07d52b570..7c5d93c9e 100644 --- a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h @@ -1,6 +1,7 @@ #pragma once #include "storm/storage/jani/expressions/ArrayExpression.h" +#include "storm/storage/expressions/Variable.h" namespace storm { namespace expressions { @@ -22,7 +23,7 @@ namespace storm { virtual ~ConstructorArrayExpression() = default; virtual void gatherVariables(std::set& variables) const override; - virtual bool containsVariables() const; + virtual bool containsVariables() const override; virtual std::shared_ptr simplify() const override; virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; @@ -38,7 +39,7 @@ namespace storm { virtual void printToStream(std::ostream& stream) const override; private: - std::shared_ptr size; + std::shared_ptr sizeExpression; storm::expressions::Variable indexVar; std::shared_ptr const& elementExpression; }; diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp index 0a449d3d5..101f53472 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -6,7 +6,7 @@ namespace storm { namespace expressions { template boost::any JaniExpressionSubstitutionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { - uint64_t size = expression.getSize()->evaluateAsInt(); + uint64_t size = expression.size()->evaluateAsInt(); std::vector> newElements; newElements.reserve(size); for (uint64_t i = 0; i < size; ++i) { @@ -17,12 +17,12 @@ namespace storm { template boost::any JaniExpressionSubstitutionVisitor::visit(ConstructorArrayExpression const& expression, boost::any const& data) { - std::shared_ptr newSize = boost::any_cast>(expression.getSize()->accept(*this, data)); + std::shared_ptr newSize = boost::any_cast>(expression.size()->accept(*this, data)); std::shared_ptr elementExpression = boost::any_cast>(expression.getElementExpression()->accept(*this, data)); STORM_LOG_THROW(this->variableToExpressionMapping.find(expression.getIndexVar()) == this->variableToExpressionMapping.end(), storm::exceptions::InvalidArgumentException, "substitution of the index variable of a constructorArrayExpression is not possible."); // If the arguments did not change, we simply push the expression itself. - if (newSize.get() == expression.getSize().get() && elementExpression.get() == expression.getElementExpression().get()) { + if (newSize.get() == expression.size().get() && elementExpression.get() == expression.getElementExpression().get()) { return expression.getSharedPointer(); } else { return std::const_pointer_cast(std::shared_ptr(new ConstructorArrayExpression(expression.getManager(), expression.getType(), newSize, expression.getIndexVar(), elementExpression))); diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h index 131c2f8ac..ca82d7df1 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h @@ -2,12 +2,12 @@ #include "storm/storage/expressions/SubstitutionVisitor.h" #include "storm/storage/jani/expressions/JaniExpressions.h" - +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" namespace storm { namespace expressions { template - class JaniExpressionSubstitutionVisitor : public SubstitutionVisitor, public ExpressionManager { + class JaniExpressionSubstitutionVisitor : public SubstitutionVisitor, public JaniExpressionVisitor { public: /*! * Creates a new substitution visitor that uses the given map to replace variables. @@ -21,6 +21,4 @@ namespace storm { virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override; }; } -} - -#endif /* STORM_STORAGE_EXPRESSIONS_SUBSTITUTIONVISITOR_H_ */ +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h index d9c86e9af..e0e76e95e 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h @@ -6,7 +6,6 @@ namespace storm { namespace expressions { - template class JaniExpressionVisitor{ public: virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) = 0; @@ -15,5 +14,3 @@ namespace storm { }; } } - -#endif /* STORM_STORAGE_EXPRESSIONS_SUBSTITUTIONVISITOR_H_ */ diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.cpp b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp index feaf5a395..23c543c80 100644 --- a/src/storm/storage/jani/expressions/ValueArrayExpression.cpp +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/expressions/ValueArrayExpression.h" #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/UnexpectedException.h" @@ -33,7 +34,7 @@ namespace storm { for (auto const& e : elements) { simplifiedElements.push_back(e->simplify()); } - return std::shared_ptr(new ValueArrayExpression(manager, type, simplifiedElements)); + return std::shared_ptr(new ValueArrayExpression(getManager(), getType(), simplifiedElements)); } boost::any ValueArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { @@ -46,7 +47,7 @@ namespace storm { stream << "array[ "; bool first = true; for (auto const& e : elements) { - e->printToStream(stream); + stream << *e; if (!first) { stream << " , "; } @@ -56,7 +57,7 @@ namespace storm { } std::shared_ptr ValueArrayExpression::size() const { - return this->manager.integer(elements.size()).getBaseExpressionPointer(); + return getManager().integer(elements.size()).getBaseExpressionPointer(); } std::shared_ptr ValueArrayExpression::at(uint64_t i) const { diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.h b/src/storm/storage/jani/expressions/ValueArrayExpression.h index 641330387..770b36db7 100644 --- a/src/storm/storage/jani/expressions/ValueArrayExpression.h +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.h @@ -10,7 +10,7 @@ namespace storm { class ValueArrayExpression : public ArrayExpression { public: - ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> elements); + ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> const& elements); // Instantiate constructors and assignments with their default implementations. @@ -22,7 +22,7 @@ namespace storm { virtual ~ValueArrayExpression() = default; virtual void gatherVariables(std::set& variables) const override; - virtual bool containsVariables() const; + virtual bool containsVariables() const override; virtual std::shared_ptr simplify() const override; virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.h b/src/storm/storage/jani/traverser/ArrayEliminator.h new file mode 100644 index 000000000..fcff57b45 --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayEliminator.h @@ -0,0 +1,56 @@ +#pragma once + + +#include + +#include "storm/storage/jani/traverser/JaniTraverser.h" + +namespace storm { + namespace jani { + class ArrayEliminator { +/* + public: + void eliminate(Model& model); + + private: + + class ArrayVariableReplacer : public JaniTraverser { + public: + + ArrayVariableReplacer() = default; + virtual ~ArrayVariableReplacer() = default; + std::unordered_map> replace(); + + virtual void traverse(Assignment const& assignment, boost::any const& data) const override; + + private: + void std::unordered_map::getMaxSizes(Model& model); + + }; + + + + }; + + : public JaniTraverser { + + public: + + struct ResultType { + bool hasLocationAssignment, hasEdgeAssignment, hasEdgeDestinationAssignment; + }; + + AssignmentsFinder() = default; + + ResultType find(Model const& model, Variable const& variable); + + virtual ~AssignmentsFinder() = default; + + virtual void traverse(Location const& location, boost::any const& data) const override; + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const override; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const override; + */ + }; + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp index 2461792b5..eb60a9358 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.cpp +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -129,10 +129,16 @@ namespace storm { traverse(assignment.getAssignedExpression(), data); } + void JaniTraverser::traverse(LValue const& lValue, boost::any const& data) const { + if (lValue.isArrayAccess()) { + traverse(lValue.getArrayIndex(), data); + } + } + void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { // intentionally left empty. } - + } } diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h index 905ad0208..9cef29afc 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.h +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -29,6 +29,7 @@ namespace storm { virtual void traverse(EdgeDestination const& edgeDestination, boost::any const& data) const; virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const; virtual void traverse(Assignment const& assignment, boost::any const& data) const; + virtual void traverse(LValue const& lValue, boost::any const& data) const; virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) const; }; } diff --git a/src/storm/storage/prism/ToJaniConverter.cpp b/src/storm/storage/prism/ToJaniConverter.cpp index 25ecca79a..f8ec3e053 100644 --- a/src/storm/storage/prism/ToJaniConverter.cpp +++ b/src/storm/storage/prism/ToJaniConverter.cpp @@ -118,7 +118,7 @@ namespace storm { } auto newExpressionVariable = manager->declareBooleanVariable(finalLabelName); storm::jani::BooleanVariable const& newTransientVariable = janiModel.addVariable(storm::jani::BooleanVariable(newExpressionVariable.getName(), newExpressionVariable, manager->boolean(false), true)); - transientLocationAssignments.emplace_back(newTransientVariable, label.getStatePredicateExpression()); + transientLocationAssignments.emplace_back(storm::jani::LValue(newTransientVariable), label.getStatePredicateExpression()); // Variables that are accessed in the label predicate expression should be made global. std::set variables = label.getStatePredicateExpression().getVariables(); @@ -156,7 +156,7 @@ namespace storm { transientLocationExpression = rewardTerm; } } - transientLocationAssignments.emplace_back(newTransientVariable, transientLocationExpression); + transientLocationAssignments.emplace_back(storm::jani::LValue(newTransientVariable), transientLocationExpression); // Variables that are accessed in a reward term should be made global. std::set variables = transientLocationExpression.getVariables(); for (auto const& variable : variables) { @@ -178,9 +178,9 @@ namespace storm { for (auto const& entry : actionIndexToExpression) { auto it = transientEdgeAssignments.find(entry.first); if (it != transientEdgeAssignments.end()) { - it->second.push_back(storm::jani::Assignment(newTransientVariable, entry.second)); + it->second.push_back(storm::jani::Assignment(storm::jani::LValue(newTransientVariable), entry.second)); } else { - std::vector assignments = {storm::jani::Assignment(newTransientVariable, entry.second)}; + std::vector assignments = {storm::jani::Assignment(storm::jani::LValue(newTransientVariable), entry.second)}; transientEdgeAssignments.emplace(entry.first, assignments); } // Variables that are accessed in a reward term should be made global. @@ -275,7 +275,7 @@ namespace storm { for (auto const& update : command.getUpdates()) { std::vector assignments; for (auto const& assignment : update.getAssignments()) { - assignments.push_back(storm::jani::Assignment(variableToVariableMap.at(assignment.getVariable()).get(), assignment.getExpression())); + assignments.push_back(storm::jani::Assignment(storm::jani::LValue(variableToVariableMap.at(assignment.getVariable()).get()), assignment.getExpression())); } if (rateExpression) { From 234671fdcaccfe3ae3e3a3bc7bfe69668a396468 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 31 Aug 2018 19:09:38 +0200 Subject: [PATCH 522/647] fixes to include paths --- src/storm/abstraction/AbstractionInformation.cpp | 2 +- src/storm/abstraction/MenuGameRefiner.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 4b61ed4d8..7e3215b3b 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -9,7 +9,7 @@ #include "storm/settings/modules/AbstractionSettings.h" #include "storm/settings/SettingsManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidOperationException.h" diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 987aaa367..292257965 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -14,7 +14,7 @@ #include "storm/utility/solver.h" #include "storm/utility/shortestPaths.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/solver/MathsatSmtSolver.h" From 5e0115161718c7e3ecc1ddd60de43b7165a9affe Mon Sep 17 00:00:00 2001 From: TimQu Date: Sun, 2 Sep 2018 12:09:51 +0200 Subject: [PATCH 523/647] jani-array fixes --- src/storm-parsers/parser/JaniParser.cpp | 5 +- src/storm/storage/jani/Assignment.cpp | 2 +- src/storm/storage/jani/Automaton.cpp | 6 ++ src/storm/storage/jani/Automaton.h | 5 + src/storm/storage/jani/LValue.cpp | 4 +- src/storm/storage/jani/Model.cpp | 10 ++ src/storm/storage/jani/Model.h | 5 + src/storm/storage/jani/OrderedAssignments.cpp | 26 +++-- src/storm/storage/jani/OrderedAssignments.h | 4 +- src/storm/storage/jani/TemplateEdge.cpp | 6 +- src/storm/storage/jani/VariableSet.cpp | 45 +++++++- src/storm/storage/jani/VariableSet.h | 24 +++++ .../jani/traverser/ArrayEliminator.cpp | 100 ++++++++++++++++++ .../storage/jani/traverser/ArrayEliminator.h | 38 +------ 14 files changed, 222 insertions(+), 58 deletions(-) create mode 100644 src/storm/storage/jani/traverser/ArrayEliminator.cpp diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 97e7a80ad..ddd518fb9 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include "storm/storage/jani/ArrayVariable.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -1299,8 +1299,7 @@ namespace storm { for (auto const& assignmentEntry : destEntry.at("assignments")) { // ref STORM_LOG_THROW(assignmentEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one ref field"); - std::string refstring = getString(assignmentEntry.at("ref"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); - storm::jani::LValue lValue = parseLValue(refstring, "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + storm::jani::LValue lValue = parseLValue(assignmentEntry.at("ref"), "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); // value STORM_LOG_THROW(assignmentEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one value field"); storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 6830abb6f..003e48762 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -15,7 +15,7 @@ namespace storm { } bool Assignment::operator==(Assignment const& other) const { - return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()) && this->getLevel() == other.getLevel(); + return this->isTransient() == other.isTransient() && this->getLValue() == other.getLValue() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()) && this->getLevel() == other.getLevel(); } bool Assignment::lValueIsVariable() const { diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 62d2576cf..58404e9a7 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -33,6 +33,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } @@ -53,6 +55,10 @@ namespace storm { RealVariable const& Automaton::addVariable(RealVariable const& variable) { return variables.addVariable(variable); } + + ArrayVariable const& Automaton::addVariable(ArrayVariable const& variable) { + return variables.addVariable(variable); + } bool Automaton::hasVariable(std::string const& name) const { return variables.hasVariable(name); diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index 869f5cd09..6e51d6440 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -70,6 +70,11 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given array variable to this automaton. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! * Retrieves the variables of this automaton. */ diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp index f8ba7eef4..27788db78 100644 --- a/src/storm/storage/jani/LValue.cpp +++ b/src/storm/storage/jani/LValue.cpp @@ -62,9 +62,9 @@ namespace storm { return false; } STORM_LOG_ASSERT(other.isArrayAccess(), "Unhandled LValue."); - if (variable->getExpressionVariable() < other.getVariable().getExpressionVariable()) { + if (getArray().getExpressionVariable() < other.getArray().getExpressionVariable()) { return true; - } else if (other.getVariable().getExpressionVariable() < variable->getExpressionVariable()) { + } else if (other.getArray().getExpressionVariable() < getArray().getExpressionVariable()) { return false; } else { return std::less()(arrayIndex, other.getArrayIndex()); diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index bd6e59c0c..d484b6cb7 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -634,6 +634,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } @@ -654,6 +656,10 @@ namespace storm { RealVariable const& Model::addVariable(RealVariable const& variable) { return globalVariables.addVariable(variable); } + + ArrayVariable const& Model::addVariable(ArrayVariable const& variable) { + return globalVariables.addVariable(variable); + } VariableSet& Model::getGlobalVariables() { return globalVariables; @@ -899,6 +905,9 @@ namespace storm { for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { variable.substitute(constantSubstitution); } + for (auto& variable : result.getGlobalVariables().getArrayVariables()) { + variable.substitute(constantSubstitution); + } // Substitute constants in initial states expression. result.setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(constantSubstitution)); @@ -993,6 +1002,7 @@ namespace storm { for (auto const& variable : this->getGlobalVariables().getBoundedIntegerVariables()) { result.push_back(variable.getRangeExpression()); } + STORM_LOG_ASSERT(this->getGlobalVariables().getArrayVariables().empty(), "This operation is unsupported if array variables are present."); if (automata.empty()) { for (auto const& automaton : this->getAutomata()) { diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 2bcf13504..4235b904b 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -190,6 +190,11 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given array variable to this model. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! * Retrieves the variables of this automaton. */ diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index bce6a0fc8..27ccd2761 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -35,8 +35,8 @@ namespace storm { auto it = lowerBound(assignment, allAssignments); // Check if an assignment to this variable is already present - if (it != allAssignments.end() && assignment.getExpressionVariable() == (*it)->getExpressionVariable()) { - STORM_LOG_THROW(addToExisting && assignment.getExpressionVariable().hasNumericalType(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); + if (it != allAssignments.end() && assignment.getLValue() == (*it)->getLValue()) { + STORM_LOG_THROW(addToExisting && assignment.getLValue().isVariable() && assignment.getExpressionVariable().hasNumericalType(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to LValue '" << (*it)->getLValue() << "' already exists."); (*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression()); } else { // Finally, insert the new element in the correct vectors. @@ -125,18 +125,19 @@ namespace storm { if (first) { std::vector newAssignments; for (uint64_t i = 0; i < allAssignments.size(); ++i) { - if (synchronous && !localVars.hasVariable(allAssignments.at(i)->getVariable())) { + auto const& iLValue = allAssignments.at(i)->getLValue(); + if (synchronous && !localVars.hasVariable(iLValue.isVariable() ? iLValue.getVariable() : iLValue.getArray())) { newAssignments.push_back(*(allAssignments.at(i))); continue; } bool readBeforeWrite = true; for (uint64_t j = i + 1; j < allAssignments.size(); ++j) { if (allAssignments.at(j)->getAssignedExpression().containsVariable( - {allAssignments.at(i)->getVariable().getExpressionVariable()})) { + {iLValue.isVariable() ? iLValue.getVariable().getExpressionVariable() : iLValue.getArray().getExpressionVariable()})) { // is read. break; } - if (allAssignments.at(j)->getVariable() == allAssignments.at(i)->getVariable()) { + if (iLValue == allAssignments.at(j)->getLValue()) { // is written, has not been read before readBeforeWrite = false; break; @@ -158,15 +159,15 @@ namespace storm { std::vector newAssignments; for (auto const& assignment : allAssignments) { newAssignments.push_back(*assignment); - if (synchronous && !localVars.hasVariable(assignment->getVariable())) { + if (synchronous && !localVars.hasVariable(assignment->getLValue().isVariable() ? assignment->getLValue().getVariable() : assignment->getLValue().getArray())) { continue; } if (assignment->getLevel() == 0) { continue; } uint64_t assNr = upperBound(assignment->getLevel() - 1); - if (assNr == isWrittenBeforeAssignment(assignment->getVariable(), assNr)) { - if (assNr == isReadBeforeAssignment(assignment->getVariable(), assNr)) { + if (assNr == isWrittenBeforeAssignment(assignment->getLValue(), assNr)) { + if (assNr == isReadBeforeAssignment(assignment->getLValue(), assNr)) { newAssignments.back().setLevel(0); changed = true; } @@ -230,7 +231,10 @@ namespace storm { return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndLValue()); } - uint64_t OrderedAssignments::isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start) const { + uint64_t OrderedAssignments::isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const { + Variable const& var = lValue.isVariable() ? lValue.getVariable() : lValue.getArray(); + // TODO: do this more carefully + STORM_LOG_WARN_COND(lValue.isVariable(), "Called a method that is not optimized for arrays."); for (uint64_t i = start; i < assignmentNumber; i++) { if (allAssignments.at(i)->getAssignedExpression().containsVariable({ var.getExpressionVariable() })) { return i; @@ -239,9 +243,9 @@ namespace storm { return assignmentNumber; } - uint64_t OrderedAssignments::isWrittenBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start) const { + uint64_t OrderedAssignments::isWrittenBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const { for (uint64_t i = start; i < assignmentNumber; i++) { - if (allAssignments.at(i)->getVariable() == var) { + if (allAssignments.at(i)->getLValue() == lValue) { return i; } } diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 45e769920..aa81f59a3 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -146,8 +146,8 @@ namespace storm { OrderedAssignments clone() const; private: - uint64_t isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; - uint64_t isWrittenBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; + uint64_t isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start = 0) const; + uint64_t isWrittenBeforeAssignment(LValue const& LValue, uint64_t assignmentNumber, uint64_t start = 0) const; /*! * Gets the number of assignments number with an assignment not higher than index. diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 6e5af6695..460e6add3 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/LValue.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -27,8 +28,9 @@ namespace storm { void TemplateEdge::finalize(Model const& containingModel) { for (auto const& destination : getDestinations()) { for (auto const& assignment : destination.getOrderedAssignments().getAllAssignments()) { - if (containingModel.getGlobalVariables().hasVariable(assignment.getExpressionVariable())) { - writtenGlobalVariables.insert(assignment.getExpressionVariable()); + Variable const& var = assignment.getLValue().isVariable() ? assignment.getLValue().getVariable() : assignment.getLValue().getArray(); + if (containingModel.getGlobalVariables().hasVariable(var.getExpressionVariable())) { + writtenGlobalVariables.insert(var.getExpressionVariable()); } } } diff --git a/src/storm/storage/jani/VariableSet.cpp b/src/storm/storage/jani/VariableSet.cpp index ac692c637..973630a2c 100644 --- a/src/storm/storage/jani/VariableSet.cpp +++ b/src/storm/storage/jani/VariableSet.cpp @@ -44,6 +44,14 @@ namespace storm { return detail::ConstVariables(realVariables.begin(), realVariables.end()); } + detail::Variables VariableSet::getArrayVariables() { + return detail::Variables(arrayVariables.begin(), arrayVariables.end()); + } + + detail::ConstVariables VariableSet::getArrayVariables() const { + return detail::ConstVariables(arrayVariables.begin(), arrayVariables.end()); + } + Variable const& VariableSet::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); @@ -53,6 +61,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Cannot add variable of unknown type."); } @@ -109,6 +119,19 @@ namespace storm { return *newVariable; } + ArrayVariable const& VariableSet::addVariable(ArrayVariable const& variable) { + STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); + std::shared_ptr newVariable = std::make_shared(variable); + variables.push_back(newVariable); + arrayVariables.push_back(newVariable); + if (variable.isTransient()) { + transientVariables.push_back(newVariable); + } + nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); + variableToVariable.emplace(variable.getExpressionVariable(), newVariable); + return *newVariable; + } + bool VariableSet::hasVariable(std::string const& name) const { return nameToVariable.find(name) != nameToVariable.end(); } @@ -174,6 +197,10 @@ namespace storm { return !realVariables.empty(); } + bool VariableSet::containsArrayVariables() const { + return !arrayVariables.empty(); + } + bool VariableSet::containsNonTransientRealVariables() const { for (auto const& variable : realVariables) { if (!variable->isTransient()) { @@ -193,7 +220,7 @@ namespace storm { } bool VariableSet::empty() const { - return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables()); + return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables() || containsRealVariables() || containsArrayVariables()); } uint_fast64_t VariableSet::getNumberOfTransientVariables() const { @@ -251,6 +278,22 @@ namespace storm { return true; } } + for (auto const& arrayVariable : this->getArrayVariables()) { + if (arrayVariable.hasInitExpression()) { + if (arrayVariable.getInitExpression().containsVariable(variables)) { + return true; + } + } + if (arrayVariable.hasElementTypeBounds()) { + auto const& bounds = arrayVariable.getElementTypeBounds(); + if (bounds.first.containsVariable(variables)) { + return true; + } + if (bounds.second.containsVariable(variables)) { + return true; + } + } + } return false; } diff --git a/src/storm/storage/jani/VariableSet.h b/src/storm/storage/jani/VariableSet.h index 6d101ad7a..9940d37a2 100644 --- a/src/storm/storage/jani/VariableSet.h +++ b/src/storm/storage/jani/VariableSet.h @@ -9,6 +9,7 @@ #include "storm/storage/jani/UnboundedIntegerVariable.h" #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/storage/jani/RealVariable.h" +#include "storm/storage/jani/ArrayVariable.h" namespace storm { namespace jani { @@ -67,6 +68,16 @@ namespace storm { * Retrieves the real variables in this set. */ detail::ConstVariables getRealVariables() const; + + /*! + * Retrieves the Array variables in this set. + */ + detail::Variables getArrayVariables(); + + /*! + * Retrieves the Array variables in this set. + */ + detail::ConstVariables getArrayVariables() const; /*! * Adds the given variable to this set. @@ -93,6 +104,11 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given real variable to this set. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! * Retrieves whether this variable set contains a variable with the given name. */ @@ -162,6 +178,11 @@ namespace storm { */ bool containsRealVariables() const; + /*! + * Retrieves whether the set of variables contains a Array variable. + */ + bool containsArrayVariables() const; + /*! * Retrieves whether the set of variables contains a non-transient real variable. */ @@ -224,6 +245,9 @@ namespace storm { /// The real variables in this set. std::vector> realVariables; + /// The array variables in this set. + std::vector> arrayVariables; + /// The transient variables in this set. std::vector> transientVariables; diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.cpp b/src/storm/storage/jani/traverser/ArrayEliminator.cpp new file mode 100644 index 000000000..2acce661b --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayEliminator.cpp @@ -0,0 +1,100 @@ +#include "storm/storage/jani/traverser/ArrayEliminator.h" + + +#include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +namespace storm { + namespace jani { + namespace detail { +/* + + + class MaxArraySizeVisitor : public ExpressionVisitor, public JaniExpressionVisitor { + virtual MaxArraySizeVisitor() = default; + virtual ~MaxArraySizeVisitor() = default; + + std::size_t getMaxSize(Expression const& expression) { + return boost::any_cast expression.accept(*this); + } + + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override { + + } + + + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override { + + } + + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override { + + } + }; + + class ArrayVariableReplacer : public JaniTraverser { + public: + + ArrayVariableReplacer() = default; + virtual ~ArrayVariableReplacer() = default; + std::unordered_map> replace(); + + virtual void traverse(Assignment const& assignment, boost::any const& data) const override; + + private: + void std::unordered_map::getMaxSizes(Model& model); + + }; + + class ArrayAccessLValueReplacer : public JaniTraverser { + } + */ + } + + ArrayEliminator::eliminate(Model& model) { + //auto variableReplacements ArrayVariableReplacer().replace(model) + + } + } +} + diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.h b/src/storm/storage/jani/traverser/ArrayEliminator.h index fcff57b45..775909e1c 100644 --- a/src/storm/storage/jani/traverser/ArrayEliminator.h +++ b/src/storm/storage/jani/traverser/ArrayEliminator.h @@ -8,48 +8,14 @@ namespace storm { namespace jani { class ArrayEliminator { -/* public: + ArrayEliminator() = default; + void eliminate(Model& model); private: - class ArrayVariableReplacer : public JaniTraverser { - public: - - ArrayVariableReplacer() = default; - virtual ~ArrayVariableReplacer() = default; - std::unordered_map> replace(); - - virtual void traverse(Assignment const& assignment, boost::any const& data) const override; - - private: - void std::unordered_map::getMaxSizes(Model& model); - - }; - - - - }; - - : public JaniTraverser { - public: - - struct ResultType { - bool hasLocationAssignment, hasEdgeAssignment, hasEdgeDestinationAssignment; - }; - - AssignmentsFinder() = default; - - ResultType find(Model const& model, Variable const& variable); - - virtual ~AssignmentsFinder() = default; - - virtual void traverse(Location const& location, boost::any const& data) const override; - virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const override; - virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const override; - */ }; } } From ea6b2117039fd2db6462265449e579ab73a26fa3 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 3 Sep 2018 09:15:27 +0200 Subject: [PATCH 524/647] fixed storing the wrong pointers to Variables in LValues --- src/storm-parsers/parser/JaniParser.cpp | 44 +++++++++++-------------- src/storm-parsers/parser/JaniParser.h | 30 +++++++++-------- src/storm/storage/jani/Model.cpp | 4 +-- src/storm/storage/jani/Model.h | 2 +- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index ddd518fb9..23d3650b0 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -107,24 +107,22 @@ namespace storm { parseActions(parsedStructure.at("actions"), model); } size_t constantsCount = parsedStructure.count("constants"); - std::unordered_map> constants; + ConstantsMap constants; STORM_LOG_THROW(constantsCount < 2, storm::exceptions::InvalidJaniException, "Constant-declarations can be given at most once."); if (constantsCount == 1) { for (auto const &constStructure : parsedStructure.at("constants")) { std::shared_ptr constant = parseConstant(constStructure, constants, "global"); - constants.emplace(constant->getName(), constant); - model.addConstant(*constant); + constants.emplace(constant->getName(), &model.addConstant(*constant)); } } size_t variablesCount = parsedStructure.count("variables"); STORM_LOG_THROW(variablesCount < 2, storm::exceptions::InvalidJaniException, "Variable-declarations can be given at most once for global variables."); - std::unordered_map> globalVars; + VariablesMap globalVars; if (variablesCount == 1) { bool requireInitialValues = parsedStructure.count("restrict-initial") == 0; for (auto const& varStructure : parsedStructure.at("variables")) { std::shared_ptr variable = parseVariable(varStructure, requireInitialValues, "global", globalVars, constants); - globalVars.emplace(variable->getName(), variable); - model.addVariable(*variable); + globalVars.emplace(variable->getName(), &model.addVariable(*variable)); } } STORM_LOG_THROW(parsedStructure.count("automata") == 1, storm::exceptions::InvalidJaniException, "Exactly one list of automata must be given"); @@ -163,19 +161,19 @@ namespace storm { } - std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context) { + std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context) { STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << context); return { parseFormula(propertyStructure.at("exp"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; } - std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context) { + std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context) { STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << context); STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << context); return { parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "Operand of operator " + opstring), parseFormula(propertyStructure.at("right"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; } - storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, std::unordered_map> const& constants) { + storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, ConstantsMap const& constants) { storm::jani::PropertyInterval pi; if (piStructure.count("lower") > 0) { pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, constants); @@ -218,7 +216,7 @@ namespace storm { return storm::logic::RewardAccumulation(accSteps, accTime, accExit); } - std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext,std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound) { + std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext,VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context, boost::optional bound) { if (propertyStructure.is_boolean()) { return std::make_shared(propertyStructure.get()); } @@ -500,7 +498,7 @@ namespace storm { } } - storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, std::unordered_map> const& globalVars, std::unordered_map> const& constants) { + storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, VariablesMap const& globalVars, ConstantsMap const& constants) { STORM_LOG_THROW(propertyStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Property must have a name"); // TODO check unique name std::string name = getString(propertyStructure.at("name"), "property-name"); @@ -566,7 +564,7 @@ namespace storm { return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), comment); } - std::shared_ptr JaniParser::parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription) { + std::shared_ptr JaniParser::parseConstant(json const& constantStructure, ConstantsMap const& constants, std::string const& scopeDescription) { STORM_LOG_THROW(constantStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); std::string name = getString(constantStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); // TODO check existance of name. @@ -635,7 +633,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scopeDescription << ")"); } - void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { + void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars) { if (typeStructure.is_string()) { if (typeStructure == "real") { result.basicType = ParsedType::BasicType::Real; @@ -679,7 +677,7 @@ namespace storm { } } - std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool prefWithScope) { + std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool prefWithScope) { STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); std::string pref = prefWithScope ? scopeDescription + VARIABLE_AUTOMATON_DELIMITER : ""; std::string name = getString(variableStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); @@ -801,12 +799,12 @@ namespace storm { STORM_LOG_THROW(expected == actual, storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects " << expected << " arguments, but got " << actual << " in " << errorInfo << "."); } - std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars,returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left}; } - std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left, right}; @@ -839,7 +837,7 @@ namespace storm { STORM_LOG_THROW(expr.getType().isArrayType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be of type 'array' in " << errorInfo << "."); } - storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { + storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars) { if (lValueStructure.is_string()) { std::string ident = getString(lValueStructure, scopeDescription); auto localVar = localVars.find(ident); @@ -867,7 +865,7 @@ namespace storm { } } - storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, std::unordered_map const& auxiliaryVariables) { { auto it = auxiliaryVariables.find(ident); if (it != auxiliaryVariables.end()) { @@ -897,7 +895,7 @@ namespace storm { return storm::expressions::Variable(); } - storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { if(expressionStructure.is_boolean()) { if(expressionStructure.get()) { return expressionManager->boolean(true); @@ -1183,25 +1181,23 @@ namespace storm { } } - storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants ) { + storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, VariablesMap const& globalVars, ConstantsMap const& constants ) { STORM_LOG_THROW(automatonStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Each automaton must have a name"); std::string name = getString(automatonStructure.at("name"), " the name field for automaton"); storm::jani::Automaton automaton(name, expressionManager->declareIntegerVariable("_loc_" + name)); uint64_t varDeclCount = automatonStructure.count("variables"); STORM_LOG_THROW(varDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of variables"); - std::unordered_map> localVars; + VariablesMap localVars; if(varDeclCount > 0) { bool requireInitialValues = automatonStructure.count("restrict-initial") == 0; for(auto const& varStructure : automatonStructure.at("variables")) { std::shared_ptr var = parseVariable(varStructure, requireInitialValues, name, globalVars, constants, localVars, true); assert(localVars.count(var->getName()) == 0); - automaton.addVariable(*var); - localVars.emplace(var->getName(), var); + localVars.emplace(var->getName(), &automaton.addVariable(*var)); } } - STORM_LOG_THROW(automatonStructure.count("locations") > 0, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' does not have locations."); std::unordered_map locIds; for(auto const& locEntry : automatonStructure.at("locations")) { diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index ed5d9fe32..e6cf5f069 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -39,6 +39,8 @@ namespace storm { public: typedef std::vector PropertyVector; + typedef std::unordered_map VariablesMap; + typedef std::unordered_map ConstantsMap; JaniParser() : expressionManager(new storm::expressions::ExpressionManager()) {} JaniParser(std::string const& jsonstring); @@ -48,39 +50,39 @@ namespace storm { protected: void readFile(std::string const& path); std::pair> parseModel(bool parseProperties = true); - storm::jani::Property parseProperty(json const& propertyStructure, std::unordered_map> const& globalVars, std::unordered_map> const& constants); - storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants); + storm::jani::Property parseProperty(json const& propertyStructure, VariablesMap const& globalVars, ConstantsMap const& constants); + storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, VariablesMap const& globalVars, ConstantsMap const& constants); struct ParsedType { enum class BasicType {Bool, Int, Real}; boost::optional basicType; boost::optional> bounds; std::unique_ptr arrayBase; }; - void parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars); - storm::jani::LValue parseLValue(json const& lValueStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}); - std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool prefWithScope = false); - storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + void parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars); + storm::jani::LValue parseLValue(json const& lValueStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}); + std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool prefWithScope = false); + storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); private: - std::shared_ptr parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription = "global"); + std::shared_ptr parseConstant(json const& constantStructure, ConstantsMap const& constants, std::string const& scopeDescription = "global"); /** * Helper for parsing the actions of a model. */ void parseActions(json const& actionStructure, storm::jani::Model& parentModel); - std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound = boost::none); - std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars= {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); - std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context, boost::optional bound = boost::none); + std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars= {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); - std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); - std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); - storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, std::unordered_map> const& constants); + std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context); + std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context); + storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, ConstantsMap const& constants); storm::logic::RewardAccumulation parseRewardAccumulation(json const& accStructure, std::string const& context); std::shared_ptr parseComposition(json const& compositionStructure); - storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, std::unordered_map const& auxiliaryVariables = {}); + storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, std::unordered_map const& auxiliaryVariables = {}); diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index d484b6cb7..9f5f19915 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -591,12 +591,12 @@ namespace storm { return nonsilentActionIndices; } - uint64_t Model::addConstant(Constant const& constant) { + Constant const& Model::addConstant(Constant const& constant) { auto it = constantToIndex.find(constant.getName()); STORM_LOG_THROW(it == constantToIndex.end(), storm::exceptions::WrongFormatException, "Cannot add constant with name '" << constant.getName() << "', because a constant with that name already exists."); constantToIndex.emplace(constant.getName(), constants.size()); constants.push_back(constant); - return constants.size() - 1; + return constants.back(); } bool Model::hasConstant(std::string const& name) const { diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 4235b904b..452a3e4c5 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -143,7 +143,7 @@ namespace storm { /*! * Adds the given constant to the model. */ - uint64_t addConstant(Constant const& constant); + Constant const& addConstant(Constant const& constant); /*! * Retrieves whether the model has a constant with the given name. From 6564abd434a7082654585b408814a46e17fc5400 Mon Sep 17 00:00:00 2001 From: TimQu Date: Mon, 3 Sep 2018 13:06:50 +0200 Subject: [PATCH 525/647] jani expression substitution now also works for array expressions --- .../storage/SymbolicModelDescription.cpp | 3 --- src/storm/storage/jani/Assignment.cpp | 5 ++-- src/storm/storage/jani/Automaton.cpp | 3 ++- .../storage/jani/BoundedIntegerVariable.cpp | 5 ++-- src/storm/storage/jani/Edge.cpp | 3 ++- src/storm/storage/jani/EdgeDestination.cpp | 4 +++- .../storage/jani/JaniLocationExpander.cpp | 8 ++++--- src/storm/storage/jani/Model.cpp | 24 +++++++++++++------ src/storm/storage/jani/Model.h | 7 +++--- src/storm/storage/jani/TemplateEdge.cpp | 3 ++- src/storm/storage/jani/Variable.cpp | 3 ++- .../JaniExpressionSubstitutionVisitor.cpp | 11 +++++++++ .../JaniExpressionSubstitutionVisitor.h | 6 +++++ 13 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index 77c1a897d..60708af6e 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -150,9 +150,6 @@ namespace storm { SymbolicModelDescription SymbolicModelDescription::preprocess(std::map const& constantDefinitions) const { if (this->isJaniModel()) { storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(constantDefinitions).substituteConstants(); - if (preparedModel.hasArrayVariables()) { - preparedModel = preparedModel.convertArrays(); - } return SymbolicModelDescription(preparedModel); } else if (this->isPrismProgram()) { return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(constantDefinitions).substituteConstants()); diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 003e48762..74f801906 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/Assignment.h" #include "storm/storage/jani/LValue.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -51,9 +52,9 @@ namespace storm { } void Assignment::substitute(std::map const& substitution) { - this->setAssignedExpression(this->getAssignedExpression().substitute(substitution).simplify()); + this->setAssignedExpression(substituteJaniExpression(this->getAssignedExpression(), substitution).simplify()); if (lValue.isArrayAccess()) { - lValue = LValue(LValue(lValue.getArray()), lValue.getArrayIndex().substitute(substitution).simplify()); + lValue = LValue(LValue(lValue.getArray()), substituteJaniExpression(lValue.getArrayIndex(), substitution).simplify()); } } diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 58404e9a7..9737d768f 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -3,6 +3,7 @@ #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/Location.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" @@ -387,7 +388,7 @@ namespace storm { location.substitute(substitution); } - this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution)); + this->setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), substitution)); edges.substitute(substitution); } diff --git a/src/storm/storage/jani/BoundedIntegerVariable.cpp b/src/storm/storage/jani/BoundedIntegerVariable.cpp index 5b851b127..79bce1eda 100644 --- a/src/storm/storage/jani/BoundedIntegerVariable.cpp +++ b/src/storm/storage/jani/BoundedIntegerVariable.cpp @@ -1,5 +1,6 @@ #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/exceptions/NotImplementedException.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" namespace storm { @@ -47,8 +48,8 @@ namespace storm { void BoundedIntegerVariable::substitute(std::map const& substitution) { Variable::substitute(substitution); - this->setLowerBound(this->getLowerBound().substitute(substitution)); - this->setUpperBound(this->getUpperBound().substitute(substitution)); + this->setLowerBound(substituteJaniExpression(this->getLowerBound(), substitution)); + this->setUpperBound(substituteJaniExpression(this->getUpperBound(), substitution)); } std::shared_ptr makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional initValue, bool transient, boost::optional lowerBound, boost::optional upperBound) { diff --git a/src/storm/storage/jani/Edge.cpp b/src/storm/storage/jani/Edge.cpp index 4460b2a65..33834b2c4 100644 --- a/src/storm/storage/jani/Edge.cpp +++ b/src/storm/storage/jani/Edge.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -76,7 +77,7 @@ namespace storm { void Edge::substitute(std::map const& substitution) { if (this->hasRate()) { - this->setRate(this->getRate().substitute(substitution)); + this->setRate(substituteJaniExpression(this->getRate(), substitution)); } for (auto& destination : destinations) { destination.substitute(substitution); diff --git a/src/storm/storage/jani/EdgeDestination.cpp b/src/storm/storage/jani/EdgeDestination.cpp index 62b92c1f0..0a9dd4b32 100644 --- a/src/storm/storage/jani/EdgeDestination.cpp +++ b/src/storm/storage/jani/EdgeDestination.cpp @@ -1,6 +1,8 @@ #include "storm/storage/jani/EdgeDestination.h" #include "storm/utility/macros.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + #include "storm/exceptions/WrongFormatException.h" namespace storm { @@ -37,7 +39,7 @@ namespace storm { } void EdgeDestination::substitute(std::map const& substitution) { - this->setProbability(this->getProbability().substitute(substitution)); + this->setProbability(substituteJaniExpression(this->getProbability(), substitution)); } bool EdgeDestination::hasAssignment(Assignment const& assignment) const { diff --git a/src/storm/storage/jani/JaniLocationExpander.cpp b/src/storm/storage/jani/JaniLocationExpander.cpp index d955a7754..8c06fb3c1 100644 --- a/src/storm/storage/jani/JaniLocationExpander.cpp +++ b/src/storm/storage/jani/JaniLocationExpander.cpp @@ -1,5 +1,7 @@ #include "storm/storage/jani/JaniLocationExpander.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + #include "storm/storage/expressions/ExpressionManager.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/IllegalArgumentException.h" @@ -83,7 +85,7 @@ namespace storm { substitutionMap[eliminatedExpressionVariable] = original.getExpressionManager().integer(newValueAndLocation.first); uint64_t newSourceIndex = newValueAndLocation.second; - storm::expressions::Expression newGuard = edge.getGuard().substitute(substitutionMap).simplify(); + storm::expressions::Expression newGuard = substituteJaniExpression(edge.getGuard(), substitutionMap).simplify(); if (!newGuard.containsVariables() && !newGuard.evaluateAsBool()) { continue; } @@ -105,9 +107,9 @@ namespace storm { } TemplateEdgeDestination ted(oa); templateEdge->addDestination(ted); - destinationLocationsAndProbabilities.emplace_back(locationVariableValueMap[destination.getLocationIndex()][value], destination.getProbability().substitute((substitutionMap))); + destinationLocationsAndProbabilities.emplace_back(locationVariableValueMap[destination.getLocationIndex()][value], substituteJaniExpression(destination.getProbability(), substitutionMap)); } - newAutomaton.addEdge(storm::jani::Edge(newSourceIndex, edge.getActionIndex(), edge.hasRate() ? boost::optional(edge.getRate().substitute(substitutionMap)) : boost::none, templateEdge, destinationLocationsAndProbabilities)); + newAutomaton.addEdge(storm::jani::Edge(newSourceIndex, edge.getActionIndex(), edge.hasRate() ? boost::optional(substituteJaniExpression(edge.getRate(), substitutionMap)) : boost::none, templateEdge, destinationLocationsAndProbabilities)); } } diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 9f5f19915..3f34b72d4 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -16,6 +16,8 @@ #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/Compositions.h" #include "storm/storage/jani/JSONExporter.h" +#include "storm/storage/jani/traverser/ArrayEliminator.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -896,7 +898,7 @@ namespace storm { std::map constantSubstitution; for (auto& constant : result.getConstants()) { if (constant.isDefined()) { - constant.define(constant.getExpression().substitute(constantSubstitution)); + constant.define(substituteJaniExpression(constant.getExpression(), constantSubstitution)); constantSubstitution[constant.getExpressionVariable()] = constant.getExpression(); } } @@ -910,7 +912,7 @@ namespace storm { } // Substitute constants in initial states expression. - result.setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(constantSubstitution)); + result.setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), constantSubstitution)); // Substitute constants in variables of automata and their edges. for (auto& automaton : result.getAutomata()) { @@ -932,13 +934,21 @@ namespace storm { return result; } - bool Model::hasArrayVariables() const { - return getExpressionManager().getNumberOfArrayVariables() != 0; + bool Model::containsArrayVariables() const { + if (getGlobalVariables().containsArrayVariables()) { + return true; + } + for (auto const& a : getAutomata()) { + if (a.getVariables().containsArrayVariables()) { + return true; + } + } + return false; } - Model Model::convertArrays() const { - std::cout << "TODO"; - return *this; + void Model::eliminateArrays(bool keepNonTrivialArrayAccess) { + ArrayEliminator arrayEliminator; + arrayEliminator.eliminate(*this); } void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 452a3e4c5..ed0d0638a 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -360,12 +360,13 @@ namespace storm { /*! * Returns true if at least one array variable occurs in the model. */ - bool hasArrayVariables() const; + bool containsArrayVariables() const; /*! - * Converts occurring (fixed size) arrays into multiple variables. + * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. + * @param keepNonTrivialArrayAccess if set, array access expressions in LValues and expressions are only replaced, if the index expression is constant. */ - Model convertArrays() const; + void eliminateArrays(bool keepNonTrivialArrayAccess = false); /*! * Retrieves whether there is an expression restricting the legal initial values of the global variables. diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 460e6add3..889d25214 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -4,6 +4,7 @@ #include "storm/storage/jani/LValue.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" namespace storm { namespace jani { @@ -61,7 +62,7 @@ namespace storm { } void TemplateEdge::substitute(std::map const& substitution) { - guard = guard.substitute(substitution); + guard = substituteJaniExpression(guard, substitution); for (auto& assignment : assignments) { assignment.substitute(substitution); diff --git a/src/storm/storage/jani/Variable.cpp b/src/storm/storage/jani/Variable.cpp index d6a67996c..50fae165b 100644 --- a/src/storm/storage/jani/Variable.cpp +++ b/src/storm/storage/jani/Variable.cpp @@ -5,6 +5,7 @@ #include "storm/storage/jani/UnboundedIntegerVariable.h" #include "storm/storage/jani/RealVariable.h" #include "storm/storage/jani/ArrayVariable.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" namespace storm { namespace jani { @@ -111,7 +112,7 @@ namespace storm { void Variable::substitute(std::map const& substitution) { if (this->hasInitExpression()) { - this->setInitExpression(this->getInitExpression().substitute(substitution)); + this->setInitExpression(substituteJaniExpression(this->getInitExpression(), substitution)); } } diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp index 101f53472..a75a7cfed 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -3,6 +3,17 @@ #include "storm/exceptions/InvalidArgumentException.h" namespace storm { + + namespace jani { + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::map const& identifierToExpressionMap) { + return JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + } + + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::unordered_map const& identifierToExpressionMap) { + return JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + } + } + namespace expressions { template boost::any JaniExpressionSubstitutionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h index ca82d7df1..ab196acee 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h @@ -5,6 +5,12 @@ #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" namespace storm { + + namespace jani { + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::map const& identifierToExpressionMap); + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::unordered_map const& identifierToExpressionMap); + } + namespace expressions { template class JaniExpressionSubstitutionVisitor : public SubstitutionVisitor, public JaniExpressionVisitor { From dadf5719348e80fa16a7130d5e9d88c49f2cec14 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 5 Sep 2018 18:52:12 +0200 Subject: [PATCH 526/647] const and non-const jani traverser --- .../jani/traverser/AssignmentsFinder.cpp | 8 +- .../jani/traverser/AssignmentsFinder.h | 2 +- .../storage/jani/traverser/JaniTraverser.cpp | 204 ++++++++++++++++-- .../storage/jani/traverser/JaniTraverser.h | 28 +++ 4 files changed, 218 insertions(+), 24 deletions(-) diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp index f1450d004..8ad36776b 100644 --- a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp @@ -9,7 +9,7 @@ namespace storm { res.hasLocationAssignment = false; res.hasEdgeAssignment = false; res.hasEdgeDestinationAssignment = false; - JaniTraverser::traverse(model, std::make_pair(&variable, &res)); + ConstJaniTraverser::traverse(model, std::make_pair(&variable, &res)); return res; } @@ -20,7 +20,7 @@ namespace storm { resVar.second->hasLocationAssignment = true; } } - JaniTraverser::traverse(location, data); + ConstJaniTraverser::traverse(location, data); } void AssignmentsFinder::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { @@ -30,7 +30,7 @@ namespace storm { resVar.second->hasEdgeAssignment = true; } } - JaniTraverser::traverse(templateEdge, data); + ConstJaniTraverser::traverse(templateEdge, data); } void AssignmentsFinder::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { @@ -40,7 +40,7 @@ namespace storm { resVar.second->hasEdgeDestinationAssignment = true; } } - JaniTraverser::traverse(templateEdgeDestination, data); + ConstJaniTraverser::traverse(templateEdgeDestination, data); } } } diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.h b/src/storm/storage/jani/traverser/AssignmentsFinder.h index 2a2d2cdd0..b6bcd376e 100644 --- a/src/storm/storage/jani/traverser/AssignmentsFinder.h +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.h @@ -7,7 +7,7 @@ namespace storm { namespace jani { - class AssignmentsFinder : public JaniTraverser { + class AssignmentsFinder : public ConstJaniTraverser { public: struct ResultType { diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp index eb60a9358..bd1b9bbf1 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.cpp +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -3,7 +3,159 @@ namespace storm { namespace jani { - void JaniTraverser::traverse(Model const& model, boost::any const& data) const { + + void JaniTraverser::traverse(Model& model, boost::any const& data) const { + for (auto& act : model.getActions()) { + traverse(act, data); + } + for (auto& c : model.getConstants()) { + traverse(c, data); + } + traverse(model.getGlobalVariables(), data); + for (auto& aut : model.getAutomata()) { + traverse(aut, data); + } + if (model.hasInitialStatesRestriction()) { + traverse(model.getInitialStatesRestriction(), data); + } + } + + void JaniTraverser::traverse(Action const& action, boost::any const& data) const { + // Intentionally left empty. + } + + void JaniTraverser::traverse(Automaton& automaton, boost::any const& data) const { + traverse(automaton.getVariables(), data); + for (auto& loc : automaton.getLocations()) { + traverse(loc, data); + } + traverse(automaton.getEdgeContainer(), data); + if (automaton.hasInitialStatesRestriction()) { + traverse(automaton.getInitialStatesRestriction(), data); + } + } + + void JaniTraverser::traverse(Constant& constant, boost::any const& data) const { + if (constant.isDefined()) { + traverse(constant.getExpression(), data); + } + } + + void JaniTraverser::traverse(VariableSet& variableSet, boost::any const& data) const { + for (auto& v : variableSet.getBooleanVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getBoundedIntegerVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getUnboundedIntegerVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getRealVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getArrayVariables()) { + traverse(v, data); + } + } + + void JaniTraverser::traverse(Location& location, boost::any const& data) const { + traverse(location.getAssignments(), data); + } + + void JaniTraverser::traverse(BooleanVariable& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(BoundedIntegerVariable& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + traverse(variable.getLowerBound(), data); + traverse(variable.getUpperBound(), data); + } + + void JaniTraverser::traverse(UnboundedIntegerVariable& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(RealVariable& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(ArrayVariable& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + if (variable.hasElementTypeBounds()) { + traverse(variable.getElementTypeBounds().first, data); + traverse(variable.getElementTypeBounds().second, data); + } + } + + void JaniTraverser::traverse(EdgeContainer& edgeContainer, boost::any const& data) const { + for (auto& templateEdge : edgeContainer.getTemplateEdges()) { + traverse(*templateEdge, data); + } + for (auto& concreteEdge : edgeContainer.getConcreteEdges()) { + traverse(concreteEdge, data); + } + } + + void JaniTraverser::traverse(TemplateEdge& templateEdge, boost::any const& data) const { + traverse(templateEdge.getGuard(), data); + for (auto& dest : templateEdge.getDestinations()) { + traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + void JaniTraverser::traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) const { + traverse(templateEdgeDestination.getOrderedAssignments(), data); + } + + void JaniTraverser::traverse(Edge& edge, boost::any const& data) const { + if (edge.hasRate()) { + traverse(edge.getRate(), data); + } + for (auto& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void JaniTraverser::traverse(EdgeDestination& edgeDestination, boost::any const& data) const { + traverse(edgeDestination.getProbability(), data); + } + + void JaniTraverser::traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const { + for (auto& assignment : orderedAssignments) { + traverse(assignment, data); + } + STORM_LOG_ASSERT(orderedAssignments.checkOrder(), "Order of ordered assignment has been violated."); + } + + void JaniTraverser::traverse(Assignment& assignment, boost::any const& data) const { + traverse(assignment.getAssignedExpression(), data); + traverse(assignment.getLValue(), data); + } + + void JaniTraverser::traverse(LValue& lValue, boost::any const& data) const { + if (lValue.isArrayAccess()) { + traverse(lValue.getArrayIndex(), data); + } + } + + void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { + // intentionally left empty. + } + + void ConstJaniTraverser::traverse(Model const& model, boost::any const& data) const { for (auto const& act : model.getActions()) { traverse(act, data); } @@ -19,11 +171,11 @@ namespace storm { } } - void JaniTraverser::traverse(Action const& action, boost::any const& data) const { + void ConstJaniTraverser::traverse(Action const& action, boost::any const& data) const { // Intentionally left empty. } - void JaniTraverser::traverse(Automaton const& automaton, boost::any const& data) const { + void ConstJaniTraverser::traverse(Automaton const& automaton, boost::any const& data) const { traverse(automaton.getVariables(), data); for (auto const& loc : automaton.getLocations()) { traverse(loc, data); @@ -34,13 +186,13 @@ namespace storm { } } - void JaniTraverser::traverse(Constant const& constant, boost::any const& data) const { + void ConstJaniTraverser::traverse(Constant const& constant, boost::any const& data) const { if (constant.isDefined()) { traverse(constant.getExpression(), data); } } - void JaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) const { + void ConstJaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) const { for (auto const& v : variableSet.getBooleanVariables()) { traverse(v, data); } @@ -53,19 +205,22 @@ namespace storm { for (auto const& v : variableSet.getRealVariables()) { traverse(v, data); } + for (auto const& v : variableSet.getArrayVariables()) { + traverse(v, data); + } } - void JaniTraverser::traverse(Location const& location, boost::any const& data) const { + void ConstJaniTraverser::traverse(Location const& location, boost::any const& data) const { traverse(location.getAssignments(), data); } - void JaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } @@ -73,19 +228,29 @@ namespace storm { traverse(variable.getUpperBound(), data); } - void JaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(RealVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(RealVariable const& variable, boost::any const& data) const { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) const { + void ConstJaniTraverser::traverse(ArrayVariable const& variable, boost::any const& data) const { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + if (variable.hasElementTypeBounds()) { + traverse(variable.getElementTypeBounds().first, data); + traverse(variable.getElementTypeBounds().second, data); + } + } + + void ConstJaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) const { for (auto const& templateEdge : edgeContainer.getTemplateEdges()) { traverse(*templateEdge, data); } @@ -94,7 +259,7 @@ namespace storm { } } - void JaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { + void ConstJaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { traverse(templateEdge.getGuard(), data); for (auto const& dest : templateEdge.getDestinations()) { traverse(dest, data); @@ -102,11 +267,11 @@ namespace storm { traverse(templateEdge.getAssignments(), data); } - void JaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { + void ConstJaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { traverse(templateEdgeDestination.getOrderedAssignments(), data); } - void JaniTraverser::traverse(Edge const& edge, boost::any const& data) const { + void ConstJaniTraverser::traverse(Edge const& edge, boost::any const& data) const { if (edge.hasRate()) { traverse(edge.getRate(), data); } @@ -115,27 +280,28 @@ namespace storm { } } - void JaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) const { + void ConstJaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) const { traverse(edgeDestination.getProbability(), data); } - void JaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const { + void ConstJaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const { for (auto const& assignment : orderedAssignments) { traverse(assignment, data); } } - void JaniTraverser::traverse(Assignment const& assignment, boost::any const& data) const { + void ConstJaniTraverser::traverse(Assignment const& assignment, boost::any const& data) const { traverse(assignment.getAssignedExpression(), data); + traverse(assignment.getLValue(), data); } - void JaniTraverser::traverse(LValue const& lValue, boost::any const& data) const { + void ConstJaniTraverser::traverse(LValue const& lValue, boost::any const& data) const { if (lValue.isArrayAccess()) { traverse(lValue.getArrayIndex(), data); } } - void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { + void ConstJaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { // intentionally left empty. } diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h index 9cef29afc..25cc4530d 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.h +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -11,6 +11,33 @@ namespace storm { public: virtual ~JaniTraverser() = default; + virtual void traverse(Model& model, boost::any const& data) const; + + virtual void traverse(Action const& action, boost::any const& data) const; + virtual void traverse(Automaton& automaton, boost::any const& data) const; + virtual void traverse(Constant& constant, boost::any const& data) const; + virtual void traverse(VariableSet& variableSet, boost::any const& data) const; + virtual void traverse(Location& location, boost::any const& data) const; + virtual void traverse(BooleanVariable& variable, boost::any const& data) const; + virtual void traverse(BoundedIntegerVariable& variable, boost::any const& data) const; + virtual void traverse(UnboundedIntegerVariable& variable, boost::any const& data) const; + virtual void traverse(RealVariable& variable, boost::any const& data) const; + virtual void traverse(ArrayVariable& variable, boost::any const& data) const; + virtual void traverse(EdgeContainer& edgeContainer, boost::any const& data) const; + virtual void traverse(TemplateEdge& templateEdge, boost::any const& data) const; + virtual void traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) const; + virtual void traverse(Edge& edge, boost::any const& data) const; + virtual void traverse(EdgeDestination& edgeDestination, boost::any const& data) const; + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const; + virtual void traverse(Assignment& assignment, boost::any const& data) const; + virtual void traverse(LValue& lValue, boost::any const& data) const; + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) const; + }; + + class ConstJaniTraverser { + public: + virtual ~ConstJaniTraverser() = default; + virtual void traverse(Model const& model, boost::any const& data) const; virtual void traverse(Action const& action, boost::any const& data) const; @@ -22,6 +49,7 @@ namespace storm { virtual void traverse(BoundedIntegerVariable const& variable, boost::any const& data) const; virtual void traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const; virtual void traverse(RealVariable const& variable, boost::any const& data) const; + virtual void traverse(ArrayVariable const& variable, boost::any const& data) const; virtual void traverse(EdgeContainer const& edgeContainer, boost::any const& data) const; virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const; virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const; From 32180591c0362129090b488a3ceb3a13e70ae81f Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 5 Sep 2018 18:53:58 +0200 Subject: [PATCH 527/647] extended jani datastructures --- src/storm/storage/jani/Assignment.cpp | 4 ++ src/storm/storage/jani/Assignment.h | 6 ++- src/storm/storage/jani/Automaton.cpp | 14 ++--- src/storm/storage/jani/Automaton.h | 12 ++++- src/storm/storage/jani/Edge.cpp | 16 +++++- src/storm/storage/jani/Edge.h | 21 +++++++- src/storm/storage/jani/EdgeContainer.cpp | 8 +-- src/storm/storage/jani/EdgeContainer.h | 4 +- src/storm/storage/jani/Location.cpp | 4 ++ src/storm/storage/jani/Location.h | 5 ++ src/storm/storage/jani/Model.cpp | 10 ++-- src/storm/storage/jani/Model.h | 6 ++- src/storm/storage/jani/OrderedAssignments.cpp | 43 +++++++++++++-- src/storm/storage/jani/OrderedAssignments.h | 13 +++-- src/storm/storage/jani/TemplateEdge.cpp | 52 ++++++++++++++----- src/storm/storage/jani/TemplateEdge.h | 20 ++++++- .../storage/jani/TemplateEdgeDestination.cpp | 8 ++- .../storage/jani/TemplateEdgeDestination.h | 3 +- src/storm/storage/jani/VariableSet.cpp | 27 ++++++++++ src/storm/storage/jani/VariableSet.h | 5 ++ .../JaniExpressionSubstitutionVisitor.cpp | 11 +++- 21 files changed, 239 insertions(+), 53 deletions(-) diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 74f801906..0632f294d 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -27,6 +27,10 @@ namespace storm { return lValue.isArrayAccess(); } + storm::jani::LValue& Assignment::getLValue() { + return lValue; + } + storm::jani::LValue const& Assignment::getLValue() const { return lValue; } diff --git a/src/storm/storage/jani/Assignment.h b/src/storm/storage/jani/Assignment.h index 5179215e7..f2a18c8a9 100644 --- a/src/storm/storage/jani/Assignment.h +++ b/src/storm/storage/jani/Assignment.h @@ -31,9 +31,13 @@ namespace storm { /*! * Retrieves the lValue that is written in this assignment. - * @return */ storm::jani::LValue const& getLValue() const; + + /*! + * Retrieves the lValue that is written in this assignment. + */ + storm::jani::LValue& getLValue(); /*! * Retrieves the Variable that is written in this assignment. diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 9737d768f..b9c1e6449 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -281,6 +281,10 @@ namespace storm { return edges; } + EdgeContainer& Automaton::getEdgeContainer() { + return edges; + } + void Automaton::addEdge(Edge const& edge) { STORM_LOG_THROW(edge.getSourceLocationIndex() < locations.size(), storm::exceptions::InvalidArgumentException, "Cannot add edge with unknown source location index '" << edge.getSourceLocationIndex() << "'."); assert(validate()); @@ -293,8 +297,6 @@ namespace storm { for (uint64_t locationIndex = edge.getSourceLocationIndex() + 1; locationIndex < locationToStartingIndex.size(); ++locationIndex) { ++locationToStartingIndex[locationIndex]; } - - } std::vector& Automaton::getEdges() { @@ -476,8 +478,8 @@ namespace storm { return false; } - void Automaton::liftTransientEdgeDestinationAssignments() { - edges.liftTransientDestinationAssignments(); + void Automaton::liftTransientEdgeDestinationAssignments(uint64_t maxLevel) { + edges.liftTransientDestinationAssignments(maxLevel); } bool Automaton::validate() const { @@ -488,8 +490,8 @@ namespace storm { return true; } - bool Automaton::usesAssignmentLevels() const { - return edges.usesAssignmentLevels(); + bool Automaton::usesAssignmentLevels(bool onlyTransient) const { + return edges.usesAssignmentLevels(onlyTransient); } bool Automaton::isLinear() const { diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index 6e51d6440..abd459735 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -197,7 +197,15 @@ namespace storm { */ ConstEdges getEdgesFromLocation(uint64_t locationIndex, uint64_t actionIndex) const; + /*! + * Retrieves the container of all edges of this automaton. + */ EdgeContainer const& getEdgeContainer() const; + + /*! + * Retrieves the container of all edges of this automaton. + */ + EdgeContainer& getEdgeContainer(); /*! * Adds the template edge to the list of edges @@ -317,12 +325,12 @@ namespace storm { /*! * Lifts the common edge destination assignments to edge assignments. */ - void liftTransientEdgeDestinationAssignments(); + void liftTransientEdgeDestinationAssignments(uint64_t maxLevel = 0); /*! * Retrieves whether the automaton uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; void simplifyIndexedAssignments(); diff --git a/src/storm/storage/jani/Edge.cpp b/src/storm/storage/jani/Edge.cpp index 33834b2c4..cbe78c699 100644 --- a/src/storm/storage/jani/Edge.cpp +++ b/src/storm/storage/jani/Edge.cpp @@ -67,6 +67,10 @@ namespace storm { return destinations; } + std::vector& Edge::getDestinations() { + return destinations; + } + std::size_t Edge::getNumberOfDestinations() const { return destinations.size(); } @@ -100,8 +104,8 @@ namespace storm { return templateEdge->hasTransientEdgeDestinationAssignments(); } - bool Edge::usesAssignmentLevels() const { - return templateEdge->usesAssignmentLevels(); + bool Edge::usesAssignmentLevels(bool onlyTransient) const { + return templateEdge->usesAssignmentLevels(onlyTransient); } void Edge::simplifyIndexedAssignments(VariableSet const& localVars) { @@ -117,6 +121,14 @@ namespace storm { } } + uint64_t const& Edge::getLowestAssignmentLevel() const { + return templateEdge->getLowestAssignmentLevel(); + } + + uint64_t const& Edge::getHighestAssignmentLevel() const { + return templateEdge->getHighestAssignmentLevel(); + } + void Edge::setTemplateEdge(std::shared_ptr const& newTe) { templateEdge = newTe; uint64_t i = 0; diff --git a/src/storm/storage/jani/Edge.h b/src/storm/storage/jani/Edge.h index 002b97d40..d47edf14f 100644 --- a/src/storm/storage/jani/Edge.h +++ b/src/storm/storage/jani/Edge.h @@ -70,6 +70,11 @@ namespace storm { */ std::vector const& getDestinations() const; + /*! + * Retrieves the destinations of this edge. + */ + std::vector& getDestinations(); + /*! * Retrieves the number of destinations of this edge. */ @@ -103,7 +108,7 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * @@ -112,9 +117,21 @@ namespace storm { void simplifyIndexedAssignments(VariableSet const& localVars); std::shared_ptr const& getTemplateEdge(); - void setTemplateEdge(std::shared_ptr const& newTe); + /*! + * Retrieves the lowest assignment level occurring in each assignment. + * If no assignment exists, this value is the highest possible integer + */ + uint64_t const& getLowestAssignmentLevel() const; + + /*! + * Retrieves the highest assignment level occurring in each assignment + * If no assignment exists, this value is always zero + */ + uint64_t const& getHighestAssignmentLevel() const; + + void assertValid() const; private: diff --git a/src/storm/storage/jani/EdgeContainer.cpp b/src/storm/storage/jani/EdgeContainer.cpp index d735bc80d..83db856ad 100644 --- a/src/storm/storage/jani/EdgeContainer.cpp +++ b/src/storm/storage/jani/EdgeContainer.cpp @@ -86,9 +86,9 @@ namespace storm { edges.clear(); } - void EdgeContainer::liftTransientDestinationAssignments() { + void EdgeContainer::liftTransientDestinationAssignments(uint64_t maxLevel) { for (auto& templateEdge : templates) { - templateEdge->liftTransientDestinationAssignments(); + templateEdge->liftTransientDestinationAssignments(maxLevel); } } @@ -111,9 +111,9 @@ namespace storm { } - bool EdgeContainer::usesAssignmentLevels() const { + bool EdgeContainer::usesAssignmentLevels(bool onlyTransient) const { for (auto const& edge : edges) { - if (edge.usesAssignmentLevels()) { + if (edge.usesAssignmentLevels(onlyTransient)) { return true; } } diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h index c2bdfe80c..550fc80e0 100644 --- a/src/storm/storage/jani/EdgeContainer.h +++ b/src/storm/storage/jani/EdgeContainer.h @@ -107,12 +107,12 @@ namespace storm { std::set getActionIndices() const; void substitute(std::map const& substitution); - void liftTransientDestinationAssignments(); + void liftTransientDestinationAssignments(uint64_t maxLevel = 0); void pushAssignmentsToDestinations(); void insertEdge(Edge const& e, uint64_t locStart, uint64_t locEnd); void insertTemplateEdge(std::shared_ptr const& te); bool isLinear() const; - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; void finalize(Model const& containingModel); void changeAssignmentVariables(std::map> const& remapping); diff --git a/src/storm/storage/jani/Location.cpp b/src/storm/storage/jani/Location.cpp index 5ab431734..7831436a7 100644 --- a/src/storm/storage/jani/Location.cpp +++ b/src/storm/storage/jani/Location.cpp @@ -23,6 +23,10 @@ namespace storm { return assignments; } + OrderedAssignments& Location::getAssignments() { + return assignments; + } + void Location::addTransientAssignment(storm::jani::Assignment const& assignment) { STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); assignments.add(assignment); diff --git a/src/storm/storage/jani/Location.h b/src/storm/storage/jani/Location.h index 75e53d575..1fc3cd65d 100644 --- a/src/storm/storage/jani/Location.h +++ b/src/storm/storage/jani/Location.h @@ -30,6 +30,11 @@ namespace storm { */ OrderedAssignments const& getAssignments() const; + /*! + * Retrieves the assignments of this location. + */ + OrderedAssignments& getAssignments(); + /*! * Adds the given transient assignment to this location. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 3f34b72d4..502c821c0 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -948,7 +948,7 @@ namespace storm { void Model::eliminateArrays(bool keepNonTrivialArrayAccess) { ArrayEliminator arrayEliminator; - arrayEliminator.eliminate(*this); + arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess); } void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { @@ -1164,9 +1164,9 @@ namespace storm { } } - void Model::liftTransientEdgeDestinationAssignments() { + void Model::liftTransientEdgeDestinationAssignments(uint64_t maxLevel) { for (auto& automaton : this->getAutomata()) { - automaton.liftTransientEdgeDestinationAssignments(); + automaton.liftTransientEdgeDestinationAssignments(maxLevel); } } @@ -1179,9 +1179,9 @@ namespace storm { return false; } - bool Model::usesAssignmentLevels() const { + bool Model::usesAssignmentLevels(bool onlyTransient) const { for (auto const& automaton : this->getAutomata()) { - if (automaton.usesAssignmentLevels()) { + if (automaton.usesAssignmentLevels(onlyTransient)) { return true; } } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index ed0d0638a..7ccc011a4 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -456,8 +456,9 @@ namespace storm { /*! * Lifts the common edge destination assignments to edge assignments. + * @param maxLevel the maximum level of assignments that are to be lifted. */ - void liftTransientEdgeDestinationAssignments(); + void liftTransientEdgeDestinationAssignments(uint64_t maxLevel = 0); /*! * Retrieves whether there is any transient edge destination assignment in the model. @@ -466,8 +467,9 @@ namespace storm { /*! * Retrieves whether the model uses an assignment level other than zero. + * @param onlyTransient if set, only transient assignments are considered */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * Checks the model for linearity. A model is linear if all expressions appearing in guards and assignments diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 27ccd2761..11f59a5d0 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -80,11 +80,19 @@ namespace storm { return true; } - bool OrderedAssignments::hasMultipleLevels() const { + bool OrderedAssignments::hasMultipleLevels(bool onlyTransient) const { if (allAssignments.empty()) { return false; } - return getLowestLevel() != 0 || getHighestLevel() != 0; + if (onlyTransient) { + for (auto const& a : allAssignments) { + if (a->isTransient()) { + return a->getLevel() != 0 || getHighestLevel(true) != 0; + } + } + return false; // no transient assignments + } + return getLowestLevel(false) != 0 || getHighestLevel(false) != 0; } bool OrderedAssignments::empty() const { @@ -101,13 +109,31 @@ namespace storm { return allAssignments.size(); } - int_fast64_t OrderedAssignments::getLowestLevel() const { + int_fast64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const { assert(!allAssignments.empty()); + if (onlyTransient) { + for (auto const& a : allAssignments) { + if (a->getLValue().isTransient()) { + return a->getLevel(); + } + } + // assert that at least one transient variable is contained. + assert(false); + } return allAssignments.front()->getLevel(); } - int_fast64_t OrderedAssignments::getHighestLevel() const { + int_fast64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const { assert(!allAssignments.empty()); + if (onlyTransient) { + for (auto aIt = allAssignments.rbegin(); aIt != allAssignments.rend(); ++aIt) { + if ((*aIt)->getLValue().isTransient()) { + return (*aIt)->getLevel(); + } + } + // assert that at least one transient variable is contained. + assert(false); + } return allAssignments.back()->getLevel(); } @@ -271,6 +297,15 @@ namespace storm { return result; } + bool OrderedAssignments::checkOrder() const { + for (std::vector>::const_iterator it = allAssignments.cbegin(); it != allAssignments.cend(); ++it) { + if (it != lowerBound(**it, allAssignments)) { + return false; + } + } + return true; + } + std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments) { stream << "["; for(auto const& e : assignments.allAssignments) { diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index aa81f59a3..54ac16e0d 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -44,7 +44,7 @@ namespace storm { * * @return True if more than one level occurs in the assignment set. */ - bool hasMultipleLevels() const; + bool hasMultipleLevels(bool onlyTransient = false) const; /** * Produces a new OrderedAssignments object with simplified leveling @@ -73,13 +73,13 @@ namespace storm { * Retrieves the lowest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getLowestLevel() const; + int_fast64_t getLowestLevel(bool onlyTransient = false) const; /*! * Retrieves the highest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getHighestLevel() const; + int_fast64_t getHighestLevel(bool onlyTransient = false) const; /*! * Retrieves whether the given assignment is contained in this set of assignments. @@ -144,7 +144,12 @@ namespace storm { friend std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments); OrderedAssignments clone() const; - + + /*! + * Checks whether this ordered assignment is in the correct order. + */ + bool checkOrder() const; + private: uint64_t isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start = 0) const; uint64_t isWrittenBeforeAssignment(LValue const& LValue, uint64_t assignmentNumber, uint64_t start = 0) const; diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 889d25214..79644f8a6 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -9,12 +9,12 @@ namespace storm { namespace jani { - TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard) { + TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(0) { // Intentionally left empty. } TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard, OrderedAssignments const& assignments, std::vector const& destinations) - : guard(guard), destinations(destinations), assignments(assignments) { + : guard(guard), destinations(destinations), assignments(assignments), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(0) { // Intentionally left empty. } @@ -27,7 +27,18 @@ namespace storm { } void TemplateEdge::finalize(Model const& containingModel) { + if (assignments.empty()) { + lowestAssignmentLevel = std::numeric_limits::max(); + highestAssignmentLevel = 0; + } else { + lowestAssignmentLevel = assignments.getLowestLevel(); + highestAssignmentLevel = assignments.getHighestLevel(); + } for (auto const& destination : getDestinations()) { + if (!destination.getOrderedAssignments().empty()) { + lowestAssignmentLevel = std::min(lowestAssignmentLevel, destination.getOrderedAssignments().getLowestLevel()); + highestAssignmentLevel = std::max(highestAssignmentLevel, destination.getOrderedAssignments().getHighestLevel()); + } for (auto const& assignment : destination.getOrderedAssignments().getAllAssignments()) { Variable const& var = assignment.getLValue().isVariable() ? assignment.getLValue().getVariable() : assignment.getLValue().getArray(); if (containingModel.getGlobalVariables().hasVariable(var.getExpressionVariable())) { @@ -53,6 +64,10 @@ namespace storm { return destinations; } + std::vector& TemplateEdge::getDestinations() { + return destinations; + } + TemplateEdgeDestination const& TemplateEdge::getDestination(uint64_t index) const { return destinations[index]; } @@ -60,6 +75,10 @@ namespace storm { OrderedAssignments const& TemplateEdge::getAssignments() const { return assignments; } + + OrderedAssignments& TemplateEdge::getAssignments() { + return assignments; + } void TemplateEdge::substitute(std::map const& substitution) { guard = substituteJaniExpression(guard, substitution); @@ -80,7 +99,7 @@ namespace storm { assignments.changeAssignmentVariables(remapping); } - void TemplateEdge::liftTransientDestinationAssignments() { + void TemplateEdge::liftTransientDestinationAssignments(uint64_t maxLevel) { if (!destinations.empty()) { auto const& destination = *destinations.begin(); @@ -88,11 +107,13 @@ namespace storm { for (auto const& assignment : destination.getOrderedAssignments().getTransientAssignments()) { // Check if we can lift the assignment to the edge. - bool canBeLifted = true; - for (auto const& destination : destinations) { - if (!destination.hasAssignment(assignment)) { - canBeLifted = false; - break; + bool canBeLifted = assignment.getLevel() <= maxLevel; + if (canBeLifted) { + for (auto const& destination : destinations) { + if (!destination.hasAssignment(assignment)) { + canBeLifted = false; + break; + } } } @@ -143,18 +164,25 @@ namespace storm { return false; } - bool TemplateEdge::usesAssignmentLevels() const { - if (assignments.hasMultipleLevels()) { + bool TemplateEdge::usesAssignmentLevels(bool onlyTransient) const { + if (assignments.hasMultipleLevels(onlyTransient)) { return true; } for (auto const& destination : this->getDestinations()) { - if (destination.usesAssignmentLevels()) { + if (destination.usesAssignmentLevels(onlyTransient)) { return true; } } return false; } - + + uint64_t const& TemplateEdge::getLowestAssignmentLevel() const { + return lowestAssignmentLevel; + } + + uint64_t const& TemplateEdge::getHighestAssignmentLevel() const { + return highestAssignmentLevel; + } bool TemplateEdge::hasEdgeDestinationAssignments() const { for (auto const& destination : destinations) { diff --git a/src/storm/storage/jani/TemplateEdge.h b/src/storm/storage/jani/TemplateEdge.h index dac58144b..4e0d2a027 100644 --- a/src/storm/storage/jani/TemplateEdge.h +++ b/src/storm/storage/jani/TemplateEdge.h @@ -32,9 +32,11 @@ namespace storm { std::size_t getNumberOfDestinations() const; std::vector const& getDestinations() const; + std::vector& getDestinations(); TemplateEdgeDestination const& getDestination(uint64_t index) const; OrderedAssignments const& getAssignments() const; + OrderedAssignments& getAssignments(); /*! * Adds a transient assignment to this edge. @@ -66,7 +68,7 @@ namespace storm { * assignments are no longer contained in the destination. Note that this may modify the semantics of the * model if assignment levels are being used somewhere in the model. */ - void liftTransientDestinationAssignments(); + void liftTransientDestinationAssignments(uint64_t maxLevel = 0); /** * Shifts the assingments from the edges to the destinations. @@ -86,8 +88,20 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; + /*! + * Retrieves the lowest assignment level occurring in each assignment. + * If no assignment exists, this value is the highest possible integer + */ + uint64_t const& getLowestAssignmentLevel() const; + + /*! + * Retrieves the highest assignment level occurring in each assignment + * If no assignment exists, this value is always zero + */ + uint64_t const& getHighestAssignmentLevel() const; + /*! * Checks the template edge for linearity. */ @@ -110,6 +124,8 @@ namespace storm { /// The assignments made when taking this edge. OrderedAssignments assignments; + uint64_t lowestAssignmentLevel, highestAssignmentLevel; + /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to finalize. boost::container::flat_set writtenGlobalVariables; diff --git a/src/storm/storage/jani/TemplateEdgeDestination.cpp b/src/storm/storage/jani/TemplateEdgeDestination.cpp index b30bbda92..df0225636 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.cpp +++ b/src/storm/storage/jani/TemplateEdgeDestination.cpp @@ -27,6 +27,10 @@ namespace storm { return assignments; } + OrderedAssignments& TemplateEdgeDestination::getOrderedAssignments() { + return assignments; + } + bool TemplateEdgeDestination::removeAssignment(Assignment const& assignment) { return assignments.remove(assignment); } @@ -43,8 +47,8 @@ namespace storm { return assignments.hasTransientAssignment(); } - bool TemplateEdgeDestination::usesAssignmentLevels() const { - return assignments.hasMultipleLevels(); + bool TemplateEdgeDestination::usesAssignmentLevels(bool onlyTransient) const { + return assignments.hasMultipleLevels(onlyTransient); } bool TemplateEdgeDestination::isLinear() const { diff --git a/src/storm/storage/jani/TemplateEdgeDestination.h b/src/storm/storage/jani/TemplateEdgeDestination.h index e6ad889b8..39e91fbd7 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.h +++ b/src/storm/storage/jani/TemplateEdgeDestination.h @@ -23,6 +23,7 @@ namespace storm { void changeAssignmentVariables(std::map> const& remapping); OrderedAssignments const& getOrderedAssignments() const; + OrderedAssignments& getOrderedAssignments(); // Convenience methods to access the assignments. bool hasAssignment(Assignment const& assignment) const; @@ -37,7 +38,7 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * Checks whether the templ. edge destination contains one or more assignments diff --git a/src/storm/storage/jani/VariableSet.cpp b/src/storm/storage/jani/VariableSet.cpp index 973630a2c..ee8a798e2 100644 --- a/src/storm/storage/jani/VariableSet.cpp +++ b/src/storm/storage/jani/VariableSet.cpp @@ -132,6 +132,33 @@ namespace storm { return *newVariable; } + std::vector> VariableSet::dropAllArrayVariables() { + if (!arrayVariables.empty()) { + for (auto const& arrVar : arrayVariables) { + nameToVariable.erase(arrVar->getName()); + variableToVariable.erase(arrVar->getExpressionVariable()); + } + std::vector> newVariables; + for (auto const& v : variables) { + if (!v->isArrayVariable()) { + newVariables.push_back(v); + } + } + variables = std::move(newVariables); + newVariables.clear(); + for (auto const& v : transientVariables) { + if (!v->isArrayVariable()) { + newVariables.push_back(v); + } + } + transientVariables = std::move(newVariables); + } + + std::vector> result = std::move(arrayVariables); + arrayVariables.clear(); + return result; + } + bool VariableSet::hasVariable(std::string const& name) const { return nameToVariable.find(name) != nameToVariable.end(); } diff --git a/src/storm/storage/jani/VariableSet.h b/src/storm/storage/jani/VariableSet.h index 9940d37a2..227535e6f 100644 --- a/src/storm/storage/jani/VariableSet.h +++ b/src/storm/storage/jani/VariableSet.h @@ -109,6 +109,11 @@ namespace storm { */ ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! + * Removes all array variables in this set + */ + std::vector> dropAllArrayVariables(); + /*! * Retrieves whether this variable set contains a variable with the given name. */ diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp index a75a7cfed..cfd421c59 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -6,15 +6,22 @@ namespace storm { namespace jani { storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::map const& identifierToExpressionMap) { - return JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + return storm::expressions::JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); } storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::unordered_map const& identifierToExpressionMap) { - return JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + return storm::expressions::JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); } } + namespace expressions { + + template + JaniExpressionSubstitutionVisitor::JaniExpressionSubstitutionVisitor(MapType const& variableToExpressionMapping) : SubstitutionVisitor(variableToExpressionMapping) { + // Intentionally left empty. + } + template boost::any JaniExpressionSubstitutionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { uint64_t size = expression.size()->evaluateAsInt(); From 4aff82c649828f1afe36974535c6f3dcbd275540 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 5 Sep 2018 18:54:20 +0200 Subject: [PATCH 528/647] array eliminator replaces lvalues and variables --- .../jani/traverser/ArrayEliminator.cpp | 340 +++++++++++++++--- .../storage/jani/traverser/ArrayEliminator.h | 8 +- 2 files changed, 306 insertions(+), 42 deletions(-) diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.cpp b/src/storm/storage/jani/traverser/ArrayEliminator.cpp index 2acce661b..15da40a42 100644 --- a/src/storm/storage/jani/traverser/ArrayEliminator.cpp +++ b/src/storm/storage/jani/traverser/ArrayEliminator.cpp @@ -1,99 +1,357 @@ #include "storm/storage/jani/traverser/ArrayEliminator.h" +#include #include "storm/storage/expressions/ExpressionVisitor.h" #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace jani { namespace detail { -/* - - - class MaxArraySizeVisitor : public ExpressionVisitor, public JaniExpressionVisitor { - virtual MaxArraySizeVisitor() = default; - virtual ~MaxArraySizeVisitor() = default; + + class MaxArraySizeExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + MaxArraySizeExpressionVisitor() = default; + virtual ~MaxArraySizeExpressionVisitor() = default; - std::size_t getMaxSize(Expression const& expression) { - return boost::any_cast expression.accept(*this); + std::size_t getMaxSize(storm::expressions::Expression const& expression, std::unordered_map arrayVariableSizeMap) { + return boost::any_cast(expression.accept(*this, &arrayVariableSizeMap)); } - virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + if (expression.getCondition()->containsVariables()) { + return std::max(boost::any_cast(expression.getThenExpression()->accept(*this, data)), boost::any_cast(expression.getElseExpression()->accept(*this, data))); + } else { + if (expression.getCondition()->evaluateAsBool()) { + return boost::any_cast(expression.getThenExpression()->accept(*this, data)); + } + return boost::any_cast(expression.getElseExpression()->accept(*this, data)); + } } - virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); } - virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); } - virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); } - virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { + std::unordered_map* arrayVariableSizeMap = boost::any_cast*>(data); + if (expression.getType().isArrayType()) { + auto varIt = arrayVariableSizeMap->find(expression.getVariable()); + if (varIt != arrayVariableSizeMap->end()) { + return varIt->second; + } + } + return static_cast(0); } - virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return boost::any_cast(expression.getOperand()->accept(*this, data)); } - virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return boost::any_cast(expression.getOperand()->accept(*this, data)); } - virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data) override { + return 0; } - virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data) override { + return 0; } - virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override { - + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data) override { + return 0; } + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + return static_cast(expression.size()->evaluateAsInt()); + } - virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override { + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + if (!expression.size()->containsVariables()) { + return static_cast(expression.size()->evaluateAsInt()); + } else { + auto vars = expression.toExpression().getVariables(); + std::string variables = ""; + for (auto const& v : vars) { + if (variables != "") { + variables += ", "; + } + variables += v.getName(); + } + if (vars.size() == 1) { + variables = "variable "; + } else { + variables = "variables "; + } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unable to get determine array size: Size of ConstructorArrayExpression still contains the " << variables << "."); + } + } + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + STORM_LOG_WARN("Array access expression on rhs of array assignment. This is not expected since nested arrays are currently not supported."); + return 0; } + }; + + class MaxArraySizeDeterminer : public ConstJaniTraverser { + public: - virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override { + typedef std::unordered_map* MapPtr; + MaxArraySizeDeterminer() = default; + virtual ~MaxArraySizeDeterminer() = default; + std::unordered_map getMaxSizes(Model const& model) { + // We repeatedly determine the max array sizes until convergence. This is to cover assignments of one array variable to another (A := B) + std::unordered_map result, previousResult; + do { + previousResult = result; + ConstJaniTraverser::traverse(model, &result); + } while (previousResult != result); + return result; } - virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override { + virtual void traverse(Assignment const& assignment, boost::any const& data) const override { + if (assignment.lValueIsVariable() && assignment.getExpressionVariable().getType().isArrayType()) { + auto& map = *boost::any_cast(data); + std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(assignment.getAssignedExpression(), map); + auto insertionRes = map.emplace(assignment.getExpressionVariable(), newSize); + if (!insertionRes.second) { + insertionRes.first->second = std::max(newSize, insertionRes.first->second); + } + } + } + virtual void traverse(ArrayVariable const& variable, boost::any const& data) const override { + if (variable.hasInitExpression()) { + auto& map = *boost::any_cast(data); + std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(variable.getInitExpression(), map); + auto insertionRes = map.emplace(variable.getExpressionVariable(), newSize); + if (!insertionRes.second) { + insertionRes.first->second = std::max(newSize, insertionRes.first->second); + } + } } }; + class ArrayVariableReplacer : public JaniTraverser { public: - ArrayVariableReplacer() = default; + typedef ArrayEliminatorData ResultType; + + ArrayVariableReplacer(storm::expressions::ExpressionManager& expressionManager, bool keepNonTrivialArrayAccess) : expressionManager(expressionManager) , keepNonTrivialArrayAccess(keepNonTrivialArrayAccess) {} + virtual ~ArrayVariableReplacer() = default; - std::unordered_map> replace(); + ResultType replace(Model& model, std::unordered_map const& arrayVarToSizesMap) { + ResultType result; + for (auto const& arraySize : arrayVarToSizesMap) { + result.replacements.emplace(arraySize.first, std::vector(arraySize.second, nullptr)); + } + traverse(model, &result); + return result; + } + + virtual void traverse(Model& model, boost::any const& data) const override { + + // Insert fresh basic variables for global array variables + auto& replacements = boost::any_cast(data)->replacements; + for (storm::jani::ArrayVariable const& arrayVariable : model.getGlobalVariables().getArrayVariables()) { + std::vector& basicVars = replacements.at(arrayVariable.getExpressionVariable()); + for (uint64_t index = 0; index < basicVars.size(); ++index) { + basicVars[index] = &model.addVariable(*getBasicVariable(arrayVariable, index)); + } + } + // drop all occuring array variables + auto elVars = model.getGlobalVariables().dropAllArrayVariables(); + auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; + eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + + for (auto& aut : model.getAutomata()) { + traverse(aut, data); + } + + // traverse remaining components + for (auto& c : model.getConstants()) { + traverse(c, data); + } + if (model.hasInitialStatesRestriction()) { + //model.setInitialStatesRestriction(); + } + } + + virtual void traverse(Automaton& automaton, boost::any const& data) const override { + // No need to traverse the init restriction. + + // Insert fresh basic variables for local array variables + auto& replacements = boost::any_cast(data)->replacements; + for (storm::jani::ArrayVariable const& arrayVariable : automaton.getVariables().getArrayVariables()) { + std::vector& basicVars = replacements.at(arrayVariable.getExpressionVariable()); + for (uint64_t index = 0; index < basicVars.size(); ++index) { + basicVars[index] = &automaton.addVariable(*getBasicVariable(arrayVariable, index)); + } + } + // drop all occuring array variables + auto elVars = automaton.getVariables().dropAllArrayVariables(); + auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; + eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + + for (auto& loc : automaton.getLocations()) { + JaniTraverser::traverse(loc, data); + } + JaniTraverser::traverse(automaton.getEdgeContainer(), data); + } + + void traverse(Constant& constant, boost::any const& data) const { + if (constant.isDefined()) { + // todo: + //traverse(constant.getExpression(), data); + } + } + + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const override { + auto const& replacements = boost::any_cast(data)->replacements; - virtual void traverse(Assignment const& assignment, boost::any const& data) const override; + // Replace array occurrences in LValues. + std::vector newAssignments; + uint64_t level = 0; + std::unordered_map> collectedArrayAccessAssignments; + for (Assignment const& assignment : orderedAssignments) { + if (assignment.getLevel() != level) { + STORM_LOG_ASSERT(assignment.getLevel() > level, "Ordered Assignment does not have the expected order."); + for (auto const& arrayAssignments : collectedArrayAccessAssignments) { + insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); + } + collectedArrayAccessAssignments.clear(); + level = assignment.getLevel(); + } + if (assignment.getLValue().isArrayAccess()) { + if (!keepNonTrivialArrayAccess || !assignment.getLValue().getArrayIndex().containsVariables()) { + auto insertionRes = collectedArrayAccessAssignments.emplace(assignment.getLValue().getArray().getExpressionVariable(), std::vector({&assignment})); + if (!insertionRes.second) { + insertionRes.first->second.push_back(&assignment); + } + continue; + } + } else if (assignment.getLValue().isVariable() && assignment.getVariable().isArrayVariable()) { + STORM_LOG_ASSERT(assignment.getAssignedExpression().getType().isArrayType(), "Assigning a non-array expression to an array variable..."); + std::vector const& arrayVariableReplacements = replacements.at(assignment.getExpressionVariable()); + for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { + auto arrayAccessExpression = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer()); + newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), arrayAccessExpression->toExpression(), level); + } + continue; + } + newAssignments.push_back(assignment); + } + for (auto const& arrayAssignments : collectedArrayAccessAssignments) { + insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); + } + collectedArrayAccessAssignments.clear(); + orderedAssignments.clear(); + for (auto const& assignment : newAssignments) { + orderedAssignments.add(assignment); + } + } private: - void std::unordered_map::getMaxSizes(Model& model); + std::shared_ptr getBasicVariable(ArrayVariable const& arrayVariable, uint64_t index) const { + std::string name = arrayVariable.getExpressionVariable().getName() + "_at_" + std::to_string(index); + storm::expressions::Expression initValue; + if (arrayVariable.hasInitExpression()) { + initValue = std::make_shared(expressionManager, arrayVariable.getExpressionVariable().getType().getElementType(), arrayVariable.getInitExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); + } + if (arrayVariable.getElementType() == ArrayVariable::ElementType::Int) { + storm::expressions::Variable exprVariable = expressionManager.declareIntegerVariable(name); + if (arrayVariable.hasElementTypeBounds()) { + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient(), arrayVariable.getElementTypeBounds().first, arrayVariable.getElementTypeBounds().second); + } else { + return std::make_shared(name, exprVariable, arrayVariable.getElementTypeBounds().first, arrayVariable.getElementTypeBounds().second); + } + } else { + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } + } else if (arrayVariable.getElementType() == ArrayVariable::ElementType::Real) { + storm::expressions::Variable exprVariable = expressionManager.declareRationalVariable(name); + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } else if (arrayVariable.getElementType() == ArrayVariable::ElementType::Bool) { + storm::expressions::Variable exprVariable = expressionManager.declareBooleanVariable(name); + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unhandled array base type."); + return nullptr; + } + + void insertLValueArrayAccessReplacements(std::vector const& arrayAccesses, std::vector const& arrayVariableReplacements, uint64_t level, std::vector& newAssignments) const { + storm::expressions::Variable const& arrayVariable = arrayAccesses.front()->getLValue().getArray().getExpressionVariable(); + bool onlyConstantIndices = true; + for (auto const& aa : arrayAccesses) { + if (aa->getLValue().getArrayIndex().containsVariables()) { + onlyConstantIndices = false; + break; + } + } + if (onlyConstantIndices) { + for (auto const& aa : arrayAccesses) { + LValue lvalue(*arrayVariableReplacements.at(aa->getLValue().getArrayIndex().evaluateAsInt())); + newAssignments.emplace_back(lvalue, aa->getAssignedExpression(), level); + } + } else { + for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { + storm::expressions::Expression assignedExpression = arrayVariableReplacements[index]->getExpressionVariable().getExpression(); + auto indexExpression = expressionManager.integer(index); + for (auto const& aa : arrayAccesses) { + assignedExpression = storm::expressions::ite(aa->getLValue().getArrayIndex() == indexExpression, aa->getAssignedExpression(), assignedExpression); + newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), assignedExpression, level); + } + } + } + } + + storm::expressions::ExpressionManager& expressionManager; + bool const keepNonTrivialArrayAccess; }; - class ArrayAccessLValueReplacer : public JaniTraverser { - } - */ - } + - ArrayEliminator::eliminate(Model& model) { - //auto variableReplacements ArrayVariableReplacer().replace(model) + } // namespace detail + ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { + auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); + ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess).replace(model, sizes); + + model.finalize(); + return result; } } } diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.h b/src/storm/storage/jani/traverser/ArrayEliminator.h index 775909e1c..4193d96fc 100644 --- a/src/storm/storage/jani/traverser/ArrayEliminator.h +++ b/src/storm/storage/jani/traverser/ArrayEliminator.h @@ -7,11 +7,17 @@ namespace storm { namespace jani { + + struct ArrayEliminatorData { + std::vector> eliminatedArrayVariables; + std::unordered_map> replacements; + }; + class ArrayEliminator { public: ArrayEliminator() = default; - void eliminate(Model& model); + ArrayEliminatorData eliminate(Model& model, bool keepNonTrivialArrayAccess = false); private: From c5a0a057c8de63150bdc9107bb1c8b69b9c1aa8e Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 7 Sep 2018 13:59:29 +0200 Subject: [PATCH 529/647] array elimination and assignment levels in janiNextStateGenerator --- .../generator/JaniNextStateGenerator.cpp | 223 ++++++++++++--- src/storm/generator/JaniNextStateGenerator.h | 11 +- .../jani/{traverser => }/ArrayEliminator.cpp | 267 +++++++++++++++--- .../jani/{traverser => }/ArrayEliminator.h | 0 src/storm/storage/jani/Model.cpp | 8 +- src/storm/storage/jani/Model.h | 5 +- src/storm/storage/jani/OrderedAssignments.cpp | 3 + .../expressions/ArrayAccessExpression.cpp | 3 +- .../jani/traverser/AssignmentLevelFinder.cpp | 19 ++ .../jani/traverser/AssignmentLevelFinder.h | 19 ++ .../jani/traverser/AssignmentsFinder.cpp | 6 +- .../jani/traverser/AssignmentsFinder.h | 6 +- .../storage/jani/traverser/JaniTraverser.cpp | 122 ++++---- .../storage/jani/traverser/JaniTraverser.h | 80 +++--- 14 files changed, 585 insertions(+), 187 deletions(-) rename src/storm/storage/jani/{traverser => }/ArrayEliminator.cpp (52%) rename src/storm/storage/jani/{traverser => }/ArrayEliminator.h (100%) create mode 100644 src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp create mode 100644 src/storm/storage/jani/traverser/AssignmentLevelFinder.h diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index cf7a7b43e..6bba78c1a 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -14,6 +14,7 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" +#include "storm/storage/jani/traverser/AssignmentLevelFinder.h" #include "storm/storage/sparse/JaniChoiceOrigins.h" @@ -26,6 +27,7 @@ #include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace generator { @@ -38,12 +40,16 @@ namespace storm { template JaniNextStateGenerator::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator(model.getExpressionManager(), options), model(model), rewardVariables(), hasStateActionRewards(false) { STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); - STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support assignment levels."); STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); - // Lift the transient edge destinations. We can do so, as we know that there are no assignment levels (because that's not supported anyway). + if (this->model.containsArrayVariables()) { + arrayEliminatorData = this->model.eliminateArrays(true); + } + + // Lift the transient edge destinations of the first assignment level. + uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); if (this->model.hasTransientEdgeDestinationAssignments()) { - this->model.liftTransientEdgeDestinationAssignments(); + this->model.liftTransientEdgeDestinationAssignments(lowestAssignmentLevel); } STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support transient edge destination assignments."); @@ -54,6 +60,34 @@ namespace storm { this->checkValid(); this->variableInformation = VariableInformation(model, this->parallelAutomata, options.isAddOutOfBoundsStateSet()); + // Find for each replaced array variable the corresponding references in the variable information + for (auto const& arrayReplacements : arrayEliminatorData.replacements) { + std::vector varInfoIndices; + for (auto const& replacedVar : arrayReplacements.second) { + if (replacedVar->getExpressionVariable().hasIntegerType()) { + uint64_t index = 0; + for (auto const& intInfo : this->variableInformation.integerVariables) { + if (intInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + } else if (replacedVar->getExpressionVariable().hasBooleanType()) { + uint64_t index = 0; + for (auto const& boolInfo : this->variableInformation.booleanVariables) { + if (boolInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + } + ++index; + } + } else { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); + } + } + arrayVariableToElementInformations.emplace(arrayReplacements.first, std::move(varInfoIndices)); + } + // Create a proper evalator. this->evaluator = std::make_unique>(model.getManager()); @@ -230,7 +264,7 @@ namespace storm { } template - CompressedState JaniNextStateGenerator::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable) { + CompressedState JaniNextStateGenerator::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable, uint64_t assignmentLevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator) { CompressedState newState(state); // Update the location of the state. @@ -240,22 +274,28 @@ namespace storm { auto assignmentIt = destination.getOrderedAssignments().getNonTransientAssignments().begin(); auto assignmentIte = destination.getOrderedAssignments().getNonTransientAssignments().end(); + if (assignmentLevel > 0) { + while (assignmentIt != assignmentIte && assignmentIt->getLevel() < assignmentLevel) { + ++assignmentIt; + } + } + // Iterate over all boolean assignments and carry them out. auto boolIt = this->variableInformation.booleanVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasBooleanType(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasBooleanType() && assignmentIt->getLevel() == assignmentLevel && assignmentIt->getLValue().isVariable(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != boolIt->variable) { ++boolIt; } - newState.set(boolIt->bitOffset, this->evaluator->asBool(assignmentIt->getAssignedExpression())); + newState.set(boolIt->bitOffset, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); } // Iterate over all integer assignments and carry them out. auto integerIt = this->variableInformation.integerVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasIntegerType(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasIntegerType() && assignmentIt->getLevel() == assignmentLevel && assignmentIt->getLValue().isVariable(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != integerIt->variable) { ++integerIt; } - int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getAssignedExpression()); + int_fast64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); if (this->options.isAddOutOfBoundsStateSet()) { if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) { return this->outOfBoundsState; @@ -268,10 +308,36 @@ namespace storm { newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); STORM_LOG_ASSERT(static_cast(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); } + // Iterate over all array access assignments and carry them out. + for (; assignmentIt != assignmentIte && assignmentIt->getLValue().isArrayAccess() && assignmentIt->getLevel() == assignmentLevel; ++assignmentIt) { + int_fast64_t arrayIndex = expressionEvaluator.asInt(assignmentIt->getLValue().getArrayIndex()); + if (assignmentIt->getAssignedExpression().hasIntegerType()) { + std::vector const& intInfoIndices = arrayVariableToElementInformations.at(assignmentIt->getLValue().getArray().getExpressionVariable()); + STORM_LOG_THROW(arrayIndex < intInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access " << assignmentIt->getLValue() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << intInfoIndices.size()); + IntegerVariableInformation const& intInfo = this->variableInformation.integerVariables[intInfoIndices[arrayIndex]]; + int_fast64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < intInfo.lowerBound || assignedValue > intInfo.upperBound) { + return this->outOfBoundsState; + } + } else if (this->options.isExplorationChecksSet()) { + STORM_LOG_THROW(assignedValue >= intInfo.lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + STORM_LOG_THROW(assignedValue <= intInfo.upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + } + newState.setFromInt(intInfo.bitOffset, intInfo.bitWidth, assignedValue - intInfo.lowerBound); + STORM_LOG_ASSERT(static_cast(newState.getAsInt(intInfo.bitOffset, intInfo.bitWidth)) + intInfo.lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(intInfo.bitOffset, intInfo.bitWidth) << " but wrote " << assignedValue << ")."); + } else if (assignmentIt->getAssignedExpression().hasBooleanType()) { + std::vector const& boolInfoIndices = arrayVariableToElementInformations.at(assignmentIt->getLValue().getArray().getExpressionVariable()); + STORM_LOG_THROW(arrayIndex < boolInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access " << assignmentIt->getLValue() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << boolInfoIndices.size()); + BooleanVariableInformation const& boolInfo = this->variableInformation.booleanVariables[boolInfoIndices[arrayIndex]]; + newState.set(boolInfo.bitOffset, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); + } else { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); + } + } // Check that we processed all assignments. - STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); - + STORM_LOG_ASSERT(assignmentIt == assignmentIte || assignmentIt->getLevel() > assignmentLevel, "Not all assignments were consumed."); return newState; } @@ -389,9 +455,16 @@ namespace storm { if (probability != storm::utility::zero()) { // Obtain target state index and add it to the list of known states. If it has not yet been // seen, we also add it to the set of states that have yet to be explored. - auto newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex]); - - StateType stateIndex = stateToIdCallback(applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex])); + uint64_t assignmentLevel = edge.getLowestAssignmentLevel(); // Might be the largest possible integer, if there is no assignment + uint64_t const& highestLevel = edge.getHighestAssignmentLevel(); + CompressedState newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, *this->evaluator); + while (assignmentLevel < highestLevel) { + ++assignmentLevel; + auto nextLevelEvaluator = storm::expressions::ExpressionEvaluator(model.getManager()); + unpackStateIntoEvaluator(newState, this->variableInformation, nextLevelEvaluator); + newState = applyUpdate(newState, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, nextLevelEvaluator); + } + StateType stateIndex = stateToIdCallback(newState); // Update the choice by adding the probability/target state to it. probability = exitRate ? exitRate.get() * probability : probability; @@ -441,42 +514,107 @@ namespace storm { currentDistribution.add(state, storm::utility::one()); EdgeIndexSet edgeIndices; + uint64_t assignmentLevel = std::numeric_limits::max(); + uint64_t highestLevel = 0; for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { - auto const& indexAndEdge = *iteratorList[i]; - if (this->getOptions().isBuildChoiceOriginsSet()) { - edgeIndices.insert(model.encodeAutomatonAndEdgeIndices(edgeCombination[i].first, indexAndEdge.first)); + edgeIndices.insert(model.encodeAutomatonAndEdgeIndices(edgeCombination[i].first, iteratorList[i]->first)); } - - storm::jani::Edge const& edge = *indexAndEdge.second; - - for (auto const& destination : edge.getDestinations()) { - for (auto const& stateProbability : currentDistribution) { - // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(stateProbability.getState(), destination, this->variableInformation.locationVariables[edgeCombination[i].first]); - - // If the new state was already found as a successor state, update the probability - // and otherwise insert it. - ValueType probability = stateProbability.getValue() * this->evaluator->asRational(destination.getProbability()); + assignmentLevel = std::min(assignmentLevel, iteratorList[i]->second->getLowestAssignmentLevel()); + highestLevel = std::max(highestLevel, iteratorList[i]->second->getHighestAssignmentLevel()); + } + + if (assignmentLevel >= highestLevel) { + // When all assignments have the same level, we can perform the assignments of the different automata sequentially + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + auto const& indexAndEdge = *iteratorList[i]; + storm::jani::Edge const& edge = *indexAndEdge.second; + + for (auto const& destination : edge.getDestinations()) { + for (auto const& stateProbability : currentDistribution) { + // Compute the new state under the current update and add it to the set of new target states. + CompressedState newTargetState = applyUpdate(stateProbability.getState(), destination, this->variableInformation.locationVariables[edgeCombination[i].first], assignmentLevel, *this->evaluator); + + // If the new state was already found as a successor state, update the probability + // and otherwise insert it. + ValueType probability = stateProbability.getValue() * this->evaluator->asRational(destination.getProbability()); + if (edge.hasRate()) { + probability *= this->evaluator->asRational(edge.getRate()); + } + if (probability != storm::utility::zero()) { + nextDistribution.add(newTargetState, probability); + } + } + } + + // Create the state-action reward for the newly created choice. + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + + nextDistribution.compress(); + + // If there is one more command to come, shift the target states one time step back. + if (i < iteratorList.size() - 1) { + currentDistribution = std::move(nextDistribution); + } + } + } else { + // If there are different assignment levels, we need to expand the possible destinations which causes an exponential blowup... + uint64_t destinationId = 0; + bool lastDestinationId = false; + do { + + // First assignment level + std::vector destinations; + std::vector locationVars; + destinations.reserve(iteratorList.size()); + locationVars.reserve(iteratorList.size()); + CompressedState successorState = state; + ValueType successorProbability = storm::utility::one(); + + uint64_t destinationIndex = destinationId; + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + storm::jani::Edge const& edge = *iteratorList[i]->second; + destinations.push_back(&edge.getDestination(destinationIndex % edge.getNumberOfDestinations())); + locationVars.push_back(&this->variableInformation.locationVariables[edgeCombination[i].first]); + std::cout << destinationIndex % edge.getNumberOfDestinations(); + if (i == iteratorList.size() - 1 && (destinationIndex % edge.getNumberOfDestinations()) == edge.getNumberOfDestinations() - 1) { + lastDestinationId = true; + } + destinationIndex /= edge.getNumberOfDestinations(); + ValueType probability = this->evaluator->asRational(destinations.back()->getProbability()); if (edge.hasRate()) { - probability *= this->evaluator->asRational(edge.getRate()); + successorProbability *= probability * this->evaluator->asRational(edge.getRate()); + } else { + successorProbability *= probability; } - if (probability != storm::utility::zero()) { - nextDistribution.add(newTargetState, probability); + if (storm::utility::isZero(successorProbability)) { + break; } + // Create the state-action reward for the newly created choice. + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + successorState = applyUpdate(successorState, *destinations.back(), *locationVars.back(), assignmentLevel, *this->evaluator); } - } - - // Create the state-action reward for the newly created choice. - auto valueIt = stateActionRewards.begin(); - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); - - nextDistribution.compress(); - - // If there is one more command to come, shift the target states one time step back. - if (i < iteratorList.size() - 1) { - currentDistribution = std::move(nextDistribution); - } + + if (!storm::utility::isZero(successorProbability)) { + // remaining assignment levels + while (assignmentLevel < highestLevel) { + ++assignmentLevel; + auto currentLevelEvaluator = storm::expressions::ExpressionEvaluator(model.getManager()); + unpackStateIntoEvaluator(successorState, this->variableInformation, currentLevelEvaluator); + auto locationVarIt = locationVars.begin(); + for (auto const& destPtr : destinations) { + successorState = applyUpdate(successorState, *destPtr, **locationVarIt, assignmentLevel, currentLevelEvaluator); + ++locationVarIt; + } + } + nextDistribution.add(successorState, successorProbability); + } + + ++destinationId; + } while (!lastDestinationId); + std::cout << std::endl; } // At this point, we applied all commands of the current command combination and newTargetStates @@ -664,6 +802,7 @@ namespace storm { auto rewardVariableIt = rewardVariables.begin(); auto rewardVariableIte = rewardVariables.end(); for (auto const& assignment : transientAssignments) { + STORM_LOG_ASSERT(assignment.getLValue().isVariable(), "Transient assignments to non-variable LValues are not supported."); while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { callback(storm::utility::zero()); ++rewardVariableIt; diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index bd6b0c922..c80452f8c 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -5,6 +5,7 @@ #include "storm/generator/NextStateGenerator.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/OrderedAssignments.h" namespace storm { @@ -66,9 +67,10 @@ namespace storm { * @params state The state to which to apply the new values. * @params update The update to apply. * @params locationVariable The location variable that is being updated. + * @params assignmentLevel The assignmentLevel that is to be considered for the update. * @return The resulting state. */ - CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable); + CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable, uint64_t assignmentlevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator); /*! * Retrieves all choices possible from the given state. @@ -137,6 +139,13 @@ namespace storm { /// A flag that stores whether at least one of the selected reward models has state-action rewards. bool hasStateActionRewards; + + /// Data from eliminating arrays + storm::jani::ArrayEliminatorData arrayEliminatorData; + + /// Maps each array variable to the index of the base variable in this->variableInformation + std::unordered_map> arrayVariableToElementInformations; + }; } diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp similarity index 52% rename from src/storm/storage/jani/traverser/ArrayEliminator.cpp rename to src/storm/storage/jani/ArrayEliminator.cpp index 15da40a42..fb50de59f 100644 --- a/src/storm/storage/jani/traverser/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -1,4 +1,4 @@ -#include "storm/storage/jani/traverser/ArrayEliminator.h" +#include "storm/storage/jani/ArrayEliminator.h" #include @@ -10,6 +10,7 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace jani { @@ -105,11 +106,188 @@ namespace storm { } virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { - STORM_LOG_WARN("Array access expression on rhs of array assignment. This is not expected since nested arrays are currently not supported."); + STORM_LOG_WARN("Found Array access expression within an array expression. This is not expected since nested arrays are currently not supported."); return 0; } }; + class ArrayExpressionEliminationVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + typedef std::shared_ptr BaseExprPtr; + + ArrayExpressionEliminationVisitor(std::unordered_map> const& replacements, std::unordered_map const& sizes) : replacements(replacements), arraySizes(sizes) {} + virtual ~ArrayExpressionEliminationVisitor() = default; + + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression, storm::expressions::Expression const& outOfBoundsExpression) { + auto res = eliminate(expression, false); + if (outOfBoundsError) { + return outOfBoundsExpression; + } else { + return res; + } + } + + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression, bool failIfOutOfBounds = true) { + outOfBoundsError = false; + // here, data is the accessed index of the most recent array access expression. Initially, there is none. + auto res = storm::expressions::Expression(boost::any_cast(expression.accept(*this, boost::any()))); + STORM_LOG_THROW(!failIfOutOfBounds || !outOfBoundsError, storm::exceptions::UnexpectedException, "Out of bounds array access occured while eliminating expression " << expression); + return res.simplify(); + } + + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + // for the condition expression, outer array accesses should not matter. + BaseExprPtr conditionExpression = boost::any_cast(expression.getCondition()->accept(*this, boost::any())); + BaseExprPtr thenExpression = boost::any_cast(expression.getThenExpression()->accept(*this, data)); + BaseExprPtr elseExpression = boost::any_cast(expression.getElseExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::IfThenElseExpression(expression.getManager(), thenExpression->getType(), conditionExpression, thenExpression, elseExpression))); + } + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryBooleanFunctionExpressions should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryNumericalFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryRelationExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); + } + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { + if (expression.getType().isArrayType()) { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate array variable to basic variable, since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + STORM_LOG_ASSERT(replacements.find(expression.getVariable()) != replacements.end(), "Unable to find array variable " << expression << " in array replacements."); + auto const& arrayVarReplacements = replacements.at(expression.getVariable()); + STORM_LOG_ASSERT(index < arrayVarReplacements.size(), "No replacement for array variable, since index " << index << " is out of bounds."); + return arrayVarReplacements[index]->getExpressionVariable().getExpression().getBaseExpressionPointer(); + } else { + return expression.getSharedPointer(); + } + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "UnaryBooleanFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "UnaryBooleanFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate ValueArrayExpression to element expression since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + if (index < static_cast(expression.size()->evaluateAsInt())) { + return expression.at(index); + } else { + outOfBoundsError = true; + return expression.at(0); + } + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate ValueArrayExpression to element expression since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + if (expression.size()->containsVariables()) { + STORM_LOG_WARN("Ignoring length of constructorArrayExpression " << expression << " as it still contains variables."); + } else if (index >= static_cast(expression.size()->evaluateAsInt())) { + outOfBoundsError = true; + } + return expression.at(index); + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + if (expression.getSecondOperand()->containsVariables()) { + //get the size of the array expression + uint64_t size = MaxArraySizeExpressionVisitor().getMaxSize(expression.getFirstOperand()->toExpression(), arraySizes); + STORM_LOG_THROW(size > 0, storm::exceptions::NotSupportedException, "Unable to get size of array expression for array access " << expression << "."); + uint64_t index = size - 1; + storm::expressions::Expression result = boost::any_cast(expression.getFirstOperand()->accept(*this, index))->toExpression(); + while (index > 0) { + --index; + result = storm::expressions::ite( + expression.getSecondOperand()->toExpression() == expression.getManager().integer(index), + boost::any_cast(expression.getFirstOperand()->accept(*this, index))->toExpression(), + result); + } + return result.getBaseExpressionPointer(); + } else { + uint64_t index = expression.getSecondOperand()->evaluateAsInt(); + return boost::any_cast(expression.getFirstOperand()->accept(*this, index)); + } + } + + private: + std::unordered_map> const& replacements; + std::unordered_map const& arraySizes; + bool outOfBoundsError; + }; + class MaxArraySizeDeterminer : public ConstJaniTraverser { public: @@ -127,7 +305,7 @@ namespace storm { return result; } - virtual void traverse(Assignment const& assignment, boost::any const& data) const override { + virtual void traverse(Assignment const& assignment, boost::any const& data) override { if (assignment.lValueIsVariable() && assignment.getExpressionVariable().getType().isArrayType()) { auto& map = *boost::any_cast(data); std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(assignment.getAssignedExpression(), map); @@ -138,7 +316,7 @@ namespace storm { } } - virtual void traverse(ArrayVariable const& variable, boost::any const& data) const override { + virtual void traverse(ArrayVariable const& variable, boost::any const& data) override { if (variable.hasInitExpression()) { auto& map = *boost::any_cast(data); std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(variable.getInitExpression(), map); @@ -156,19 +334,21 @@ namespace storm { typedef ArrayEliminatorData ResultType; - ArrayVariableReplacer(storm::expressions::ExpressionManager& expressionManager, bool keepNonTrivialArrayAccess) : expressionManager(expressionManager) , keepNonTrivialArrayAccess(keepNonTrivialArrayAccess) {} + ArrayVariableReplacer(storm::expressions::ExpressionManager& expressionManager, bool keepNonTrivialArrayAccess, std::unordered_map const& arrayVarToSizesMap) : expressionManager(expressionManager) , keepNonTrivialArrayAccess(keepNonTrivialArrayAccess), arraySizes(arrayVarToSizesMap) {} virtual ~ArrayVariableReplacer() = default; - ResultType replace(Model& model, std::unordered_map const& arrayVarToSizesMap) { + ResultType replace(Model& model) { + ResultType result; - for (auto const& arraySize : arrayVarToSizesMap) { + arrayExprEliminator = std::make_unique(result.replacements, arraySizes); + for (auto const& arraySize : arraySizes) { result.replacements.emplace(arraySize.first, std::vector(arraySize.second, nullptr)); } traverse(model, &result); return result; } - virtual void traverse(Model& model, boost::any const& data) const override { + virtual void traverse(Model& model, boost::any const& data) override { // Insert fresh basic variables for global array variables auto& replacements = boost::any_cast(data)->replacements; @@ -183,20 +363,20 @@ namespace storm { auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + // Make new variable replacements known to the expression eliminator + arrayExprEliminator = std::make_unique(replacements, arraySizes); + for (auto& aut : model.getAutomata()) { traverse(aut, data); } - // traverse remaining components - for (auto& c : model.getConstants()) { - traverse(c, data); - } + // traversal of remaining components if (model.hasInitialStatesRestriction()) { - //model.setInitialStatesRestriction(); + model.setInitialStatesRestriction(arrayExprEliminator->eliminate(model.getInitialStatesRestriction())); } } - virtual void traverse(Automaton& automaton, boost::any const& data) const override { + virtual void traverse(Automaton& automaton, boost::any const& data) override { // No need to traverse the init restriction. // Insert fresh basic variables for local array variables @@ -212,23 +392,23 @@ namespace storm { auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + // Make new variable replacements known to the expression eliminator + arrayExprEliminator = std::make_unique(replacements, arraySizes); + for (auto& loc : automaton.getLocations()) { JaniTraverser::traverse(loc, data); } JaniTraverser::traverse(automaton.getEdgeContainer(), data); - } - - void traverse(Constant& constant, boost::any const& data) const { - if (constant.isDefined()) { - // todo: - //traverse(constant.getExpression(), data); + + if (automaton.hasInitialStatesRestriction()) { + automaton.setInitialStatesRestriction(arrayExprEliminator->eliminate(automaton.getInitialStatesRestriction())); } } - - virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const override { + + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) override { auto const& replacements = boost::any_cast(data)->replacements; - // Replace array occurrences in LValues. + // Replace array occurrences in LValues and assigned expressions. std::vector newAssignments; uint64_t level = 0; std::unordered_map> collectedArrayAccessAssignments; @@ -253,12 +433,14 @@ namespace storm { STORM_LOG_ASSERT(assignment.getAssignedExpression().getType().isArrayType(), "Assigning a non-array expression to an array variable..."); std::vector const& arrayVariableReplacements = replacements.at(assignment.getExpressionVariable()); for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { - auto arrayAccessExpression = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer()); - newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), arrayAccessExpression->toExpression(), level); + auto const& replacement = *arrayVariableReplacements[index]; + auto arrayAccessExpression = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); + arrayAccessExpression = arrayExprEliminator->eliminate(arrayAccessExpression, getOutOfBoundsValue(replacement)); + newAssignments.emplace_back(LValue(replacement), arrayAccessExpression, level); } continue; } - newAssignments.push_back(assignment); + newAssignments.emplace_back(assignment.getLValue(), arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); } for (auto const& arrayAssignments : collectedArrayAccessAssignments) { insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); @@ -276,7 +458,7 @@ namespace storm { std::string name = arrayVariable.getExpressionVariable().getName() + "_at_" + std::to_string(index); storm::expressions::Expression initValue; if (arrayVariable.hasInitExpression()) { - initValue = std::make_shared(expressionManager, arrayVariable.getExpressionVariable().getType().getElementType(), arrayVariable.getInitExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); + initValue = arrayExprEliminator->eliminate(std::make_shared(expressionManager, arrayVariable.getExpressionVariable().getType().getElementType(), arrayVariable.getInitExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression()); } if (arrayVariable.getElementType() == ArrayVariable::ElementType::Int) { storm::expressions::Variable exprVariable = expressionManager.declareIntegerVariable(name); @@ -324,31 +506,50 @@ namespace storm { if (onlyConstantIndices) { for (auto const& aa : arrayAccesses) { LValue lvalue(*arrayVariableReplacements.at(aa->getLValue().getArrayIndex().evaluateAsInt())); - newAssignments.emplace_back(lvalue, aa->getAssignedExpression(), level); + newAssignments.emplace_back(lvalue, arrayExprEliminator->eliminate(aa->getAssignedExpression()), level); } } else { for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { storm::expressions::Expression assignedExpression = arrayVariableReplacements[index]->getExpressionVariable().getExpression(); auto indexExpression = expressionManager.integer(index); for (auto const& aa : arrayAccesses) { - assignedExpression = storm::expressions::ite(aa->getLValue().getArrayIndex() == indexExpression, aa->getAssignedExpression(), assignedExpression); + assignedExpression = storm::expressions::ite(aa->getLValue().getArrayIndex() == indexExpression, arrayExprEliminator->eliminate(aa->getAssignedExpression()), assignedExpression); newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), assignedExpression, level); } } } } + storm::expressions::Expression getOutOfBoundsValue(Variable const& var) const { + if (var.hasInitExpression()) { + return var.getInitExpression(); + } + if (var.isBooleanVariable()) { + return expressionManager.boolean(false); + } + if (var.isBoundedIntegerVariable()) { + return var.asBoundedIntegerVariable().getLowerBound(); + } + if (var.isUnboundedIntegerVariable()) { + return expressionManager.integer(0); + } + if (var.isRealVariable()) { + return expressionManager.rational(0.0); + } + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unhandled variabe type"); + return storm::expressions::Expression(); + } + + std::unique_ptr arrayExprEliminator; storm::expressions::ExpressionManager& expressionManager; bool const keepNonTrivialArrayAccess; + std::unordered_map const& arraySizes; }; - - - } // namespace detail ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); - ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess).replace(model, sizes); + ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); model.finalize(); return result; diff --git a/src/storm/storage/jani/traverser/ArrayEliminator.h b/src/storm/storage/jani/ArrayEliminator.h similarity index 100% rename from src/storm/storage/jani/traverser/ArrayEliminator.h rename to src/storm/storage/jani/ArrayEliminator.h diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 502c821c0..6ff5cd28a 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -946,9 +946,13 @@ namespace storm { return false; } - void Model::eliminateArrays(bool keepNonTrivialArrayAccess) { + ArrayEliminatorData Model::eliminateArrays(bool keepNonTrivialArrayAccess) { ArrayEliminator arrayEliminator; - arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess); + return arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess); + } + + void Model::eliminateArrays() { + eliminateArrays(false); } void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 7ccc011a4..937f58f42 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -33,6 +33,7 @@ namespace storm { class Automaton; class Exporter; class SynchronizationVector; + class ArrayEliminatorData; class Model { public: @@ -365,8 +366,10 @@ namespace storm { /*! * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. * @param keepNonTrivialArrayAccess if set, array access expressions in LValues and expressions are only replaced, if the index expression is constant. + * @return data from the elimination. If non-trivial array accesses are kept, pointers to remaining array variables point to this data. */ - void eliminateArrays(bool keepNonTrivialArrayAccess = false); + ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess); + void eliminateArrays(); /*! * Retrieves whether there is an expression restricting the legal initial values of the global variables. diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 11f59a5d0..c81e7df0d 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -185,6 +185,9 @@ namespace storm { std::vector newAssignments; for (auto const& assignment : allAssignments) { newAssignments.push_back(*assignment); + if (assignment->isTransient() && !assignment->getAssignedExpression().containsVariables()) { + // Since we do not support + } if (synchronous && !localVars.hasVariable(assignment->getLValue().isVariable() ? assignment->getLValue().getVariable() : assignment->getLValue().getArray())) { continue; } diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp index 1f3980fc9..6590845db 100644 --- a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp @@ -19,6 +19,7 @@ namespace storm { boost::any ArrayAccessExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_ASSERT(janiVisitor != nullptr, "Visitor of jani expression should be of type JaniVisitor."); STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); return janiVisitor->visit(*this, data); } @@ -29,7 +30,7 @@ namespace storm { } else { stream << "(" << *getFirstOperand() << ")"; } - stream << "[" << getSecondOperand() << "]"; + stream << "[" << *getSecondOperand() << "]"; } } } \ No newline at end of file diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp new file mode 100644 index 000000000..442ba4bd4 --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp @@ -0,0 +1,19 @@ +#include "storm/storage/jani/traverser/AssignmentLevelFinder.h" + + +namespace storm { + namespace jani { + + uint64_t AssignmentLevelFinder::getLowestAssignmentLevel(Model const& model) { + uint64_t res = std::numeric_limits::max(); + ConstJaniTraverser::traverse(model, &res); + return res; + } + + void AssignmentLevelFinder::traverse(Assignment const& assignment, boost::any const& data) { + auto& res = *boost::any_cast(data); + res = std::min(res, assignment.getLevel()); + } + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.h b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h new file mode 100644 index 000000000..7a5a4a4fc --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h @@ -0,0 +1,19 @@ +#pragma once + +#include "storm/storage/jani/traverser/JaniTraverser.h" + +namespace storm { + namespace jani { + class AssignmentLevelFinder : public ConstJaniTraverser { + public: + + AssignmentLevelFinder() = default; + virtual ~AssignmentLevelFinder() = default; + + uint64_t getLowestAssignmentLevel(Model const& model); + + virtual void traverse(Assignment const& assignment, boost::any const& data) override; + }; + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp index 8ad36776b..db7cfccf8 100644 --- a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp @@ -13,7 +13,7 @@ namespace storm { return res; } - void AssignmentsFinder::traverse(Location const& location, boost::any const& data) const { + void AssignmentsFinder::traverse(Location const& location, boost::any const& data) { auto resVar = boost::any_cast>(data); for (auto const& assignment : location.getAssignments()) { if (assignment.getVariable() == *resVar.first) { @@ -23,7 +23,7 @@ namespace storm { ConstJaniTraverser::traverse(location, data); } - void AssignmentsFinder::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { + void AssignmentsFinder::traverse(TemplateEdge const& templateEdge, boost::any const& data) { auto resVar = boost::any_cast>(data); for (auto const& assignment : templateEdge.getAssignments()) { if (assignment.getVariable() == *resVar.first) { @@ -33,7 +33,7 @@ namespace storm { ConstJaniTraverser::traverse(templateEdge, data); } - void AssignmentsFinder::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { + void AssignmentsFinder::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) { auto resVar = boost::any_cast>(data); for (auto const& assignment : templateEdgeDestination.getOrderedAssignments()) { if (assignment.getVariable() == *resVar.first) { diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.h b/src/storm/storage/jani/traverser/AssignmentsFinder.h index b6bcd376e..514d29208 100644 --- a/src/storm/storage/jani/traverser/AssignmentsFinder.h +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.h @@ -20,9 +20,9 @@ namespace storm { virtual ~AssignmentsFinder() = default; - virtual void traverse(Location const& location, boost::any const& data) const override; - virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const override; - virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const override; + virtual void traverse(Location const& location, boost::any const& data) override; + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) override; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) override; }; } } diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp index bd1b9bbf1..787682ede 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.cpp +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -4,7 +4,7 @@ namespace storm { namespace jani { - void JaniTraverser::traverse(Model& model, boost::any const& data) const { + void JaniTraverser::traverse(Model& model, boost::any const& data) { for (auto& act : model.getActions()) { traverse(act, data); } @@ -20,11 +20,11 @@ namespace storm { } } - void JaniTraverser::traverse(Action const& action, boost::any const& data) const { + void JaniTraverser::traverse(Action const& action, boost::any const& data) { // Intentionally left empty. } - - void JaniTraverser::traverse(Automaton& automaton, boost::any const& data) const { + + void JaniTraverser::traverse(Automaton& automaton, boost::any const& data) { traverse(automaton.getVariables(), data); for (auto& loc : automaton.getLocations()) { traverse(loc, data); @@ -34,14 +34,14 @@ namespace storm { traverse(automaton.getInitialStatesRestriction(), data); } } - - void JaniTraverser::traverse(Constant& constant, boost::any const& data) const { + + void JaniTraverser::traverse(Constant& constant, boost::any const& data) { if (constant.isDefined()) { traverse(constant.getExpression(), data); } } - - void JaniTraverser::traverse(VariableSet& variableSet, boost::any const& data) const { + + void JaniTraverser::traverse(VariableSet& variableSet, boost::any const& data) { for (auto& v : variableSet.getBooleanVariables()) { traverse(v, data); } @@ -58,18 +58,18 @@ namespace storm { traverse(v, data); } } - - void JaniTraverser::traverse(Location& location, boost::any const& data) const { + + void JaniTraverser::traverse(Location& location, boost::any const& data) { traverse(location.getAssignments(), data); } - - void JaniTraverser::traverse(BooleanVariable& variable, boost::any const& data) const { + + void JaniTraverser::traverse(BooleanVariable& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(BoundedIntegerVariable& variable, boost::any const& data) const { + void JaniTraverser::traverse(BoundedIntegerVariable& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } @@ -77,19 +77,19 @@ namespace storm { traverse(variable.getUpperBound(), data); } - void JaniTraverser::traverse(UnboundedIntegerVariable& variable, boost::any const& data) const { + void JaniTraverser::traverse(UnboundedIntegerVariable& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(RealVariable& variable, boost::any const& data) const { + void JaniTraverser::traverse(RealVariable& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void JaniTraverser::traverse(ArrayVariable& variable, boost::any const& data) const { + void JaniTraverser::traverse(ArrayVariable& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } @@ -99,7 +99,7 @@ namespace storm { } } - void JaniTraverser::traverse(EdgeContainer& edgeContainer, boost::any const& data) const { + void JaniTraverser::traverse(EdgeContainer& edgeContainer, boost::any const& data) { for (auto& templateEdge : edgeContainer.getTemplateEdges()) { traverse(*templateEdge, data); } @@ -108,19 +108,19 @@ namespace storm { } } - void JaniTraverser::traverse(TemplateEdge& templateEdge, boost::any const& data) const { + void JaniTraverser::traverse(TemplateEdge& templateEdge, boost::any const& data) { traverse(templateEdge.getGuard(), data); for (auto& dest : templateEdge.getDestinations()) { traverse(dest, data); } traverse(templateEdge.getAssignments(), data); } - - void JaniTraverser::traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) const { + + void JaniTraverser::traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) { traverse(templateEdgeDestination.getOrderedAssignments(), data); } - - void JaniTraverser::traverse(Edge& edge, boost::any const& data) const { + + void JaniTraverser::traverse(Edge& edge, boost::any const& data) { if (edge.hasRate()) { traverse(edge.getRate(), data); } @@ -128,34 +128,34 @@ namespace storm { traverse(dest, data); } } - - void JaniTraverser::traverse(EdgeDestination& edgeDestination, boost::any const& data) const { + + void JaniTraverser::traverse(EdgeDestination& edgeDestination, boost::any const& data) { traverse(edgeDestination.getProbability(), data); } - - void JaniTraverser::traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const { + + void JaniTraverser::traverse(OrderedAssignments& orderedAssignments, boost::any const& data) { for (auto& assignment : orderedAssignments) { traverse(assignment, data); } STORM_LOG_ASSERT(orderedAssignments.checkOrder(), "Order of ordered assignment has been violated."); } - - void JaniTraverser::traverse(Assignment& assignment, boost::any const& data) const { + + void JaniTraverser::traverse(Assignment& assignment, boost::any const& data) { traverse(assignment.getAssignedExpression(), data); traverse(assignment.getLValue(), data); } - void JaniTraverser::traverse(LValue& lValue, boost::any const& data) const { + void JaniTraverser::traverse(LValue& lValue, boost::any const& data) { if (lValue.isArrayAccess()) { traverse(lValue.getArrayIndex(), data); } } - void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { + void JaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) { // intentionally left empty. } - void ConstJaniTraverser::traverse(Model const& model, boost::any const& data) const { + void ConstJaniTraverser::traverse(Model const& model, boost::any const& data) { for (auto const& act : model.getActions()) { traverse(act, data); } @@ -171,11 +171,11 @@ namespace storm { } } - void ConstJaniTraverser::traverse(Action const& action, boost::any const& data) const { + void ConstJaniTraverser::traverse(Action const& action, boost::any const& data) { // Intentionally left empty. } - - void ConstJaniTraverser::traverse(Automaton const& automaton, boost::any const& data) const { + + void ConstJaniTraverser::traverse(Automaton const& automaton, boost::any const& data) { traverse(automaton.getVariables(), data); for (auto const& loc : automaton.getLocations()) { traverse(loc, data); @@ -185,14 +185,14 @@ namespace storm { traverse(automaton.getInitialStatesRestriction(), data); } } - - void ConstJaniTraverser::traverse(Constant const& constant, boost::any const& data) const { + + void ConstJaniTraverser::traverse(Constant const& constant, boost::any const& data) { if (constant.isDefined()) { traverse(constant.getExpression(), data); } } - - void ConstJaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) const { + + void ConstJaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) { for (auto const& v : variableSet.getBooleanVariables()) { traverse(v, data); } @@ -209,18 +209,18 @@ namespace storm { traverse(v, data); } } - - void ConstJaniTraverser::traverse(Location const& location, boost::any const& data) const { + + void ConstJaniTraverser::traverse(Location const& location, boost::any const& data) { traverse(location.getAssignments(), data); } - - void ConstJaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) const { + + void ConstJaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void ConstJaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } @@ -228,19 +228,19 @@ namespace storm { traverse(variable.getUpperBound(), data); } - void ConstJaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void ConstJaniTraverser::traverse(RealVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(RealVariable const& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } } - void ConstJaniTraverser::traverse(ArrayVariable const& variable, boost::any const& data) const { + void ConstJaniTraverser::traverse(ArrayVariable const& variable, boost::any const& data) { if (variable.hasInitExpression()) { traverse(variable.getInitExpression(), data); } @@ -250,7 +250,7 @@ namespace storm { } } - void ConstJaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) const { + void ConstJaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) { for (auto const& templateEdge : edgeContainer.getTemplateEdges()) { traverse(*templateEdge, data); } @@ -259,19 +259,19 @@ namespace storm { } } - void ConstJaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) const { + void ConstJaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) { traverse(templateEdge.getGuard(), data); for (auto const& dest : templateEdge.getDestinations()) { traverse(dest, data); } traverse(templateEdge.getAssignments(), data); } - - void ConstJaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const { + + void ConstJaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) { traverse(templateEdgeDestination.getOrderedAssignments(), data); } - - void ConstJaniTraverser::traverse(Edge const& edge, boost::any const& data) const { + + void ConstJaniTraverser::traverse(Edge const& edge, boost::any const& data) { if (edge.hasRate()) { traverse(edge.getRate(), data); } @@ -279,29 +279,29 @@ namespace storm { traverse(dest, data); } } - - void ConstJaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) const { + + void ConstJaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) { traverse(edgeDestination.getProbability(), data); } - - void ConstJaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const { + + void ConstJaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) { for (auto const& assignment : orderedAssignments) { traverse(assignment, data); } } - - void ConstJaniTraverser::traverse(Assignment const& assignment, boost::any const& data) const { + + void ConstJaniTraverser::traverse(Assignment const& assignment, boost::any const& data) { traverse(assignment.getAssignedExpression(), data); traverse(assignment.getLValue(), data); } - - void ConstJaniTraverser::traverse(LValue const& lValue, boost::any const& data) const { + + void ConstJaniTraverser::traverse(LValue const& lValue, boost::any const& data) { if (lValue.isArrayAccess()) { traverse(lValue.getArrayIndex(), data); } } - void ConstJaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) const { + void ConstJaniTraverser::traverse(storm::expressions::Expression const& expression, boost::any const& data) { // intentionally left empty. } diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h index 25cc4530d..685c76a85 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.h +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -11,54 +11,54 @@ namespace storm { public: virtual ~JaniTraverser() = default; - virtual void traverse(Model& model, boost::any const& data) const; + virtual void traverse(Model& model, boost::any const& data); - virtual void traverse(Action const& action, boost::any const& data) const; - virtual void traverse(Automaton& automaton, boost::any const& data) const; - virtual void traverse(Constant& constant, boost::any const& data) const; - virtual void traverse(VariableSet& variableSet, boost::any const& data) const; - virtual void traverse(Location& location, boost::any const& data) const; - virtual void traverse(BooleanVariable& variable, boost::any const& data) const; - virtual void traverse(BoundedIntegerVariable& variable, boost::any const& data) const; - virtual void traverse(UnboundedIntegerVariable& variable, boost::any const& data) const; - virtual void traverse(RealVariable& variable, boost::any const& data) const; - virtual void traverse(ArrayVariable& variable, boost::any const& data) const; - virtual void traverse(EdgeContainer& edgeContainer, boost::any const& data) const; - virtual void traverse(TemplateEdge& templateEdge, boost::any const& data) const; - virtual void traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) const; - virtual void traverse(Edge& edge, boost::any const& data) const; - virtual void traverse(EdgeDestination& edgeDestination, boost::any const& data) const; - virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) const; - virtual void traverse(Assignment& assignment, boost::any const& data) const; - virtual void traverse(LValue& lValue, boost::any const& data) const; - virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) const; + virtual void traverse(Action const& action, boost::any const& data); + virtual void traverse(Automaton& automaton, boost::any const& data); + virtual void traverse(Constant& constant, boost::any const& data); + virtual void traverse(VariableSet& variableSet, boost::any const& data); + virtual void traverse(Location& location, boost::any const& data); + virtual void traverse(BooleanVariable& variable, boost::any const& data); + virtual void traverse(BoundedIntegerVariable& variable, boost::any const& data); + virtual void traverse(UnboundedIntegerVariable& variable, boost::any const& data); + virtual void traverse(RealVariable& variable, boost::any const& data); + virtual void traverse(ArrayVariable& variable, boost::any const& data); + virtual void traverse(EdgeContainer& edgeContainer, boost::any const& data); + virtual void traverse(TemplateEdge& templateEdge, boost::any const& data); + virtual void traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data); + virtual void traverse(Edge& edge, boost::any const& data); + virtual void traverse(EdgeDestination& edgeDestination, boost::any const& data); + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data); + virtual void traverse(Assignment& assignment, boost::any const& data); + virtual void traverse(LValue& lValue, boost::any const& data); + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data); }; class ConstJaniTraverser { public: virtual ~ConstJaniTraverser() = default; - virtual void traverse(Model const& model, boost::any const& data) const; + virtual void traverse(Model const& model, boost::any const& data); - virtual void traverse(Action const& action, boost::any const& data) const; - virtual void traverse(Automaton const& automaton, boost::any const& data) const; - virtual void traverse(Constant const& constant, boost::any const& data) const; - virtual void traverse(VariableSet const& variableSet, boost::any const& data) const; - virtual void traverse(Location const& location, boost::any const& data) const; - virtual void traverse(BooleanVariable const& variable, boost::any const& data) const; - virtual void traverse(BoundedIntegerVariable const& variable, boost::any const& data) const; - virtual void traverse(UnboundedIntegerVariable const& variable, boost::any const& data) const; - virtual void traverse(RealVariable const& variable, boost::any const& data) const; - virtual void traverse(ArrayVariable const& variable, boost::any const& data) const; - virtual void traverse(EdgeContainer const& edgeContainer, boost::any const& data) const; - virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) const; - virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) const; - virtual void traverse(Edge const& edge, boost::any const& data) const; - virtual void traverse(EdgeDestination const& edgeDestination, boost::any const& data) const; - virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) const; - virtual void traverse(Assignment const& assignment, boost::any const& data) const; - virtual void traverse(LValue const& lValue, boost::any const& data) const; - virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) const; + virtual void traverse(Action const& action, boost::any const& data); + virtual void traverse(Automaton const& automaton, boost::any const& data); + virtual void traverse(Constant const& constant, boost::any const& data); + virtual void traverse(VariableSet const& variableSet, boost::any const& data); + virtual void traverse(Location const& location, boost::any const& data); + virtual void traverse(BooleanVariable const& variable, boost::any const& data); + virtual void traverse(BoundedIntegerVariable const& variable, boost::any const& data); + virtual void traverse(UnboundedIntegerVariable const& variable, boost::any const& data); + virtual void traverse(RealVariable const& variable, boost::any const& data); + virtual void traverse(ArrayVariable const& variable, boost::any const& data); + virtual void traverse(EdgeContainer const& edgeContainer, boost::any const& data); + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data); + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data); + virtual void traverse(Edge const& edge, boost::any const& data); + virtual void traverse(EdgeDestination const& edgeDestination, boost::any const& data); + virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any const& data); + virtual void traverse(Assignment const& assignment, boost::any const& data); + virtual void traverse(LValue const& lValue, boost::any const& data); + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data); }; } } From e2cb68b31f2338135e0b001fcd576a10053d9c5f Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 7 Sep 2018 13:59:49 +0200 Subject: [PATCH 530/647] Enable array elimination in jit builder --- src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp index 245e9d54d..9a7042d81 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp @@ -107,6 +107,10 @@ namespace storm { transientVariables.insert(variable.getExpressionVariable()); } + if (this->model.containsArrayVariables()) { + this->model.eliminateArrays(); + } + // Construct vector of the automata to be put in parallel. storm::jani::Composition const& topLevelComposition = this->model.getSystemComposition(); if (topLevelComposition.isAutomatonComposition()) { From 6aaafea55435b88b889c4330cf514ce11bf9e9bb Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 7 Sep 2018 16:36:05 +0200 Subject: [PATCH 531/647] added possibility to lift transient edge destination assignments to the edge by scaling with the probability (only if this preserves the considered properties). --- src/storm/builder/BuilderOptions.cpp | 16 ++- src/storm/builder/BuilderOptions.h | 16 ++- .../generator/JaniNextStateGenerator.cpp | 113 +++++++++++++----- src/storm/generator/JaniNextStateGenerator.h | 2 +- src/storm/storage/jani/OrderedAssignments.cpp | 52 ++++---- src/storm/storage/jani/OrderedAssignments.h | 5 + 6 files changed, 135 insertions(+), 69 deletions(-) diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index d4d729d21..271a4e873 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -1,6 +1,7 @@ #include "storm/builder/BuilderOptions.h" #include "storm/logic/Formulas.h" +#include "storm/logic/FragmentSpecification.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BuildSettings.h" @@ -36,7 +37,7 @@ namespace storm { return boost::get(labelOrExpression); } - BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), addOverlappingGuardsLabel(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) { + BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), scaleAndLiftTransitionRewards(true), explorationChecks(false), addOverlappingGuardsLabel(false), addOutOfBoundsState(false), showProgress(false), showProgressDelay(0) { // Intentionally left empty. } @@ -85,6 +86,10 @@ namespace storm { for (auto const& formula : atomicExpressionFormulas) { addLabel(formula->getExpression()); } + + storm::logic::FragmentSpecification transitionRewardScalingFragment = storm::logic::csl().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setLongRunAverageOperatorsAllowed(true).setMultiObjectiveFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setStepBoundedCumulativeRewardFormulasAllowed(true).setTimeBoundedCumulativeRewardFormulasAllowed(true); + scaleAndLiftTransitionRewards = scaleAndLiftTransitionRewards && formula.isInFragment(transitionRewardScalingFragment); + } void BuilderOptions::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { @@ -160,6 +165,10 @@ namespace storm { return buildAllLabels; } + bool BuilderOptions::isScaleAndLiftTransitionRewardsSet() const { + return scaleAndLiftTransitionRewards; + } + bool BuilderOptions::isAddOutOfBoundsStateSet() const { return addOutOfBoundsState; } @@ -237,6 +246,11 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::setScaleAndLiftTransitionRewards(bool newValue) { + scaleAndLiftTransitionRewards = newValue; + return *this; + } + BuilderOptions& BuilderOptions::setAddOutOfBoundsState(bool newValue) { addOutOfBoundsState = newValue; return *this; diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index 904d45de6..eba9ff1da 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -107,6 +107,7 @@ namespace storm { bool isBuildAllLabelsSet() const; bool isExplorationChecksSet() const; bool isShowProgressSet() const; + bool isScaleAndLiftTransitionRewardsSet() const; bool isAddOutOfBoundsStateSet() const; bool isAddOverlappingGuardLabelSet() const; uint64_t getShowProgressDelay() const; @@ -157,6 +158,13 @@ namespace storm { * @return this */ BuilderOptions& setExplorationChecks(bool newValue = true); + + /** + * Should extra checks be performed during exploration + * @param newValue The new value (default true) + * @return this + */ + BuilderOptions& setScaleAndLiftTransitionRewards(bool newValue = true); /** * Should a state for out of bounds be constructed @@ -191,16 +199,19 @@ namespace storm { /// If one of these labels/expressions evaluates to the given bool, the builder can abort the exploration. std::vector> terminalStates; - + /// A flag indicating whether or not to build choice labels. bool buildChoiceLabels; - + /// A flag indicating whether or not to build for each state the variable valuation from which it originates. bool buildStateValuations; // A flag that indicates whether or not to generate the information from which parts of the model specification // each choice originates. bool buildChoiceOrigins; + + /// A flag that stores whether potentially occurring transition rewards should be scaled and lifted to the edge + bool scaleAndLiftTransitionRewards; /// A flag that stores whether exploration checks are to be performed. bool explorationChecks; @@ -216,6 +227,7 @@ namespace storm { /// The delay for printing progress information. uint64_t showProgressDelay; + }; } diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 6bba78c1a..8f68f4c1c 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -42,6 +42,7 @@ namespace storm { STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); + // Eliminate arrays if necessary. if (this->model.containsArrayVariables()) { arrayEliminatorData = this->model.eliminateArrays(true); } @@ -50,8 +51,16 @@ namespace storm { uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); if (this->model.hasTransientEdgeDestinationAssignments()) { this->model.liftTransientEdgeDestinationAssignments(lowestAssignmentLevel); + if (this->model.hasTransientEdgeDestinationAssignments()) { + STORM_LOG_THROW(options.isScaleAndLiftTransitionRewardsSet(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support transient edge destination assignments."); + } else { + // There are no edge destination assignments so we turn the lifting to edges off. + this->options.setScaleAndLiftTransitionRewards(false); + } + } else { + // There are no edge destination assignments so we turn the lifting to edges off. + this->options.setScaleAndLiftTransitionRewards(false); } - STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support transient edge destination assignments."); // Create all synchronization-related information, e.g. the automata that are put in parallel. this->createSynchronizationInformation(); @@ -358,7 +367,7 @@ namespace storm { uint64_t currentLocationIndex = locations[automatonIndex]; storm::jani::Location const& location = automaton.getLocation(currentLocationIndex); auto valueIt = stateRewards.begin(); - performTransientAssignments(location.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + performTransientAssignments(location.getAssignments().getTransientAssignments(), *this->evaluator, [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); ++automatonIndex; } result.addStateRewards(std::move(stateRewards)); @@ -446,6 +455,7 @@ namespace storm { } Choice choice(edge.getActionIndex(), static_cast(exitRate)); + std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); // Iterate over all updates of the current command. ValueType probabilitySum = storm::utility::zero(); @@ -457,13 +467,26 @@ namespace storm { // seen, we also add it to the set of states that have yet to be explored. uint64_t assignmentLevel = edge.getLowestAssignmentLevel(); // Might be the largest possible integer, if there is no assignment uint64_t const& highestLevel = edge.getHighestAssignmentLevel(); + bool hasTransientRewardAssignments = destination.hasTransientAssignment(); CompressedState newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, *this->evaluator); + if (hasTransientRewardAssignments) { + STORM_LOG_ASSERT(this->options.isScaleAndLiftTransitionRewardsSet(), "Transition rewards are not supported and scaling to action rewards is disabled."); + // Create the rewards for this destination + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(destination.getOrderedAssignments().getTransientAssignments(assignmentLevel), *this->evaluator, [&] (ValueType const& value) { *valueIt += (value * probability); ++valueIt; } ); + } while (assignmentLevel < highestLevel) { ++assignmentLevel; - auto nextLevelEvaluator = storm::expressions::ExpressionEvaluator(model.getManager()); - unpackStateIntoEvaluator(newState, this->variableInformation, nextLevelEvaluator); - newState = applyUpdate(newState, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, nextLevelEvaluator); + auto currentLevelEvaluator = storm::expressions::ExpressionEvaluator(model.getManager()); + unpackStateIntoEvaluator(newState, this->variableInformation, currentLevelEvaluator); + newState = applyUpdate(newState, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, currentLevelEvaluator); + if (hasTransientRewardAssignments) { + // update the rewards for this destination + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(destination.getOrderedAssignments().getTransientAssignments(assignmentLevel), currentLevelEvaluator, [&] (ValueType const& value) { *valueIt += (value * probability); ++valueIt; } ); + } } + StateType stateIndex = stateToIdCallback(newState); // Update the choice by adding the probability/target state to it. @@ -476,8 +499,10 @@ namespace storm { } } - // Create the state-action reward for the newly created choice. - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addReward(value); } ); + // Create the state-action reward for the newly created choice. Note that edge assignments are all transient and we assume that no transient variables occur on the rhs of transient assignments, i.e., the assignment level does not matter here + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), *this->evaluator, [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + choice.addRewards(std::move(stateActionRewards)); if (this->options.isExplorationChecksSet()) { // Check that the resulting distribution is in fact a distribution. @@ -510,7 +535,7 @@ namespace storm { bool done = false; while (!done) { std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); - + currentDistribution.add(state, storm::utility::one()); EdgeIndexSet edgeIndices; @@ -531,26 +556,31 @@ namespace storm { storm::jani::Edge const& edge = *indexAndEdge.second; for (auto const& destination : edge.getDestinations()) { - for (auto const& stateProbability : currentDistribution) { - // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(stateProbability.getState(), destination, this->variableInformation.locationVariables[edgeCombination[i].first], assignmentLevel, *this->evaluator); - - // If the new state was already found as a successor state, update the probability - // and otherwise insert it. - ValueType probability = stateProbability.getValue() * this->evaluator->asRational(destination.getProbability()); - if (edge.hasRate()) { - probability *= this->evaluator->asRational(edge.getRate()); + ValueType destinationProbability = this->evaluator->asRational(destination.getProbability()); + if (!storm::utility::isZero(destinationProbability)) { + if (destination.hasTransientAssignment()) { + STORM_LOG_ASSERT(this->options.isScaleAndLiftTransitionRewardsSet(), "Transition rewards are not supported and scaling to action rewards is disabled."); + // add the rewards for this destination + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), *this->evaluator, [&] (ValueType const& value) { *valueIt += (value * destinationProbability); ++valueIt; } ); } - if (probability != storm::utility::zero()) { - nextDistribution.add(newTargetState, probability); + for (auto const& stateProbability : currentDistribution) { + // Compute the new state under the current update and add it to the set of new target states. + CompressedState newTargetState = applyUpdate(stateProbability.getState(), destination, this->variableInformation.locationVariables[edgeCombination[i].first], assignmentLevel, *this->evaluator); + + // If the new state was already found as a successor state, update the probability + // and insert it. + ValueType probability = destinationProbability * stateProbability.getValue(); + if (edge.hasRate()) { + probability *= this->evaluator->asRational(edge.getRate()); + } + if (probability != storm::utility::zero()) { + nextDistribution.add(newTargetState, probability); + } } } } - // Create the state-action reward for the newly created choice. - auto valueIt = stateActionRewards.begin(); - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); - nextDistribution.compress(); // If there is one more command to come, shift the target states one time step back. @@ -562,13 +592,18 @@ namespace storm { // If there are different assignment levels, we need to expand the possible destinations which causes an exponential blowup... uint64_t destinationId = 0; bool lastDestinationId = false; + std::vector destinationRewards; + std::vector destinations; + std::vector locationVars; + destinations.reserve(iteratorList.size()); + locationVars.reserve(iteratorList.size()); + do { // First assignment level - std::vector destinations; - std::vector locationVars; - destinations.reserve(iteratorList.size()); - locationVars.reserve(iteratorList.size()); + destinations.clear(); + locationVars.clear(); + destinationRewards.assign(destinationRewards.size(), storm::utility::zero()); CompressedState successorState = state; ValueType successorProbability = storm::utility::one(); @@ -591,10 +626,12 @@ namespace storm { if (storm::utility::isZero(successorProbability)) { break; } - // Create the state-action reward for the newly created choice. - auto valueIt = stateActionRewards.begin(); - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + successorState = applyUpdate(successorState, *destinations.back(), *locationVars.back(), assignmentLevel, *this->evaluator); + + // add the reward for this destination to the destination rewards + auto valueIt = destinationRewards.begin(); + performTransientAssignments(destinations.back()->getOrderedAssignments().getTransientAssignments(assignmentLevel), *this->evaluator, [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); } if (!storm::utility::isZero(successorProbability)) { @@ -606,17 +643,27 @@ namespace storm { auto locationVarIt = locationVars.begin(); for (auto const& destPtr : destinations) { successorState = applyUpdate(successorState, *destPtr, **locationVarIt, assignmentLevel, currentLevelEvaluator); + // add the reward for this destination to the destination rewards + auto valueIt = destinationRewards.begin(); + performTransientAssignments(destinations.back()->getOrderedAssignments().getTransientAssignments(assignmentLevel), currentLevelEvaluator, [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); ++locationVarIt; } } nextDistribution.add(successorState, successorProbability); + storm::utility::vector::addScaledVector(stateActionRewards, destinationRewards, successorProbability); } - ++destinationId; } while (!lastDestinationId); std::cout << std::endl; } + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + storm::jani::Edge const& edge = *iteratorList[i]->second; + // Add the state-action reward for the newly created choice. Note that edge assignments are all transient and we assume that no transient variables occur on the rhs of transient assignments, i.e., the assignment level does not matter here + auto valueIt = stateActionRewards.begin(); + performTransientAssignments(edge.getAssignments().getTransientAssignments(), *this->evaluator, [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + } + // At this point, we applied all commands of the current command combination and newTargetStates // contains all target states and their respective probabilities. That means we are now ready to // add the choice to the list of transitions. @@ -792,7 +839,7 @@ namespace storm { } template - void JaniNextStateGenerator::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function const& callback) { + void JaniNextStateGenerator::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, storm::expressions::ExpressionEvaluator const& expressionEvaluator, std::function const& callback) { // If there are no reward variables, there is no need to iterate at all. if (rewardVariables.empty()) { return; @@ -810,7 +857,7 @@ namespace storm { if (rewardVariableIt == rewardVariableIte) { break; } else if (*rewardVariableIt == assignment.getExpressionVariable()) { - callback(ValueType(this->evaluator->asRational(assignment.getAssignedExpression()))); + callback(ValueType(expressionEvaluator.asRational(assignment.getAssignedExpression()))); ++rewardVariableIt; } } diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index c80452f8c..bec4112cd 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -105,7 +105,7 @@ namespace storm { * Treats the given transient assignments by calling the callback function whenever a transient assignment * to one of the reward variables of this generator is performed. */ - void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function const& callback); + void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, storm::expressions::ExpressionEvaluator const& expressionEvaluator, std::function const& callback); /*! * Builds the information structs for the reward models. diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index c81e7df0d..8b46a3d7a 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -81,18 +81,10 @@ namespace storm { } bool OrderedAssignments::hasMultipleLevels(bool onlyTransient) const { - if (allAssignments.empty()) { + if ((onlyTransient ? transientAssignments : allAssignments).empty()) { return false; } - if (onlyTransient) { - for (auto const& a : allAssignments) { - if (a->isTransient()) { - return a->getLevel() != 0 || getHighestLevel(true) != 0; - } - } - return false; // no transient assignments - } - return getLowestLevel(false) != 0 || getHighestLevel(false) != 0; + return getLowestLevel(onlyTransient) != 0 || getHighestLevel(onlyTransient) != 0; } bool OrderedAssignments::empty() const { @@ -110,31 +102,15 @@ namespace storm { } int_fast64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const { - assert(!allAssignments.empty()); - if (onlyTransient) { - for (auto const& a : allAssignments) { - if (a->getLValue().isTransient()) { - return a->getLevel(); - } - } - // assert that at least one transient variable is contained. - assert(false); - } - return allAssignments.front()->getLevel(); + auto const& as = onlyTransient ? transientAssignments : allAssignments; + assert(!as.empty()); + return as.front()->getLevel(); } int_fast64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const { - assert(!allAssignments.empty()); - if (onlyTransient) { - for (auto aIt = allAssignments.rbegin(); aIt != allAssignments.rend(); ++aIt) { - if ((*aIt)->getLValue().isTransient()) { - return (*aIt)->getLevel(); - } - } - // assert that at least one transient variable is contained. - assert(false); - } - return allAssignments.back()->getLevel(); + auto const& as = onlyTransient ? transientAssignments : allAssignments; + assert(!as.empty()); + return as.back()->getLevel(); } bool OrderedAssignments::contains(Assignment const& assignment) const { @@ -222,6 +198,18 @@ namespace storm { return detail::ConstAssignments(nonTransientAssignments.begin(), nonTransientAssignments.end()); } + detail::ConstAssignments OrderedAssignments::getTransientAssignments(int_fast64_t assignmentLevel) const { + auto begin = transientAssignments.begin(); + while (begin != transientAssignments.end() && (*begin)->getLevel() < assignmentLevel) { + ++begin; + } + auto end = begin; + while (end != transientAssignments.end() && (*begin)->getLevel() == assignmentLevel) { + ++end; + } + return detail::ConstAssignments(begin, end); + } + bool OrderedAssignments::hasTransientAssignment() const { return !transientAssignments.empty(); } diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 54ac16e0d..4d15268e7 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -96,6 +96,11 @@ namespace storm { */ detail::ConstAssignments getTransientAssignments() const; + /*! + * Returns all transient assignments in this set of assignments. + */ + detail::ConstAssignments getTransientAssignments(int_fast64_t assignmentLevel) const; + /*! * Returns all non-transient assignments in this set of assignments. */ From 51be5326951ddae273d9a598d90c22f1bd39cfb8 Mon Sep 17 00:00:00 2001 From: dehnert Date: Fri, 7 Sep 2018 22:22:26 +0200 Subject: [PATCH 532/647] pulled out parsing from abstraction-refinement classes --- src/storm-cli-utilities/model-handling.h | 64 ++++++++++++++++++- .../abstraction/AbstractionInformation.cpp | 32 +--------- .../abstraction/AbstractionInformation.h | 12 +++- src/storm/abstraction/MenuGameAbstractor.h | 9 +++ src/storm/abstraction/MenuGameRefiner.cpp | 35 +--------- src/storm/abstraction/MenuGameRefiner.h | 12 +++- .../jani/JaniMenuGameAbstractor.cpp | 2 +- .../abstraction/jani/JaniMenuGameAbstractor.h | 2 +- .../prism/PrismMenuGameAbstractor.cpp | 4 +- .../prism/PrismMenuGameAbstractor.h | 2 +- src/storm/api/verification.h | 21 ++++-- src/storm/logic/RewardAccumulation.cpp | 2 +- .../abstraction/GameBasedMdpModelChecker.cpp | 10 +-- .../abstraction/GameBasedMdpModelChecker.h | 23 ++++++- 14 files changed, 147 insertions(+), 83 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 524d772be..aaca1ec04 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -553,12 +553,72 @@ namespace storm { } } + std::vector parseConstraints(storm::expressions::ExpressionManager const& expressionManager, std::string const& constraintsString) { + std::vector constraints; + + std::vector constraintsAsStrings; + boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(",")); + + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + for (auto const& constraintString : constraintsAsStrings) { + storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString); + STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << "."); + constraints.emplace_back(constraint); + } + + return constraints; + } + + std::vector> parseInjectedRefinementPredicates(storm::expressions::ExpressionManager const& expressionManager, std::string const& refinementPredicatesString) { + std::vector> injectedRefinementPredicates; + + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + std::vector predicateGroupsAsStrings; + boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";")); + + for (auto const& predicateGroupString : predicateGroupsAsStrings) { + std::vector predicatesAsStrings; + boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); + + injectedRefinementPredicates.emplace_back(); + for (auto const& predicateString : predicatesAsStrings) { + storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); + STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); + injectedRefinementPredicates.back().emplace_back(predicate); + } + STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end()); + } + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end()); + + return injectedRefinementPredicates; + } + template void verifyWithAbstractionRefinementEngine(SymbolicInput const& input) { STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); - verifyProperties(input, [&input] (std::shared_ptr const& formula, std::shared_ptr const& states) { + storm::settings::modules::AbstractionSettings const& abstractionSettings = storm::settings::getModule(); + storm::api::AbstractionRefinementOptions options(parseConstraints(input.model->getManager(), abstractionSettings.getConstraintString()), parseInjectedRefinementPredicates(input.model->getManager(), abstractionSettings.getInjectedRefinementPredicates())); + + verifyProperties(input, [&input,&options] (std::shared_ptr const& formula, std::shared_ptr const& states) { STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states."); - return storm::api::verifyWithAbstractionRefinementEngine(input.model.get(), storm::api::createTask(formula, true)); + return storm::api::verifyWithAbstractionRefinementEngine(input.model.get(), storm::api::createTask(formula, true), options); }); } diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 7e3215b3b..23fb06985 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -1,16 +1,9 @@ #include "storm/abstraction/AbstractionInformation.h" -#include - #include "storm/storage/BitVector.h" #include "storm/storage/dd/DdManager.h" -#include "storm/settings/modules/AbstractionSettings.h" -#include "storm/settings/SettingsManager.h" - -#include "storm-parsers/parser/ExpressionParser.h" - #include "storm/utility/macros.h" #include "storm/exceptions/InvalidOperationException.h" @@ -21,29 +14,8 @@ namespace storm { namespace abstraction { template - AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), abstractedVariables(abstractedVariables), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()), allLocationIdentities(ddManager->getBddOne()), expressionToBddMap() { - - // Obtain additional constraints from the settings. - auto const& settings = storm::settings::getModule(); - if (settings.isConstraintsSet()) { - std::string constraintsString = settings.getConstraintString(); - - std::vector constraintsAsStrings; - boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(",")); - - storm::parser::ExpressionParser expressionParser(expressionManager); - std::unordered_map variableMapping; - for (auto const& variableTypePair : expressionManager) { - variableMapping[variableTypePair.first.getName()] = variableTypePair.first; - } - expressionParser.setIdentifierMapping(variableMapping); - - for (auto const& constraintString : constraintsAsStrings) { - storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString); - STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << "."); - constraints.emplace_back(constraint); - } - } + AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, AbstractionInformationOptions const& options, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), abstractedVariables(abstractedVariables), constraints(options.constraints), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()), allLocationIdentities(ddManager->getBddOne()), expressionToBddMap() { + // Intentionally left empty. } template diff --git a/src/storm/abstraction/AbstractionInformation.h b/src/storm/abstraction/AbstractionInformation.h index e47e7ab2b..a6eb1f9c5 100644 --- a/src/storm/abstraction/AbstractionInformation.h +++ b/src/storm/abstraction/AbstractionInformation.h @@ -27,6 +27,16 @@ namespace storm { namespace abstraction { + struct AbstractionInformationOptions { + AbstractionInformationOptions() = default; + + AbstractionInformationOptions(std::vector const& constraints) : constraints(constraints) { + // Intentionally left empty. + } + + std::vector constraints; + }; + template class AbstractionInformation { public: @@ -38,7 +48,7 @@ namespace storm { * @param smtSolver An SMT solver that is used to detect equivalent predicates. * @param ddManager The manager responsible for the DDs. */ - AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager = std::make_shared>()); + AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, AbstractionInformationOptions const& options = AbstractionInformationOptions(), std::shared_ptr> ddManager = std::make_shared>()); /*! * Adds the given variable. diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 1887d60ec..92b3cc97b 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -21,6 +21,15 @@ namespace storm { template class AbstractionInformation; + struct MenuGameAbstractorOptions { + MenuGameAbstractorOptions() = default; + MenuGameAbstractorOptions(std::vector&& constraints) : constraints(std::move(constraints)) { + // Intentionally left empty. + } + + std::vector constraints; + }; + template class MenuGameAbstractor { public: diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 292257965..23f2f4f34 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -66,7 +66,7 @@ namespace storm { } template - MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), rankPredicates(false), addedAllGuardsFlag(false), pivotSelectionHeuristic(), splitter(), equivalenceChecker(std::move(smtSolver)) { + MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver, MenuGameRefinerOptions const& options) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), rankPredicates(false), addedAllGuardsFlag(false), refinementPredicatesToInject(options.refinementPredicates), pivotSelectionHeuristic(), splitter(), equivalenceChecker(std::move(smtSolver)) { auto const& abstractionSettings = storm::settings::getModule(); @@ -97,39 +97,6 @@ namespace storm { storm::expressions::Expression initialExpression = this->abstractor.get().getInitialExpression(); performRefinement(createGlobalRefinement(preprocessPredicates({initialExpression}, RefinementPredicates::Source::InitialExpression))); } - - if (abstractionSettings.isInjectRefinementPredicatesSet()) { - auto const& expressionManager = abstractor.getAbstractionInformation().getExpressionManager(); - storm::parser::ExpressionParser expressionParser(expressionManager); - std::unordered_map variableMapping; - for (auto const& variableTypePair : expressionManager) { - variableMapping[variableTypePair.first.getName()] = variableTypePair.first; - } - expressionParser.setIdentifierMapping(variableMapping); - - std::string predicatesString = abstractionSettings.getInjectedRefinementPredicates(); - std::vector predicateGroupsAsStrings; - boost::split(predicateGroupsAsStrings, predicatesString, boost::is_any_of(";")); - - for (auto const& predicateGroupString : predicateGroupsAsStrings) { - std::vector predicatesAsStrings; - boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); - - refinementPredicatesToInject.emplace_back(); - for (auto const& predicateString : predicatesAsStrings) { - storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); - STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); - refinementPredicatesToInject.back().emplace_back(predicate); - } - STORM_LOG_THROW(!refinementPredicatesToInject.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); - - // Finally reverse the list, because we take the predicates from the back. - std::reverse(refinementPredicatesToInject.back().begin(), refinementPredicatesToInject.back().end()); - } - - // Finally reverse the list, because we take the predicates from the back. - std::reverse(refinementPredicatesToInject.begin(), refinementPredicatesToInject.end()); - } } template diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index cb6d48fd4..c8a384057 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -98,13 +98,23 @@ namespace storm { template class ExplicitQuantitativeResultMinMax; + struct MenuGameRefinerOptions { + MenuGameRefinerOptions() = default; + + MenuGameRefinerOptions(std::vector>&& refinementPredicates) : refinementPredicates(std::move(refinementPredicates)) { + // Intentionally left empty. + } + + std::vector> refinementPredicates; + }; + template class MenuGameRefiner { public: /*! * Creates a refiner for the provided abstractor. */ - MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver); + MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver, MenuGameRefinerOptions const& options = MenuGameRefinerOptions()); /*! * Refines the abstractor with the given predicates. diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index 493b70e4b..a71d78f04 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -35,7 +35,7 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager())), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { + JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager()), AbstractionInformationOptions(options.constraints)), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { // Check whether the model is linear as the abstraction requires this. STORM_LOG_WARN_COND(model.isLinear(), "The model appears to contain non-linear expressions, which may cause malfunctioning of the abstraction."); diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 80c625072..d9f04f828 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -46,7 +46,7 @@ namespace storm { * @param model The concrete model for which to build the abstraction. * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. */ - JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory); + JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options = MenuGameAbstractorOptions()); JaniMenuGameAbstractor(JaniMenuGameAbstractor const&) = default; JaniMenuGameAbstractor& operator=(JaniMenuGameAbstractor const&) = default; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 92b7e3bfb..19001708a 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -33,8 +33,8 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory) - : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager(), program.getAllExpressionVariables(), smtSolverFactory->create(program.getManager())), modules(), initialStateAbstractor(abstractionInformation, {program.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(false) { + PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) + : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager(), program.getAllExpressionVariables(), smtSolverFactory->create(program.getManager()), AbstractionInformationOptions(options.constraints)), modules(), initialStateAbstractor(abstractionInformation, {program.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(false) { // For now, we assume that there is a single module. If the program has more than one module, it needs // to be flattened before the procedure. diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index a9ef79413..91c4fd2c7 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -46,7 +46,7 @@ namespace storm { * @param program The concrete program for which to build the abstraction. * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. */ - PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory); + PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options = MenuGameAbstractorOptions()); PrismMenuGameAbstractor(PrismMenuGameAbstractor const&) = default; PrismMenuGameAbstractor& operator=(PrismMenuGameAbstractor const&) = default; diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 2bec11dcf..27392b81e 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -24,6 +24,7 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/EliminationSettings.h" +#include "storm/settings/modules/AbstractionSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" @@ -37,19 +38,31 @@ namespace storm { return storm::modelchecker::CheckTask(*formula, onlyInitialStatesRelevant); } + struct AbstractionRefinementOptions { + AbstractionRefinementOptions() = default; + AbstractionRefinementOptions(std::vector&& constraints, std::vector>&& injectedRefinementPredicates) : constraints(std::move(constraints)), injectedRefinementPredicates(std::move(injectedRefinementPredicates)) { + // Intentionally left empty. + } + + std::vector constraints; + std::vector> injectedRefinementPredicates; + }; + template - typename std::enable_if::value || std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task) { + typename std::enable_if::value || std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task, AbstractionRefinementOptions const& options = AbstractionRefinementOptions()) { STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::NotSupportedException, "Can only treat DTMCs/MDPs using the abstraction refinement engine."); std::unique_ptr result; + storm::modelchecker::GameBasedMdpModelCheckerOptions modelCheckerOptions(options.constraints, options.injectedRefinementPredicates); + if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { - storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); + storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model, modelCheckerOptions); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP) { - storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); + storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model, modelCheckerOptions); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } @@ -60,7 +73,7 @@ namespace storm { } template - typename std::enable_if::value && !std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&) { + typename std::enable_if::value && !std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&, AbstractionRefinementOptions const& = AbstractionRefinementOptions()) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type."); } diff --git a/src/storm/logic/RewardAccumulation.cpp b/src/storm/logic/RewardAccumulation.cpp index 32065268a..4a4ba4366 100644 --- a/src/storm/logic/RewardAccumulation.cpp +++ b/src/storm/logic/RewardAccumulation.cpp @@ -3,7 +3,7 @@ namespace storm { namespace logic { - RewardAccumulation::RewardAccumulation(bool steps, bool time, bool exit) : steps(steps), time(time), exit(exit){ + RewardAccumulation::RewardAccumulation(bool steps, bool time, bool exit) : time(time), steps(steps), exit(exit){ // Intentionally left empty } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index d1cb9190b..30a495706 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -60,7 +60,7 @@ namespace storm { using detail::PreviousExplicitResult; template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision(), storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, GameBasedMdpModelCheckerOptions const& options, std::shared_ptr const& smtSolverFactory) : options(options), smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision(), storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { if (model.hasUndefinedConstants()) { auto undefinedConstants = model.getUndefinedConstants(); @@ -559,10 +559,11 @@ namespace storm { storm::OptimizationDirection player1Direction = getPlayer1Direction(checkTask); // Create the abstractor. + storm::abstraction::MenuGameAbstractorOptions abstractorOptions(std::move(options.constraints)); if (preprocessedModel.isPrismProgram()) { - abstractor = std::make_shared>(preprocessedModel.asPrismProgram(), smtSolverFactory); + abstractor = std::make_shared>(preprocessedModel.asPrismProgram(), smtSolverFactory, abstractorOptions); } else { - abstractor = std::make_shared>(preprocessedModel.asJaniModel(), smtSolverFactory); + abstractor = std::make_shared>(preprocessedModel.asJaniModel(), smtSolverFactory, abstractorOptions); } if (!constraintExpression.isTrue()) { abstractor->addTerminalStates(!constraintExpression); @@ -571,7 +572,8 @@ namespace storm { abstractor->setTargetStates(targetStateExpression); // Create a refiner that can be used to refine the abstraction when needed. - storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); + storm::abstraction::MenuGameRefinerOptions refinerOptions(std::move(options.injectedRefinementPredicates)); + storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager()), refinerOptions); refiner.refine(initialPredicates, false); storm::dd::Bdd globalConstraintStates = abstractor->getStates(constraintExpression); diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index c8af37073..513b688e4 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -3,6 +3,8 @@ #include "storm/modelchecker/AbstractModelChecker.h" +#include + #include "storm/storage/prism/Program.h" #include "storm/storage/dd/DdType.h" @@ -18,6 +20,11 @@ #include "storm/settings/modules/AbstractionSettings.h" +#include "storm-parsers/parser/ExpressionParser.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" + #include "storm/utility/ConstantsComparator.h" #include "storm/utility/solver.h" #include "storm/utility/graph.h" @@ -72,6 +79,16 @@ namespace storm { }; } + struct GameBasedMdpModelCheckerOptions { + GameBasedMdpModelCheckerOptions() = default; + GameBasedMdpModelCheckerOptions(std::vector const& constraints, std::vector> const& injectedRefinementPredicates) : constraints(constraints), injectedRefinementPredicates(injectedRefinementPredicates) { + // Intentionally left empty. + } + + std::vector constraints; + std::vector> injectedRefinementPredicates; + }; + template class GameBasedMdpModelChecker : public AbstractModelChecker { public: @@ -82,9 +99,10 @@ namespace storm { * verification calls will be answererd with respect to this model. * * @param model The model description that (symbolically) specifies the model to check. + * @param options Additional options for the abstraction-refinement process. * @param smtSolverFactory A factory used to create SMT solver when necessary. */ - explicit GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory = std::make_shared()); + explicit GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, GameBasedMdpModelCheckerOptions const& options = GameBasedMdpModelCheckerOptions(), std::shared_ptr const& smtSolverFactory = std::make_shared()); /// Overridden methods from super class. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -125,6 +143,9 @@ namespace storm { */ storm::expressions::Expression getExpression(storm::logic::Formula const& formula); + /// The options customizing the abstraction-refinement process. + GameBasedMdpModelCheckerOptions options; + /// The preprocessed model that contains only one module/automaton and otherwhise corresponds to the semantics /// of the original model description. storm::storage::SymbolicModelDescription preprocessedModel; From 21aabc5b05d281fb14453eaea897a24634e5d130 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 10 Sep 2018 12:44:56 +0200 Subject: [PATCH 533/647] fixing treatment of zero-states in game solver causing problems in policy iteration and non-unique solutions --- src/storm/solver/StandardGameSolver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 7661392ca..f0ef60564 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -159,14 +159,16 @@ namespace storm { targetStates = storm::utility::vector::filterGreaterZero(subB); zeroStates = ~storm::utility::graph::performProbGreater0(submatrix.transpose(), storm::storage::BitVector(targetStates.size(), true), targetStates); } + bool asEquationSystem = false; if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { submatrix.convertToEquationSystem(); + asEquationSystem = true; } if (!this->hasUniqueSolution()) { for (auto state : zeroStates) { for (auto& element : submatrix.getRow(state)) { if (element.getColumn() == state) { - element.setValue(storm::utility::one()); + element.setValue(asEquationSystem ? storm::utility::one() : storm::utility::zero()); } else { element.setValue(storm::utility::zero()); } @@ -177,7 +179,6 @@ namespace storm { auto submatrixSolver = linearEquationSolverFactory->create(environmentOfSolver, std::move(submatrix)); if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); - } if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); @@ -211,7 +212,7 @@ namespace storm { for (auto state : zeroStates) { for (auto& element : submatrix.getRow(state)) { if (element.getColumn() == state) { - element.setValue(storm::utility::one()); + element.setValue(asEquationSystem ? storm::utility::one() : storm::utility::zero()); } else { element.setValue(storm::utility::zero()); } From e2b5d6fcb120f66166623a89a1cb1d58bc0fa448 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 10 Sep 2018 14:03:46 +0200 Subject: [PATCH 534/647] automatically switching to Eigen as default when using exact mode --- src/storm/solver/LinearEquationSolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index 44eb42db0..14cda16bc 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -88,9 +88,9 @@ namespace storm { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if it is not supported by this value type - if (type == EquationSolverType::Gmmxx) { - type = EquationSolverType::Eigen; - STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver since the selected one does not support exact computations."); + if (type != EquationSolverType::Eigen && type != EquationSolverType::Topological && (env.solver().isLinearEquationSolverTypeSetFromDefaultValue() || type == EquationSolverType::Gmmxx)) { + STORM_LOG_INFO("Selecting '" + toString(EquationSolverType::Eigen) + "' as the linear equation solver since the previously selected one (" << toString(type) << ") does not support exact computations."); + type = EquationSolverType::Eigen; } switch (type) { @@ -110,8 +110,8 @@ namespace storm { // Adjust the solver type if it is not supported by this value type if (type == EquationSolverType::Gmmxx || type == EquationSolverType::Native) { + STORM_LOG_INFO("Selecting '" + toString(EquationSolverType::Eigen) + "' as the linear equation solver since the previously selected one (" << toString(type) << ") does not support parametric computations."); type = EquationSolverType::Eigen; - STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver since the selected one does not support parametric computations."); } switch (type) { From c3d40d634b460767a26e289cd21e2deb35f558b9 Mon Sep 17 00:00:00 2001 From: dehnert Date: Mon, 10 Sep 2018 22:57:06 +0200 Subject: [PATCH 535/647] started working on the github issues by Linda --- src/storm-parsers/api/properties.cpp | 14 +++++++------- .../parser/FormulaParserGrammar.cpp | 17 +++++++++++++---- src/storm-parsers/parser/FormulaParserGrammar.h | 8 ++++++-- src/storm/api/properties.cpp | 2 +- src/storm/logic/AtomicExpressionFormula.cpp | 4 ++++ src/storm/logic/AtomicExpressionFormula.h | 3 ++- src/storm/logic/BinaryPathFormula.cpp | 5 +++++ src/storm/logic/BinaryPathFormula.h | 3 ++- src/storm/logic/BinaryStateFormula.cpp | 5 +++++ src/storm/logic/BinaryStateFormula.h | 1 + src/storm/logic/BoundedUntilFormula.cpp | 16 ++++++++++++++++ src/storm/logic/BoundedUntilFormula.h | 3 ++- src/storm/logic/ConditionalFormula.cpp | 5 +++++ src/storm/logic/ConditionalFormula.h | 3 ++- src/storm/logic/CumulativeRewardFormula.cpp | 6 ++++++ src/storm/logic/CumulativeRewardFormula.h | 3 ++- src/storm/logic/Formula.cpp | 12 +++++++++++- src/storm/logic/Formula.h | 4 +++- src/storm/logic/InstantaneousRewardFormula.cpp | 4 ++++ src/storm/logic/InstantaneousRewardFormula.h | 2 ++ src/storm/logic/OperatorFormula.cpp | 4 ++++ src/storm/logic/OperatorFormula.h | 2 ++ src/storm/logic/UnaryPathFormula.cpp | 4 ++++ src/storm/logic/UnaryPathFormula.h | 3 ++- src/storm/logic/UnaryStateFormula.cpp | 4 ++++ src/storm/logic/UnaryStateFormula.h | 1 + src/storm/storage/expressions/Expression.cpp | 4 ++++ src/storm/storage/expressions/Expression.h | 8 ++++++++ 28 files changed, 128 insertions(+), 22 deletions(-) diff --git a/src/storm-parsers/api/properties.cpp b/src/storm-parsers/api/properties.cpp index 425fee410..0a33be5b2 100644 --- a/src/storm-parsers/api/properties.cpp +++ b/src/storm-parsers/api/properties.cpp @@ -17,7 +17,7 @@ namespace storm { namespace api { - boost::optional > parsePropertyFilter(std::string const &propertyFilter) { + boost::optional> parsePropertyFilter(std::string const& propertyFilter) { if (propertyFilter == "all") { return boost::none; } @@ -26,7 +26,7 @@ namespace storm { return propertyNameSet; } - std::vector parseProperties(storm::parser::FormulaParser &formulaParser, std::string const &inputString, boost::optional > const &propertyFilter) { + std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter) { // If the given property is a file, we parse it as a file, otherwise we assume it's a property. std::vector properties; if (std::ifstream(inputString).good()) { @@ -39,25 +39,25 @@ namespace storm { return filterProperties(properties, propertyFilter); } - std::vector parseProperties(std::string const &inputString, boost::optional > const &propertyFilter) { + std::vector parseProperties(std::string const& inputString, boost::optional > const& propertyFilter) { auto exprManager = std::make_shared(); storm::parser::FormulaParser formulaParser(exprManager); return parseProperties(formulaParser, inputString, propertyFilter); } - std::vector parsePropertiesForJaniModel(std::string const &inputString, storm::jani::Model const &model, boost::optional > const &propertyFilter) { + std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional > const& propertyFilter) { storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); auto formulas = parseProperties(formulaParser, inputString, propertyFilter); return substituteConstantsInProperties(formulas, model.getConstantsSubstitution()); } - std::vector parsePropertiesForPrismProgram(std::string const &inputString, storm::prism::Program const &program, boost::optional > const &propertyFilter) { + std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional > const& propertyFilter) { storm::parser::FormulaParser formulaParser(program); auto formulas = parseProperties(formulaParser, inputString, propertyFilter); return substituteConstantsInProperties(formulas, program.getConstantsSubstitution()); } - std::vector parsePropertiesForSymbolicModelDescription(std::string const &inputString, storm::storage::SymbolicModelDescription const &modelDescription, boost::optional > const &propertyFilter) { + std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional > const& propertyFilter) { std::vector result; if (modelDescription.isPrismProgram()) { result = storm::api::parsePropertiesForPrismProgram(inputString, modelDescription.asPrismProgram(), propertyFilter); @@ -68,4 +68,4 @@ namespace storm { return result; } } -} \ No newline at end of file +} diff --git a/src/storm-parsers/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp index 2cd8773c9..31e436c2d 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -133,7 +133,7 @@ namespace storm { formulaName = qi::lit("\"") >> identifier >> qi::lit("\"") >> qi::lit(":"); formulaName.name("formula name"); - constantDefinition = (qi::lit("const") > qi::eps[qi::_a = true] > -(qi::lit("int") | qi::lit("double")[qi::_a = false]) >> identifier)[phoenix::bind(&FormulaParserGrammar::addConstant, phoenix::ref(*this), qi::_1, qi::_a)]; + constantDefinition = (qi::lit("const") > -(qi::lit("int")[qi::_a = ConstantDataType::Integer] | qi::lit("bool")[qi::_a = ConstantDataType::Bool] | qi::lit("double")[qi::_a = ConstantDataType::Rational]) >> identifier >> -(qi::lit("=") > expressionParser))[phoenix::bind(&FormulaParserGrammar::addConstant, phoenix::ref(*this), qi::_1, qi::_a, qi::_2)]; constantDefinition.name("constant definition"); #pragma clang diagnostic push @@ -208,15 +208,24 @@ namespace storm { this->identifiers_.add(identifier, expression); } - void FormulaParserGrammar::addConstant(std::string const& name, bool integer) { + void FormulaParserGrammar::addConstant(std::string const& name, ConstantDataType type, boost::optional const& expression) { STORM_LOG_ASSERT(manager, "Mutable expression manager required to define new constants."); storm::expressions::Variable newVariable; - if (integer) { + STORM_LOG_THROW(!manager->hasVariable(name), storm::exceptions::WrongFormatException, "Invalid constant definition '" << name << "' in property: variable already exists."); + + if (type == ConstantDataType::Bool) { + newVariable = manager->declareBooleanVariable(name); + } else if (type == ConstantDataType::Integer) { newVariable = manager->declareIntegerVariable(name); } else { newVariable = manager->declareRationalVariable(name); } - addIdentifierExpression(name, newVariable); + + if (expression) { + addIdentifierExpression(name, expression.get()); + } else { + addIdentifierExpression(name, newVariable); + } } bool FormulaParserGrammar::areConstantDefinitionsAllowed() const { diff --git a/src/storm-parsers/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h index c9d5ae020..c9f7e8327 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -145,7 +145,11 @@ namespace storm { qi::rule(), Skipper> start; - qi::rule, Skipper> constantDefinition; + enum class ConstantDataType { + Bool, Integer, Rational + }; + + qi::rule, Skipper> constantDefinition; qi::rule identifier; qi::rule formulaName; @@ -197,7 +201,7 @@ namespace storm { boost::spirit::qi::real_parser> strict_double; bool areConstantDefinitionsAllowed() const; - void addConstant(std::string const& name, bool integer); + void addConstant(std::string const& name, ConstantDataType type, boost::optional const& expression); void addProperty(std::vector& properties, boost::optional const& name, std::shared_ptr const& formula); std::shared_ptr createTimeBoundReference(storm::logic::TimeBoundType const& type, boost::optional const& rewardModelName) const; diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index e5010d8b9..b1e36af86 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -13,7 +13,6 @@ namespace storm { namespace api { - std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution) { std::vector preprocessedProperties; for (auto const& property : properties) { @@ -58,5 +57,6 @@ namespace storm { } return formulas; } + } } diff --git a/src/storm/logic/AtomicExpressionFormula.cpp b/src/storm/logic/AtomicExpressionFormula.cpp index b7af29bfb..6fe7b6fdb 100644 --- a/src/storm/logic/AtomicExpressionFormula.cpp +++ b/src/storm/logic/AtomicExpressionFormula.cpp @@ -24,6 +24,10 @@ namespace storm { atomicExpressionFormulas.push_back(std::dynamic_pointer_cast(this->shared_from_this())); } + void AtomicExpressionFormula::gatherUsedVariables(std::set& usedVariables) const { + expression.gatherVariables(usedVariables); + } + std::ostream& AtomicExpressionFormula::writeToStream(std::ostream& out) const { out << expression; return out; diff --git a/src/storm/logic/AtomicExpressionFormula.h b/src/storm/logic/AtomicExpressionFormula.h index bf3a2982f..21168493b 100644 --- a/src/storm/logic/AtomicExpressionFormula.h +++ b/src/storm/logic/AtomicExpressionFormula.h @@ -22,7 +22,8 @@ namespace storm { virtual std::ostream& writeToStream(std::ostream& out) const override; virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + private: // The atomic expression represented by this node in the formula tree. storm::expressions::Expression expression; diff --git a/src/storm/logic/BinaryPathFormula.cpp b/src/storm/logic/BinaryPathFormula.cpp index b6db33e01..5de44c0c5 100644 --- a/src/storm/logic/BinaryPathFormula.cpp +++ b/src/storm/logic/BinaryPathFormula.cpp @@ -33,6 +33,11 @@ namespace storm { this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } + void BinaryPathFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + } + bool BinaryPathFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/BinaryPathFormula.h b/src/storm/logic/BinaryPathFormula.h index 82a93d344..13f2573cc 100644 --- a/src/storm/logic/BinaryPathFormula.h +++ b/src/storm/logic/BinaryPathFormula.h @@ -23,7 +23,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/BinaryStateFormula.cpp b/src/storm/logic/BinaryStateFormula.cpp index 83535081c..b2f45e269 100644 --- a/src/storm/logic/BinaryStateFormula.cpp +++ b/src/storm/logic/BinaryStateFormula.cpp @@ -32,5 +32,10 @@ namespace storm { this->getLeftSubformula().gatherReferencedRewardModels(referencedRewardModels); this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + void BinaryStateFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + } } } diff --git a/src/storm/logic/BinaryStateFormula.h b/src/storm/logic/BinaryStateFormula.h index 85c996342..67c85a0b1 100644 --- a/src/storm/logic/BinaryStateFormula.h +++ b/src/storm/logic/BinaryStateFormula.h @@ -21,6 +21,7 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; private: std::shared_ptr leftSubformula; diff --git a/src/storm/logic/BoundedUntilFormula.cpp b/src/storm/logic/BoundedUntilFormula.cpp index 6054e7cd3..e06327511 100644 --- a/src/storm/logic/BoundedUntilFormula.cpp +++ b/src/storm/logic/BoundedUntilFormula.cpp @@ -84,6 +84,22 @@ namespace storm { } } + void BoundedUntilFormula::gatherUsedVariables(std::set& usedVariables) const { + if (hasMultiDimensionalSubformulas()) { + for (unsigned i = 0; i < this->getDimension(); ++i) { + this->getLeftSubformula(i).gatherUsedVariables(usedVariables); + this->getRightSubformula(i).gatherUsedVariables(usedVariables); + this->getLowerBound(i).gatherVariables(usedVariables); + this->getUpperBound(i).gatherVariables(usedVariables); + } + } else { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + this->getLowerBound().gatherVariables(usedVariables); + this->getUpperBound().gatherVariables(usedVariables); + } + } + bool BoundedUntilFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/BoundedUntilFormula.h b/src/storm/logic/BoundedUntilFormula.h index eed5c5220..5ae10e8b5 100644 --- a/src/storm/logic/BoundedUntilFormula.h +++ b/src/storm/logic/BoundedUntilFormula.h @@ -24,7 +24,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/ConditionalFormula.cpp b/src/storm/logic/ConditionalFormula.cpp index 31043e07b..a02af1877 100644 --- a/src/storm/logic/ConditionalFormula.cpp +++ b/src/storm/logic/ConditionalFormula.cpp @@ -49,6 +49,11 @@ namespace storm { this->getConditionFormula().gatherReferencedRewardModels(referencedRewardModels); } + void ConditionalFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + this->getConditionFormula().gatherUsedVariables(usedVariables); + } + bool ConditionalFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/ConditionalFormula.h b/src/storm/logic/ConditionalFormula.h index 30af1a3a6..3a32b3463 100644 --- a/src/storm/logic/ConditionalFormula.h +++ b/src/storm/logic/ConditionalFormula.h @@ -28,7 +28,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/CumulativeRewardFormula.cpp b/src/storm/logic/CumulativeRewardFormula.cpp index bbf21cbf0..7abcdc7e4 100644 --- a/src/storm/logic/CumulativeRewardFormula.cpp +++ b/src/storm/logic/CumulativeRewardFormula.cpp @@ -47,6 +47,12 @@ namespace storm { } } + void CumulativeRewardFormula::gatherUsedVariables(std::set& usedVariables) const { + for (unsigned i = 0; i < this->getDimension(); ++i) { + this->getBound(i).gatherVariables(usedVariables); + } + } + TimeBoundReference const& CumulativeRewardFormula::getTimeBoundReference() const { STORM_LOG_ASSERT(!isMultiDimensional(), "Cumulative Reward Formula is multi-dimensional."); return getTimeBoundReference(0); diff --git a/src/storm/logic/CumulativeRewardFormula.h b/src/storm/logic/CumulativeRewardFormula.h index 4c436037e..cccd1ac9e 100644 --- a/src/storm/logic/CumulativeRewardFormula.h +++ b/src/storm/logic/CumulativeRewardFormula.h @@ -24,7 +24,8 @@ namespace storm { virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual std::ostream& writeToStream(std::ostream& out) const override; TimeBoundReference const& getTimeBoundReference() const; diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 3f871908e..62030b0ec 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -431,6 +431,12 @@ namespace storm { return result; } + std::set Formula::getUsedVariables() const { + std::set usedVariables; + this->gatherUsedVariables(usedVariables); + return usedVariables; + } + std::set Formula::getReferencedRewardModels() const { std::set referencedRewardModels; this->gatherReferencedRewardModels(referencedRewardModels); @@ -480,7 +486,11 @@ namespace storm { void Formula::gatherReferencedRewardModels(std::set&) const { return; } - + + void Formula::gatherUsedVariables(std::set& usedVariables) const { + return; + } + std::string Formula::toString() const { std::stringstream str2; writeToStream(str2); diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index a76dd0ef7..c9180b742 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -192,6 +192,7 @@ namespace storm { std::vector> getAtomicExpressionFormulas() const; std::vector> getAtomicLabelFormulas() const; + std::set getUsedVariables() const; std::set getReferencedRewardModels() const; std::shared_ptr asSharedPointer(); @@ -218,7 +219,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const; - + virtual void gatherUsedVariables(std::set& usedVariables) const; + private: // Currently empty. }; diff --git a/src/storm/logic/InstantaneousRewardFormula.cpp b/src/storm/logic/InstantaneousRewardFormula.cpp index f702ca578..37bdee1c9 100644 --- a/src/storm/logic/InstantaneousRewardFormula.cpp +++ b/src/storm/logic/InstantaneousRewardFormula.cpp @@ -60,6 +60,10 @@ namespace storm { return value; } + void InstantaneousRewardFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getBound().gatherVariables(usedVariables); + } + void InstantaneousRewardFormula::checkNoVariablesInBound(storm::expressions::Expression const& bound) { STORM_LOG_THROW(!bound.containsVariables(), storm::exceptions::InvalidOperationException, "Cannot evaluate time-instant '" << bound << "' as it contains undefined constants."); } diff --git a/src/storm/logic/InstantaneousRewardFormula.h b/src/storm/logic/InstantaneousRewardFormula.h index ee9b5b28f..69e5dd38f 100644 --- a/src/storm/logic/InstantaneousRewardFormula.h +++ b/src/storm/logic/InstantaneousRewardFormula.h @@ -35,6 +35,8 @@ namespace storm { template ValueType getBound() const; + virtual void gatherUsedVariables(std::set& usedVariables) const override; + private: static void checkNoVariablesInBound(storm::expressions::Expression const& bound); diff --git a/src/storm/logic/OperatorFormula.cpp b/src/storm/logic/OperatorFormula.cpp index 3b0fbcd1c..40ac6d307 100644 --- a/src/storm/logic/OperatorFormula.cpp +++ b/src/storm/logic/OperatorFormula.cpp @@ -85,6 +85,10 @@ namespace storm { return !this->hasBound(); } + void OperatorFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getThreshold().gatherVariables(usedVariables); + } + std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { if (hasOptimalityType()) { out << (getOptimalityType() == OptimizationDirection::Minimize ? "min" : "max"); diff --git a/src/storm/logic/OperatorFormula.h b/src/storm/logic/OperatorFormula.h index 502cfaec6..a396f21ac 100644 --- a/src/storm/logic/OperatorFormula.h +++ b/src/storm/logic/OperatorFormula.h @@ -49,6 +49,8 @@ namespace storm { virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual std::ostream& writeToStream(std::ostream& out) const override; protected: diff --git a/src/storm/logic/UnaryPathFormula.cpp b/src/storm/logic/UnaryPathFormula.cpp index fd9dd6ae8..6f3404d4f 100644 --- a/src/storm/logic/UnaryPathFormula.cpp +++ b/src/storm/logic/UnaryPathFormula.cpp @@ -26,6 +26,10 @@ namespace storm { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } + void UnaryPathFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + } + bool UnaryPathFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/UnaryPathFormula.h b/src/storm/logic/UnaryPathFormula.h index d1fd8e2c9..b78c3d6a3 100644 --- a/src/storm/logic/UnaryPathFormula.h +++ b/src/storm/logic/UnaryPathFormula.h @@ -22,7 +22,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/UnaryStateFormula.cpp b/src/storm/logic/UnaryStateFormula.cpp index e46d3f345..b253ead87 100644 --- a/src/storm/logic/UnaryStateFormula.cpp +++ b/src/storm/logic/UnaryStateFormula.cpp @@ -27,6 +27,10 @@ namespace storm { void UnaryStateFormula::gatherReferencedRewardModels(std::set& referencedRewardModels) const { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + void UnaryStateFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + } } } diff --git a/src/storm/logic/UnaryStateFormula.h b/src/storm/logic/UnaryStateFormula.h index ae26700a2..490e15d3d 100644 --- a/src/storm/logic/UnaryStateFormula.h +++ b/src/storm/logic/UnaryStateFormula.h @@ -20,6 +20,7 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; private: std::shared_ptr subformula; diff --git a/src/storm/storage/expressions/Expression.cpp b/src/storm/storage/expressions/Expression.cpp index 1d31f4c6f..56eaa30ff 100644 --- a/src/storm/storage/expressions/Expression.cpp +++ b/src/storm/storage/expressions/Expression.cpp @@ -127,6 +127,10 @@ namespace storm { return result; } + void Expression::gatherVariables(std::set& variables) const { + this->getBaseExpression().gatherVariables(variables); + } + bool Expression::containsVariable(std::set const& variables) const { std::set appearingVariables = this->getVariables(); std::set intersection; diff --git a/src/storm/storage/expressions/Expression.h b/src/storm/storage/expressions/Expression.h index 5778f7214..262e09208 100644 --- a/src/storm/storage/expressions/Expression.h +++ b/src/storm/storage/expressions/Expression.h @@ -262,6 +262,14 @@ namespace storm { */ std::set getVariables() const; + /*! + * Retrieves the set of all variables that appear in the expression. These variables are added to the given + * set. + * + * @param variables The set to which to add the variables. + */ + void gatherVariables(std::set& variables) const; + /*! * Retrieves whether the expression contains any of the given variables. * From 6ab7859c8411a79fd636b6cabfc9e9c4c0deb216 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 11 Sep 2018 14:10:51 +0200 Subject: [PATCH 536/647] fixing more of Lindas issues --- src/storm-cli-utilities/model-handling.h | 54 ++++++++++++++----- src/storm-dft/api/storm-dft.cpp | 2 +- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 9 ++-- .../parser/FormulaParserGrammar.cpp | 18 +++++-- .../parser/FormulaParserGrammar.h | 3 ++ src/storm-parsers/parser/JaniParser.cpp | 2 +- src/storm/logic/BoundedUntilFormula.cpp | 16 ++++-- src/storm/logic/OperatorFormula.cpp | 5 +- .../RewardAccumulationEliminationVisitor.cpp | 2 +- .../settings/modules/AbstractionSettings.cpp | 4 +- src/storm/storage/jani/Property.cpp | 33 ++++++++---- src/storm/storage/jani/Property.h | 9 +++- 12 files changed, 112 insertions(+), 45 deletions(-) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index aaca1ec04..67a3dbbe9 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -131,6 +131,19 @@ namespace storm { } } + // Make sure there are no undefined constants remaining in any property. + for (auto const& property : output.properties) { + std::set usedUndefinedConstants = property.getUndefinedConstants(); + if (!usedUndefinedConstants.empty()) { + std::vector undefinedConstantsNames; + for (auto const& constant : usedUndefinedConstants) { + undefinedConstantsNames.emplace_back(constant.getName()); + } + + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The property '" << property << " still refers to the undefined constants " << boost::algorithm::join(undefinedConstantsNames, ",") << "."); + } + } + // Check whether conversion for PRISM to JANI is requested or necessary. if (input.model && input.model.get().isPrismProgram()) { bool transformToJani = ioSettings.isPrismToJaniSet(); @@ -567,6 +580,10 @@ namespace storm { expressionParser.setIdentifierMapping(variableMapping); for (auto const& constraintString : constraintsAsStrings) { + if (constraintString.empty()) { + continue; + } + storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString); STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << "."); constraints.emplace_back(constraint); @@ -588,25 +605,34 @@ namespace storm { std::vector predicateGroupsAsStrings; boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";")); - for (auto const& predicateGroupString : predicateGroupsAsStrings) { - std::vector predicatesAsStrings; - boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); - - injectedRefinementPredicates.emplace_back(); - for (auto const& predicateString : predicatesAsStrings) { - storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); - STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); - injectedRefinementPredicates.back().emplace_back(predicate); + if (!predicateGroupsAsStrings.empty()) { + for (auto const& predicateGroupString : predicateGroupsAsStrings) { + if (predicateGroupString.empty()) { + continue; + } + + std::vector predicatesAsStrings; + boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); + + if (!predicatesAsStrings.empty()) { + injectedRefinementPredicates.emplace_back(); + for (auto const& predicateString : predicatesAsStrings) { + storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); + STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); + injectedRefinementPredicates.back().emplace_back(predicate); + } + + STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end()); + } } - STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); // Finally reverse the list, because we take the predicates from the back. - std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end()); + std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end()); } - // Finally reverse the list, because we take the predicates from the back. - std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end()); - return injectedRefinementPredicates; } diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp index c2431d8e9..b8794372c 100644 --- a/src/storm-dft/api/storm-dft.cpp +++ b/src/storm-dft/api/storm-dft.cpp @@ -57,7 +57,7 @@ namespace storm { auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - std::vector res({storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}); + std::vector res({storm::jani::Property("time-bounded", tbUntil, {}), storm::jani::Property("mttf", rewFormula, {})}); return res; } ); diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index 744b76eb4..0e723cdbd 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -275,11 +275,12 @@ namespace storm { auto const& deadlockVar = addDeadlockTransientVariable(model, getUniqueVarName(*expressionManager, "deadl")); auto deadlock = std::make_shared(deadlockVar.getExpressionVariable().getExpression()); auto trueFormula = std::make_shared(true); + std::set emptyVariableSet; auto maxReachDeadlock = std::make_shared( std::make_shared(deadlock, storm::logic::FormulaContext::Probability), storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); - standardProperties.emplace_back("MaxPrReachDeadlock", maxReachDeadlock, "The maximal probability to eventually reach a deadlock."); + standardProperties.emplace_back("MaxPrReachDeadlock", maxReachDeadlock, emptyVariableSet, "The maximal probability to eventually reach a deadlock."); auto exprTB = expressionManager->declareRationalVariable(getUniqueVarName(*expressionManager, "TIME_BOUND")); auto janiTB = storm::jani::Constant(exprTB.getName(), exprTB); @@ -289,15 +290,15 @@ namespace storm { auto maxReachDeadlockTimeBounded = std::make_shared( std::make_shared(trueFormula, deadlock, boost::none, tb, tbr), storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); - standardProperties.emplace_back("MaxPrReachDeadlockTB", maxReachDeadlockTimeBounded, "The maximal probability to reach a deadlock within 'TIME_BOUND' steps."); + standardProperties.emplace_back("MaxPrReachDeadlockTB", maxReachDeadlockTimeBounded, emptyVariableSet, "The maximal probability to reach a deadlock within 'TIME_BOUND' steps."); auto expTimeDeadlock = std::make_shared( std::make_shared(deadlock, storm::logic::FormulaContext::Time), storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); - standardProperties.emplace_back("MinExpTimeDeadlock", expTimeDeadlock, "The minimal expected time to reach a deadlock."); + standardProperties.emplace_back("MinExpTimeDeadlock", expTimeDeadlock, emptyVariableSet, "The minimal expected time to reach a deadlock."); } } -} \ No newline at end of file +} diff --git a/src/storm-parsers/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp index 31e436c2d..ceca76e8e 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -224,6 +224,7 @@ namespace storm { if (expression) { addIdentifierExpression(name, expression.get()); } else { + undefinedConstants.insert(newVariable); addIdentifierExpression(name, newVariable); } } @@ -417,24 +418,31 @@ namespace storm { return std::shared_ptr(new storm::logic::MultiObjectiveFormula(subformulas)); } } - + + std::set FormulaParserGrammar::getUndefinedConstants(std::shared_ptr const& formula) const { + std::set result; + std::set usedVariables = formula->getUsedVariables(); + std::set_intersection(usedVariables.begin(), usedVariables.end(), undefinedConstants.begin(), undefinedConstants.end(), std::inserter(result, result.begin())); + return result; + } + storm::jani::Property FormulaParserGrammar::createProperty(boost::optional const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr const& formula, std::shared_ptr const& states) { storm::jani::FilterExpression filterExpression(formula, filterType, states); ++propertyCount; if (propertyName) { - return storm::jani::Property(propertyName.get(), filterExpression); + return storm::jani::Property(propertyName.get(), filterExpression, this->getUndefinedConstants(formula)); } else { - return storm::jani::Property(std::to_string(propertyCount -1 ), filterExpression); + return storm::jani::Property(std::to_string(propertyCount - 1), filterExpression, this->getUndefinedConstants(formula)); } } storm::jani::Property FormulaParserGrammar::createPropertyWithDefaultFilterTypeAndStates(boost::optional const& propertyName, std::shared_ptr const& formula) { ++propertyCount; if (propertyName) { - return storm::jani::Property(propertyName.get(), formula); + return storm::jani::Property(propertyName.get(), formula, this->getUndefinedConstants(formula)); } else { - return storm::jani::Property(std::to_string(propertyCount), formula); + return storm::jani::Property(std::to_string(propertyCount), formula, this->getUndefinedConstants(formula)); } } diff --git a/src/storm-parsers/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h index c9f7e8327..75012aaf4 100644 --- a/src/storm-parsers/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -230,6 +230,7 @@ namespace storm { std::shared_ptr createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType); std::shared_ptr createMultiFormula(std::vector> const& subformulas); + std::set getUndefinedConstants(std::shared_ptr const& formula) const; storm::jani::Property createProperty(boost::optional const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr const& formula, std::shared_ptr const& states); storm::jani::Property createPropertyWithDefaultFilterTypeAndStates(boost::optional const& propertyName, std::shared_ptr const& formula); @@ -237,6 +238,8 @@ namespace storm { phoenix::function handler; uint64_t propertyCount; + + std::set undefinedConstants; }; } diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 881bc5785..1909a47ef 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -560,7 +560,7 @@ namespace storm { STORM_LOG_THROW(statesFormula, storm::exceptions::NotImplementedException, "Could not derive states formula."); STORM_LOG_THROW(expressionStructure.count("values") == 1, storm::exceptions::InvalidJaniException, "Values as input for a filter must be given"); auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); - return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), comment); + return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), {}, comment); } std::shared_ptr JaniParser::parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription) { diff --git a/src/storm/logic/BoundedUntilFormula.cpp b/src/storm/logic/BoundedUntilFormula.cpp index e06327511..89be6a2ba 100644 --- a/src/storm/logic/BoundedUntilFormula.cpp +++ b/src/storm/logic/BoundedUntilFormula.cpp @@ -89,14 +89,22 @@ namespace storm { for (unsigned i = 0; i < this->getDimension(); ++i) { this->getLeftSubformula(i).gatherUsedVariables(usedVariables); this->getRightSubformula(i).gatherUsedVariables(usedVariables); - this->getLowerBound(i).gatherVariables(usedVariables); - this->getUpperBound(i).gatherVariables(usedVariables); + if (this->hasLowerBound(i)) { + this->getLowerBound(i).gatherVariables(usedVariables); + } + if (this->hasUpperBound(i)) { + this->getUpperBound(i).gatherVariables(usedVariables); + } } } else { this->getLeftSubformula().gatherUsedVariables(usedVariables); this->getRightSubformula().gatherUsedVariables(usedVariables); - this->getLowerBound().gatherVariables(usedVariables); - this->getUpperBound().gatherVariables(usedVariables); + if (this->hasLowerBound()) { + this->getLowerBound().gatherVariables(usedVariables); + } + if (this->hasUpperBound()) { + this->getUpperBound().gatherVariables(usedVariables); + } } } diff --git a/src/storm/logic/OperatorFormula.cpp b/src/storm/logic/OperatorFormula.cpp index 40ac6d307..a86e5a47a 100644 --- a/src/storm/logic/OperatorFormula.cpp +++ b/src/storm/logic/OperatorFormula.cpp @@ -86,7 +86,10 @@ namespace storm { } void OperatorFormula::gatherUsedVariables(std::set& usedVariables) const { - this->getThreshold().gatherVariables(usedVariables); + UnaryStateFormula::gatherUsedVariables(usedVariables); + if (this->hasBound()) { + this->getThreshold().gatherVariables(usedVariables); + } } std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp index 710f959f1..e78948dce 100644 --- a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp @@ -25,7 +25,7 @@ namespace storm { auto formula = eliminateRewardAccumulations(*p.getFilter().getFormula()); auto states = eliminateRewardAccumulations(*p.getFilter().getStatesFormula()); storm::jani::FilterExpression fe(formula, p.getFilter().getFilterType(), states); - p = storm::jani::Property(p.getName(), storm::jani::FilterExpression(formula, p.getFilter().getFilterType(), states), p.getComment()); + p = storm::jani::Property(p.getName(), storm::jani::FilterExpression(formula, p.getFilter().getFilterType(), states), p.getUndefinedConstants(), p.getComment()); } } diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 7300f8451..d437e81e8 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -111,11 +111,11 @@ namespace storm { .build()); this->addOption(storm::settings::OptionBuilder(moduleName, constraintsOptionName, true, "Specifies additional constraints used by the abstraction.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").build()) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").setDefaultValueString("").build()) .build()); this->addOption(storm::settings::OptionBuilder(moduleName, injectRefinementPredicatesOptionName, true, "Specifies predicates used by the refinement instead of the derived predicates.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("predicates", "The (semicolon-separated) refinement predicates to use.").build()) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("predicates", "The (semicolon-separated) refinement predicates to use.").setDefaultValueString("").build()) .build()); this->addOption(storm::settings::OptionBuilder(moduleName, fixPlayer1StrategyOptionName, true, "Sets whether to fix player 1 strategies.") diff --git a/src/storm/storage/jani/Property.cpp b/src/storm/storage/jani/Property.cpp index 73c6d0dec..fbf84edeb 100644 --- a/src/storm/storage/jani/Property.cpp +++ b/src/storm/storage/jani/Property.cpp @@ -1,20 +1,19 @@ #include "Property.h" + namespace storm { namespace jani { - - std::ostream& operator<<(std::ostream& os, FilterExpression const& fe) { - return os << "Obtain " << toString(fe.getFilterType()) << " of the '" << fe.getStatesFormula() << "'-states with values described by '" << *fe.getFormula() << "'"; + return os << "Obtain " << toString(fe.getFilterType()) << " of the '" << *fe.getStatesFormula() << "'-states with values described by '" << *fe.getFormula() << "'"; } - Property::Property(std::string const& name, std::shared_ptr const& formula, std::string const& comment) - : name(name), comment(comment), filterExpression(FilterExpression(formula)) { + Property::Property(std::string const& name, std::shared_ptr const& formula, std::set const& undefinedConstants, std::string const& comment) + : name(name), comment(comment), filterExpression(FilterExpression(formula)), undefinedConstants(undefinedConstants) { // Intentionally left empty. } - Property::Property(std::string const& name, FilterExpression const& fe, std::string const& comment) - : name(name), comment(comment), filterExpression(fe) { + Property::Property(std::string const& name, FilterExpression const& fe, std::set const& undefinedConstants, std::string const& comment) + : name(name), comment(comment), filterExpression(fe), undefinedConstants(undefinedConstants) { // Intentionally left empty. } @@ -27,11 +26,17 @@ namespace storm { } Property Property::substitute(std::map const& substitution) const { - return Property(name, filterExpression.substitute(substitution), comment); + std::set remainingUndefinedConstants; + for (auto const& constant : undefinedConstants) { + if (substitution.find(constant) == substitution.end()) { + remainingUndefinedConstants.insert(constant); + } + } + return Property(name, filterExpression.substitute(substitution), remainingUndefinedConstants, comment); } Property Property::substituteLabels(std::map const& substitution) const { - return Property(name, filterExpression.substituteLabels(substitution), comment); + return Property(name, filterExpression.substituteLabels(substitution), undefinedConstants, comment); } FilterExpression const& Property::getFilter() const { @@ -42,8 +47,16 @@ namespace storm { return this->filterExpression.getFormula(); } + std::set const& Property::getUndefinedConstants() const { + return undefinedConstants; + } + + bool Property::containsUndefinedConstants() const { + return !undefinedConstants.empty(); + } + std::ostream& operator<<(std::ostream& os, Property const& p) { - return os << "(" << p.getName() << ") : " << p.getFilter(); + return os << "(" << p.getName() << "): " << p.getFilter(); } } diff --git a/src/storm/storage/jani/Property.h b/src/storm/storage/jani/Property.h index 74aceab5c..6207ff1de 100644 --- a/src/storm/storage/jani/Property.h +++ b/src/storm/storage/jani/Property.h @@ -78,9 +78,10 @@ namespace storm { * Constructs the property * @param name the name * @param formula the formula representation + * @param undefinedConstants the undefined constants used in the property * @param comment An optional comment */ - Property(std::string const& name, std::shared_ptr const& formula, std::string const& comment = ""); + Property(std::string const& name, std::shared_ptr const& formula, std::set const& undefinedConstants, std::string const& comment = ""); /** * Constructs the property @@ -88,7 +89,7 @@ namespace storm { * @param formula the formula representation * @param comment An optional comment */ - Property(std::string const& name, FilterExpression const& fe, std::string const& comment = ""); + Property(std::string const& name, FilterExpression const& fe, std::set const& undefinedConstants, std::string const& comment = ""); /** * Get the provided name @@ -107,11 +108,15 @@ namespace storm { FilterExpression const& getFilter() const; + std::set const& getUndefinedConstants() const; + bool containsUndefinedConstants() const; + std::shared_ptr getRawFormula() const; private: std::string name; std::string comment; FilterExpression filterExpression; + std::set undefinedConstants; }; From a7bb70f698a3f4dd634f293c005c0c6a1d76913d Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 11 Sep 2018 15:29:08 +0200 Subject: [PATCH 537/647] exporting array expressions --- src/storm/storage/jani/JSONExporter.cpp | 73 +++++++++++++++++++++++-- src/storm/storage/jani/JSONExporter.h | 7 ++- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index cc45468c0..9a741da86 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -693,6 +693,35 @@ namespace storm { return modernjson::json(expression.getValueAsDouble()); } + boost::any ExpressionToJson::visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "av"; + std::vector elements; + uint64_t size = expression.size()->evaluateAsInt(); + for (uint64_t i = 0; i < size; ++i) { + elements.push_back(boost::any_cast(expression.at(i)->accept(*this, data))); + } + opDecl["elements"] = elements; + return opDecl; + } + + boost::any ExpressionToJson::visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "ac"; + opDecl["var"] = expression.getIndexVar().getName(); + opDecl["length"] = boost::any_cast(expression.size()->accept(*this, data)); + opDecl["exp"] = boost::any_cast(expression.getElementExpression()->accept(*this, data)); + return opDecl; + } + + boost::any ExpressionToJson::visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "aa"; + opDecl["exp"] = boost::any_cast(expression.getOperand(0)->accept(*this, data)); + opDecl["index"] = boost::any_cast(expression.getOperand(1)->accept(*this, data)); + return opDecl; + } + void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid, bool compact) { std::ofstream stream; storm::utility::openFile(filepath, stream); @@ -759,6 +788,7 @@ namespace storm { return modernjson::json(constantDeclarations); } + modernjson::json buildVariablesArray(storm::jani::VariableSet const& varSet, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) { std::vector variableDeclarations; for(auto const& variable : varSet) { @@ -770,18 +800,40 @@ namespace storm { modernjson::json typeDesc; if(variable.isBooleanVariable()) { typeDesc = "bool"; - } else if(variable.isRealVariable()) { + } else if (variable.isRealVariable()) { typeDesc = "real"; - } else if(variable.isUnboundedIntegerVariable()) { + } else if (variable.isUnboundedIntegerVariable()) { typeDesc = "int"; - } else { - assert(variable.isBoundedIntegerVariable()); + } else if (variable.isBoundedIntegerVariable()) { typeDesc["kind"] = "bounded"; typeDesc["base"] = "int"; typeDesc["lower-bound"] = buildExpression(variable.asBoundedIntegerVariable().getLowerBound(), constants, globalVariables, localVariables); typeDesc["upper-bound"] = buildExpression(variable.asBoundedIntegerVariable().getUpperBound(), constants, globalVariables, localVariables); + } else { + assert(variable.isArrayVariable()); + typeDesc["kind"] = "array"; + switch (variable.asArrayVariable().getElementType()) { + case storm::jani::ArrayVariable::ElementType::Bool: + typeDesc["base"] = "bool"; + break; + case storm::jani::ArrayVariable::ElementType::Real: + typeDesc["base"] = "real"; + break; + case storm::jani::ArrayVariable::ElementType::Int: + if (variable.asArrayVariable().hasElementTypeBounds()) { + modernjson::json baseTypeDescr; + baseTypeDescr["kind"] = "bounded"; + baseTypeDescr["base "] = "int"; + baseTypeDescr["lower-bound"] = buildExpression(variable.asArrayVariable().getElementTypeBounds().first, constants, globalVariables, localVariables); + baseTypeDescr["upper-bound"] = buildExpression(variable.asArrayVariable().getElementTypeBounds().second, constants, globalVariables, localVariables); + typeDesc["base"] = baseTypeDescr; + } else { + typeDesc["base"] = "int"; + } + break; + } + typeDesc["base"] = "int"; } - varEntry["type"] = typeDesc; if(variable.hasInitExpression()) { varEntry["initial-value"] = buildExpression(variable.getInitExpression(), constants, globalVariables, localVariables); @@ -797,7 +849,16 @@ namespace storm { bool addIndex = orderedAssignments.hasMultipleLevels(); for(auto const& assignment : orderedAssignments) { modernjson::json assignmentEntry; - assignmentEntry["ref"] = assignment.getVariable().getName(); + if (assignment.getLValue().isVariable()) { + assignmentEntry["ref"] = assignment.getVariable().getName(); + } else { + STORM_LOG_ASSERT(assignment.getLValue().isArrayAccess(), "Unhandled LValue " << assignment.getLValue()); + modernjson::json arrayAccess; + arrayAccess["op"] = "aa"; + arrayAccess["exp"] = assignment.getLValue().getArray().getName(); + arrayAccess["index"] = buildExpression(assignment.getLValue().getArrayIndex(), constants, globalVariables, localVariables); + assignmentEntry["ref"] = std::move(arrayAccess); + } assignmentEntry["value"] = buildExpression(assignment.getAssignedExpression(), constants, globalVariables, localVariables); if(addIndex) { assignmentEntry["index"] = assignment.getLevel(); diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 1f1a49db8..334e804ca 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -2,6 +2,7 @@ #include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" #include "storm/logic/FormulaVisitor.h" #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" @@ -15,7 +16,7 @@ namespace modernjson { namespace storm { namespace jani { - class ExpressionToJson : public storm::expressions::ExpressionVisitor { + class ExpressionToJson : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { public: static modernjson::json translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables); @@ -30,6 +31,10 @@ namespace storm { virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data); + private: ExpressionToJson(std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) : constants(constants), globalVariables(globalVariables), localVariables(localVariables) {} From 62893e01cf93362f82386a3d1d29c7c1be3ded14 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 11 Sep 2018 15:41:56 +0200 Subject: [PATCH 538/647] changing debug output slightly --- src/storm/abstraction/prism/CommandAbstractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index d73526454..51eef2cc4 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -98,7 +98,7 @@ namespace storm { template void CommandAbstractor::recomputeCachedBddWithDecomposition() { - STORM_LOG_TRACE("Recomputing BDD for command with index " << command.get().getGlobalIndex() << " (" << command.get() << ") using the decomposition."); + STORM_LOG_TRACE("Recomputing BDD for command " << command.get() << " [with index " << command.get().getGlobalIndex() << "] using the decomposition."); auto start = std::chrono::high_resolution_clock::now(); // compute a decomposition of the command From fdd3334e6ffdccbf0e8c492414415c3ecb132791 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 11 Sep 2018 17:19:21 +0200 Subject: [PATCH 539/647] properly implemented model features --- src/storm-parsers/parser/JaniParser.cpp | 11 ++++- src/storm/storage/jani/JSONExporter.cpp | 12 +++-- src/storm/storage/jani/JSONExporter.h | 7 ++- src/storm/storage/jani/Model.cpp | 8 ++++ src/storm/storage/jani/Model.h | 14 ++++++ src/storm/storage/jani/ModelFeatures.cpp | 56 ++++++++++++++++++++++++ src/storm/storage/jani/ModelFeatures.h | 29 ++++++++++++ 7 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 src/storm/storage/jani/ModelFeatures.cpp create mode 100644 src/storm/storage/jani/ModelFeatures.h diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 23d3650b0..16bf04056 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -95,10 +95,17 @@ namespace storm { size_t featuresCount = parsedStructure.count("features"); STORM_LOG_THROW(featuresCount < 2, storm::exceptions::InvalidJaniException, "features-declarations can be given at most once."); if (featuresCount == 1) { - std::unordered_set supportedFeatures = {"derived-operators", "state-exit-rewards"}; for (auto const& feature : parsedStructure.at("features")) { std::string featureStr = getString(feature, "Model feature"); - STORM_LOG_WARN_COND(supportedFeatures.find(featureStr) != supportedFeatures.end(), "Storm does not support the model feature " << featureStr << "."); + if (featureStr == "arrays") { + model.getModelFeatures().add(storm::jani::ModelFeature::Arrays); + } else if (featureStr == "derived-operators") { + model.getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + } else if (featureStr == "state-exit-rewards") { + model.getModelFeatures().add(storm::jani::ModelFeature::StateExitRewards); + } else { + STORM_LOG_WARN("Storm does not support the model feature " << featureStr << "."); + } } } size_t actionCount = parsedStructure.count("actions"); diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 9a741da86..3da43c78b 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -196,11 +196,11 @@ namespace storm { } } - modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model, std::set& modelFeatures) { + modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) { FormulaToJaniJson translator(model); auto result = boost::any_cast(formula.accept(translator)); if (translator.containsStateExitRewards()) { - modelFeatures.insert("state-exit-rewards"); + modelFeatures.add(storm::jani::ModelFeature::StateExitRewards); } return result; } @@ -971,7 +971,7 @@ namespace storm { } void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) { - modelFeatures = {"derived-operators"}; + modelFeatures = janiModel.getModelFeatures(); jsonStruct["jani-version"] = janiModel.getJaniVersion(); jsonStruct["name"] = janiModel.getName(); jsonStruct["type"] = to_string(janiModel.getModelType()); @@ -1011,7 +1011,7 @@ namespace storm { } } - modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model, std::set& modelFeatures) { + modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) { modernjson::json propDecl; propDecl["states"]["op"] = "initial"; propDecl["op"] = "filter"; @@ -1023,6 +1023,10 @@ namespace storm { void JsonExporter::convertProperties( std::vector const& formulas, storm::jani::Model const& model) { std::vector properties; + + // Unset model-features that only relate to properties. These are only set if such properties actually exist. + modelFeatures.remove(storm::jani::ModelFeature::StateExitRewards); + uint64_t index = 0; for(auto const& f : formulas) { modernjson::json propDecl; diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 334e804ca..ce95a2c0f 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -46,7 +46,7 @@ namespace storm { class FormulaToJaniJson : public storm::logic::FormulaVisitor { public: - static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& model, std::set& modelFeatures); + static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures); bool containsStateExitRewards() const; // Returns true iff the previously translated formula contained state exit rewards virtual boost::any visit(storm::logic::AtomicExpressionFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::AtomicLabelFormula const& f, boost::any const& data) const; @@ -96,13 +96,12 @@ namespace storm { void appendVariableDeclaration(storm::jani::Variable const& variable); modernjson::json finalize() { - std::vector featureVector(modelFeatures.begin(), modelFeatures.end()); - jsonStruct["features"] = featureVector; + jsonStruct["features"] = modelFeatures.toString(); return jsonStruct; } modernjson::json jsonStruct; - std::set modelFeatures; + storm::jani::ModelFeatures modelFeatures; }; } diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 6ff5cd28a..c326e7314 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -114,6 +114,14 @@ namespace storm { return modelType; } + ModelFeatures const& Model::getModelFeatures() const { + return modelFeatures; + } + + ModelFeatures& Model::getModelFeatures() { + return modelFeatures; + } + std::string const& Model::getName() const { return name; } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 937f58f42..3224c0353 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -14,6 +14,7 @@ #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/Location.h" #include "storm/storage/jani/TemplateEdge.h" +#include "storm/storage/jani/ModelFeatures.h" #include "storm/utility/solver.h" #include "storm/utility/vector.h" @@ -77,6 +78,16 @@ namespace storm { */ ModelType const& getModelType() const; + /*! + * Retrieves the enabled model features + */ + ModelFeatures const& getModelFeatures() const; + + /*! + * Retrieves the enabled model features + */ + ModelFeatures& getModelFeatures(); + /*! * Retrieves the name of the model. */ @@ -523,6 +534,9 @@ namespace storm { /// The JANI-version used to specify the model. uint64_t version; + /// The features enabled for this model. + ModelFeatures modelFeatures; + /// The manager responsible for the expressions in this model. std::shared_ptr expressionManager; diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp new file mode 100644 index 000000000..755ac99d8 --- /dev/null +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -0,0 +1,56 @@ +#include "storm/storage/jani/ModelFeatures.h" + +#include "storm/utility/macros.h" + +namespace storm { + namespace jani { + + std::string toString(ModelFeature const& modelFeature) { + switch(modelFeature) { + case ModelFeature::Arrays: + return "arrays"; + case ModelFeature::DerivedOperators: + return "derived-operators"; + case ModelFeature::StateExitRewards: + return "state-exit-rewards"; + } + STORM_LOG_ASSERT(false, "Unhandled model feature"); + return "Unhandled-feature"; + } + + std::string ModelFeatures::toString() const { + std::string res = "["; + bool first = true; + for (auto const& f : features) { + if (!first) { + res += ", "; + } + res += storm::jani::toString(f); + first = false; + } + res += "]"; + return res; + } + + bool ModelFeatures::hasArrays() const { + return features.count(ModelFeature::Arrays) > 0; + } + + bool ModelFeatures::hasDerivedOperators() const { + return features.count(ModelFeature::DerivedOperators) > 0; + } + + bool ModelFeatures::hasStateExitRewards() const { + return features.count(ModelFeature::StateExitRewards) > 0; + } + + void ModelFeatures::add(ModelFeature const& modelFeature) { + features.insert(modelFeature); + } + + void ModelFeatures::remove(ModelFeature const& modelFeature) { + features.erase(modelFeature); + } + + } +} diff --git a/src/storm/storage/jani/ModelFeatures.h b/src/storm/storage/jani/ModelFeatures.h new file mode 100644 index 000000000..f2604af96 --- /dev/null +++ b/src/storm/storage/jani/ModelFeatures.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +namespace storm { + namespace jani { + + enum class ModelFeature {Arrays, DerivedOperators, StateExitRewards}; + + std::string toString(ModelFeature const& modelFeature); + + class ModelFeatures { + + public: + std::string toString() const; + + bool hasArrays() const; + bool hasDerivedOperators() const; + bool hasStateExitRewards() const; + + void add(ModelFeature const& modelFeature); + void remove(ModelFeature const& modelFeature); + + private: + std::set features; + }; + } +} From ed45fa80e648b58988f78f23865cdf5e881a3721 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 11 Sep 2018 18:00:51 +0200 Subject: [PATCH 540/647] debugging array elimination --- src/storm/storage/jani/ArrayEliminator.cpp | 85 +++++++++------ src/storm/storage/jani/TemplateEdge.cpp | 4 + src/storm/storage/jani/TemplateEdge.h | 1 + .../jani/expressions/JaniExpressionVisitor.h | 4 +- .../jani/traverser/ArrayExpressionFinder.cpp | 102 ++++++++++++++++++ .../jani/traverser/ArrayExpressionFinder.h | 18 ++++ 6 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp create mode 100644 src/storm/storage/jani/traverser/ArrayExpressionFinder.h diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp index fb50de59f..114e8ef3a 100644 --- a/src/storm/storage/jani/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -5,6 +5,8 @@ #include "storm/storage/expressions/ExpressionVisitor.h" #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" #include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" + #include "storm/storage/expressions/Expressions.h" #include "storm/storage/jani/expressions/JaniExpressions.h" #include "storm/storage/expressions/ExpressionManager.h" @@ -118,20 +120,10 @@ namespace storm { ArrayExpressionEliminationVisitor(std::unordered_map> const& replacements, std::unordered_map const& sizes) : replacements(replacements), arraySizes(sizes) {} virtual ~ArrayExpressionEliminationVisitor() = default; - storm::expressions::Expression eliminate(storm::expressions::Expression const& expression, storm::expressions::Expression const& outOfBoundsExpression) { - auto res = eliminate(expression, false); - if (outOfBoundsError) { - return outOfBoundsExpression; - } else { - return res; - } - } - - storm::expressions::Expression eliminate(storm::expressions::Expression const& expression, bool failIfOutOfBounds = true) { - outOfBoundsError = false; + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression) { // here, data is the accessed index of the most recent array access expression. Initially, there is none. auto res = storm::expressions::Expression(boost::any_cast(expression.accept(*this, boost::any()))); - STORM_LOG_THROW(!failIfOutOfBounds || !outOfBoundsError, storm::exceptions::UnexpectedException, "Out of bounds array access occured while eliminating expression " << expression); + STORM_LOG_ASSERT(!containsArrayExpression(res), "Expression still contains array expressions. Before: " << std::endl << expression << std::endl << "After:" << std::endl << res); return res.simplify(); } @@ -242,12 +234,8 @@ namespace storm { STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate ValueArrayExpression to element expression since it does not seem to be within an array access expression."); uint64_t index = boost::any_cast(data); STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); - if (index < static_cast(expression.size()->evaluateAsInt())) { - return expression.at(index); - } else { - outOfBoundsError = true; - return expression.at(0); - } + STORM_LOG_THROW(index < static_cast(expression.size()->evaluateAsInt()), storm::exceptions::UnexpectedException, "Out of bounds array access occured while accessing index " << index << " of expression " << expression); + return expression.at(index); } virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { @@ -255,8 +243,8 @@ namespace storm { uint64_t index = boost::any_cast(data); if (expression.size()->containsVariables()) { STORM_LOG_WARN("Ignoring length of constructorArrayExpression " << expression << " as it still contains variables."); - } else if (index >= static_cast(expression.size()->evaluateAsInt())) { - outOfBoundsError = true; + } else { + STORM_LOG_THROW(index < static_cast(expression.size()->evaluateAsInt()), storm::exceptions::UnexpectedException, "Out of bounds array access occured while accessing index " << index << " of expression " << expression); } return expression.at(index); } @@ -270,22 +258,22 @@ namespace storm { storm::expressions::Expression result = boost::any_cast(expression.getFirstOperand()->accept(*this, index))->toExpression(); while (index > 0) { --index; - result = storm::expressions::ite( - expression.getSecondOperand()->toExpression() == expression.getManager().integer(index), + storm::expressions::Expression isCurrentIndex = boost::any_cast(expression.getSecondOperand()->accept(*this, boost::any()))->toExpression() == expression.getManager().integer(index); + result = storm::expressions::ite(isCurrentIndex, boost::any_cast(expression.getFirstOperand()->accept(*this, index))->toExpression(), result); } return result.getBaseExpressionPointer(); } else { uint64_t index = expression.getSecondOperand()->evaluateAsInt(); - return boost::any_cast(expression.getFirstOperand()->accept(*this, index)); + auto result = boost::any_cast(expression.getFirstOperand()->accept(*this, index)); + return result; } } private: std::unordered_map> const& replacements; std::unordered_map const& arraySizes; - bool outOfBoundsError; }; class MaxArraySizeDeterminer : public ConstJaniTraverser { @@ -404,6 +392,28 @@ namespace storm { automaton.setInitialStatesRestriction(arrayExprEliminator->eliminate(automaton.getInitialStatesRestriction())); } } + + void traverse(TemplateEdge& templateEdge, boost::any const& data) override { + templateEdge.setGuard(arrayExprEliminator->eliminate(templateEdge.getGuard())); + for (auto& dest : templateEdge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + + void traverse(Edge& edge, boost::any const& data) override { + if (edge.hasRate()) { + edge.setRate(arrayExprEliminator->eliminate(edge.getRate())); + } + for (auto& dest : edge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + } + + void traverse(EdgeDestination& edgeDestination, boost::any const& data) override { + edgeDestination.setProbability(arrayExprEliminator->eliminate(edgeDestination.getProbability())); + } virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) override { auto const& replacements = boost::any_cast(data)->replacements; @@ -428,19 +438,31 @@ namespace storm { insertionRes.first->second.push_back(&assignment); } continue; + } else { + // Keeping array access LValue + LValue newLValue(LValue(assignment.getLValue().getArray()), arrayExprEliminator->eliminate(assignment.getLValue().getArrayIndex())); + newAssignments.emplace_back(newLValue, arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); } } else if (assignment.getLValue().isVariable() && assignment.getVariable().isArrayVariable()) { STORM_LOG_ASSERT(assignment.getAssignedExpression().getType().isArrayType(), "Assigning a non-array expression to an array variable..."); std::vector const& arrayVariableReplacements = replacements.at(assignment.getExpressionVariable()); + // Get the maximum size of the array expression on the rhs + uint64_t rhsSize = MaxArraySizeExpressionVisitor().getMaxSize(assignment.getAssignedExpression(), arraySizes); + STORM_LOG_ASSERT(arrayVariableReplacements.size() >= rhsSize, "Array size too small."); for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { auto const& replacement = *arrayVariableReplacements[index]; - auto arrayAccessExpression = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); - arrayAccessExpression = arrayExprEliminator->eliminate(arrayAccessExpression, getOutOfBoundsValue(replacement)); - newAssignments.emplace_back(LValue(replacement), arrayAccessExpression, level); + storm::expressions::Expression newRhs; + if (index < rhsSize) { + newRhs = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); + } else { + newRhs = getOutOfBoundsValue(replacement); + } + newRhs = arrayExprEliminator->eliminate(newRhs); + newAssignments.emplace_back(LValue(replacement), newRhs, level); } - continue; + } else { + newAssignments.emplace_back(assignment.getLValue(), arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); } - newAssignments.emplace_back(assignment.getLValue(), arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); } for (auto const& arrayAssignments : collectedArrayAccessAssignments) { insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); @@ -513,9 +535,9 @@ namespace storm { storm::expressions::Expression assignedExpression = arrayVariableReplacements[index]->getExpressionVariable().getExpression(); auto indexExpression = expressionManager.integer(index); for (auto const& aa : arrayAccesses) { - assignedExpression = storm::expressions::ite(aa->getLValue().getArrayIndex() == indexExpression, arrayExprEliminator->eliminate(aa->getAssignedExpression()), assignedExpression); - newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), assignedExpression, level); + assignedExpression = storm::expressions::ite(arrayExprEliminator->eliminate(aa->getLValue().getArrayIndex()) == indexExpression, arrayExprEliminator->eliminate(aa->getAssignedExpression()), assignedExpression); } + newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), assignedExpression, level); } } } @@ -552,6 +574,7 @@ namespace storm { ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); model.finalize(); + STORM_LOG_ASSERT(!containsArrayExpression(model), "the model still contains array expressions."); return result; } } diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 79644f8a6..a1ea3f7b5 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -56,6 +56,10 @@ namespace storm { return guard; } + void TemplateEdge::setGuard(storm::expressions::Expression const& newGuard) { + guard = newGuard; + } + std::size_t TemplateEdge::getNumberOfDestinations() const { return destinations.size(); } diff --git a/src/storm/storage/jani/TemplateEdge.h b/src/storm/storage/jani/TemplateEdge.h index 4e0d2a027..0928c50e0 100644 --- a/src/storm/storage/jani/TemplateEdge.h +++ b/src/storm/storage/jani/TemplateEdge.h @@ -21,6 +21,7 @@ namespace storm { TemplateEdge(storm::expressions::Expression const& guard, OrderedAssignments const& assignments, std::vector const& destinations); storm::expressions::Expression const& getGuard() const; + void setGuard(storm::expressions::Expression const& newGuard); void addDestination(TemplateEdgeDestination const& destination); diff --git a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h index e0e76e95e..61808bb0d 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h @@ -1,12 +1,12 @@ #pragma once -#include "storm/storage/expressions/SubstitutionVisitor.h" +#include "storm/storage/expressions/ExpressionVisitor.h" #include "storm/storage/jani/expressions/JaniExpressions.h" namespace storm { namespace expressions { - class JaniExpressionVisitor{ + class JaniExpressionVisitor { public: virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) = 0; virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) = 0; diff --git a/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp new file mode 100644 index 000000000..f9c80a36a --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp @@ -0,0 +1,102 @@ +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" + +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + + namespace detail { + class ArrayExpressionFinderExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getCondition()->accept(*this, data)) || + boost::any_cast(expression.getThenExpression()->accept(*this, data)) || + boost::any_cast(expression.getElseExpression()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return expression.getOperand()->accept(*this, data); + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return expression.getOperand()->accept(*this, data); + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + return true; + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + return true; + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + return true; + } + }; + + class ArrayExpressionFinderTraverser : public ConstJaniTraverser { + public: + virtual void traverse(Model const& model, boost::any const& data) override { + ConstJaniTraverser::traverse(model, data); + } + + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { + auto& res = *boost::any_cast(data); + res = res || containsArrayExpression(expression); + } + }; + } + + + bool containsArrayExpression(Model const& model) { + bool result = false; + detail::ArrayExpressionFinderTraverser().traverse(model, &result); + return result; + } + + bool containsArrayExpression(storm::expressions::Expression const& expression) { + detail::ArrayExpressionFinderExpressionVisitor v; + return boost::any_cast(expression.accept(v, boost::none)); + } + } +} + diff --git a/src/storm/storage/jani/traverser/ArrayExpressionFinder.h b/src/storm/storage/jani/traverser/ArrayExpressionFinder.h new file mode 100644 index 000000000..c924472cd --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayExpressionFinder.h @@ -0,0 +1,18 @@ +#pragma once + + +namespace storm { + + namespace expressions { + class Expression; + } + + namespace jani { + + class Model; + + bool containsArrayExpression(Model const& model); + bool containsArrayExpression(storm::expressions::Expression const& expr); + } +} + From ba6856274017f3c7da7f4e6f68555c9c1ec6dc98 Mon Sep 17 00:00:00 2001 From: TimQu Date: Tue, 11 Sep 2018 18:38:32 +0200 Subject: [PATCH 541/647] moved array variable replacement information into VariableInformation --- .../generator/JaniNextStateGenerator.cpp | 39 ++-------------- src/storm/generator/JaniNextStateGenerator.h | 5 +- src/storm/generator/VariableInformation.cpp | 46 +++++++++++++++++++ src/storm/generator/VariableInformation.h | 9 ++++ 4 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 8f68f4c1c..9af945704 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -68,34 +68,7 @@ namespace storm { // Now we are ready to initialize the variable information. this->checkValid(); this->variableInformation = VariableInformation(model, this->parallelAutomata, options.isAddOutOfBoundsStateSet()); - - // Find for each replaced array variable the corresponding references in the variable information - for (auto const& arrayReplacements : arrayEliminatorData.replacements) { - std::vector varInfoIndices; - for (auto const& replacedVar : arrayReplacements.second) { - if (replacedVar->getExpressionVariable().hasIntegerType()) { - uint64_t index = 0; - for (auto const& intInfo : this->variableInformation.integerVariables) { - if (intInfo.variable == replacedVar->getExpressionVariable()) { - varInfoIndices.push_back(index); - break; - } - ++index; - } - } else if (replacedVar->getExpressionVariable().hasBooleanType()) { - uint64_t index = 0; - for (auto const& boolInfo : this->variableInformation.booleanVariables) { - if (boolInfo.variable == replacedVar->getExpressionVariable()) { - varInfoIndices.push_back(index); - } - ++index; - } - } else { - STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); - } - } - arrayVariableToElementInformations.emplace(arrayReplacements.first, std::move(varInfoIndices)); - } + this->variableInformation.registerArrayVariableReplacements(arrayEliminatorData); // Create a proper evalator. this->evaluator = std::make_unique>(model.getManager()); @@ -321,9 +294,7 @@ namespace storm { for (; assignmentIt != assignmentIte && assignmentIt->getLValue().isArrayAccess() && assignmentIt->getLevel() == assignmentLevel; ++assignmentIt) { int_fast64_t arrayIndex = expressionEvaluator.asInt(assignmentIt->getLValue().getArrayIndex()); if (assignmentIt->getAssignedExpression().hasIntegerType()) { - std::vector const& intInfoIndices = arrayVariableToElementInformations.at(assignmentIt->getLValue().getArray().getExpressionVariable()); - STORM_LOG_THROW(arrayIndex < intInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access " << assignmentIt->getLValue() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << intInfoIndices.size()); - IntegerVariableInformation const& intInfo = this->variableInformation.integerVariables[intInfoIndices[arrayIndex]]; + IntegerVariableInformation const& intInfo = this->variableInformation.getIntegerArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); int_fast64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); if (this->options.isAddOutOfBoundsStateSet()) { if (assignedValue < intInfo.lowerBound || assignedValue > intInfo.upperBound) { @@ -336,9 +307,7 @@ namespace storm { newState.setFromInt(intInfo.bitOffset, intInfo.bitWidth, assignedValue - intInfo.lowerBound); STORM_LOG_ASSERT(static_cast(newState.getAsInt(intInfo.bitOffset, intInfo.bitWidth)) + intInfo.lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(intInfo.bitOffset, intInfo.bitWidth) << " but wrote " << assignedValue << ")."); } else if (assignmentIt->getAssignedExpression().hasBooleanType()) { - std::vector const& boolInfoIndices = arrayVariableToElementInformations.at(assignmentIt->getLValue().getArray().getExpressionVariable()); - STORM_LOG_THROW(arrayIndex < boolInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access " << assignmentIt->getLValue() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << boolInfoIndices.size()); - BooleanVariableInformation const& boolInfo = this->variableInformation.booleanVariables[boolInfoIndices[arrayIndex]]; + BooleanVariableInformation const& boolInfo = this->variableInformation.getBooleanArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); newState.set(boolInfo.bitOffset, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); } else { STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); @@ -612,6 +581,7 @@ namespace storm { storm::jani::Edge const& edge = *iteratorList[i]->second; destinations.push_back(&edge.getDestination(destinationIndex % edge.getNumberOfDestinations())); locationVars.push_back(&this->variableInformation.locationVariables[edgeCombination[i].first]); + STORM_LOG_ASSERT(edge.getNumberOfDestinations() > 0, "Found an edge with zero destinations. This is not expected."); std::cout << destinationIndex % edge.getNumberOfDestinations(); if (i == iteratorList.size() - 1 && (destinationIndex % edge.getNumberOfDestinations()) == edge.getNumberOfDestinations() - 1) { lastDestinationId = true; @@ -653,6 +623,7 @@ namespace storm { storm::utility::vector::addScaledVector(stateActionRewards, destinationRewards, successorProbability); } ++destinationId; + std::cout << "\t"; } while (!lastDestinationId); std::cout << std::endl; } diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index bec4112cd..e9bd01a07 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -140,11 +140,8 @@ namespace storm { /// A flag that stores whether at least one of the selected reward models has state-action rewards. bool hasStateActionRewards; - /// Data from eliminating arrays + /// Data from eliminated array expressions. These are required to keep references to array variables in LValues alive. storm::jani::ArrayEliminatorData arrayEliminatorData; - - /// Maps each array variable to the index of the base variable in this->variableInformation - std::unordered_map> arrayVariableToElementInformations; }; diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index e4befba41..36134c182 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -4,6 +4,7 @@ #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Automaton.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/expressions/ExpressionManager.h" @@ -109,6 +110,51 @@ namespace storm { sortVariables(); } + void VariableInformation::registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData) { + arrayVariableToElementInformations.clear(); + // Find for each replaced array variable the corresponding references in this variable information + for (auto const& arrayReplacements : arrayEliminatorData.replacements) { + std::vector varInfoIndices; + for (auto const& replacedVar : arrayReplacements.second) { + if (replacedVar->getExpressionVariable().hasIntegerType()) { + uint64_t index = 0; + for (auto const& intInfo : integerVariables) { + if (intInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + } else if (replacedVar->getExpressionVariable().hasBooleanType()) { + uint64_t index = 0; + for (auto const& boolInfo : booleanVariables) { + if (boolInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + } else { + STORM_LOG_ASSERT(false, "Unhandled type of base variable."); + } + } + STORM_LOG_ASSERT(arrayReplacements.second.size() == varInfoIndices.size(), "Could not find a basic variable for every array variable replacement."); + this->arrayVariableToElementInformations.emplace(arrayReplacements.first, std::move(varInfoIndices)); + } + } + + BooleanVariableInformation const& VariableInformation::getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& boolInfoIndices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < boolInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << boolInfoIndices.size()); + return booleanVariables[boolInfoIndices[arrayIndex]]; + } + + IntegerVariableInformation const& VariableInformation::getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& intInfoIndices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < intInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << intInfoIndices.size()); + return integerVariables[intInfoIndices[arrayIndex]]; + } + void VariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton) { uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(automaton.getNumberOfLocations()))); locationVariables.emplace_back(automaton.getLocationExpressionVariable(), automaton.getNumberOfLocations() - 1, totalBitOffset, bitwidth); diff --git a/src/storm/generator/VariableInformation.h b/src/storm/generator/VariableInformation.h index fac200d1a..a8d53090e 100644 --- a/src/storm/generator/VariableInformation.h +++ b/src/storm/generator/VariableInformation.h @@ -2,6 +2,7 @@ #define STORM_GENERATOR_VARIABLEINFORMATION_H_ #include +#include #include #include @@ -15,6 +16,7 @@ namespace storm { namespace jani { class Model; class Automaton; + class ArrayEliminatorData; } namespace generator { @@ -81,6 +83,10 @@ namespace storm { VariableInformation() = default; uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const; + void registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData); + BooleanVariableInformation const& getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + IntegerVariableInformation const& getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + /// The total bit offset over all variables. uint_fast64_t totalBitOffset; @@ -92,6 +98,9 @@ namespace storm { /// The integer variables. std::vector integerVariables; + + /// Replacements for each array variable + std::unordered_map> arrayVariableToElementInformations; bool hasOutOfBoundsBit() const; From 2ff18771eb4a87525e8d0f39dfc7e005b6e5012a Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 11 Sep 2018 19:51:35 +0200 Subject: [PATCH 542/647] adding a corrected valid-block-mode for game-based abstraction --- .../abstraction/prism/CommandAbstractor.cpp | 28 +++++++++++++++++-- .../abstraction/prism/CommandAbstractor.h | 3 ++ .../prism/PrismMenuGameAbstractor.cpp | 23 ++++++++++----- .../prism/PrismMenuGameAbstractor.h | 3 ++ src/storm/logic/BoundedUntilFormula.cpp | 6 ++-- .../settings/modules/AbstractionSettings.cpp | 18 ++++++++++++ .../settings/modules/AbstractionSettings.h | 10 +++++++ 7 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index 51eef2cc4..a57c990c7 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -13,6 +13,9 @@ #include "storm/storage/prism/Command.h" #include "storm/storage/prism/Update.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/AbstractionSettings.h" + #include "storm/utility/solver.h" #include "storm/utility/macros.h" @@ -23,7 +26,7 @@ namespace storm { namespace abstraction { namespace prism { template - CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { + CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addAssignmentRelatedVariablesToSourcePredicates(false), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); @@ -43,6 +46,9 @@ namespace storm { assignedVariables.insert(assignment.getVariable()); } } + + auto const& abstractionSettings = storm::settings::getModule(); + addAssignmentRelatedVariablesToSourcePredicates = abstractionSettings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::MorePredicates; } template @@ -283,7 +289,7 @@ namespace storm { } } - // Then enumerate the solutions for each of the blocks of the decomposition + // Then enumerate the solutions for each of the blocks of the decomposition. uint64_t usedNondeterminismVariables = 0; uint64_t blockCounter = 0; std::vector> blockBdds; @@ -489,6 +495,12 @@ namespace storm { storm::expressions::Variable const& assignedVariable = assignment.getVariable(); auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); + + // Predicates that are indirectly related to the assigned variables are relevant for the source state (if requested). + if (this->addAssignmentRelatedVariablesToSourcePredicates) { + auto const& assignedVariableBlock = localExpressionInformation.getRelatedExpressions(assignedVariable); + result.first.insert(assignedVariableBlock.begin(), assignedVariableBlock.end()); + } } return result; @@ -508,6 +520,18 @@ namespace storm { result.second.push_back(relevantUpdatePredicates.second); } +// std::cout << "relevant predicates for command " << command.get().getGlobalIndex() << std::endl; +// std::cout << "source predicates" << std::endl; +// for (auto const& i : result.first) { +// std::cout << this->getAbstractionInformation().getPredicateByIndex(i) << std::endl; +// } +// for (uint64_t i = 0; i < result.second.size(); ++i) { +// std::cout << "destination " << i << std::endl; +// for (auto const& j : result.second[i]) { +// std::cout << this->getAbstractionInformation().getPredicateByIndex(j) << std::endl; +// } +// } + return result; } diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index 9cc48b3b2..f37abbdb5 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -247,6 +247,9 @@ namespace storm { // A flag indicating whether to use the decomposition when abstracting. bool useDecomposition; + // Whether or not to add predicates indirectly related to assignment variables to relevant source predicates. + bool addAssignmentRelatedVariablesToSourcePredicates; + // A flag indicating whether the guard of the command was added as a predicate. If this is true, there // is no need to compute bottom states. bool skipBottomStates; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 19001708a..4db02a199 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -66,6 +66,7 @@ namespace storm { // For each module of the concrete program, we create an abstract counterpart. auto const& settings = storm::settings::getModule(); bool useDecomposition = settings.isUseDecompositionSet(); + restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration; bool debug = settings.isDebugSet(); for (auto const& module : program.getModules()) { this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition, debug); @@ -92,8 +93,10 @@ namespace storm { // Refine initial state abstractor. initialStateAbstractor.refine(predicateIndices); - // Refine the valid blocks. - validBlockAbstractor.refine(predicateIndices); + if (restrictToValidBlocks) { + // Refine the valid blocks. + validBlockAbstractor.refine(predicateIndices); + } refinementPerformed |= !command.getPredicates().empty(); } @@ -175,15 +178,21 @@ namespace storm { } relevantStatesWatch.stop(); - storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + storm::dd::Bdd extendedTransitionRelation = nonTerminalStates && game.bdd; + storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); + if (restrictToValidBlocks) { + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); - // Compute the choices with only valid successors so we can restrict the game to these. - auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + // Compute the choices with only valid successors so we can restrict the game to these. + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + + // Restrict the proper parts. + extendedTransitionRelation &= validBlocks && choicesWithOnlyValidSuccessors; + initialStates &= validBlocks; + } // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd extendedTransitionRelation = validBlocks && nonTerminalStates && game.bdd && choicesWithOnlyValidSuccessors; storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); - storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates() && validBlocks; initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 91c4fd2c7..9e829726e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -159,6 +159,9 @@ namespace storm { // A state-set abstractor used to determine the initial states of the abstraction. StateSetAbstractor initialStateAbstractor; + // A flag indicating whether the valid blocks need to be computed and the game restricted to these. + bool restrictToValidBlocks; + // An object that is used to compute the valid blocks. ValidBlockAbstractor validBlockAbstractor; diff --git a/src/storm/logic/BoundedUntilFormula.cpp b/src/storm/logic/BoundedUntilFormula.cpp index 89be6a2ba..1933db10e 100644 --- a/src/storm/logic/BoundedUntilFormula.cpp +++ b/src/storm/logic/BoundedUntilFormula.cpp @@ -99,10 +99,10 @@ namespace storm { } else { this->getLeftSubformula().gatherUsedVariables(usedVariables); this->getRightSubformula().gatherUsedVariables(usedVariables); - if (this->hasLowerBound()) { + if (this->hasLowerBound(0)) { this->getLowerBound().gatherVariables(usedVariables); } - if (this->hasUpperBound()) { + if (this->hasUpperBound(0)) { this->getUpperBound().gatherVariables(usedVariables); } } @@ -189,7 +189,7 @@ namespace storm { } bool BoundedUntilFormula::hasUpperBound() const { - for(auto const& ub : upperBound) { + for (auto const& ub : upperBound) { if (static_cast(ub)) { return true; } diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index d437e81e8..3f02b352a 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -33,6 +33,7 @@ namespace storm { const std::string AbstractionSettings::injectRefinementPredicatesOptionName = "injectref"; const std::string AbstractionSettings::fixPlayer1StrategyOptionName = "fixpl1strat"; const std::string AbstractionSettings::fixPlayer2StrategyOptionName = "fixpl2strat"; + const std::string AbstractionSettings::validBlockModeOptionName = "validmode"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; @@ -132,6 +133,13 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("off").build()) .build()); + + std::vector validModes = {"morepreds", "blockenum"}; + this->addOption(storm::settings::OptionBuilder(moduleName, validBlockModeOptionName, true, "Sets the mode to guarantee valid blocks only.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(validModes)) + .setDefaultValueString("morepreds").build()) + .build()); + } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -266,6 +274,16 @@ namespace storm { return this->getOption(fixPlayer2StrategyOptionName).getArgumentByName("value").getValueAsString() == "on"; } + AbstractionSettings::ValidBlockMode AbstractionSettings::getValidBlockMode() const { + std::string modeAsString = this->getOption(validBlockModeOptionName).getArgumentByName("mode").getValueAsString(); + if (modeAsString == "morepreds") { + return ValidBlockMode::MorePredicates; + } else if (modeAsString == "blockenum") { + return ValidBlockMode::BlockEnumeration; + } + return ValidBlockMode::MorePredicates; + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index dbcaffd9d..4619f300c 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -31,6 +31,10 @@ namespace storm { Dd, Sparse }; + enum class ValidBlockMode { + MorePredicates, BlockEnumeration + }; + /*! * Creates a new set of abstraction settings. */ @@ -186,6 +190,11 @@ namespace storm { */ bool isFixPlayer2StrategySet() const; + /*! + * Retrieves the selected mode to guarantee valid blocks. + */ + ValidBlockMode getValidBlockMode() const; + const static std::string moduleName; private: @@ -209,6 +218,7 @@ namespace storm { const static std::string injectRefinementPredicatesOptionName; const static std::string fixPlayer1StrategyOptionName; const static std::string fixPlayer2StrategyOptionName; + const static std::string validBlockModeOptionName; }; } From a178f4563f1193d1442281ca180f45be73720743 Mon Sep 17 00:00:00 2001 From: dehnert Date: Tue, 11 Sep 2018 21:06:14 +0200 Subject: [PATCH 543/647] slight polishing of valid-block-mode treatment, also for JANI --- .../abstraction/jani/AutomatonAbstractor.cpp | 4 +-- .../abstraction/jani/AutomatonAbstractor.h | 2 +- src/storm/abstraction/jani/EdgeAbstractor.cpp | 13 ++++++++- src/storm/abstraction/jani/EdgeAbstractor.h | 5 +++- .../jani/JaniMenuGameAbstractor.cpp | 29 +++++++++++++------ .../abstraction/jani/JaniMenuGameAbstractor.h | 3 ++ .../abstraction/prism/CommandAbstractor.cpp | 13 ++++----- .../abstraction/prism/CommandAbstractor.h | 4 +-- .../abstraction/prism/ModuleAbstractor.cpp | 4 +-- .../abstraction/prism/ModuleAbstractor.h | 2 +- .../prism/PrismMenuGameAbstractor.cpp | 4 ++- 11 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index 21481f00c..5d399fc56 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -24,12 +24,12 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { + AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { // For each concrete command, we create an abstract counterpart. uint64_t edgeId = 0; for (auto const& edge : automaton.getEdges()) { - edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition, debug); + edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); ++edgeId; } diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index 3053de3c4..9b58ba9c1 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -35,7 +35,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); + AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); AutomatonAbstractor(AutomatonAbstractor const&) = default; AutomatonAbstractor& operator=(AutomatonAbstractor const&) = default; diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index 950221dcd..ee52cae71 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace jani { template - EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory), debug(debug) { + EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addPredicatesForValidBlocks(addPredicatesForValidBlocks), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(edge.getNumberOfDestinations()); @@ -43,6 +43,11 @@ namespace storm { assignedVariables.insert(assignment.getExpressionVariable()); } } + + // Log whether or not predicates are added to ensure valid blocks. + if (this->addPredicatesForValidBlocks) { + STORM_LOG_DEBUG("Adding more predicates to ensure valid blocks."); + } } template @@ -489,6 +494,12 @@ namespace storm { storm::expressions::Variable const& assignedVariable = assignment.getExpressionVariable(); auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); + + // Predicates that are indirectly related to the assigned variables are relevant for the source state (if requested). + if (this->addPredicatesForValidBlocks) { + auto const& assignedVariableBlock = localExpressionInformation.getRelatedExpressions(assignedVariable); + result.first.insert(assignedVariableBlock.begin(), assignedVariableBlock.end()); + } } return result; diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index 3c8c1d21b..8c02e8b76 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -58,7 +58,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use an edge decomposition during abstraction. */ - EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); + EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); /*! * Refines the abstract edge with the given predicates. @@ -246,6 +246,9 @@ namespace storm { // A flag indicating whether to use the decomposition when abstracting. bool useDecomposition; + + // Whether or not to add predicates indirectly related to assignment variables to relevant source predicates. + bool addPredicatesForValidBlocks; // A flag indicating whether the computation of bottom states can be skipped (for example, if the bottom // states become empty at some point). diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index a71d78f04..991870ede 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -35,7 +35,7 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager()), AbstractionInformationOptions(options.constraints)), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { + JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager()), AbstractionInformationOptions(options.constraints)), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), restrictToValidBlocks(false), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { // Check whether the model is linear as the abstraction requires this. STORM_LOG_WARN_COND(model.isLinear(), "The model appears to contain non-linear expressions, which may cause malfunctioning of the abstraction."); @@ -70,9 +70,11 @@ namespace storm { // For each module of the concrete program, we create an abstract counterpart. auto const& settings = storm::settings::getModule(); bool useDecomposition = settings.isUseDecompositionSet(); + restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration; + bool addPredicatesForValidBlocks = !restrictToValidBlocks; bool debug = settings.isDebugSet(); for (auto const& automaton : model.getAutomata()) { - automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition, debug); + automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } // Retrieve global BDDs/ADDs so we can multiply them in the abstraction process. @@ -97,8 +99,10 @@ namespace storm { // Refine initial state abstractor. initialStateAbstractor.refine(predicateIndices); - // Refine the valid blocks. - validBlockAbstractor.refine(predicateIndices); + if (this->restrictToValidBlocks) { + // Refine the valid blocks. + validBlockAbstractor.refine(predicateIndices); + } refinementPerformed |= !command.getPredicates().empty(); } @@ -183,15 +187,22 @@ namespace storm { } relevantStatesWatch.stop(); - storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + storm::dd::Bdd extendedTransitionRelation = nonTerminalStates && game.bdd; + storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); + if (this->restrictToValidBlocks) { + STORM_LOG_DEBUG("Restricting to valid blocks."); + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); - // Compute the choices with only valid successors so we can restrict the game to these. - auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + // Compute the choices with only valid successors so we can restrict the game to these. + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + + // Restrict the proper parts. + extendedTransitionRelation &= validBlocks && choicesWithOnlyValidSuccessors; + initialStates &= validBlocks; + } // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd extendedTransitionRelation = validBlocks && nonTerminalStates && game.bdd && choicesWithOnlyValidSuccessors; storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); - storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates() && validBlocks; initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index d9f04f828..2017b2c17 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -159,6 +159,9 @@ namespace storm { // A state-set abstractor used to determine the initial states of the abstraction. StateSetAbstractor initialStateAbstractor; + // A flag indicating whether the valid blocks need to be computed and the game restricted to these. + bool restrictToValidBlocks; + // An object that is used to compute the valid blocks. ValidBlockAbstractor validBlockAbstractor; diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index a57c990c7..ecb415655 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -13,9 +13,6 @@ #include "storm/storage/prism/Command.h" #include "storm/storage/prism/Update.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/AbstractionSettings.h" - #include "storm/utility/solver.h" #include "storm/utility/macros.h" @@ -26,7 +23,7 @@ namespace storm { namespace abstraction { namespace prism { template - CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addAssignmentRelatedVariablesToSourcePredicates(false), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { + CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addPredicatesForValidBlocks(addPredicatesForValidBlocks), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); @@ -47,8 +44,10 @@ namespace storm { } } - auto const& abstractionSettings = storm::settings::getModule(); - addAssignmentRelatedVariablesToSourcePredicates = abstractionSettings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::MorePredicates; + // Log whether or not predicates are added to ensure valid blocks. + if (this->addPredicatesForValidBlocks) { + STORM_LOG_DEBUG("Adding more predicates to ensure valid blocks."); + } } template @@ -497,7 +496,7 @@ namespace storm { result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); // Predicates that are indirectly related to the assigned variables are relevant for the source state (if requested). - if (this->addAssignmentRelatedVariablesToSourcePredicates) { + if (this->addPredicatesForValidBlocks) { auto const& assignedVariableBlock = localExpressionInformation.getRelatedExpressions(assignedVariable); result.first.insert(assignedVariableBlock.begin(), assignedVariableBlock.end()); } diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index f37abbdb5..e6f8f6a6f 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -56,7 +56,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); + CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); /*! * Refines the abstract command with the given predicates. @@ -248,7 +248,7 @@ namespace storm { bool useDecomposition; // Whether or not to add predicates indirectly related to assignment variables to relevant source predicates. - bool addAssignmentRelatedVariablesToSourcePredicates; + bool addPredicatesForValidBlocks; // A flag indicating whether the guard of the command was added as a predicate. If this is true, there // is no need to compute bottom states. diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index ab031eeab..f17d47df3 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -23,11 +23,11 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { + ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { // For each concrete command, we create an abstract counterpart. for (auto const& command : module.getCommands()) { - commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition, debug); + commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index 9771347c6..72a7bb492 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -38,7 +38,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag that governs whether to use the decomposition in the abstraction. */ - ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool debug); + ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); ModuleAbstractor(ModuleAbstractor const&) = default; ModuleAbstractor& operator=(ModuleAbstractor const&) = default; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 4db02a199..9e018ce3e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -67,9 +67,10 @@ namespace storm { auto const& settings = storm::settings::getModule(); bool useDecomposition = settings.isUseDecompositionSet(); restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration; + bool addPredicatesForValidBlocks = !restrictToValidBlocks; bool debug = settings.isDebugSet(); for (auto const& module : program.getModules()) { - this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition, debug); + this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } // Retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later. @@ -181,6 +182,7 @@ namespace storm { storm::dd::Bdd extendedTransitionRelation = nonTerminalStates && game.bdd; storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); if (restrictToValidBlocks) { + STORM_LOG_DEBUG("Restricting to valid blocks."); storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); // Compute the choices with only valid successors so we can restrict the game to these. From 69cbc285477580a617c03117cd9f926acdfdb5ae Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 12 Sep 2018 12:51:47 +0200 Subject: [PATCH 544/647] fixes for arrays --- src/storm-parsers/parser/JaniParser.cpp | 9 ++++++-- .../generator/JaniNextStateGenerator.cpp | 22 +++++++++++-------- src/storm/generator/VariableInformation.cpp | 3 ++- src/storm/storage/jani/ArrayEliminator.cpp | 10 +++++++++ src/storm/storage/jani/ArrayEliminator.h | 7 ++++++ 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 16bf04056..c21add9e7 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -788,12 +788,17 @@ namespace storm { if (setInitValFromDefault) { initVal = storm::expressions::ValueArrayExpression(*expressionManager, exprVariableType, {}).toExpression(); } + std::shared_ptr result; if (initVal) { STORM_LOG_THROW(initVal->getType().isArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scopeDescription + ") should be an Array"); - return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType, initVal.get(), transientVar); + result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType, initVal.get(), transientVar); } else { - return std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType); + result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType); } + if (type.arrayBase->bounds) { + result->setElementTypeBounds(type.arrayBase->bounds->first, type.arrayBase->bounds->second); + } + return result; } STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 9af945704..7801db91d 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -46,7 +46,7 @@ namespace storm { if (this->model.containsArrayVariables()) { arrayEliminatorData = this->model.eliminateArrays(true); } - + // Lift the transient edge destinations of the first assignment level. uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); if (this->model.hasTransientEdgeDestinationAssignments()) { @@ -67,7 +67,7 @@ namespace storm { // Now we are ready to initialize the variable information. this->checkValid(); - this->variableInformation = VariableInformation(model, this->parallelAutomata, options.isAddOutOfBoundsStateSet()); + this->variableInformation = VariableInformation(this->model, this->parallelAutomata, options.isAddOutOfBoundsStateSet()); this->variableInformation.registerArrayVariableReplacements(arrayEliminatorData); // Create a proper evalator. @@ -504,8 +504,9 @@ namespace storm { bool done = false; while (!done) { std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); - + currentDistribution.clear(); currentDistribution.add(state, storm::utility::one()); + nextDistribution.clear(); EdgeIndexSet edgeIndices; uint64_t assignmentLevel = std::numeric_limits::max(); @@ -549,12 +550,12 @@ namespace storm { } } } - nextDistribution.compress(); - + // If there is one more command to come, shift the target states one time step back. if (i < iteratorList.size() - 1) { currentDistribution = std::move(nextDistribution); + nextDistribution.clear(); } } } else { @@ -582,7 +583,6 @@ namespace storm { destinations.push_back(&edge.getDestination(destinationIndex % edge.getNumberOfDestinations())); locationVars.push_back(&this->variableInformation.locationVariables[edgeCombination[i].first]); STORM_LOG_ASSERT(edge.getNumberOfDestinations() > 0, "Found an edge with zero destinations. This is not expected."); - std::cout << destinationIndex % edge.getNumberOfDestinations(); if (i == iteratorList.size() - 1 && (destinationIndex % edge.getNumberOfDestinations()) == edge.getNumberOfDestinations() - 1) { lastDestinationId = true; } @@ -623,10 +623,9 @@ namespace storm { storm::utility::vector::addScaledVector(stateActionRewards, destinationRewards, successorProbability); } ++destinationId; - std::cout << "\t"; } while (!lastDestinationId); - std::cout << std::endl; } + nextDistribution.compress(); for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { storm::jani::Edge const& edge = *iteratorList[i]->second; @@ -793,10 +792,15 @@ namespace storm { // As in JANI we can use transient boolean variable assignments in locations to identify states, we need to // create a list of boolean transient variables and the expressions that define them. std::unordered_map transientVariableToExpressionMap; + bool translateArrays = !this->arrayEliminatorData.replacements.empty(); for (auto const& variable : model.getGlobalVariables().getTransientVariables()) { if (variable.isBooleanVariable()) { if (this->options.isBuildAllLabelsSet() || this->options.getLabelNames().find(variable.getName()) != this->options.getLabelNames().end()) { - transientVariableToExpressionMap[variable.getExpressionVariable()] = model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata); + storm::expressions::Expression labelExpression = model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata); + if (translateArrays) { + labelExpression = this->arrayEliminatorData.transformExpression(labelExpression); + } + transientVariableToExpressionMap[variable.getExpressionVariable()] = std::move(labelExpression); } } } diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 36134c182..8c710f504 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -125,6 +125,7 @@ namespace storm { } ++index; } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); } else if (replacedVar->getExpressionVariable().hasBooleanType()) { uint64_t index = 0; for (auto const& boolInfo : booleanVariables) { @@ -134,11 +135,11 @@ namespace storm { } ++index; } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); } else { STORM_LOG_ASSERT(false, "Unhandled type of base variable."); } } - STORM_LOG_ASSERT(arrayReplacements.second.size() == varInfoIndices.size(), "Could not find a basic variable for every array variable replacement."); this->arrayVariableToElementInformations.emplace(arrayReplacements.first, std::move(varInfoIndices)); } } diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp index 114e8ef3a..d3d7d47fb 100644 --- a/src/storm/storage/jani/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -569,6 +569,15 @@ namespace storm { }; } // namespace detail + storm::expressions::Expression ArrayEliminatorData::transformExpression(storm::expressions::Expression const& arrayExpression) const { + std::unordered_map arraySizes; + for (auto const& r : replacements) { + arraySizes.emplace(r.first, r.second.size()); + } + detail::ArrayExpressionEliminationVisitor eliminator(replacements, arraySizes); + return eliminator.eliminate(arrayExpression); + } + ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); @@ -577,6 +586,7 @@ namespace storm { STORM_LOG_ASSERT(!containsArrayExpression(model), "the model still contains array expressions."); return result; } + } } diff --git a/src/storm/storage/jani/ArrayEliminator.h b/src/storm/storage/jani/ArrayEliminator.h index 4193d96fc..860aa37ea 100644 --- a/src/storm/storage/jani/ArrayEliminator.h +++ b/src/storm/storage/jani/ArrayEliminator.h @@ -11,12 +11,19 @@ namespace storm { struct ArrayEliminatorData { std::vector> eliminatedArrayVariables; std::unordered_map> replacements; + + // Transforms the given expression (which might contain array expressions) to an equivalent expression without array variables. + storm::expressions::Expression transformExpression(storm::expressions::Expression const& arrayExpression) const; }; class ArrayEliminator { public: ArrayEliminator() = default; + /*! + * Eliminates all array references in the given model by replacing them with basic variables. + */ + ArrayEliminatorData eliminate(Model& model, bool keepNonTrivialArrayAccess = false); private: From 274bfef6527e30e46bb0e79c7bc6fa6b1ea2850d Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 12 Sep 2018 14:29:48 +0200 Subject: [PATCH 545/647] started to extend storm-conv for array elimination --- src/storm-conv-cli/storm-conv.cpp | 35 +++++++++++++++++++ src/storm-conv/api/storm-conv.cpp | 14 ++++++-- src/storm-conv/api/storm-conv.h | 2 +- .../options/JaniConversionOptions.cpp | 4 +-- .../converter/options/JaniConversionOptions.h | 8 ++++- .../modules/ConversionInputSettings.cpp | 13 ++++++- .../modules/ConversionInputSettings.h | 11 ++++++ .../settings/modules/JaniExportSettings.cpp | 12 +++++++ .../settings/modules/JaniExportSettings.h | 6 ++++ src/storm-gspn/api/storm-gspn.cpp | 5 +-- src/storm-pgcl-cli/storm-pgcl.cpp | 2 +- src/storm/storage/jani/Model.cpp | 7 ++-- src/storm/storage/jani/Model.h | 8 ++++- 13 files changed, 113 insertions(+), 14 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index a499fccf2..1977cfdb7 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -124,14 +124,49 @@ namespace storm { } } + void processJaniInput() { + auto const& input = storm::settings::getModule(); + + // Parse the jani model + auto janiModelProperties = storm::api::parseJaniModel(input.getJaniInputFilename()); + storm::storage::SymbolicModelDescription janiModel(janiModelProperties.first); + // Parse properties (if available, otherwise take the ones from the jani file) + std::vector properties; + if (input.isPropertyInputSet()) { + boost::optional> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter()); + properties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), janiModel, propertyFilter); + } else { + properties.insert(properties.end(), janiModelProperties.second.begin(), janiModelProperties.second.end()); + } + + // Substitute constant definitions in program and properties. + std::string constantDefinitionString = input.getConstantDefinitionString(); + auto constantDefinitions = janiModel.parseConstantDefinitions(constantDefinitionString); + janiModel = janiModel.preprocess(constantDefinitions); + if (!properties.empty()) { + properties = storm::api::substituteConstantsInProperties(properties, constantDefinitions); + } + + // Branch on the type of output + auto const& output = storm::settings::getModule(); + if (output.isJaniOutputSet()) { +// processJaniInputJaniOutput(janiModel.asJaniModel(), properties); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible."); + } + } + void processOptions() { // Start by setting some urgent options (log levels, etc.) setUrgentOptions(); // Branch on the type of input auto const& input = storm::settings::getModule(); + STORM_LOG_THROW(!(input.isPrismInputSet() && input.isJaniInputSet()), storm::exceptions::InvalidSettingsException, "Multiple input options were set."); if (input.isPrismInputSet()) { processPrismInput(); + } else if (input.isJaniInputSet()) { + processJaniInput(); } } } diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index aa37dd191..9a965fb65 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -11,7 +11,7 @@ namespace storm { namespace api { - void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options) { + void transformJani(storm::jani::Model& janiModel, std::vector& properties, storm::converter::JaniConversionOptions const& options) { if (!options.locationVariables.empty()) { for (auto const& pair : options.locationVariables) { @@ -21,7 +21,7 @@ namespace storm { } } - if (options.exportFlattened) { + if (options.flatten) { std::shared_ptr smtSolverFactory; if (storm::settings::hasModule()) { smtSolverFactory = std::make_shared(); @@ -35,6 +35,14 @@ namespace storm { janiModel.makeStandardJaniCompliant(); } + if (!options.allowArrays && janiModel.getModelFeatures().hasArrays()) { + janiModel.eliminateArrays(properties); + } + + //if (!options.allowFunctions && janiModel.getModelFeatures().hasFunctions()) { + //janiModel = janiModel.substituteFunctions(); + //} + if (options.modelName) { janiModel.setName(options.modelName.get()); } @@ -53,7 +61,7 @@ namespace storm { } // Postprocess Jani model based on the options - postprocessJani(res.first, options.janiOptions); + transformJani(res.first, res.second, options.janiOptions); return res; } diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h index 42cbf804d..12e45269d 100644 --- a/src/storm-conv/api/storm-conv.h +++ b/src/storm-conv/api/storm-conv.h @@ -15,7 +15,7 @@ namespace storm { namespace api { - void postprocessJani(storm::jani::Model& janiModel, storm::converter::JaniConversionOptions options); + void transformJani(storm::jani::Model& janiModel, std::vector& properties, storm::converter::JaniConversionOptions const& options); std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()); diff --git a/src/storm-conv/converter/options/JaniConversionOptions.cpp b/src/storm-conv/converter/options/JaniConversionOptions.cpp index 7b72c4797..4b7a78d76 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.cpp +++ b/src/storm-conv/converter/options/JaniConversionOptions.cpp @@ -3,11 +3,11 @@ namespace storm { namespace converter { - JaniConversionOptions::JaniConversionOptions() : standardCompliant(false), exportFlattened(false) { + JaniConversionOptions::JaniConversionOptions() : standardCompliant(false), flatten(false), allowArrays(true), allowFunctions(true) { // Intentionally left empty }; - JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), standardCompliant(settings.isExportAsStandardJaniSet()), exportFlattened(settings.isExportFlattenedSet()) { + JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), standardCompliant(settings.isExportAsStandardJaniSet()), flatten(settings.isExportFlattenedSet()), allowArrays(!settings.isEliminateArraysSet()), allowFunctions(!settings.isEliminateFunctionsSet()) { // Intentionally left empty }; } diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h index 000d9cc3b..34452315b 100644 --- a/src/storm-conv/converter/options/JaniConversionOptions.h +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -21,11 +21,17 @@ namespace storm { bool standardCompliant; /// If set, the model is transformed into a single automaton - bool exportFlattened; + bool flatten; /// If given, the model will get this name boost::optional modelName; + /// If not set, arrays in the model are eliminated + bool allowArrays; + + /// if not set, functions in the model are eliminated + bool allowFunctions; + }; } } diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.cpp b/src/storm-conv/settings/modules/ConversionInputSettings.cpp index cc91d597c..090efe901 100644 --- a/src/storm-conv/settings/modules/ConversionInputSettings.cpp +++ b/src/storm-conv/settings/modules/ConversionInputSettings.cpp @@ -20,6 +20,7 @@ namespace storm { const std::string ConversionInputSettings::prismInputOptionName = "prism"; const std::string ConversionInputSettings::prismCompatibilityOptionName = "prismcompat"; const std::string ConversionInputSettings::prismCompatibilityOptionShortName = "pc"; + const std::string ConversionInputSettings::janiInputOptionName = "jani"; ConversionInputSettings::ConversionInputSettings() : ModuleSettings(moduleName) { @@ -27,10 +28,12 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("property or filename", "The formula or the file containing the formulas.").build()) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filter", "The names of the properties to check.").setDefaultValueString("all").build()) .build()); - this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (i.e., via --" + prismInputOptionName + ").").setShortName(constantsOptionShortName) + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (e.g., via --" + prismInputOptionName + ").").setShortName(constantsOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, prismCompatibilityOptionName, false, "Enables PRISM compatibility. This may be necessary to process some PRISM models.").setShortName(prismCompatibilityOptionShortName).build()); } @@ -42,6 +45,14 @@ namespace storm { return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString(); } + bool ConversionInputSettings::isJaniInputSet() const { + return this->getOption(janiInputOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getJaniInputFilename() const { + return this->getOption(janiInputOptionName).getArgumentByName("filename").getValueAsString(); + } + bool ConversionInputSettings::isPrismCompatibilityEnabled() const { return this->getOption(prismCompatibilityOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.h b/src/storm-conv/settings/modules/ConversionInputSettings.h index 41cf6549e..27e0b4795 100644 --- a/src/storm-conv/settings/modules/ConversionInputSettings.h +++ b/src/storm-conv/settings/modules/ConversionInputSettings.h @@ -63,6 +63,16 @@ namespace storm { */ bool isPrismCompatibilityEnabled() const; + /*! + * Retrieves whether the Jani option was set. + */ + bool isJaniInputSet() const; + + /*! + * Retrieves the name of the file that contains the jani model specification if the model was given. + */ + std::string getJaniInputFilename() const; + bool check() const override; void finalize() override; @@ -78,6 +88,7 @@ namespace storm { static const std::string prismInputOptionName; static const std::string prismCompatibilityOptionName; static const std::string prismCompatibilityOptionShortName; + static const std::string janiInputOptionName; }; diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp index 707e91dac..37fb525ab 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.cpp +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -20,6 +20,8 @@ namespace storm { const std::string JaniExportSettings::locationVariablesOptionName = "location-variables"; const std::string JaniExportSettings::globalVariablesOptionName = "globalvars"; const std::string JaniExportSettings::compactJsonOptionName = "compactjson"; + const std::string JaniExportSettings::eliminateArraysOptionName = "eliminate-arrays"; + const std::string JaniExportSettings::eliminateFunctionsOptionName = "eliminate-functions"; JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { @@ -28,6 +30,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, compactJsonOptionName, false, "If set, the size of the resulting jani file will be reduced at the cost of (human-)readability.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, eliminateArraysOptionName, false, "If set, transforms the model such that array variables/expressions are eliminated.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, eliminateFunctionsOptionName, false, "If set, transforms the model such that functions are eliminated.").build()); } bool JaniExportSettings::isExportAsStandardJaniSet() const { @@ -66,6 +70,14 @@ namespace storm { return this->getOption(compactJsonOptionName).getHasOptionBeenSet(); } + bool JaniExportSettings::isEliminateArraysSet() const { + return this->getOption(eliminateArraysOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isEliminateFunctionsSet() const { + return this->getOption(eliminateFunctionsOptionName).getHasOptionBeenSet(); + } + void JaniExportSettings::finalize() { } diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h index 99e00ea9b..985eabe4a 100644 --- a/src/storm-conv/settings/modules/JaniExportSettings.h +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -23,6 +23,10 @@ namespace storm { bool isGlobalVarsSet() const; bool isCompactJsonSet() const; + + bool isEliminateArraysSet() const; + + bool isEliminateFunctionsSet() const; std::vector> getLocationVariables() const; @@ -38,6 +42,8 @@ namespace storm { static const std::string locationVariablesOptionName; static const std::string globalVariablesOptionName; static const std::string compactJsonOptionName; + static const std::string eliminateArraysOptionName; + static const std::string eliminateFunctionsOptionName; }; } diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp index 63da78250..e9f23fe48 100644 --- a/src/storm-gspn/api/storm-gspn.cpp +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -66,12 +66,13 @@ namespace storm { storm::builder::JaniGSPNBuilder builder(gspn); storm::jani::Model* model = builder.build("gspn_automaton", exportSettings.isAddJaniPropertiesSet()); - storm::api::postprocessJani(*model, options); - auto properties = janiProperyGetter(builder); if (exportSettings.isAddJaniPropertiesSet()) { properties.insert(properties.end(), builder.getStandardProperties().begin(), builder.getStandardProperties().end()); } + + storm::api::transformJani(*model, properties, options); + storm::api::exportJaniToFile(*model, properties, exportSettings.getWriteToJaniFilename(), jani.isCompactJsonSet()); delete model; } diff --git a/src/storm-pgcl-cli/storm-pgcl.cpp b/src/storm-pgcl-cli/storm-pgcl.cpp index fe4585023..2c81dc945 100644 --- a/src/storm-pgcl-cli/storm-pgcl.cpp +++ b/src/storm-pgcl-cli/storm-pgcl.cpp @@ -41,7 +41,7 @@ void initializeSettings() { void handleJani(storm::jani::Model& model) { auto const& jani = storm::settings::getModule(); storm::converter::JaniConversionOptions options(jani); - storm::api::postprocessJani(model, options); + storm::api::transformJani(model, {}, options); if (storm::settings::getModule().isToJaniSet()) { storm::api::exportJaniToFile(model, {}, storm::settings::getModule().getWriteToJaniFilename(), jani.isCompactJsonSet()); } else { diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index c326e7314..c59eb5a34 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -959,8 +959,11 @@ namespace storm { return arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess); } - void Model::eliminateArrays() { - eliminateArrays(false); + void Model::eliminateArrays(std::vector& properties) { + auto data = eliminateArrays(false); + for (auto& p : properties) { + data.transformProperty(p); + } } void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 3224c0353..6bce3603d 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -35,6 +35,7 @@ namespace storm { class Exporter; class SynchronizationVector; class ArrayEliminatorData; + class Property; class Model { public: @@ -380,7 +381,12 @@ namespace storm { * @return data from the elimination. If non-trivial array accesses are kept, pointers to remaining array variables point to this data. */ ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess); - void eliminateArrays(); + + /*! + * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. + * @param properties also eliminates array expressions in the given properties + */ + void eliminateArrays(std::vector& properties); /*! * Retrieves whether there is an expression restricting the legal initial values of the global variables. From 7c61a16d9157b7be316ac6b855d4dd11532a4271 Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 12 Sep 2018 16:16:33 +0200 Subject: [PATCH 546/647] fixes for array expressions, support to translate properties that consider array expressions, translating array models in cli --- src/storm-cli-utilities/CMakeLists.txt | 2 +- src/storm-cli-utilities/model-handling.h | 10 ++ src/storm/builder/BuilderOptions.cpp | 20 +++- src/storm/builder/BuilderOptions.h | 10 +- src/storm/builder/DdJaniModelBuilder.cpp | 3 + .../jit/ExplicitJitJaniModelBuilder.cpp | 15 +-- .../generator/JaniNextStateGenerator.cpp | 10 +- src/storm/generator/NextStateGenerator.cpp | 6 +- .../logic/ExpressionSubstitutionVisitor.cpp | 99 +++++++++++++++++++ .../logic/ExpressionSubstitutionVisitor.h | 33 +++++++ src/storm/logic/Formula.cpp | 12 ++- src/storm/logic/Formula.h | 1 + src/storm/storage/jani/ArrayEliminator.cpp | 9 +- src/storm/storage/jani/ArrayEliminator.h | 3 + src/storm/storage/jani/Model.cpp | 3 +- src/storm/storage/jani/ModelFeatures.cpp | 4 + src/storm/storage/jani/ModelFeatures.h | 3 + src/storm/storage/jani/Property.cpp | 4 + src/storm/storage/jani/Property.h | 9 +- 19 files changed, 228 insertions(+), 28 deletions(-) create mode 100644 src/storm/logic/ExpressionSubstitutionVisitor.cpp create mode 100644 src/storm/logic/ExpressionSubstitutionVisitor.h diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index de4c0fde1..ee67568ba 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers storm-conv) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 524d772be..14cd9aa3f 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -4,6 +4,7 @@ #include "storm-counterexamples/api/counterexamples.h" #include "storm-parsers/api/storm-parsers.h" +#include "storm-conv/api/storm-conv.h" #include "storm/utility/resources.h" #include "storm/utility/file.h" @@ -154,6 +155,15 @@ namespace storm { } } + if (output.model && output.model.get().isJaniModel()) { + storm::converter::JaniConversionOptions options; + options.allowFunctions = false; + options.allowArrays = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && !buildSettings.isJitSet(); + options.standardCompliant = false; + options.flatten = false; + output.preprocessedProperties = output.properties; + storm::api::transformJani(output.model.get().asJaniModel(), output.preprocessedProperties.get(), options); + } return output; } diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index 271a4e873..069f44b68 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -129,7 +129,7 @@ namespace storm { return labelNames; } - std::vector const& BuilderOptions::getExpressionLabels() const { + std::vector> const& BuilderOptions::getExpressionLabels() const { return expressionLabels; } @@ -211,7 +211,9 @@ namespace storm { } BuilderOptions& BuilderOptions::addLabel(storm::expressions::Expression const& expression) { - expressionLabels.emplace_back(expression); + std::stringstream stream; + stream << expression; + expressionLabels.emplace_back(stream.str(), expression); return *this; } @@ -261,5 +263,19 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::substituteExpressions(std::function const& substitutionFunction) { + for (auto& e : expressionLabels) { + e.second = substitutionFunction(e.second); + } + + for (auto& t : terminalStates) { + if (t.first.isExpression()) { + t.first = LabelOrExpression(substitutionFunction(t.first.getExpression())); + } + } + return *this; + } + + } } diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index eba9ff1da..813f31b67 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -96,7 +96,7 @@ namespace storm { * Which expression labels are built * @return */ - std::vector const& getExpressionLabels() const; + std::vector> const& getExpressionLabels() const; std::vector> const& getTerminalStates() const; bool hasTerminalStates() const; void clearTerminalStates(); @@ -179,7 +179,11 @@ namespace storm { */ BuilderOptions& setAddOverlappingGuardsLabel(bool newValue = true); - + /** + * Substitutes all expressions occurring in these options. + */ + BuilderOptions& substituteExpressions(std::function const& substitutionFunction); + private: /// A flag that indicates whether all reward models are to be built. In this case, the reward model names are /// to be ignored. @@ -195,7 +199,7 @@ namespace storm { std::set labelNames; /// The expression that are to be used for creating the state labeling. - std::vector expressionLabels; + std::vector> expressionLabels; /// If one of these labels/expressions evaluates to the given bool, the builder can abort the exploration. std::vector> terminalStates; diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index 4260c7c7f..47cd321db 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -1986,6 +1986,9 @@ namespace storm { } STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::WrongFormatException, "The symbolic JANI model builder currently does not support assignment levels."); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The dd jani model builder does not support the following model feature(s): " << features.toString() << "."); storm::jani::Model preparedModel = model; diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp index 9a7042d81..d34a6c9f1 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp @@ -107,10 +107,6 @@ namespace storm { transientVariables.insert(variable.getExpressionVariable()); } - if (this->model.containsArrayVariables()) { - this->model.eliminateArrays(); - } - // Construct vector of the automata to be put in parallel. storm::jani::Composition const& topLevelComposition = this->model.getSystemComposition(); if (topLevelComposition.isAutomatonComposition()) { @@ -151,6 +147,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The input model contains undefined constants that influence the graph structure of the underlying model, which is not allowed."); } #endif + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidArgumentException, "The jit model builder does not support the following model feature(s): " << features.toString() << "."); + //STORM_LOG_THROW(!model.reusesActionsInComposition(), storm::exceptions::InvalidArgumentException, "The jit JANI model builder currently does not support reusing actions in parallel composition"); // Comment this in to print the JANI model for debugging purposes. @@ -1562,11 +1562,12 @@ namespace storm { } std::set expressionLabelStrings; - for (auto const& expression : this->options.getExpressionLabels()) { + for (auto const& expressionLabel : this->options.getExpressionLabels()) { cpptempl::data_map label; - std::string expressionLabelString = expression.toString(); + std::string const& expressionLabelString = expressionLabel.first; + auto const& expression = expressionLabel.second; if(expressionLabelStrings.count(expressionLabelString) == 0) { - label["name"] = expression.toString(); + label["name"] = expressionLabelString; label["predicate"] = expressionTranslator.translate(shiftVariablesWrtLowerBound(expression), storm::expressions::ToCppTranslationOptions(variablePrefixes, variableToName, storm::expressions::ToCppTranslationMode::CastDouble)); labels.push_back(label); expressionLabelStrings.insert(expressionLabelString); diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 7801db91d..8575f3a7d 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -3,7 +3,6 @@ #include "storm/models/sparse/StateLabeling.h" #include "storm/storage/expressions/SimpleValuation.h" - #include "storm/solver/SmtSolver.h" #include "storm/storage/jani/Edge.h" @@ -15,6 +14,7 @@ #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/traverser/AssignmentLevelFinder.h" +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" #include "storm/storage/sparse/JaniChoiceOrigins.h" @@ -42,10 +42,15 @@ namespace storm { STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); // Eliminate arrays if necessary. - if (this->model.containsArrayVariables()) { + if (features.hasArrays()) { arrayEliminatorData = this->model.eliminateArrays(true); + this->options.substituteExpressions([this](storm::expressions::Expression const& exp) {return arrayEliminatorData.transformExpression(exp);}); + features.remove(storm::jani::ModelFeature::Arrays); } + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator does not support the following model feature(s): " << features.toString() << "."); // Lift the transient edge destinations of the first assignment level. uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); @@ -809,7 +814,6 @@ namespace storm { for (auto const& element : transientVariableToExpressionMap) { transientVariableExpressions.push_back(std::make_pair(element.first.getName(), element.second)); } - return NextStateGenerator::label(stateStorage, initialStateIndices, deadlockStateIndices, transientVariableExpressions); } diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index 3b3186b68..6e1d91bc4 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -67,11 +67,7 @@ namespace storm { template storm::models::sparse::StateLabeling NextStateGenerator::label(storm::storage::sparse::StateStorage const& stateStorage, std::vector const& initialStateIndices, std::vector const& deadlockStateIndices, std::vector> labelsAndExpressions) { - for (auto const& expression : this->options.getExpressionLabels()) { - std::stringstream stream; - stream << expression; - labelsAndExpressions.push_back(std::make_pair(stream.str(), expression)); - } + labelsAndExpressions.insert(labelsAndExpressions.end(), this->options.getExpressionLabels().begin(), this->options.getExpressionLabels().end()); // Make the labels unique. std::sort(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair const& a, std::pair const& b) { return a.first < b.first; } ); diff --git a/src/storm/logic/ExpressionSubstitutionVisitor.cpp b/src/storm/logic/ExpressionSubstitutionVisitor.cpp new file mode 100644 index 000000000..267fcf42c --- /dev/null +++ b/src/storm/logic/ExpressionSubstitutionVisitor.cpp @@ -0,0 +1,99 @@ +#include "storm/logic/ExpressionSubstitutionVisitor.h" + +#include "storm/logic/Formulas.h" + +namespace storm { + namespace logic { + + std::shared_ptr ExpressionSubstitutionVisitor::substitute(Formula const& f, std::function const& substitutionFunction) const { + boost::any result = f.accept(*this, &substitutionFunction); + return boost::any_cast>(result); + } + + OperatorInformation substituteOperatorInformation(OperatorInformation const& operatorInformation, std::function const& substitutionFunction) { + boost::optional bound; + if(operatorInformation.bound) { + bound = Bound(operatorInformation.bound->comparisonType, substitutionFunction(operatorInformation.bound->threshold)); + } + return OperatorInformation(operatorInformation.optimalityType, bound); + } + + boost::any ExpressionSubstitutionVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); + } + + boost::any ExpressionSubstitutionVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::vector> lowerBounds, upperBounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + if (f.hasLowerBound(i)) { + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), substitutionFunction(f.getLowerBound(i)))); + } else { + lowerBounds.emplace_back(); + } + if (f.hasUpperBound(i)) { + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), substitutionFunction(f.getUpperBound(i)))); + } else { + upperBounds.emplace_back(); + } + timeBoundReferences.push_back(f.getTimeBoundReference(i)); + } + if (f.hasMultiDimensionalSubformulas()) { + std::vector> leftSubformulas, rightSubformulas; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + leftSubformulas.push_back(boost::any_cast>(f.getLeftSubformula(i).accept(*this, data))); + rightSubformulas.push_back(boost::any_cast>(f.getRightSubformula(i).accept(*this, data))); + } + return std::static_pointer_cast(std::make_shared(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences)); + } else { + std::shared_ptr left = boost::any_cast>(f.getLeftSubformula().accept(*this, data)); + std::shared_ptr right = boost::any_cast>(f.getRightSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(left, right, lowerBounds, upperBounds, timeBoundReferences)); + } + } + + boost::any ExpressionSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + std::vector bounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + bounds.emplace_back(TimeBound(f.isBoundStrict(i), substitutionFunction(f.getBound(i)))); + timeBoundReferences.push_back(f.getTimeBoundReference(i)); + } + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences)); + } + + boost::any ExpressionSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getBound()), f.getTimeBoundType())); + } + + boost::any ExpressionSubstitutionVisitor::visit(AtomicExpressionFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getExpression()))); + } + + + } +} diff --git a/src/storm/logic/ExpressionSubstitutionVisitor.h b/src/storm/logic/ExpressionSubstitutionVisitor.h new file mode 100644 index 000000000..e594f9b79 --- /dev/null +++ b/src/storm/logic/ExpressionSubstitutionVisitor.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "storm/logic/CloneVisitor.h" + +#include "storm/storage/expressions/Expression.h" + +namespace storm { + + namespace logic { + + class ExpressionSubstitutionVisitor : public CloneVisitor { + public: + ExpressionSubstitutionVisitor() = default; + + std::shared_ptr substitute(Formula const& f, std::function const& substitutionFunction) const; + + virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(ProbabilityOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; + virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(AtomicExpressionFormula const& f, boost::any const& data) const override; + + }; + + } +} + diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 3f871908e..aa27d8dbf 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -3,7 +3,8 @@ #include "storm/logic/FragmentChecker.h" #include "storm/logic/FormulaInformationVisitor.h" -#include "storm/logic/VariableSubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" +#include "storm/logic/ExpressionSubstitutionVisitor.h" #include "storm/logic/LabelSubstitutionVisitor.h" #include "storm/logic/ToExpressionVisitor.h" @@ -438,8 +439,13 @@ namespace storm { } std::shared_ptr Formula::substitute(std::map const& substitution) const { - VariableSubstitutionVisitor visitor(substitution); - return visitor.substitute(*this); + storm::expressions::JaniExpressionSubstitutionVisitor> v(substitution); + return substitute([&v](storm::expressions::Expression const& exp) {return v.substitute(exp);}); + } + + std::shared_ptr Formula::substitute(std::function const& expressionSubstitution) const { + ExpressionSubstitutionVisitor visitor; + return visitor.substitute(*this, expressionSubstitution); } std::shared_ptr Formula::substitute(std::map const& labelSubstitution) const { diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index a76dd0ef7..44826ff9e 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -198,6 +198,7 @@ namespace storm { std::shared_ptr asSharedPointer() const; std::shared_ptr substitute(std::map const& substitution) const; + std::shared_ptr substitute(std::function const& expressionSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp index d3d7d47fb..e733c295e 100644 --- a/src/storm/storage/jani/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -578,15 +578,20 @@ namespace storm { return eliminator.eliminate(arrayExpression); } + void ArrayEliminatorData::transformProperty(storm::jani::Property& property) const { + property = property.substitute([this](storm::expressions::Expression const& exp) {return transformExpression(exp);}); + } + ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); ArrayEliminatorData result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); - + if (!keepNonTrivialArrayAccess) { + model.getModelFeatures().remove(ModelFeature::Arrays); + } model.finalize(); STORM_LOG_ASSERT(!containsArrayExpression(model), "the model still contains array expressions."); return result; } - } } diff --git a/src/storm/storage/jani/ArrayEliminator.h b/src/storm/storage/jani/ArrayEliminator.h index 860aa37ea..70d2fe897 100644 --- a/src/storm/storage/jani/ArrayEliminator.h +++ b/src/storm/storage/jani/ArrayEliminator.h @@ -4,6 +4,7 @@ #include #include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/Property.h" namespace storm { namespace jani { @@ -14,6 +15,8 @@ namespace storm { // Transforms the given expression (which might contain array expressions) to an equivalent expression without array variables. storm::expressions::Expression transformExpression(storm::expressions::Expression const& arrayExpression) const; + // Transforms the given property (which might contain array expressions) to an equivalent property without array variables. + void transformProperty(storm::jani::Property& property) const; }; class ArrayEliminator { diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index c59eb5a34..a02a919eb 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -16,7 +16,7 @@ #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/Compositions.h" #include "storm/storage/jani/JSONExporter.h" -#include "storm/storage/jani/traverser/ArrayEliminator.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -69,6 +69,7 @@ namespace storm { if (this != &other) { this->name = other.name; this->modelType = other.modelType; + this->modelFeatures = other.modelFeatures; this->version = other.version; this->expressionManager = other.expressionManager; this->actions = other.actions; diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp index 755ac99d8..ada96c565 100644 --- a/src/storm/storage/jani/ModelFeatures.cpp +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -44,6 +44,10 @@ namespace storm { return features.count(ModelFeature::StateExitRewards) > 0; } + bool ModelFeatures::empty() const { + return features.empty(); + } + void ModelFeatures::add(ModelFeature const& modelFeature) { features.insert(modelFeature); } diff --git a/src/storm/storage/jani/ModelFeatures.h b/src/storm/storage/jani/ModelFeatures.h index f2604af96..363ee236c 100644 --- a/src/storm/storage/jani/ModelFeatures.h +++ b/src/storm/storage/jani/ModelFeatures.h @@ -19,6 +19,9 @@ namespace storm { bool hasDerivedOperators() const; bool hasStateExitRewards() const; + // Returns true, if no model feature is enabled. + bool empty() const; + void add(ModelFeature const& modelFeature); void remove(ModelFeature const& modelFeature); diff --git a/src/storm/storage/jani/Property.cpp b/src/storm/storage/jani/Property.cpp index 73c6d0dec..2da62b33e 100644 --- a/src/storm/storage/jani/Property.cpp +++ b/src/storm/storage/jani/Property.cpp @@ -30,6 +30,10 @@ namespace storm { return Property(name, filterExpression.substitute(substitution), comment); } + Property Property::substitute(std::function const& substitutionFunction) const { + return Property(name, filterExpression.substitute(substitutionFunction), comment); + } + Property Property::substituteLabels(std::map const& substitution) const { return Property(name, filterExpression.substituteLabels(substitution), comment); } diff --git a/src/storm/storage/jani/Property.h b/src/storm/storage/jani/Property.h index 74aceab5c..140afa3e7 100644 --- a/src/storm/storage/jani/Property.h +++ b/src/storm/storage/jani/Property.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "storm/modelchecker/results/FilterType.h" #include "storm/logic/Formulas.h" #include "storm/logic/FragmentSpecification.h" @@ -54,10 +56,14 @@ namespace storm { return FilterExpression(formula->substitute(substitution), ft, statesFormula->substitute(substitution)); } + FilterExpression substitute(std::function const& substitutionFunction) const { + return FilterExpression(formula->substitute(substitutionFunction), ft, statesFormula->substitute(substitutionFunction)); + } + FilterExpression substituteLabels(std::map const& labelSubstitution) const { return FilterExpression(formula->substitute(labelSubstitution), ft, statesFormula->substitute(labelSubstitution)); } - + private: // For now, we assume that the states are always the initial states. std::shared_ptr formula; @@ -103,6 +109,7 @@ namespace storm { std::string const& getComment() const; Property substitute(std::map const& substitution) const; + Property substitute(std::function const& substitutionFunction) const; Property substituteLabels(std::map const& labelSubstitution) const; FilterExpression const& getFilter() const; From 7ee196bdbb9529ebd0dcfa7d6949596d740e1ecb Mon Sep 17 00:00:00 2001 From: TimQu Date: Wed, 12 Sep 2018 16:19:41 +0200 Subject: [PATCH 547/647] jani2jani conversions in storm-conv --- src/storm-conv-cli/storm-conv.cpp | 53 ++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 1977cfdb7..72cba3e3d 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -52,6 +52,7 @@ namespace storm { options.suffix = ""; options.janiOptions = storm::converter::JaniConversionOptions(jani); + // Get the name of the output file std::string outputFilename = ""; if (output.isJaniOutputFilenameSet()) { outputFilename = output.getJaniOutputFilename(); @@ -71,6 +72,8 @@ namespace storm { suffix = suffix + ".jani"; outputFilename += suffix; } + + // Find a good model name auto startOfFilename = outputFilename.rfind("/"); if (startOfFilename == std::string::npos) { startOfFilename = 0; @@ -83,6 +86,7 @@ namespace storm { } options.janiOptions.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename); + auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); if (outputFilename != "") { @@ -124,6 +128,53 @@ namespace storm { } } + void processJaniInputJaniOutput(storm::jani::Model const& janiModel, std::vector const& properties) { + auto const& output = storm::settings::getModule(); + auto const& input = storm::settings::getModule(); + auto const& jani = storm::settings::getModule(); + + storm::converter::JaniConversionOptions options(jani); + + // Get the name of the output file + std::string outputFilename = ""; + if (output.isJaniOutputFilenameSet()) { + outputFilename = output.getJaniOutputFilename(); + } else if (input.isJaniInputSet() && !output.isStdOutOutputEnabled()) { + outputFilename = input.getJaniInputFilename(); + // Remove extension if present + auto dotPos = outputFilename.rfind('.'); + if (dotPos != std::string::npos) { + outputFilename.erase(dotPos); + } + outputFilename += "_converted.jani"; + } + + // Get a good model name from the output filename + auto startOfFilename = outputFilename.rfind("/"); + if (startOfFilename == std::string::npos) { + startOfFilename = 0; + } else { + ++startOfFilename; + } + auto endOfFilename = outputFilename.rfind("."); + if (endOfFilename == std::string::npos) { + endOfFilename = outputFilename.size(); + } + options.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename); + + auto transformedJaniModel = janiModel; + auto transformedProperties = properties; + storm::api::transformJani(transformedJaniModel, transformedProperties, options); + + if (outputFilename != "") { + storm::api::exportJaniToFile(transformedJaniModel, transformedProperties, outputFilename, jani.isCompactJsonSet()); + } + + if (output.isStdOutOutputEnabled()) { + storm::api::printJaniToStream(transformedJaniModel, transformedProperties, std::cout, jani.isCompactJsonSet()); + } + } + void processJaniInput() { auto const& input = storm::settings::getModule(); @@ -150,7 +201,7 @@ namespace storm { // Branch on the type of output auto const& output = storm::settings::getModule(); if (output.isJaniOutputSet()) { -// processJaniInputJaniOutput(janiModel.asJaniModel(), properties); + processJaniInputJaniOutput(janiModel.asJaniModel(), properties); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible."); } From 3fd952277026791d30e6132f0d16cef51eb68c55 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 12 Sep 2018 18:12:59 +0200 Subject: [PATCH 548/647] Replaced permutation assertion by exception to give better warning --- src/storm-dft/modelchecker/dft/DFTModelChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index 24e39a0f5..2a2a62e14 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -110,7 +110,7 @@ namespace storm { int limK = invResults ? -1 : nrM+1; int chK = invResults ? -1 : 1; // WARNING: there is a bug for computing permutations with more than 32 elements - STORM_LOG_ASSERT(res.size() < 32, "Permutations work only for < 32 elements"); + STORM_LOG_THROW(res.size() < 32, storm::exceptions::NotSupportedException, "Permutations work only for < 32 elements"); for(int cK = nrK; cK != limK; cK += chK ) { STORM_LOG_ASSERT(cK >= 0, "ck negative."); size_t permutation = smallestIntWithNBitsSet(static_cast(cK)); From 0e0a3dd9afbfead92c5754023510292bf131cf00 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 12 Sep 2018 18:17:39 +0200 Subject: [PATCH 549/647] Fixed problem with BitVector size mismatch for DFT states --- src/storm-dft/builder/ExplicitDFTModelBuilder.cpp | 2 +- src/storm-dft/storage/dft/DFT.h | 5 +++-- src/storm-dft/storage/dft/DFTState.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 82a566496..93e1170be 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -58,7 +58,7 @@ namespace storm { usedHeuristic(storm::settings::getModule().getApproximationHeuristic()), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), - stateStorage(((dft.stateVectorSize() / 64) + 1) * 64), + stateStorage(dft.stateBitVectorSize()), // TODO Matthias: make choosable //explorationQueue(dft.nrElements()+1, 0, 1) explorationQueue(200, 0, 0.9) diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index c373c8199..aed02807d 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -80,8 +80,9 @@ namespace storm { void copyElements(std::vector elements, storm::builder::DFTBuilder builder) const; - size_t stateVectorSize() const { - return mStateVectorSize; + size_t stateBitVectorSize() const { + // Ensure multiple of 64 + return (mStateVectorSize / 64 + (mStateVectorSize % 64 != 0)) * 64; } size_t nrElements() const { diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 29c1e525f..9d8a4d9d2 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -6,7 +6,7 @@ namespace storm { namespace storage { template - DFTState::DFTState(DFT const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) { + DFTState::DFTState(DFT const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateBitVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) { // TODO Matthias: use construct() // Initialize uses From 70b79caf41fdef32bb2e0d7a60923ac99296fdb9 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Wed, 12 Sep 2018 18:18:21 +0200 Subject: [PATCH 550/647] Travis: Use carl tag 18.08 to avoid problems with C++17 --- travis/build_carl_helper.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/travis/build_carl_helper.sh b/travis/build_carl_helper.sh index cfb1a31a6..595f0576a 100755 --- a/travis/build_carl_helper.sh +++ b/travis/build_carl_helper.sh @@ -19,6 +19,7 @@ run() { travis_fold start install_carl git clone https://github.com/smtrat/carl.git cd carl + git checkout 18.08 mkdir build cd build cmake .. "${CMAKE_ARGS[@]}" From d0461f168b13491c39a852ed561cc6f75da16778 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 13 Sep 2018 10:01:54 +0200 Subject: [PATCH 551/647] support for negative assignment levels --- src/storm-parsers/parser/JaniParser.cpp | 10 ++++-- .../generator/JaniNextStateGenerator.cpp | 31 ++++++++----------- src/storm/generator/JaniNextStateGenerator.h | 2 +- src/storm/storage/jani/Assignment.cpp | 2 +- src/storm/storage/jani/Assignment.h | 4 +-- src/storm/storage/jani/Automaton.cpp | 2 +- src/storm/storage/jani/Automaton.h | 2 +- src/storm/storage/jani/Edge.cpp | 4 +-- src/storm/storage/jani/Edge.h | 4 +-- src/storm/storage/jani/EdgeContainer.cpp | 2 +- src/storm/storage/jani/EdgeContainer.h | 2 +- src/storm/storage/jani/Model.cpp | 2 +- src/storm/storage/jani/Model.h | 2 +- src/storm/storage/jani/OrderedAssignments.cpp | 29 +++++++++++------ src/storm/storage/jani/OrderedAssignments.h | 13 +++++--- src/storm/storage/jani/TemplateEdge.cpp | 18 +++++------ src/storm/storage/jani/TemplateEdge.h | 8 ++--- .../jani/traverser/AssignmentLevelFinder.cpp | 8 ++--- .../jani/traverser/AssignmentLevelFinder.h | 2 +- 19 files changed, 81 insertions(+), 66 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index c21add9e7..63423299d 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -61,6 +61,12 @@ namespace storm { return static_cast(num); } + int64_t getSignedInt(json const& structure, std::string const& errorInfo) { + STORM_LOG_THROW(structure.is_number(), storm::exceptions::InvalidJaniException, "Expected a number in " << errorInfo << ", got '" << structure.dump() << "'"); + int num = structure.front(); + return static_cast(num); + } + std::pair> JaniParser::parse(std::string const& path) { JaniParser parser; @@ -1313,9 +1319,9 @@ namespace storm { storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); // TODO check types // index - uint64_t assignmentIndex = 0; // default. + int64_t assignmentIndex = 0; // default. if(assignmentEntry.count("index") > 0) { - assignmentIndex = getUnsignedInt(assignmentEntry.at("index"), "assignment index in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); + assignmentIndex = getSignedInt(assignmentEntry.at("index"), "assignment index in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); } assignments.emplace_back(lValue, assignmentExpr, assignmentIndex); } diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 8575f3a7d..bd034ece7 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -53,7 +53,7 @@ namespace storm { STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator does not support the following model feature(s): " << features.toString() << "."); // Lift the transient edge destinations of the first assignment level. - uint64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); + int64_t lowestAssignmentLevel = storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model); if (this->model.hasTransientEdgeDestinationAssignments()) { this->model.liftTransientEdgeDestinationAssignments(lowestAssignmentLevel); if (this->model.hasTransientEdgeDestinationAssignments()) { @@ -251,25 +251,20 @@ namespace storm { } template - CompressedState JaniNextStateGenerator::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable, uint64_t assignmentLevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator) { + CompressedState JaniNextStateGenerator::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable, int64_t assignmentLevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator) { CompressedState newState(state); // Update the location of the state. setLocation(newState, locationVariable, destination.getLocationIndex()); // Then perform the assignments. - auto assignmentIt = destination.getOrderedAssignments().getNonTransientAssignments().begin(); - auto assignmentIte = destination.getOrderedAssignments().getNonTransientAssignments().end(); - - if (assignmentLevel > 0) { - while (assignmentIt != assignmentIte && assignmentIt->getLevel() < assignmentLevel) { - ++assignmentIt; - } - } + auto const& assignments = destination.getOrderedAssignments().getNonTransientAssignments(assignmentLevel); + auto assignmentIt = assignments.begin(); + auto assignmentIte = assignments.end(); // Iterate over all boolean assignments and carry them out. auto boolIt = this->variableInformation.booleanVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasBooleanType() && assignmentIt->getLevel() == assignmentLevel && assignmentIt->getLValue().isVariable(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasBooleanType() && assignmentIt->getLValue().isVariable(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != boolIt->variable) { ++boolIt; } @@ -278,7 +273,7 @@ namespace storm { // Iterate over all integer assignments and carry them out. auto integerIt = this->variableInformation.integerVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasIntegerType() && assignmentIt->getLevel() == assignmentLevel && assignmentIt->getLValue().isVariable(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasIntegerType() && assignmentIt->getLValue().isVariable(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != integerIt->variable) { ++integerIt; } @@ -296,7 +291,7 @@ namespace storm { STORM_LOG_ASSERT(static_cast(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); } // Iterate over all array access assignments and carry them out. - for (; assignmentIt != assignmentIte && assignmentIt->getLValue().isArrayAccess() && assignmentIt->getLevel() == assignmentLevel; ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->getLValue().isArrayAccess(); ++assignmentIt) { int_fast64_t arrayIndex = expressionEvaluator.asInt(assignmentIt->getLValue().getArrayIndex()); if (assignmentIt->getAssignedExpression().hasIntegerType()) { IntegerVariableInformation const& intInfo = this->variableInformation.getIntegerArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); @@ -320,7 +315,7 @@ namespace storm { } // Check that we processed all assignments. - STORM_LOG_ASSERT(assignmentIt == assignmentIte || assignmentIt->getLevel() > assignmentLevel, "Not all assignments were consumed."); + STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); return newState; } @@ -439,8 +434,8 @@ namespace storm { if (probability != storm::utility::zero()) { // Obtain target state index and add it to the list of known states. If it has not yet been // seen, we also add it to the set of states that have yet to be explored. - uint64_t assignmentLevel = edge.getLowestAssignmentLevel(); // Might be the largest possible integer, if there is no assignment - uint64_t const& highestLevel = edge.getHighestAssignmentLevel(); + int64_t assignmentLevel = edge.getLowestAssignmentLevel(); // Might be the largest possible integer, if there is no assignment + int64_t const& highestLevel = edge.getHighestAssignmentLevel(); bool hasTransientRewardAssignments = destination.hasTransientAssignment(); CompressedState newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, *this->evaluator); if (hasTransientRewardAssignments) { @@ -514,8 +509,8 @@ namespace storm { nextDistribution.clear(); EdgeIndexSet edgeIndices; - uint64_t assignmentLevel = std::numeric_limits::max(); - uint64_t highestLevel = 0; + int64_t assignmentLevel = std::numeric_limits::max(); + int64_t highestLevel = std::numeric_limits::min(); for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { if (this->getOptions().isBuildChoiceOriginsSet()) { edgeIndices.insert(model.encodeAutomatonAndEdgeIndices(edgeCombination[i].first, iteratorList[i]->first)); diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index e9bd01a07..f84665db1 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -70,7 +70,7 @@ namespace storm { * @params assignmentLevel The assignmentLevel that is to be considered for the update. * @return The resulting state. */ - CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable, uint64_t assignmentlevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator); + CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable, int64_t assignmentlevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator); /*! * Retrieves all choices possible from the given state. diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 0632f294d..3235eacfe 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -11,7 +11,7 @@ namespace storm { namespace jani { - Assignment::Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, uint64_t level) : lValue(lValue), expression(expression), level(level) { + Assignment::Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, int64_t level) : lValue(lValue), expression(expression), level(level) { // Intentionally left empty } diff --git a/src/storm/storage/jani/Assignment.h b/src/storm/storage/jani/Assignment.h index f2a18c8a9..ac616cd39 100644 --- a/src/storm/storage/jani/Assignment.h +++ b/src/storm/storage/jani/Assignment.h @@ -13,7 +13,7 @@ namespace storm { /*! * Creates an assignment of the given expression to the given LValue. */ - Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, uint64_t index = 0); + Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, int64_t level = 0); Assignment(Assignment const&) = default; bool operator==(Assignment const& other) const; @@ -96,7 +96,7 @@ namespace storm { storm::expressions::Expression expression; // The level of the assignment. - uint64_t level; + int64_t level; }; /*! diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index b9c1e6449..14a1e7b2f 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -478,7 +478,7 @@ namespace storm { return false; } - void Automaton::liftTransientEdgeDestinationAssignments(uint64_t maxLevel) { + void Automaton::liftTransientEdgeDestinationAssignments(int64_t maxLevel) { edges.liftTransientDestinationAssignments(maxLevel); } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index abd459735..c6422fb1a 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -325,7 +325,7 @@ namespace storm { /*! * Lifts the common edge destination assignments to edge assignments. */ - void liftTransientEdgeDestinationAssignments(uint64_t maxLevel = 0); + void liftTransientEdgeDestinationAssignments(int64_t maxLevel = 0); /*! * Retrieves whether the automaton uses an assignment level other than zero. diff --git a/src/storm/storage/jani/Edge.cpp b/src/storm/storage/jani/Edge.cpp index cbe78c699..240317817 100644 --- a/src/storm/storage/jani/Edge.cpp +++ b/src/storm/storage/jani/Edge.cpp @@ -121,11 +121,11 @@ namespace storm { } } - uint64_t const& Edge::getLowestAssignmentLevel() const { + int64_t const& Edge::getLowestAssignmentLevel() const { return templateEdge->getLowestAssignmentLevel(); } - uint64_t const& Edge::getHighestAssignmentLevel() const { + int64_t const& Edge::getHighestAssignmentLevel() const { return templateEdge->getHighestAssignmentLevel(); } diff --git a/src/storm/storage/jani/Edge.h b/src/storm/storage/jani/Edge.h index d47edf14f..c6ab6d28d 100644 --- a/src/storm/storage/jani/Edge.h +++ b/src/storm/storage/jani/Edge.h @@ -123,13 +123,13 @@ namespace storm { * Retrieves the lowest assignment level occurring in each assignment. * If no assignment exists, this value is the highest possible integer */ - uint64_t const& getLowestAssignmentLevel() const; + int64_t const& getLowestAssignmentLevel() const; /*! * Retrieves the highest assignment level occurring in each assignment * If no assignment exists, this value is always zero */ - uint64_t const& getHighestAssignmentLevel() const; + int64_t const& getHighestAssignmentLevel() const; void assertValid() const; diff --git a/src/storm/storage/jani/EdgeContainer.cpp b/src/storm/storage/jani/EdgeContainer.cpp index 83db856ad..f2e3b9855 100644 --- a/src/storm/storage/jani/EdgeContainer.cpp +++ b/src/storm/storage/jani/EdgeContainer.cpp @@ -86,7 +86,7 @@ namespace storm { edges.clear(); } - void EdgeContainer::liftTransientDestinationAssignments(uint64_t maxLevel) { + void EdgeContainer::liftTransientDestinationAssignments(int64_t maxLevel) { for (auto& templateEdge : templates) { templateEdge->liftTransientDestinationAssignments(maxLevel); } diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h index 550fc80e0..bf1e0cbe9 100644 --- a/src/storm/storage/jani/EdgeContainer.h +++ b/src/storm/storage/jani/EdgeContainer.h @@ -107,7 +107,7 @@ namespace storm { std::set getActionIndices() const; void substitute(std::map const& substitution); - void liftTransientDestinationAssignments(uint64_t maxLevel = 0); + void liftTransientDestinationAssignments(int64_t maxLevel = 0); void pushAssignmentsToDestinations(); void insertEdge(Edge const& e, uint64_t locStart, uint64_t locEnd); void insertTemplateEdge(std::shared_ptr const& te); diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index a02a919eb..d84762fc7 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -1180,7 +1180,7 @@ namespace storm { } } - void Model::liftTransientEdgeDestinationAssignments(uint64_t maxLevel) { + void Model::liftTransientEdgeDestinationAssignments(int64_t maxLevel) { for (auto& automaton : this->getAutomata()) { automaton.liftTransientEdgeDestinationAssignments(maxLevel); } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 6bce3603d..274d17490 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -478,7 +478,7 @@ namespace storm { * Lifts the common edge destination assignments to edge assignments. * @param maxLevel the maximum level of assignments that are to be lifted. */ - void liftTransientEdgeDestinationAssignments(uint64_t maxLevel = 0); + void liftTransientEdgeDestinationAssignments(int64_t maxLevel = 0); /*! * Retrieves whether there is any transient edge destination assignment in the model. diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 8b46a3d7a..747fbcecd 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -101,13 +101,13 @@ namespace storm { return allAssignments.size(); } - int_fast64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const { + int64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const { auto const& as = onlyTransient ? transientAssignments : allAssignments; assert(!as.empty()); return as.front()->getLevel(); } - int_fast64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const { + int64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const { auto const& as = onlyTransient ? transientAssignments : allAssignments; assert(!as.empty()); return as.back()->getLevel(); @@ -198,15 +198,24 @@ namespace storm { return detail::ConstAssignments(nonTransientAssignments.begin(), nonTransientAssignments.end()); } - detail::ConstAssignments OrderedAssignments::getTransientAssignments(int_fast64_t assignmentLevel) const { - auto begin = transientAssignments.begin(); - while (begin != transientAssignments.end() && (*begin)->getLevel() < assignmentLevel) { - ++begin; + struct AssignmentLevelToLevelComparator { + bool operator()(std::shared_ptr const& left, int64_t const& right) const { + return left->getLevel() < right; } - auto end = begin; - while (end != transientAssignments.end() && (*begin)->getLevel() == assignmentLevel) { - ++end; + bool operator()(int64_t const& left, std::shared_ptr const& right) const { + return left < right->getLevel(); } + }; + + detail::ConstAssignments OrderedAssignments::getTransientAssignments(int64_t assignmentLevel) const { + auto begin = std::lower_bound(transientAssignments.begin(), transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + auto end = std::upper_bound(begin, transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + return detail::ConstAssignments(begin, end); + } + + detail::ConstAssignments OrderedAssignments::getNonTransientAssignments(int64_t assignmentLevel) const { + auto begin = std::lower_bound(nonTransientAssignments.begin(), nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + auto end = std::upper_bound(begin, nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); return detail::ConstAssignments(begin, end); } @@ -247,7 +256,7 @@ namespace storm { std::vector>::const_iterator OrderedAssignments::lowerBound(Assignment const& assignment, std::vector> const& assignments) { return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndLValue()); } - + uint64_t OrderedAssignments::isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const { Variable const& var = lValue.isVariable() ? lValue.getVariable() : lValue.getArray(); // TODO: do this more carefully diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 4d15268e7..de914b738 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -73,13 +73,13 @@ namespace storm { * Retrieves the lowest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getLowestLevel(bool onlyTransient = false) const; + int64_t getLowestLevel(bool onlyTransient = false) const; /*! * Retrieves the highest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getHighestLevel(bool onlyTransient = false) const; + int64_t getHighestLevel(bool onlyTransient = false) const; /*! * Retrieves whether the given assignment is contained in this set of assignments. @@ -99,12 +99,17 @@ namespace storm { /*! * Returns all transient assignments in this set of assignments. */ - detail::ConstAssignments getTransientAssignments(int_fast64_t assignmentLevel) const; + detail::ConstAssignments getTransientAssignments(int64_t assignmentLevel) const; /*! * Returns all non-transient assignments in this set of assignments. */ detail::ConstAssignments getNonTransientAssignments() const; + + /*! + * Returns all non-transient assignments in this set of assignments. + */ + detail::ConstAssignments getNonTransientAssignments(int64_t assignmentLevel) const; /*! * Retrieves whether the set of assignments has at least one transient assignment. @@ -167,7 +172,7 @@ namespace storm { uint64_t upperBound(int64_t index) const; static std::vector>::const_iterator lowerBound(Assignment const& assignment, std::vector> const& assignments); - + // The vectors to store the assignments. These need to be ordered at all times. std::vector> allAssignments; std::vector> transientAssignments; diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index a1ea3f7b5..51fee6578 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -9,12 +9,12 @@ namespace storm { namespace jani { - TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(0) { + TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(std::numeric_limits::min()) { // Intentionally left empty. } TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard, OrderedAssignments const& assignments, std::vector const& destinations) - : guard(guard), destinations(destinations), assignments(assignments), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(0) { + : guard(guard), destinations(destinations), assignments(assignments), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(std::numeric_limits::min()) { // Intentionally left empty. } @@ -28,16 +28,16 @@ namespace storm { void TemplateEdge::finalize(Model const& containingModel) { if (assignments.empty()) { - lowestAssignmentLevel = std::numeric_limits::max(); - highestAssignmentLevel = 0; + lowestAssignmentLevel = std::numeric_limits::max(); + highestAssignmentLevel = std::numeric_limits::min(); } else { lowestAssignmentLevel = assignments.getLowestLevel(); highestAssignmentLevel = assignments.getHighestLevel(); } for (auto const& destination : getDestinations()) { if (!destination.getOrderedAssignments().empty()) { - lowestAssignmentLevel = std::min(lowestAssignmentLevel, destination.getOrderedAssignments().getLowestLevel()); - highestAssignmentLevel = std::max(highestAssignmentLevel, destination.getOrderedAssignments().getHighestLevel()); + lowestAssignmentLevel = std::min(lowestAssignmentLevel, destination.getOrderedAssignments().getLowestLevel()); + highestAssignmentLevel = std::max(highestAssignmentLevel, destination.getOrderedAssignments().getHighestLevel()); } for (auto const& assignment : destination.getOrderedAssignments().getAllAssignments()) { Variable const& var = assignment.getLValue().isVariable() ? assignment.getLValue().getVariable() : assignment.getLValue().getArray(); @@ -103,7 +103,7 @@ namespace storm { assignments.changeAssignmentVariables(remapping); } - void TemplateEdge::liftTransientDestinationAssignments(uint64_t maxLevel) { + void TemplateEdge::liftTransientDestinationAssignments(int64_t maxLevel) { if (!destinations.empty()) { auto const& destination = *destinations.begin(); @@ -180,11 +180,11 @@ namespace storm { return false; } - uint64_t const& TemplateEdge::getLowestAssignmentLevel() const { + int64_t const& TemplateEdge::getLowestAssignmentLevel() const { return lowestAssignmentLevel; } - uint64_t const& TemplateEdge::getHighestAssignmentLevel() const { + int64_t const& TemplateEdge::getHighestAssignmentLevel() const { return highestAssignmentLevel; } diff --git a/src/storm/storage/jani/TemplateEdge.h b/src/storm/storage/jani/TemplateEdge.h index 0928c50e0..1606bec85 100644 --- a/src/storm/storage/jani/TemplateEdge.h +++ b/src/storm/storage/jani/TemplateEdge.h @@ -69,7 +69,7 @@ namespace storm { * assignments are no longer contained in the destination. Note that this may modify the semantics of the * model if assignment levels are being used somewhere in the model. */ - void liftTransientDestinationAssignments(uint64_t maxLevel = 0); + void liftTransientDestinationAssignments(int64_t maxLevel = 0); /** * Shifts the assingments from the edges to the destinations. @@ -95,13 +95,13 @@ namespace storm { * Retrieves the lowest assignment level occurring in each assignment. * If no assignment exists, this value is the highest possible integer */ - uint64_t const& getLowestAssignmentLevel() const; + int64_t const& getLowestAssignmentLevel() const; /*! * Retrieves the highest assignment level occurring in each assignment * If no assignment exists, this value is always zero */ - uint64_t const& getHighestAssignmentLevel() const; + int64_t const& getHighestAssignmentLevel() const; /*! * Checks the template edge for linearity. @@ -125,7 +125,7 @@ namespace storm { /// The assignments made when taking this edge. OrderedAssignments assignments; - uint64_t lowestAssignmentLevel, highestAssignmentLevel; + int64_t lowestAssignmentLevel, highestAssignmentLevel; /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to finalize. diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp index 442ba4bd4..0872c1f4f 100644 --- a/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp @@ -4,15 +4,15 @@ namespace storm { namespace jani { - uint64_t AssignmentLevelFinder::getLowestAssignmentLevel(Model const& model) { - uint64_t res = std::numeric_limits::max(); + int64_t AssignmentLevelFinder::getLowestAssignmentLevel(Model const& model) { + int64_t res = std::numeric_limits::max(); ConstJaniTraverser::traverse(model, &res); return res; } void AssignmentLevelFinder::traverse(Assignment const& assignment, boost::any const& data) { - auto& res = *boost::any_cast(data); - res = std::min(res, assignment.getLevel()); + auto& res = *boost::any_cast(data); + res = std::min(res, assignment.getLevel()); } } } diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.h b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h index 7a5a4a4fc..c8887df7a 100644 --- a/src/storm/storage/jani/traverser/AssignmentLevelFinder.h +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h @@ -10,7 +10,7 @@ namespace storm { AssignmentLevelFinder() = default; virtual ~AssignmentLevelFinder() = default; - uint64_t getLowestAssignmentLevel(Model const& model); + int64_t getLowestAssignmentLevel(Model const& model); virtual void traverse(Assignment const& assignment, boost::any const& data) override; }; From 46e39e6a6e188ef80286f7dff7033b46c1c748e5 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 13 Sep 2018 11:40:56 +0200 Subject: [PATCH 552/647] Removed statistics in BitVectorHashmap which were only used for debugging purposes --- src/storm/storage/BitVectorHashMap.cpp | 23 ----------------------- src/storm/storage/BitVectorHashMap.h | 7 ------- 2 files changed, 30 deletions(-) diff --git a/src/storm/storage/BitVectorHashMap.cpp b/src/storm/storage/BitVectorHashMap.cpp index 67c151bde..25b0b5791 100644 --- a/src/storm/storage/BitVectorHashMap.cpp +++ b/src/storm/storage/BitVectorHashMap.cpp @@ -54,13 +54,6 @@ namespace storm { buckets = storm::storage::BitVector(bucketSize * (1ull << currentSize)); occupied = storm::storage::BitVector(1ull << currentSize); values = std::vector(1ull << currentSize); - -#ifndef NDEBUG - numberOfInsertions = 0; - numberOfInsertionProbingSteps = 0; - numberOfFinds = 0; - numberOfFindProbingSteps = 0; -#endif } template @@ -81,11 +74,7 @@ namespace storm { template void BitVectorHashMap::increaseSize() { ++currentSize; -#ifndef NDEBUG - STORM_LOG_TRACE("Increasing size of hash map from " << (1ull << (currentSize - 1)) << " to " << (1ull << currentSize) << ". Stats: " << numberOfFinds << " finds (avg. " << (numberOfFindProbingSteps / static_cast(numberOfFinds)) << " probing steps), " << numberOfInsertions << " insertions (avg. " << (numberOfInsertionProbingSteps / static_cast(numberOfInsertions)) << " probing steps)."); -#else STORM_LOG_TRACE("Increasing size of hash map from " << (1ull << (currentSize - 1)) << " to " << (1ull << currentSize) << "."); -#endif // Create new containers and swap them with the old ones. storm::storage::BitVector oldBuckets(bucketSize * (1ull << currentSize)); @@ -170,15 +159,9 @@ namespace storm { template std::pair BitVectorHashMap::findBucket(storm::storage::BitVector const& key) const { -#ifndef NDEBUG - ++numberOfFinds; -#endif uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); while (isBucketOccupied(bucket)) { -#ifndef NDEBUG - ++numberOfFindProbingSteps; -#endif if (buckets.matches(bucket * bucketSize, key)) { return std::make_pair(true, bucket); } @@ -193,15 +176,9 @@ namespace storm { template std::pair BitVectorHashMap::findBucketToInsert(storm::storage::BitVector const& key) { -#ifndef NDEBUG - ++numberOfInsertions; -#endif uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); while (isBucketOccupied(bucket)) { -#ifndef NDEBUG - ++numberOfInsertionProbingSteps; -#endif if (buckets.matches(bucket * bucketSize, key)) { return std::make_pair(true, bucket); } diff --git a/src/storm/storage/BitVectorHashMap.h b/src/storm/storage/BitVectorHashMap.h index 38310aa4f..db1b659d1 100644 --- a/src/storm/storage/BitVectorHashMap.h +++ b/src/storm/storage/BitVectorHashMap.h @@ -234,13 +234,6 @@ namespace storm { // Functor object that are used to perform the actual hashing. Hash hasher; -#ifndef NDEBUG - // Some performance metrics. - mutable uint64_t numberOfInsertions; - mutable uint64_t numberOfInsertionProbingSteps; - mutable uint64_t numberOfFinds; - mutable uint64_t numberOfFindProbingSteps; -#endif }; } From 5d2110962475699837ac14a219ef8c1323a17bcf Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 13 Sep 2018 12:58:53 +0200 Subject: [PATCH 553/647] Removed redundant method findBucketToInsert() --- src/storm/storage/BitVectorHashMap.cpp | 19 +------------------ src/storm/storage/BitVectorHashMap.h | 13 ------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/src/storm/storage/BitVectorHashMap.cpp b/src/storm/storage/BitVectorHashMap.cpp index 25b0b5791..1301c4fa5 100644 --- a/src/storm/storage/BitVectorHashMap.cpp +++ b/src/storm/storage/BitVectorHashMap.cpp @@ -102,7 +102,7 @@ namespace storm { std::pair BitVectorHashMap::findOrAddAndGetBucket(storm::storage::BitVector const& key, ValueType const& value) { checkIncreaseSize(); - std::pair flagAndBucket = this->findBucketToInsert(key); + std::pair flagAndBucket = this->findBucket(key); if (flagAndBucket.first) { return std::make_pair(values[flagAndBucket.second], flagAndBucket.second); } else { @@ -174,23 +174,6 @@ namespace storm { return std::make_pair(false, bucket); } - template - std::pair BitVectorHashMap::findBucketToInsert(storm::storage::BitVector const& key) { - uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); - - while (isBucketOccupied(bucket)) { - if (buckets.matches(bucket * bucketSize, key)) { - return std::make_pair(true, bucket); - } - ++bucket; - if (bucket == (1ull << currentSize)) { - bucket = 0; - } - } - - return std::make_pair(false, bucket); - } - template std::pair BitVectorHashMap::getBucketAndValue(uint64_t bucket) const { return std::make_pair(buckets.get(bucket * bucketSize, bucketSize), values[bucket]); diff --git a/src/storm/storage/BitVectorHashMap.h b/src/storm/storage/BitVectorHashMap.h index db1b659d1..7484c9445 100644 --- a/src/storm/storage/BitVectorHashMap.h +++ b/src/storm/storage/BitVectorHashMap.h @@ -170,19 +170,6 @@ namespace storm { */ std::pair findBucket(storm::storage::BitVector const& key) const; - /*! - * Searches for the bucket into which the given key can be inserted. If no empty bucket can be found, the - * size of the underlying data structure is increased. - * - * @param key The key to search for. - * @param increaseStorage A flag indicating whether the storage should be increased if no bucket can be found. - * @return A tuple whose first component indicates whether the key is already contained in the map, whose - * second component indicates in which bucket the key is supposed to be stored and whose third component is - * an error flag indicating that the bucket could not be found (e.g. due to the restriction that the storage - * must not be increased). - */ - std::pair findBucketToInsert(storm::storage::BitVector const& key); - /*! * Inserts the given key-value pair without resizing the underlying storage. If that fails, this is * indicated by the return value. From ee87c50313690a96374f7febd1dcfbb9b033fd30 Mon Sep 17 00:00:00 2001 From: TimQu Date: Thu, 13 Sep 2018 13:33:31 +0200 Subject: [PATCH 554/647] fixed some issues related to jani parsing --- src/storm-parsers/parser/JaniParser.cpp | 76 +++++++++++++++++-------- src/storm/storage/jani/LValue.cpp | 2 +- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 63423299d..4c897b5a1 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -67,7 +67,6 @@ namespace storm { return static_cast(num); } - std::pair> JaniParser::parse(std::string const& path) { JaniParser parser; parser.readFile(path); @@ -107,6 +106,8 @@ namespace storm { model.getModelFeatures().add(storm::jani::ModelFeature::Arrays); } else if (featureStr == "derived-operators") { model.getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + } else if (featureStr == "functions") { + model.getModelFeatures().add(storm::jani::ModelFeature::Functions); } else if (featureStr == "state-exit-rewards") { model.getModelFeatures().add(storm::jani::ModelFeature::StateExitRewards); } else { @@ -480,7 +481,7 @@ namespace storm { assert(args.size() == 1); return std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); - } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">") { + } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">" || opString == "=" || opString == "≠") { assert(bound == boost::none); storm::logic::ComparisonType ct; if(opString == "≥") { @@ -492,17 +493,38 @@ namespace storm { } else if (opString == ">") { ct = storm::logic::ComparisonType::Greater; } - if (propertyStructure.at("left").count("op") > 0 && (propertyStructure.at("left").at("op") == "Pmin" || propertyStructure.at("left").at("op") == "Pmax" || propertyStructure.at("left").at("op") == "Emin" || propertyStructure.at("left").at("op") == "Emax" || propertyStructure.at("left").at("op") == "Smin" || propertyStructure.at("left").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("right"), "Threshold for operator " + propertyStructure.at("left").at("op").get(),{},{}); - STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported"); - return parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - - } else if(propertyStructure.at("right").count("op") > 0 && (propertyStructure.at("right").at("op") == "Pmin" || propertyStructure.at("right").at("op") == "Pmax" || propertyStructure.at("right").at("op") == "Emin" || propertyStructure.at("right").at("op") == "Emax" || propertyStructure.at("right").at("op") == "Smin" || propertyStructure.at("right").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("left"), "Threshold for operator " + propertyStructure.at("right").at("op").get(),{},{}); - return parseFormula(propertyStructure.at("right"),formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons are allowed."); + + std::vector const leftRight = {"left", "right"}; + for (uint64_t i = 0; i < 2; ++i) { + if (propertyStructure.at(leftRight[i]).count("op") > 0) { + std::string propertyOperatorString = getString(propertyStructure.at(leftRight[i]).at("op"), "property-operator"); + std::set const propertyOperatorStrings = {"Pmin", "Pmax","Emin", "Emax", "Smin", "Smax"}; + if (propertyOperatorStrings.count(propertyOperatorString) > 0) { + auto boundExpr = parseExpression(propertyStructure.at(leftRight[1-i]), "Threshold for operator " + propertyStructure.at(leftRight[i]).at("op").get(), {}, constants); + if ((opString == "=" || opString == "≠")) { + STORM_LOG_THROW(!boundExpr.containsVariables(), storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + auto boundValue = boundExpr.evaluateAsRational(); + if (storm::utility::isZero(boundValue)) { + if (opString == "=") { + ct = storm::logic::ComparisonType::LessEqual; + } else { + ct = storm::logic::ComparisonType::Greater; + } + } else if (storm::utility::isOne(boundValue) && (propertyOperatorString == "Pmin" || propertyOperatorString == "Pmax")) { + if (opString == "=") { + ct = storm::logic::ComparisonType::GreaterEqual; + } else { + ct = storm::logic::ComparisonType::Less; + } + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + } + } + return parseFormula(propertyStructure.at(leftRight[i]), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, boundExpr)); + } + } } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons for properties are supported."); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opString); } @@ -914,26 +936,26 @@ namespace storm { } storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { - if(expressionStructure.is_boolean()) { - if(expressionStructure.get()) { + if (expressionStructure.is_boolean()) { + if (expressionStructure.get()) { return expressionManager->boolean(true); } else { return expressionManager->boolean(false); } - } else if(expressionStructure.is_number_integer()) { + } else if (expressionStructure.is_number_integer()) { return expressionManager->integer(expressionStructure.get()); - } else if(expressionStructure.is_number_float()) { + } else if (expressionStructure.is_number_float()) { // For now, just take the double. // TODO make this a rational number return expressionManager->rational(expressionStructure.get()); - } else if(expressionStructure.is_string()) { + } else if (expressionStructure.is_string()) { std::string ident = expressionStructure.get(); - return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars)); - } else if(expressionStructure.is_object()) { - if(expressionStructure.count("distribution") == 1) { + return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars, auxiliaryVariables)); + } else if (expressionStructure.is_object()) { + if (expressionStructure.count("distribution") == 1) { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scopeDescription << "."); } - if(expressionStructure.count("op") == 1) { + if (expressionStructure.count("op") == 1) { std::string opstring = getString(expressionStructure.at("op"), scopeDescription); std::vector arguments = {}; if(opstring == "ite") { @@ -985,6 +1007,9 @@ namespace storm { } else if (opstring == "=") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::iff(arguments[0], arguments[1]); @@ -995,6 +1020,9 @@ namespace storm { } else if (opstring == "≠") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::xclusiveor(arguments[0], arguments[1]); @@ -1165,10 +1193,10 @@ namespace storm { std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scopeDescription + ")."); STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scopeDescription + ")."); auto newAuxVars = auxiliaryVariables; - storm::expressions::Variable indexVar = expressionManager->declareIntegerVariable(indexVarName); + storm::expressions::Variable indexVar = expressionManager->declareFreshIntegerVariable(false, "ac_" + indexVarName); newAuxVars.emplace(indexVarName, indexVar); - STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scopeDescription + ")."); - storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array constructor operator requires exactly one exp (at " + scopeDescription + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp of array constructor in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); return std::make_shared(*expressionManager, expressionManager->getArrayType(exp.getType()), length.getBaseExpressionPointer(), indexVar, exp.getBaseExpressionPointer())->toExpression(); } else if (unsupportedOpstrings.count(opstring) > 0){ STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm"); diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp index 27788db78..7ae2b3e42 100644 --- a/src/storm/storage/jani/LValue.cpp +++ b/src/storm/storage/jani/LValue.cpp @@ -77,7 +77,7 @@ namespace storm { return other.isVariable() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable(); } else { STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); - return other.isArrayAccess() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); + return other.isArrayAccess() && getArray().getExpressionVariable() == other.getArray().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); } } From ced0d3fbb91fa46bdff002e8f71f1e76e52e03c6 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Thu, 13 Sep 2018 16:08:42 +0200 Subject: [PATCH 555/647] Assertion requiring equal bitsizes of BitVectorHashMap and key --- src/storm/storage/BitVectorHashMap.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storm/storage/BitVectorHashMap.cpp b/src/storm/storage/BitVectorHashMap.cpp index 1301c4fa5..652d4e99f 100644 --- a/src/storm/storage/BitVectorHashMap.cpp +++ b/src/storm/storage/BitVectorHashMap.cpp @@ -159,6 +159,7 @@ namespace storm { template std::pair BitVectorHashMap::findBucket(storm::storage::BitVector const& key) const { + STORM_LOG_ASSERT(key.size() == bucketSize, "Size of bit vector and size of buckets do not match"); uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); while (isBucketOccupied(bucket)) { From 2febe36a655b222e1ce449f653fe38c68e07e179 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 08:54:46 +0200 Subject: [PATCH 556/647] removed dependency on storm-conv --- src/storm-cli-utilities/CMakeLists.txt | 2 +- src/storm-cli-utilities/model-handling.h | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index ee67568ba..de4c0fde1 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers storm-conv) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 14cd9aa3f..057f3f436 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -4,7 +4,6 @@ #include "storm-counterexamples/api/counterexamples.h" #include "storm-parsers/api/storm-parsers.h" -#include "storm-conv/api/storm-conv.h" #include "storm/utility/resources.h" #include "storm/utility/file.h" @@ -156,13 +155,11 @@ namespace storm { } if (output.model && output.model.get().isJaniModel()) { - storm::converter::JaniConversionOptions options; - options.allowFunctions = false; - options.allowArrays = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && !buildSettings.isJitSet(); - options.standardCompliant = false; - options.flatten = false; - output.preprocessedProperties = output.properties; - storm::api::transformJani(output.model.get().asJaniModel(), output.preprocessedProperties.get(), options); + // Check if arrays need to be eliminated + if (coreSettings.getEngine() != storm::settings::modules::CoreSettings::Engine::Sparse || buildSettings.isJitSet()) { + output.preprocessedProperties = output.properties; + output.model.get().asJaniModel().eliminateArrays(output.preprocessedProperties.get()); + } } return output; } From b1272c58b6f66b4f3537999c5927be15272d767c Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 08:58:26 +0200 Subject: [PATCH 557/647] Parsing and exporting of jani-functions --- src/storm-parsers/parser/JaniParser.cpp | 600 ++++++++++-------- src/storm-parsers/parser/JaniParser.h | 62 +- src/storm/storage/jani/Automaton.cpp | 17 + src/storm/storage/jani/Automaton.h | 20 +- src/storm/storage/jani/FunctionDefinition.cpp | 30 + src/storm/storage/jani/FunctionDefinition.h | 61 ++ src/storm/storage/jani/JSONExporter.cpp | 84 ++- src/storm/storage/jani/JSONExporter.h | 6 +- src/storm/storage/jani/Model.cpp | 15 + src/storm/storage/jani/Model.h | 19 + src/storm/storage/jani/ModelFeatures.cpp | 6 + src/storm/storage/jani/ModelFeatures.h | 3 +- .../expressions/FunctionCallExpression.cpp | 75 +++ .../jani/expressions/FunctionCallExpression.h | 42 ++ .../JaniExpressionSubstitutionVisitor.cpp | 9 + .../JaniExpressionSubstitutionVisitor.h | 1 + .../jani/expressions/JaniExpressionVisitor.h | 1 + .../jani/expressions/JaniExpressions.h | 1 + .../jani/traverser/ArrayExpressionFinder.cpp | 9 + 19 files changed, 770 insertions(+), 291 deletions(-) create mode 100644 src/storm/storage/jani/FunctionDefinition.cpp create mode 100644 src/storm/storage/jani/FunctionDefinition.h create mode 100644 src/storm/storage/jani/expressions/FunctionCallExpression.cpp create mode 100644 src/storm/storage/jani/expressions/FunctionCallExpression.h diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 4c897b5a1..78e9c20a3 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -120,36 +120,58 @@ namespace storm { if (actionCount > 0) { parseActions(parsedStructure.at("actions"), model); } + + Scope scope(name); + + // Parse constants size_t constantsCount = parsedStructure.count("constants"); ConstantsMap constants; + scope.constants = &constants; STORM_LOG_THROW(constantsCount < 2, storm::exceptions::InvalidJaniException, "Constant-declarations can be given at most once."); if (constantsCount == 1) { for (auto const &constStructure : parsedStructure.at("constants")) { - std::shared_ptr constant = parseConstant(constStructure, constants, "global"); + std::shared_ptr constant = parseConstant(constStructure, scope.refine("constants[" + std::to_string(constants.size()) + "]")); constants.emplace(constant->getName(), &model.addConstant(*constant)); } } + + // Parse variables size_t variablesCount = parsedStructure.count("variables"); STORM_LOG_THROW(variablesCount < 2, storm::exceptions::InvalidJaniException, "Variable-declarations can be given at most once for global variables."); VariablesMap globalVars; + scope.globalVars = &globalVars; if (variablesCount == 1) { bool requireInitialValues = parsedStructure.count("restrict-initial") == 0; for (auto const& varStructure : parsedStructure.at("variables")) { - std::shared_ptr variable = parseVariable(varStructure, requireInitialValues, "global", globalVars, constants); + std::shared_ptr variable = parseVariable(varStructure, requireInitialValues, scope.refine("variables[" + std::to_string(globalVars.size()))); globalVars.emplace(variable->getName(), &model.addVariable(*variable)); } } + + uint64_t funDeclCount = parsedStructure.count("functions"); + STORM_LOG_THROW(funDeclCount < 2, storm::exceptions::InvalidJaniException, "Model '" << name << "' has more than one list of functions"); + FunctionsMap globalFuns; + scope.globalFunctions = &globalFuns; + if (funDeclCount > 0) { + for (auto const& funStructure : parsedStructure.at("functions")) { + storm::jani::FunctionDefinition funDef = parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(globalFuns.size()) + "] of model " + name)); + assert(globalFuns.count(funDef.getName()) == 0); + //TODO globalFuns.emplace(funDef.getName(), &model.addFunction(funDef)); + } + } + + // Parse Automata STORM_LOG_THROW(parsedStructure.count("automata") == 1, storm::exceptions::InvalidJaniException, "Exactly one list of automata must be given"); STORM_LOG_THROW(parsedStructure.at("automata").is_array(), storm::exceptions::InvalidJaniException, "Automata must be an array"); // Automatons can only be parsed after constants and variables. for (auto const& automataEntry : parsedStructure.at("automata")) { - model.addAutomaton(parseAutomaton(automataEntry, model, globalVars, constants)); + model.addAutomaton(parseAutomaton(automataEntry, model, scope.refine("automata[" + std::to_string(model.getNumberOfAutomata()) + "]"))); } STORM_LOG_THROW(parsedStructure.count("restrict-initial") < 2, storm::exceptions::InvalidJaniException, "Model has multiple initial value restrictions"); storm::expressions::Expression initialValueRestriction = expressionManager->boolean(true); - if(parsedStructure.count("restrict-initial") > 0) { + if (parsedStructure.count("restrict-initial") > 0) { STORM_LOG_THROW(parsedStructure.at("restrict-initial").count("exp") == 1, storm::exceptions::InvalidJaniException, "Model needs an expression inside the initial restricion"); - initialValueRestriction = parseExpression(parsedStructure.at("restrict-initial").at("exp"), "Initial value restriction for automaton " + name, globalVars, constants); + initialValueRestriction = parseExpression(parsedStructure.at("restrict-initial").at("exp"), scope.refine("Initial value restriction")); } model.setInitialStatesRestriction(initialValueRestriction); STORM_LOG_THROW(parsedStructure.count("system") == 1, storm::exceptions::InvalidJaniException, "Exactly one system description must be given"); @@ -161,7 +183,7 @@ namespace storm { STORM_LOG_THROW(parsedStructure.at("properties").is_array(), storm::exceptions::InvalidJaniException, "Properties should be an array"); for(auto const& propertyEntry : parsedStructure.at("properties")) { try { - auto prop = this->parseProperty(propertyEntry, globalVars, constants); + auto prop = this->parseProperty(propertyEntry, scope.refine("property[" + std::to_string(properties.size()) + "]")); properties.emplace(prop.getName(), prop); } catch (storm::exceptions::NotSupportedException const& ex) { STORM_LOG_WARN("Cannot handle property: " << ex.what()); @@ -175,22 +197,22 @@ namespace storm { } - std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context) { - STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << context); - return { parseFormula(propertyStructure.at("exp"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; + std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope) { + STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << scope.description); + return { parseFormula(propertyStructure.at("exp"), formulaContext, scope.refine("Operand of operator " + opstring)) }; } - std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context) { - STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << context); - STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << context); - return { parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "Operand of operator " + opstring), parseFormula(propertyStructure.at("right"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; + std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope) { + STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << scope.description); + STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << scope.description); + return { parseFormula(propertyStructure.at("left"), formulaContext, scope.refine("Operand of operator " + opstring)), parseFormula(propertyStructure.at("right"), formulaContext, scope.refine("Operand of operator " + opstring)) }; } - storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, ConstantsMap const& constants) { + storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, Scope const& scope) { storm::jani::PropertyInterval pi; if (piStructure.count("lower") > 0) { - pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, constants); + pi.lowerBound = parseExpression(piStructure.at("lower"), scope.refine("Lower bound for property interval")); } if (piStructure.count("lower-exclusive") > 0) { STORM_LOG_THROW(pi.lowerBound.isInitialized(), storm::exceptions::InvalidJaniException, "Lower-exclusive can only be set if a lower bound is present"); @@ -198,7 +220,7 @@ namespace storm { } if (piStructure.count("upper") > 0) { - pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval", {}, constants); + pi.upperBound = parseExpression(piStructure.at("upper"), scope.refine("Upper bound for property interval")); } if (piStructure.count("upper-exclusive") > 0) { @@ -207,8 +229,6 @@ namespace storm { } STORM_LOG_THROW(pi.lowerBound.isInitialized() || pi.upperBound.isInitialized(), storm::exceptions::InvalidJaniException, "Bounded operator must have a bounded interval, but no bounds found in '" << piStructure << "'"); return pi; - - } storm::logic::RewardAccumulation JaniParser::parseRewardAccumulation(json const& accStructure, std::string const& context) { @@ -230,7 +250,7 @@ namespace storm { return storm::logic::RewardAccumulation(accSteps, accTime, accExit); } - std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext,VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context, boost::optional bound) { + std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, Scope const& scope, boost::optional bound) { if (propertyStructure.is_boolean()) { return std::make_shared(propertyStructure.get()); } @@ -239,7 +259,7 @@ namespace storm { return std::make_shared(propertyStructure.get()); } } - storm::expressions::Expression expr = parseExpression(propertyStructure, "expression in property", globalVars, constants, {}, true); + storm::expressions::Expression expr = parseExpression(propertyStructure, scope.refine("expression in property"), true); if(expr.isInitialized()) { assert(bound == boost::none); return std::make_shared(expr); @@ -247,7 +267,7 @@ namespace storm { std::string opString = getString(propertyStructure.at("op"), "Operation description"); if(opString == "Pmin" || opString == "Pmax") { - std::vector> args = parseUnaryFormulaArgument(propertyStructure, storm::logic::FormulaContext::Probability, opString, globalVars, constants, ""); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, storm::logic::FormulaContext::Probability, opString, scope); assert(args.size() == 1); storm::logic::OperatorInformation opInfo; opInfo.optimalityType = opString == "Pmin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; @@ -259,8 +279,8 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Forall and Exists are currently not supported"); } else if (opString == "Emin" || opString == "Emax") { bool time=false; - STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); - storm::expressions::Expression rewExpr = parseExpression(propertyStructure.at("exp"), "Reward expression in " + context, globalVars, constants); + STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << scope.description); + storm::expressions::Expression rewExpr = parseExpression(propertyStructure.at("exp"), scope.refine("Reward expression")); if (rewExpr.isVariable()) { time = false; } else { @@ -273,14 +293,14 @@ namespace storm { storm::logic::RewardAccumulation rewardAccumulation(false, false, false); if (propertyStructure.count("accumulate") > 0) { - rewardAccumulation = parseRewardAccumulation(propertyStructure.at("accumulate"), context); + rewardAccumulation = parseRewardAccumulation(propertyStructure.at("accumulate"), scope.description); } if (propertyStructure.count("step-instant") > 0) { - STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + context); - STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + context); + STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + scope.description); + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + scope.description); - storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), "Step instant in " + context, globalVars, constants); + storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), scope.refine("Step instant")); if(rewardAccumulation.isEmpty()) { if (rewExpr.isVariable()) { std::string rewardName = rewExpr.getVariables().begin()->getName(); @@ -297,9 +317,9 @@ namespace storm { } } } else if (propertyStructure.count("time-instant") > 0) { - STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a time-instant and a reward-instant in " + context); + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a time-instant and a reward-instant in " + scope.description); - storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); + storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), scope.refine("time instant")); if(rewardAccumulation.isEmpty()) { if (rewExpr.isVariable()) { @@ -320,11 +340,11 @@ namespace storm { std::vector bounds; std::vector boundReferences; for (auto const& rewInst : propertyStructure.at("reward-instants")) { - storm::expressions::Expression rewInstExpression = parseExpression(rewInst.at("exp"), "Reward expression in " + context, globalVars, constants); + storm::expressions::Expression rewInstExpression = parseExpression(rewInst.at("exp"), scope.refine("Reward expression")); STORM_LOG_THROW(!rewInstExpression.isVariable(), storm::exceptions::NotSupportedException, "Reward bounded cumulative reward formulas should only argue over reward expressions."); - storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rewInst.at("accumulate"), context); + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rewInst.at("accumulate"), scope.description); boundReferences.emplace_back(rewInstExpression.getVariables().begin()->getName(), boundRewardAccumulation); - storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), "reward instant in " + context, globalVars, constants); + storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), scope.refine("reward instant")); bounds.emplace_back(false, rewInstantExpr); } if (rewExpr.isVariable()) { @@ -336,8 +356,8 @@ namespace storm { } else { std::shared_ptr subformula; if (propertyStructure.count("reach") > 0) { - auto context = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; - subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), context, globalVars, constants, "Reach-expression of operator " + opString), context, rewardAccumulation); + auto formulaContext = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; + subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), formulaContext, scope.refine("Reach-expression of operator " + opString)), formulaContext, rewardAccumulation); } else { subformula = std::make_shared(rewardAccumulation); } @@ -375,10 +395,10 @@ namespace storm { assert(bound == boost::none); std::vector> args; if (opString == "U") { - args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); } else { assert(opString == "F"); - args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, ""); + args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope); args.push_back(args[0]); args[0] = storm::logic::BooleanLiteralFormula::getTrueFormula(); } @@ -386,7 +406,7 @@ namespace storm { std::vector> lowerBounds, upperBounds; std::vector tbReferences; if (propertyStructure.count("step-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds"), constants); + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds"), scope.refine("step-bounded until").clearVariables()); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); @@ -401,7 +421,7 @@ namespace storm { tbReferences.emplace_back(storm::logic::TimeBoundType::Steps); } if (propertyStructure.count("time-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds"), constants); + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds"), scope.refine("time-bounded until").clearVariables()); boost::optional lowerBound, upperBound; if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); @@ -417,11 +437,11 @@ namespace storm { } if (propertyStructure.count("reward-bounds") > 0 ) { for (auto const& rbStructure : propertyStructure.at("reward-bounds")) { - storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds"), constants); - STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); - storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), "Reward expression in " + context, globalVars, constants); + storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds"), scope.refine("reward-bounded until").clearVariables()); + STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << scope.description); + storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), scope.refine("Reward expression")); STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); - storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rbStructure.at("accumulate"), context); + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rbStructure.at("accumulate"), scope.description); tbReferences.emplace_back(rewExpr.getVariables().begin()->getName(), boundRewardAccumulation); std::string rewardName = rewExpr.getVariables().begin()->getName(); STORM_LOG_WARN("Reward-type (steps, time) is deduced from model type."); @@ -447,7 +467,7 @@ namespace storm { } } else if (opString == "G") { assert(bound == boost::none); - std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, "Subformula of globally operator " + context); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope.refine("Subformula of globally operator ")); if (propertyStructure.count("step-bounds") > 0) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Globally and step-bounds are not supported currently"); } else if (propertyStructure.count("time-bounds") > 0) { @@ -465,19 +485,19 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Release is not supported"); } else if (opString == "∧" || opString == "∨") { assert(bound == boost::none); - std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); assert(args.size() == 2); storm::logic::BinaryBooleanStateFormula::OperatorType oper = opString == "∧" ? storm::logic::BinaryBooleanStateFormula::OperatorType::And : storm::logic::BinaryBooleanStateFormula::OperatorType::Or; return std::make_shared(oper, args[0], args[1]); } else if (opString == "⇒") { assert(bound == boost::none); - std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); assert(args.size() == 2); std::shared_ptr tmp = std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); return std::make_shared(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, tmp, args[1]); } else if (opString == "¬") { assert(bound == boost::none); - std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, ""); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope); assert(args.size() == 1); return std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); @@ -500,7 +520,7 @@ namespace storm { std::string propertyOperatorString = getString(propertyStructure.at(leftRight[i]).at("op"), "property-operator"); std::set const propertyOperatorStrings = {"Pmin", "Pmax","Emin", "Emax", "Smin", "Smax"}; if (propertyOperatorStrings.count(propertyOperatorString) > 0) { - auto boundExpr = parseExpression(propertyStructure.at(leftRight[1-i]), "Threshold for operator " + propertyStructure.at(leftRight[i]).at("op").get(), {}, constants); + auto boundExpr = parseExpression(propertyStructure.at(leftRight[1-i]), scope.refine("Threshold for operator " + propertyStructure.at(leftRight[i]).at("op").get())); if ((opString == "=" || opString == "≠")) { STORM_LOG_THROW(!boundExpr.containsVariables(), storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); auto boundValue = boundExpr.evaluateAsRational(); @@ -520,7 +540,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); } } - return parseFormula(propertyStructure.at(leftRight[i]), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, boundExpr)); + return parseFormula(propertyStructure.at(leftRight[i]), formulaContext, scope, storm::logic::Bound(ct, boundExpr)); } } } @@ -533,7 +553,7 @@ namespace storm { } } - storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, VariablesMap const& globalVars, ConstantsMap const& constants) { + storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, Scope const& scope) { STORM_LOG_THROW(propertyStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Property must have a name"); // TODO check unique name std::string name = getString(propertyStructure.at("name"), "property-name"); @@ -586,7 +606,7 @@ namespace storm { if (!statesFormula) { try { // Try to parse the states as formula. - statesFormula = parseFormula(expressionStructure.at("states"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); + statesFormula = parseFormula(expressionStructure.at("states"), storm::logic::FormulaContext::Undefined, scope.refine("Values of property " + name)); } catch (storm::exceptions::NotSupportedException const& ex) { throw ex; } catch (storm::exceptions::NotImplementedException const& ex) { @@ -595,48 +615,48 @@ namespace storm { } STORM_LOG_THROW(statesFormula, storm::exceptions::NotImplementedException, "Could not derive states formula."); STORM_LOG_THROW(expressionStructure.count("values") == 1, storm::exceptions::InvalidJaniException, "Values as input for a filter must be given"); - auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); + auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, scope.refine("Values of property " + name)); return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), comment); } - std::shared_ptr JaniParser::parseConstant(json const& constantStructure, ConstantsMap const& constants, std::string const& scopeDescription) { - STORM_LOG_THROW(constantStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); - std::string name = getString(constantStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); + std::shared_ptr JaniParser::parseConstant(json const& constantStructure, Scope const& scope) { + STORM_LOG_THROW(constantStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scope.description + ") must have a name"); + std::string name = getString(constantStructure.at("name"), "variable-name in " + scope.description + "-scope"); // TODO check existance of name. // TODO store prefix in variable. std::string exprManagerName = name; - STORM_LOG_THROW(constantStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Constant '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); + STORM_LOG_THROW(constantStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Constant '" + name + "' (scope: " + scope.description + ") must have a (single) type-declaration."); size_t valueCount = constantStructure.count("value"); storm::expressions::Expression initExpr; - STORM_LOG_THROW(valueCount < 2, storm::exceptions::InvalidJaniException, "Value for constant '" + name + "' (scope: " + scopeDescription + ") must be given at most once."); + STORM_LOG_THROW(valueCount < 2, storm::exceptions::InvalidJaniException, "Value for constant '" + name + "' (scope: " + scope.description + ") must be given at most once."); if (valueCount == 1) { // Read initial value before; that makes creation later on a bit easier, and has as an additional benefit that we do not need to check whether the variable occurs also on the assignment. - initExpr = parseExpression(constantStructure.at("value"), "Value of constant " + name + " (scope: " + scopeDescription + ")", {}, constants); + initExpr = parseExpression(constantStructure.at("value"), scope.refine("Value of constant " + name)); assert(initExpr.isInitialized()); } if (constantStructure.at("type").is_object()) { -// STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scopeDescription << ") kind must be given"); -// std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scopeDescription + ") "); +// STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scope.description << ") kind must be given"); +// std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scope.description + ") "); // if(kind == "bounded") { // // First do the bounds, that makes the code a bit more streamlined -// STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound must be given"); -// storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable "+ name + " (scope: " + scopeDescription + ")"); +// STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") lower-bound must be given"); +// storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable "+ name + " (scope: " + scope.description + ")"); // assert(lowerboundExpr.isInitialized()); -// STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") upper-bound must be given"); -// storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")"); +// STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") upper-bound must be given"); +// storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scope.description + ")"); // assert(upperboundExpr.isInitialized()); -// STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") base must be given"); -// std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scopeDescription + ") "); +// STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") base must be given"); +// std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scope.description + ") "); // if(basictype == "int") { -// STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); -// STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); +// STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scope.description << ") must be integer-typed"); +// STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scope.description << ") must be integer-typed"); // return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), lowerboundExpr, upperboundExpr); // } else { -// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scopeDescription << ") "); +// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scope.description << ") "); // } // } else { -// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); +// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scope.description << ") "); // } } else if(constantStructure.at("type").is_string()) { @@ -661,83 +681,121 @@ namespace storm { } } else { // TODO clocks. - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << constantStructure.at("type").dump() << " for constant '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << constantStructure.at("type").dump() << " for constant '" << name << "' (scope: " << scope.description << ")"); } } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scope.description << ")"); } - void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars) { + void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, Scope const& scope) { if (typeStructure.is_string()) { if (typeStructure == "real") { result.basicType = ParsedType::BasicType::Real; + result.expressionType = expressionManager->getRationalType(); } else if (typeStructure == "bool") { result.basicType = ParsedType::BasicType::Bool; + result.expressionType = expressionManager->getBooleanType(); } else if (typeStructure == "int") { result.basicType = ParsedType::BasicType::Int; + result.expressionType = expressionManager->getIntegerType(); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << variableName << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << variableName << "' (scope: " << scope.description << ")"); } } else if (typeStructure.is_object()) { - STORM_LOG_THROW(typeStructure.count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << variableName << "(scope: " << scopeDescription << ") kind must be given"); - std::string kind = getString(typeStructure.at("kind"), "kind for complex type as in variable " + variableName + "(scope: " + scopeDescription + ") "); + STORM_LOG_THROW(typeStructure.count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << variableName << "(scope: " << scope.description << ") kind must be given"); + std::string kind = getString(typeStructure.at("kind"), "kind for complex type as in variable " + variableName + "(scope: " + scope.description + ") "); if (kind == "bounded") { - STORM_LOG_THROW(typeStructure.count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") lower-bound must be given"); - storm::expressions::Expression lowerboundExpr = parseExpression(typeStructure.at("lower-bound"), "Lower bound for variable " + variableName + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + STORM_LOG_THROW(typeStructure.count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scope.description << ") lower-bound must be given"); + storm::expressions::Expression lowerboundExpr = parseExpression(typeStructure.at("lower-bound"), scope.refine("Lower bound for variable " + variableName)); assert(lowerboundExpr.isInitialized()); - STORM_LOG_THROW(typeStructure.count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") upper-bound must be given"); - storm::expressions::Expression upperboundExpr = parseExpression(typeStructure.at("upper-bound"), "Upper bound for variable "+ variableName + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); + STORM_LOG_THROW(typeStructure.count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scope.description << ") upper-bound must be given"); + storm::expressions::Expression upperboundExpr = parseExpression(typeStructure.at("upper-bound"), scope.refine("Upper bound for variable "+ variableName)); assert(upperboundExpr.isInitialized()); - STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scopeDescription << ") base must be given"); - std::string basictype = getString(typeStructure.at("base"), "base for bounded type as in variable " + variableName + "(scope: " + scopeDescription + ") "); + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scope.description << ") base must be given"); + std::string basictype = getString(typeStructure.at("base"), "base for bounded type as in variable " + variableName + "(scope: " + scope.description + ") "); if (basictype == "int") { - STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ") must be integer-typed"); - STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ") must be integer-typed"); + STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << variableName << "(scope: " << scope.description << ") must be integer-typed"); + STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << variableName << "(scope: " << scope.description << ") must be integer-typed"); if (!lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { - STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << variableName << "(scope: " << scopeDescription << ")"); + STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << variableName << "(scope: " << scope.description << ")"); } result.basicType = ParsedType::BasicType::Int; + result.expressionType = expressionManager->getIntegerType(); result.bounds = std::make_pair(lowerboundExpr, upperboundExpr); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << variableName << "(scope: " << scopeDescription << ") "); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << variableName << "(scope: " << scope.description << ") "); } } else if (kind == "array") { - STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For array type as in variable " << variableName << "(scope: " << scopeDescription << ") base must be given"); + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For array type as in variable " << variableName << "(scope: " << scope.description << ") base must be given"); result.arrayBase = std::make_unique(); - parseType(*result.arrayBase, typeStructure.at("base"), variableName, scopeDescription, globalVars, constants, localVars); + parseType(*result.arrayBase, typeStructure.at("base"), variableName, scope); + result.expressionType = expressionManager->getArrayType(result.arrayBase->expressionType); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << variableName << "(scope: " << scopeDescription << ") "); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << variableName << "(scope: " << scope.description << ") "); } } } - std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool prefWithScope) { - STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); - std::string pref = prefWithScope ? scopeDescription + VARIABLE_AUTOMATON_DELIMITER : ""; - std::string name = getString(variableStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); + storm::jani::FunctionDefinition JaniParser::parseFunctionDefinition(json const& functionDefinitionStructure, Scope const& scope, std::string const& parameterNamePrefix) { + STORM_LOG_THROW(functionDefinitionStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Function definition (scope: " + scope.description + ") must have a name"); + std::string functionName = getString(functionDefinitionStructure.at("name"), "function-name in " + scope.description); + // TODO check existence of name. + STORM_LOG_THROW(functionDefinitionStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have a (single) type-declaration."); + ParsedType type; + parseType(type, functionDefinitionStructure.at("type"), functionName, scope); + + std::unordered_map parameterNameToVariableMap; + std::vector parameters; + if (functionDefinitionStructure.count("parameters")) { + STORM_LOG_THROW(functionDefinitionStructure.count("parameters") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have exactly one list of parameters."); + for (auto const& parameterStructure : functionDefinitionStructure.at("parameters")) { + STORM_LOG_THROW(parameterStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Parameter declaration of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ") must have a name"); + std::string parameterName = getString(functionDefinitionStructure.at("name"), "parameter-name of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ")"); + ParsedType parameterType; + STORM_LOG_THROW(functionDefinitionStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Parameter declaration of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ") must have exactly one type."); + parseType(parameterType, parameterStructure.at("type"), parameterName, scope.refine("parameter declaration of parameter " + std::to_string(parameters.size()) + " of function definition " + functionName)); + STORM_LOG_WARN_COND(!parameterType.bounds.is_initialized(), "Bounds on parameter" + parameterName + " of function definition " + functionName + " will be ignored."); + + std::string exprParameterName = parameterNamePrefix + functionName + VARIABLE_AUTOMATON_DELIMITER + parameterName; + parameters.push_back(expressionManager->declareVariable(exprParameterName, parameterType.expressionType)); + parameterNameToVariableMap.emplace(parameterName, parameters.back()); + } + } + + STORM_LOG_THROW(functionDefinitionStructure.count("body") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have a (single) body."); + storm::expressions::Expression functionBody = parseExpression(functionDefinitionStructure.at("body"), scope.refine("body of function definition " + functionName), false, parameterNameToVariableMap); + STORM_LOG_WARN_COND(functionBody.getType() == type.expressionType, "Type of body of function " + functionName + "' (scope: " + scope.description + ") has type " << functionBody.getType() << " although the function type is given as " << type.expressionType); + + return storm::jani::FunctionDefinition(functionName, type.expressionType, parameters, functionBody); + } + + + std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, Scope const& scope, std::string const& namePrefix) { + STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scope.description + ") must have a name"); + std::string name = getString(variableStructure.at("name"), "variable-name in " + scope.description + "-scope"); // TODO check existance of name. // TODO store prefix in variable. - std::string exprManagerName = pref + name; + std::string exprManagerName = namePrefix + name; bool transientVar = defaultVariableTransient; // Default value for variables. size_t tvarcount = variableStructure.count("transient"); - STORM_LOG_THROW(tvarcount <= 1, storm::exceptions::InvalidJaniException, "Multiple definitions of transient not allowed in variable '" + name + "' (scope: " + scopeDescription + ") "); + STORM_LOG_THROW(tvarcount <= 1, storm::exceptions::InvalidJaniException, "Multiple definitions of transient not allowed in variable '" + name + "' (scope: " + scope.description + ") "); if(tvarcount == 1) { - transientVar = getBoolean(variableStructure.at("transient"), "transient-attribute in variable '" + name + "' (scope: " + scopeDescription + ") "); + transientVar = getBoolean(variableStructure.at("transient"), "transient-attribute in variable '" + name + "' (scope: " + scope.description + ") "); } - STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); + STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scope.description + ") must have a (single) type-declaration."); ParsedType type; - parseType(type, variableStructure.at("type"), name, scopeDescription, globalVars, constants, localVars); + parseType(type, variableStructure.at("type"), name, scope); size_t initvalcount = variableStructure.count("initial-value"); if(transientVar) { - STORM_LOG_THROW(initvalcount == 1, storm::exceptions::InvalidJaniException, "Initial value must be given once for transient variable '" + name + "' (scope: " + scopeDescription + ") "+ name + "' (scope: " + scopeDescription + ") "); + STORM_LOG_THROW(initvalcount == 1, storm::exceptions::InvalidJaniException, "Initial value must be given once for transient variable '" + name + "' (scope: " + scope.description + ") "+ name + "' (scope: " + scope.description + ") "); } else { - STORM_LOG_THROW(initvalcount <= 1, storm::exceptions::InvalidJaniException, "Initial value can be given at most one for variable " + name + "' (scope: " + scopeDescription + ")"); + STORM_LOG_THROW(initvalcount <= 1, storm::exceptions::InvalidJaniException, "Initial value can be given at most one for variable " + name + "' (scope: " + scope.description + ")"); } boost::optional initVal; if (initvalcount == 1 && !variableStructure.at("initial-value").is_null()) { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); + initVal = parseExpression(variableStructure.at("initial-value"), scope.refine("Initial value for variable " + name)); } else { assert(!transientVar); } @@ -750,7 +808,7 @@ namespace storm { initVal = expressionManager->rational(defaultRationalInitialValue); } if (initVal) { - STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scopeDescription + ") should be a rational"); + STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scope.description + ") should be a rational"); return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar); } else { return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName)); @@ -765,7 +823,7 @@ namespace storm { } } if (initVal) { - STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); + STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scope.description + ") should be an integer"); if (type.bounds) { return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, type.bounds->first, type.bounds->second); } else { @@ -784,7 +842,7 @@ namespace storm { initVal = expressionManager->boolean(defaultBooleanInitialValue); } if (initVal) { - STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scopeDescription + ") should be a Boolean"); + STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scope.description + ") should be a Boolean"); if (transientVar) { labels.insert(name); } @@ -794,7 +852,7 @@ namespace storm { } } } else if (type.arrayBase) { - STORM_LOG_THROW(type.arrayBase->basicType, storm::exceptions::InvalidJaniException, "Array base type for variable " + name + "(scope " + scopeDescription + ") should be a BasicType or a BoundedType."); + STORM_LOG_THROW(type.arrayBase->basicType, storm::exceptions::InvalidJaniException, "Array base type for variable " + name + "(scope " + scope.description + ") should be a BasicType or a BoundedType."); storm::jani::ArrayVariable::ElementType elementType; storm::expressions::Type exprVariableType; switch (type.arrayBase->basicType.get()) { @@ -818,7 +876,7 @@ namespace storm { } std::shared_ptr result; if (initVal) { - STORM_LOG_THROW(initVal->getType().isArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scopeDescription + ") should be an Array"); + STORM_LOG_THROW(initVal->getType().isArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scope.description + ") should be an Array"); result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType, initVal.get(), transientVar); } else { result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType); @@ -829,7 +887,7 @@ namespace storm { return result; } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scope.description << ")"); } /** @@ -839,14 +897,14 @@ namespace storm { STORM_LOG_THROW(expected == actual, storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects " << expected << " arguments, but got " << actual << " in " << errorInfo << "."); } - std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars,returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), scope.refine("Argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left}; } - std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); - storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), scope.refine("Left argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), scope.refine("Right argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left, right}; } /** @@ -877,65 +935,65 @@ namespace storm { STORM_LOG_THROW(expr.getType().isArrayType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be of type 'array' in " << errorInfo << "."); } - storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars) { + storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, Scope const& scope) { if (lValueStructure.is_string()) { - std::string ident = getString(lValueStructure, scopeDescription); - auto localVar = localVars.find(ident); - if (localVar != localVars.end()) { - return storm::jani::LValue(*localVar->second); - } - auto globalVar = globalVars.find(ident); - if (globalVar != globalVars.end()) { - return storm::jani::LValue(*globalVar->second); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + std::string ident = getString(lValueStructure, scope.description); + if (scope.localVars != nullptr) { + auto localVar = scope.localVars->find(ident); + if (localVar != scope.localVars->end()) { + return storm::jani::LValue(*localVar->second); + } } + STORM_LOG_THROW(scope.globalVars != nullptr, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); + auto globalVar = scope.globalVars->find(ident); + STORM_LOG_THROW(globalVar != scope.globalVars->end(), storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); + return storm::jani::LValue(*globalVar->second); } else if (lValueStructure.count("op") == 1) { - std::string opstring = getString(lValueStructure.at("op"), scopeDescription); - STORM_LOG_THROW(opstring == "aa", storm::exceptions::InvalidJaniException, "Unknown operation '" << opstring << "' occurs in " << scopeDescription); - STORM_LOG_THROW(lValueStructure.count("exp"), storm::exceptions::InvalidJaniException, "Missing 'exp' in array access at " << scopeDescription); - storm::jani::LValue exp = parseLValue(lValueStructure.at("exp"), "LValue description of array expression in " + scopeDescription, globalVars, constants, localVars); - STORM_LOG_THROW(lValueStructure.count("index"), storm::exceptions::InvalidJaniException, "Missing 'index' in array access at " << scopeDescription); - storm::expressions::Expression index = parseExpression(lValueStructure.at("index"), "Index expression of array access at " + scopeDescription, globalVars, constants, localVars); + std::string opstring = getString(lValueStructure.at("op"), scope.description); + STORM_LOG_THROW(opstring == "aa", storm::exceptions::InvalidJaniException, "Unknown operation '" << opstring << "' occurs in " << scope.description); + STORM_LOG_THROW(lValueStructure.count("exp"), storm::exceptions::InvalidJaniException, "Missing 'exp' in array access at " << scope.description); + storm::jani::LValue exp = parseLValue(lValueStructure.at("exp"), scope.refine("LValue description of array expression")); + STORM_LOG_THROW(lValueStructure.count("index"), storm::exceptions::InvalidJaniException, "Missing 'index' in array access at " << scope.description); + storm::expressions::Expression index = parseExpression(lValueStructure.at("index"), scope.refine("Index expression of array access")); return storm::jani::LValue(exp, index); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown LValue '" << lValueStructure.dump() << "' occurs in " << scopeDescription); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown LValue '" << lValueStructure.dump() << "' occurs in " << scope.description); // Silly warning suppression. - return storm::jani::LValue(*localVars.end()->second); + return storm::jani::LValue(*scope.globalVars->end()->second); } } - storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, Scope const& scope, std::unordered_map const& auxiliaryVariables) { { auto it = auxiliaryVariables.find(ident); if (it != auxiliaryVariables.end()) { return it->second; } } - { - auto it = localVars.find(ident); - if (it != localVars.end()) { + if (scope.localVars != nullptr) { + auto it = scope.localVars->find(ident); + if (it != scope.localVars->end()) { return it->second->getExpressionVariable(); } } - { - auto it = globalVars.find(ident); - if (it != globalVars.end()) { + if (scope.globalVars != nullptr) { + auto it = scope.globalVars->find(ident); + if (it != scope.globalVars->end()) { return it->second->getExpressionVariable(); } } - { - auto it = constants.find(ident); - if (it != constants.end()) { + if (scope.constants != nullptr) { + auto it = scope.constants->find(ident); + if (it != scope.constants->end()) { return it->second->getExpressionVariable(); } } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); // Silly warning suppression. return storm::expressions::Variable(); } - storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { if (expressionStructure.is_boolean()) { if (expressionStructure.get()) { return expressionManager->boolean(true); @@ -950,229 +1008,229 @@ namespace storm { return expressionManager->rational(expressionStructure.get()); } else if (expressionStructure.is_string()) { std::string ident = expressionStructure.get(); - return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars, auxiliaryVariables)); + return storm::expressions::Expression(getVariableOrConstantExpression(ident, scope, auxiliaryVariables)); } else if (expressionStructure.is_object()) { if (expressionStructure.count("distribution") == 1) { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scope.description << "."); } if (expressionStructure.count("op") == 1) { - std::string opstring = getString(expressionStructure.at("op"), scopeDescription); + std::string opstring = getString(expressionStructure.at("op"), scope.description); std::vector arguments = {}; if(opstring == "ite") { STORM_LOG_THROW(expressionStructure.count("if") == 1, storm::exceptions::InvalidJaniException, "If operator required"); STORM_LOG_THROW(expressionStructure.count("else") == 1, storm::exceptions::InvalidJaniException, "Else operator required"); STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "Then operator required"); - arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); - arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); - arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); - ensureNumberOfArguments(3, arguments.size(), opstring, scopeDescription); + arguments.push_back(parseExpression(expressionStructure.at("if"), scope.refine("if-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("then"), scope.refine("then-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("else"), scope.refine("else-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + ensureNumberOfArguments(3, arguments.size(), opstring, scope.description); assert(arguments.size() == 3); - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); return storm::expressions::ite(arguments[0], arguments[1], arguments[2]); } else if (opstring == "∨") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return arguments[0] || arguments[1]; } else if (opstring == "∧") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return arguments[0] && arguments[1]; } else if (opstring == "⇒") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return (!arguments[0]) || arguments[1]; } else if (opstring == "¬") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); if(!arguments[0].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); return !arguments[0]; } else if (opstring == "=") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } if(arguments[0].hasBooleanType()) { - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return storm::expressions::iff(arguments[0], arguments[1]); } else { - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] == arguments[1]; } } else if (opstring == "≠") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } if(arguments[0].hasBooleanType()) { - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return storm::expressions::xclusiveor(arguments[0], arguments[1]); } else { - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] != arguments[1]; } } else if (opstring == "<") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] < arguments[1]; } else if (opstring == "≤") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] <= arguments[1]; } else if (opstring == ">") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] > arguments[1]; } else if (opstring == "≥") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] >= arguments[1]; } else if (opstring == "+") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] + arguments[1]; } else if (opstring == "-") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] - arguments[1]; } else if (opstring == "-") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription,globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return -arguments[0]; } else if (opstring == "*") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] * arguments[1]; } else if (opstring == "/") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] / arguments[1]; } else if (opstring == "%") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] % arguments[1]; } else if (opstring == "max") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return storm::expressions::maximum(arguments[0],arguments[1]); } else if (opstring == "min") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return storm::expressions::minimum(arguments[0],arguments[1]); } else if (opstring == "floor") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::floor(arguments[0]); } else if (opstring == "ceil") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::ceil(arguments[0]); } else if (opstring == "abs") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::abs(arguments[0]); } else if (opstring == "sgn") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::sign(arguments[0]); } else if (opstring == "trc") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::truncate(arguments[0]); } else if (opstring == "pow") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0]^arguments[1]; } else if (opstring == "exp") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "exp operation is not yet implemented"); } else if (opstring == "log") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "log operation is not yet implemented"); } else if (opstring == "aa") { - STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scopeDescription + ")."); - storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); - STORM_LOG_THROW(expressionStructure.count("index") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one index (at " + scopeDescription + ")."); - storm::expressions::Expression index = parseExpression(expressionStructure.at("index"), "index in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); - ensureArrayType(exp, opstring, 0, scopeDescription); - ensureIntegerType(index, opstring, 1, scopeDescription); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scope.description + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), scope.refine("'exp' of array access operator"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + STORM_LOG_THROW(expressionStructure.count("index") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one index (at " + scope.description + ")."); + storm::expressions::Expression index = parseExpression(expressionStructure.at("index"), scope.refine("index of array access operator"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureArrayType(exp, opstring, 0, scope.description); + ensureIntegerType(index, opstring, 1, scope.description); return std::make_shared(exp.getManager(), exp.getType().getElementType(), exp.getBaseExpressionPointer(), index.getBaseExpressionPointer())->toExpression(); } else if (opstring == "av") { - STORM_LOG_THROW(expressionStructure.count("elements") == 1, storm::exceptions::InvalidJaniException, "Array value operator requires exactly one 'elements' (at " + scopeDescription + ")."); + STORM_LOG_THROW(expressionStructure.count("elements") == 1, storm::exceptions::InvalidJaniException, "Array value operator requires exactly one 'elements' (at " + scope.description + ")."); std::vector> elements; storm::expressions::Type commonType; bool first = true; for (auto const& element : expressionStructure.at("elements")) { - elements.push_back(parseExpression(element, "element " + std::to_string(elements.size()) + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); + elements.push_back(parseExpression(element, scope.refine("element " + std::to_string(elements.size()) + " of array value expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); if (first) { commonType = elements.back()->getType(); first = false; @@ -1180,37 +1238,56 @@ namespace storm { if (commonType.isIntegerType() && elements.back()->getType().isRationalType()) { commonType = elements.back()->getType(); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Incompatible element types " << commonType << " and " << elements.back()->getType() << " of array value expression at " << scopeDescription); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Incompatible element types " << commonType << " and " << elements.back()->getType() << " of array value expression at " << scope.description); } } } return std::make_shared(*expressionManager, expressionManager->getArrayType(commonType), elements)->toExpression(); } else if (opstring == "ac") { - STORM_LOG_THROW(expressionStructure.count("length") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one length (at " + scopeDescription + ")."); - storm::expressions::Expression length = parseExpression(expressionStructure.at("length"), "index in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); - ensureIntegerType(length, opstring, 1, scopeDescription); - STORM_LOG_THROW(expressionStructure.count("var") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one var (at " + scopeDescription + ")."); - std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scopeDescription + ")."); - STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scopeDescription + ")."); + STORM_LOG_THROW(expressionStructure.count("length") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one length (at " + scope.description + ")."); + storm::expressions::Expression length = parseExpression(expressionStructure.at("length"), scope.refine("index of array constructor expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureIntegerType(length, opstring, 1, scope.description); + STORM_LOG_THROW(expressionStructure.count("var") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one var (at " + scope.description + ")."); + std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scope.description + ")."); + STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scope.description + ")."); auto newAuxVars = auxiliaryVariables; storm::expressions::Variable indexVar = expressionManager->declareFreshIntegerVariable(false, "ac_" + indexVarName); newAuxVars.emplace(indexVarName, indexVar); - STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array constructor operator requires exactly one exp (at " + scopeDescription + ")."); - storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp of array constructor in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array constructor operator requires exactly one exp (at " + scope.description + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), scope.refine("exp of array constructor"), returnNoneInitializedOnUnknownOperator, newAuxVars); return std::make_shared(*expressionManager, expressionManager->getArrayType(exp.getType()), length.getBaseExpressionPointer(), indexVar, exp.getBaseExpressionPointer())->toExpression(); - } else if (unsupportedOpstrings.count(opstring) > 0){ + } else if (opstring == "call") { + STORM_LOG_THROW(expressionStructure.count("function") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one function (at " + scope.description + ")."); + std::string functionName = getString(expressionStructure.at("function"), "in function call operator (at " + scope.description + ")."); + storm::jani::FunctionDefinition const* functionDefinition; + if (scope.localFunctions != nullptr && scope.localFunctions->count(functionName) > 0) { + functionDefinition = scope.localFunctions->at(functionName); + } else if (scope.globalFunctions != nullptr && scope.globalFunctions->count(functionName) > 0){ + functionDefinition = scope.globalFunctions->at(functionName); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Function call operator calls unknown function '" + functionName + "' (at " + scope.description + ")."); + } + STORM_LOG_THROW(expressionStructure.count("args") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one args (at " + scope.description + ")."); + std::vector> args; + if (expressionStructure.count("args") > 0) { + STORM_LOG_THROW(expressionStructure.count("args") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one args (at " + scope.description + ")."); + for (auto const& arg : expressionStructure.at("args")) { + args.push_back(parseExpression(arg, scope.refine("argument " + std::to_string(args.size()) + " of function call expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); + } + } + return std::make_shared(*expressionManager, functionDefinition->getType(), functionName, args)->toExpression(); + } else if (unsupportedOpstrings.count(opstring) > 0) { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm"); - } else { if(returnNoneInitializedOnUnknownOperator) { return storm::expressions::Expression(); } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opstring << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opstring << " in " << scope.description << "."); } } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported operator declaration found for complex expressions as " << expressionStructure.dump() << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported operator declaration found for complex expressions as " << expressionStructure.dump() << " in " << scope.description << "."); } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported expression found at " << expressionStructure.dump() << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported expression found at " << expressionStructure.dump() << " in " << scope.description << "."); // Silly warning suppression. return storm::expressions::Expression(); @@ -1227,23 +1304,37 @@ namespace storm { } } - storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, VariablesMap const& globalVars, ConstantsMap const& constants ) { + storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, Scope const& globalScope) { STORM_LOG_THROW(automatonStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Each automaton must have a name"); std::string name = getString(automatonStructure.at("name"), " the name field for automaton"); + Scope scope = globalScope.refine(name); storm::jani::Automaton automaton(name, expressionManager->declareIntegerVariable("_loc_" + name)); uint64_t varDeclCount = automatonStructure.count("variables"); STORM_LOG_THROW(varDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of variables"); VariablesMap localVars; - if(varDeclCount > 0) { + scope.localVars = &localVars; + if (varDeclCount > 0) { bool requireInitialValues = automatonStructure.count("restrict-initial") == 0; for(auto const& varStructure : automatonStructure.at("variables")) { - std::shared_ptr var = parseVariable(varStructure, requireInitialValues, name, globalVars, constants, localVars, true); + std::shared_ptr var = parseVariable(varStructure, requireInitialValues, scope.refine("variables[" + std::to_string(localVars.size()) + "] of automaton " + name), name + VARIABLE_AUTOMATON_DELIMITER); assert(localVars.count(var->getName()) == 0); localVars.emplace(var->getName(), &automaton.addVariable(*var)); } } + uint64_t funDeclCount = automatonStructure.count("functions"); + STORM_LOG_THROW(funDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of functions"); + FunctionsMap localFuns; + scope.localFunctions = &localFuns; + if (funDeclCount > 0) { + for (auto const& funStructure : automatonStructure.at("functions")) { + storm::jani::FunctionDefinition funDef = parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(localFuns.size()) + "] of automaton " + name), name + VARIABLE_AUTOMATON_DELIMITER); + assert(localFuns.count(funDef.getName()) == 0); + //TODO localVars.emplace(funDef.getName(), &automaton.addFunction(funDef)); + } + } + STORM_LOG_THROW(automatonStructure.count("locations") > 0, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' does not have locations."); std::unordered_map locIds; for(auto const& locEntry : automatonStructure.at("locations")) { @@ -1257,9 +1348,9 @@ namespace storm { for(auto const& transientValueEntry : locEntry.at("transient-values")) { STORM_LOG_THROW(transientValueEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one ref that is assigned to"); STORM_LOG_THROW(transientValueEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one assigned value"); - storm::jani::LValue lValue = parseLValue(transientValueEntry.at("ref"), "LHS of assignment in location " + locName + " (automaton '" + name + "')", globalVars, constants, localVars); + storm::jani::LValue lValue = parseLValue(transientValueEntry.at("ref"), scope.refine("LHS of assignment in location " + locName)); STORM_LOG_THROW(lValue.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " << lValue << " in location " + locName + " (automaton: '" + name + "')"); - storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of lValue in location " + locName + " (automaton: '" + name + "')", globalVars, constants, localVars); + storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), scope.refine("Assignment of lValue in location " + locName)); transientAssignments.emplace_back(lValue, rhs); } } @@ -1274,12 +1365,11 @@ namespace storm { storm::expressions::Expression initialValueRestriction = expressionManager->boolean(true); if(automatonStructure.count("restrict-initial") > 0) { STORM_LOG_THROW(automatonStructure.at("restrict-initial").count("exp") == 1, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' needs an expression inside the initial restricion"); - initialValueRestriction = parseExpression(automatonStructure.at("restrict-initial").at("exp"), "Initial value restriction for automaton " + name, globalVars, constants, localVars); + initialValueRestriction = parseExpression(automatonStructure.at("restrict-initial").at("exp"), scope.refine("Initial value restriction")); } automaton.setInitialStatesRestriction(initialValueRestriction); - STORM_LOG_THROW(automatonStructure.count("edges") > 0, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' must have a list of edges"); for(auto const& edgeEntry : automatonStructure.at("edges")) { // source location @@ -1299,7 +1389,7 @@ namespace storm { storm::expressions::Expression rateExpr; if(edgeEntry.count("rate") > 0) { STORM_LOG_THROW(edgeEntry.at("rate").count("exp") == 1, storm::exceptions::InvalidJaniException, "Rate in edge from '" << sourceLoc << "' in automaton '" << name << "' must have a defing expression."); - rateExpr = parseExpression(edgeEntry.at("rate").at("exp"), "rate expression in edge from '" + sourceLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + rateExpr = parseExpression(edgeEntry.at("rate").at("exp"), scope.refine("rate expression in edge from '" + sourceLoc)); STORM_LOG_THROW(rateExpr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Rate '" << rateExpr << "' has not a numerical type"); } // guard @@ -1307,7 +1397,7 @@ namespace storm { storm::expressions::Expression guardExpr = expressionManager->boolean(true); if(edgeEntry.count("guard") == 1) { STORM_LOG_THROW(edgeEntry.at("guard").count("exp") == 1, storm::exceptions::InvalidJaniException, "Guard in edge from '" + sourceLoc + "' in automaton '" + name + "' must have one expression"); - guardExpr = parseExpression(edgeEntry.at("guard").at("exp"), "guard expression in edge from '" + sourceLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + guardExpr = parseExpression(edgeEntry.at("guard").at("exp"), scope.refine("guard expression in edge from '" + sourceLoc)); STORM_LOG_THROW(guardExpr.hasBooleanType(), storm::exceptions::InvalidJaniException, "Guard " << guardExpr << " does not have Boolean type."); } assert(guardExpr.isInitialized()); @@ -1329,7 +1419,7 @@ namespace storm { probExpr = expressionManager->rational(1.0); } else { STORM_LOG_THROW(destEntry.at("probability").count("exp") == 1, storm::exceptions::InvalidJaniException, "Destination in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have a probability expression."); - probExpr = parseExpression(destEntry.at("probability").at("exp"), "probability expression in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + probExpr = parseExpression(destEntry.at("probability").at("exp"), scope.refine("probability expression in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); } assert(probExpr.isInitialized()); STORM_LOG_THROW(probExpr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Probability expression " << probExpr << " does not have a numerical type." ); @@ -1341,10 +1431,10 @@ namespace storm { for (auto const& assignmentEntry : destEntry.at("assignments")) { // ref STORM_LOG_THROW(assignmentEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one ref field"); - storm::jani::LValue lValue = parseLValue(assignmentEntry.at("ref"), "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + storm::jani::LValue lValue = parseLValue(assignmentEntry.at("ref"), scope.refine("Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); // value STORM_LOG_THROW(assignmentEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one value field"); - storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), scope.refine("assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); // TODO check types // index int64_t assignmentIndex = 0; // default. diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h index e6cf5f069..7716126a2 100644 --- a/src/storm-parsers/parser/JaniParser.h +++ b/src/storm-parsers/parser/JaniParser.h @@ -1,5 +1,6 @@ #pragma once #include "storm/storage/jani/Constant.h" +#include "storm/storage/jani/FunctionDefinition.h" #include "storm/storage/jani/LValue.h" #include "storm/logic/Formula.h" #include "storm/logic/Bound.h" @@ -32,8 +33,6 @@ namespace storm { /* * The JANI format parser. * Parses Models and Properties - * - * TODO some parts are copy-heavy, a bit of cleaning is good as soon as the format is stable. */ class JaniParser { @@ -41,48 +40,75 @@ namespace storm { typedef std::vector PropertyVector; typedef std::unordered_map VariablesMap; typedef std::unordered_map ConstantsMap; + typedef std::unordered_map FunctionsMap; JaniParser() : expressionManager(new storm::expressions::ExpressionManager()) {} JaniParser(std::string const& jsonstring); static std::pair> parse(std::string const& path); - protected: void readFile(std::string const& path); + + struct Scope { + Scope(std::string description = "global", ConstantsMap const* constants = nullptr, VariablesMap const* globalVars = nullptr, FunctionsMap const* globalFunctions = nullptr, VariablesMap const* localVars = nullptr, FunctionsMap const* localFunctions = nullptr) : description(description) , constants(constants), globalVars(globalVars), globalFunctions(globalFunctions), localVars(localVars), localFunctions(localFunctions) {}; + + Scope(Scope const& other) = default; + std::string description; + ConstantsMap const* constants; + VariablesMap const* globalVars; + FunctionsMap const* globalFunctions; + VariablesMap const* localVars; + FunctionsMap const* localFunctions; + Scope refine(std::string const& prependedDescription = "") const { + Scope res(*this); + if (prependedDescription != "") { + res.description = "'" + prependedDescription + "' at " + res.description; + } + return res; + } + + Scope& clearVariables() { + this->globalVars = nullptr; + this->localVars = nullptr; + return *this; + } + }; + std::pair> parseModel(bool parseProperties = true); - storm::jani::Property parseProperty(json const& propertyStructure, VariablesMap const& globalVars, ConstantsMap const& constants); - storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, VariablesMap const& globalVars, ConstantsMap const& constants); + storm::jani::Property parseProperty(json const& propertyStructure, Scope const& scope); + storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, Scope const& scope); struct ParsedType { enum class BasicType {Bool, Int, Real}; boost::optional basicType; boost::optional> bounds; std::unique_ptr arrayBase; + storm::expressions::Type expressionType; }; - void parseType(ParsedType& result, json const& typeStructure, std::string variableName, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars); - storm::jani::LValue parseLValue(json const& lValueStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}); - std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool prefWithScope = false); - storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + void parseType(ParsedType& result, json const& typeStructure, std::string variableName, Scope const& scope); + storm::jani::LValue parseLValue(json const& lValueStructure, Scope const& scope); + std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, Scope const& scope, std::string const& namePrefix = ""); + storm::expressions::Expression parseExpression(json const& expressionStructure, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); private: - std::shared_ptr parseConstant(json const& constantStructure, ConstantsMap const& constants, std::string const& scopeDescription = "global"); + std::shared_ptr parseConstant(json const& constantStructure, Scope const& scope); + storm::jani::FunctionDefinition parseFunctionDefinition(json const& functionDefinitionStructure, Scope const& scope, std::string const& parameterNamePrefix = ""); /** * Helper for parsing the actions of a model. */ void parseActions(json const& actionStructure, storm::jani::Model& parentModel); - std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context, boost::optional bound = boost::none); - std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars= {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); - std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, Scope const& scope, boost::optional bound = boost::none); + std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); - std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context); - std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, VariablesMap const& globalVars, ConstantsMap const& constants, std::string const& context); - storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, ConstantsMap const& constants); + std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope); + std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope); + storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, Scope const& scope); storm::logic::RewardAccumulation parseRewardAccumulation(json const& accStructure, std::string const& context); - std::shared_ptr parseComposition(json const& compositionStructure); - storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars = {}, std::unordered_map const& auxiliaryVariables = {}); + storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, Scope const& scope, std::unordered_map const& auxiliaryVariables = {}); diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 14a1e7b2f..c1b375b2b 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -85,6 +85,20 @@ namespace storm { return variables.hasTransientVariable(); } + FunctionDefinition const& Automaton::addFunctionDefinition(FunctionDefinition const& functionDefinition) { + auto insertionRes = functionDefinitions.emplace(functionDefinition.getName(), functionDefinition); + STORM_LOG_THROW(insertionRes.second, storm::exceptions::InvalidArgumentException, " a function with the name " << functionDefinition.getName() << " already exists in this automaton (" << this->getName() << ")"); + return insertionRes.first->second; + } + + std::unordered_map const& Automaton::getFunctionDefinitions() const { + return functionDefinitions; + } + + std::unordered_map Automaton::getFunctionDefinitions() { + return functionDefinitions; + } + bool Automaton::hasLocation(std::string const& name) const { return locationToIndex.find(name) != locationToIndex.end(); } @@ -385,6 +399,9 @@ namespace storm { for (auto& variable : this->getVariables().getBoundedIntegerVariables()) { variable.substitute(substitution); } + for (auto& variable : this->getVariables().getArrayVariables()) { + variable.substitute(substitution); + } for (auto& location : this->getLocations()) { location.substitute(substitution); diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index c6422fb1a..ed67d2efc 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -9,7 +9,7 @@ #include "storm/storage/jani/VariableSet.h" #include "storm/storage/jani/TemplateEdgeContainer.h" #include "storm/storage/jani/EdgeContainer.h" - +#include "storm/storage/jani/FunctionDefinition.h" namespace storm { namespace jani { @@ -99,6 +99,21 @@ namespace storm { */ bool hasTransientVariable() const; + /*! + * Adds the given function definition + */ + FunctionDefinition const& addFunctionDefinition(FunctionDefinition const& functionDefinition); + + /*! + * Retrieves all function definitions of this automaton + */ + std::unordered_map const& getFunctionDefinitions() const; + + /*! + * Retrieves all function definitions of this automaton + */ + std::unordered_map getFunctionDefinitions(); + /*! * Retrieves whether the automaton has a location with the given name. */ @@ -356,6 +371,9 @@ namespace storm { /// The set of variables of this automaton. VariableSet variables; + /// A mapping from names to function definitions + std::unordered_map functionDefinitions; + /// The locations of the automaton. std::vector locations; diff --git a/src/storm/storage/jani/FunctionDefinition.cpp b/src/storm/storage/jani/FunctionDefinition.cpp new file mode 100644 index 000000000..2bac96f91 --- /dev/null +++ b/src/storm/storage/jani/FunctionDefinition.cpp @@ -0,0 +1,30 @@ +#include "storm/storage/jani/FunctionDefinition.h" + +namespace storm { + namespace jani { + + FunctionDefinition::FunctionDefinition(std::string const& name, storm::expressions::Type const& type, std::vector const& parameters, storm::expressions::Expression const& functionBody) : name(name), type(type), parameters(parameters), functionBody(functionBody) { + // Intentionally left empty. + } + + std::string const& FunctionDefinition::getName() const { + return name; + } + + storm::expressions::Type const& FunctionDefinition::getType() const { + return type; + } + + std::vector const& FunctionDefinition::getParameters() const { + return parameters; + } + + storm::expressions::Expression const& FunctionDefinition::getFunctionBody() const { + return functionBody; + } + + void FunctionDefinition::setFunctionBody(storm::expressions::Expression const& body) { + functionBody = body; + } + } +} diff --git a/src/storm/storage/jani/FunctionDefinition.h b/src/storm/storage/jani/FunctionDefinition.h new file mode 100644 index 000000000..51eabf937 --- /dev/null +++ b/src/storm/storage/jani/FunctionDefinition.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include + +#include "storm/storage/expressions/Variable.h" +#include "storm/storage/expressions/Expression.h" + +namespace storm { + namespace jani { + + class FunctionDefinition { + public: + /*! + * Creates a functionDefinition. + */ + FunctionDefinition(std::string const& name, storm::expressions::Type const& type, std::vector const& parameters, storm::expressions::Expression const& functionBody); + + /*! + * Retrieves the name of the function. + */ + std::string const& getName() const; + + /*! + * Retrieves the type of the function. + */ + storm::expressions::Type const& getType() const; + + /*! + * Retrieves the parameters of the function + */ + std::vector const& getParameters() const; + + /*! + * Retrieves the expression that defines the function + */ + storm::expressions::Expression const& getFunctionBody() const; + + /*! + * sets the expression that defines the function + */ + void setFunctionBody(storm::expressions::Expression const& body); + + private: + // The name of the function. + std::string name; + + // The type of the function + storm::expressions::Type type; + + // The parameters + std::vector parameters; + + // The body of the function + storm::expressions::Expression functionBody; + }; + + } +} diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 3da43c78b..4bfb71e03 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -36,9 +36,9 @@ namespace storm { namespace jani { - modernjson::json buildExpression(storm::expressions::Expression const& exp, std::vector const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet()) { + modernjson::json buildExpression(storm::expressions::Expression const& exp, std::vector const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet(), std::unordered_set const& auxiliaryVariables = {}) { STORM_LOG_TRACE("Exporting " << exp); - return ExpressionToJson::translate(exp, constants, globalVariables, localVariables); + return ExpressionToJson::translate(exp, constants, globalVariables, localVariables, auxiliaryVariables); } class CompositionJsonExporter : public CompositionVisitor { @@ -616,13 +616,13 @@ namespace storm { } } - modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables) { // Simplify the expression first and reduce the nesting auto simplifiedExpr = expr.simplify().reduceNesting(); - ExpressionToJson visitor(constants, globalVariables, localVariables); + ExpressionToJson visitor(constants, globalVariables, localVariables, auxiliaryVariables); return boost::any_cast(simplifiedExpr.accept(visitor, boost::none)); } @@ -657,7 +657,9 @@ namespace storm { return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::VariableExpression const& expression, boost::any const&) { - if (globalVariables.hasVariable(expression.getVariable())) { + if (auxiliaryVariables.count(expression.getVariableName())) { + return modernjson::json(expression.getVariableName()); + } else if (globalVariables.hasVariable(expression.getVariable())) { return modernjson::json(globalVariables.getVariable(expression.getVariable()).getName()); } else if (localVariables.hasVariable(expression.getVariable())) { return modernjson::json(localVariables.getVariable(expression.getVariable()).getName()); @@ -701,7 +703,7 @@ namespace storm { for (uint64_t i = 0; i < size; ++i) { elements.push_back(boost::any_cast(expression.at(i)->accept(*this, data))); } - opDecl["elements"] = elements; + opDecl["elements"] = std::move(elements); return opDecl; } @@ -710,7 +712,11 @@ namespace storm { opDecl["op"] = "ac"; opDecl["var"] = expression.getIndexVar().getName(); opDecl["length"] = boost::any_cast(expression.size()->accept(*this, data)); + bool inserted = auxiliaryVariables.insert(expression.getIndexVar().getName()).second; opDecl["exp"] = boost::any_cast(expression.getElementExpression()->accept(*this, data)); + if (inserted) { + auxiliaryVariables.erase(expression.getIndexVar().getName()); + } return opDecl; } @@ -722,6 +728,18 @@ namespace storm { return opDecl; } + boost::any ExpressionToJson::visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "call"; + opDecl["function"] = expression.getIdentifier(); + std::vector arguments; + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + arguments.push_back(boost::any_cast(expression.getArgument(i)->accept(*this, data))); + } + opDecl["args"] = std::move(arguments); + return opDecl; + } + void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid, bool compact) { std::ofstream stream; storm::utility::openFile(filepath, stream); @@ -832,16 +850,54 @@ namespace storm { } break; } - typeDesc["base"] = "int"; } varEntry["type"] = typeDesc; - if(variable.hasInitExpression()) { + if (variable.hasInitExpression()) { varEntry["initial-value"] = buildExpression(variable.getInitExpression(), constants, globalVariables, localVariables); } variableDeclarations.push_back(varEntry); } return modernjson::json(variableDeclarations); - + } + + modernjson::json buildTypeDescription(storm::expressions::Type const& type) { + modernjson::json typeDescr; + if (type.isIntegerType()) { + typeDescr = "int"; + } else if (type.isRationalType()) { + typeDescr = "real"; + } else if (type.isBooleanType()) { + typeDescr = "bool"; + } else if (type.isArrayType()) { + typeDescr["kind"] = "array"; + typeDescr["base"] = buildTypeDescription(type.getElementType()); + } else { + assert(false); + } + return typeDescr; + } + + modernjson::json buildFunctionsArray(std::unordered_map const& functionDefinitions, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) { + std::vector functionDeclarations; + for (auto const& nameFunDef : functionDefinitions) { + storm::jani::FunctionDefinition const& funDef = nameFunDef.second; + modernjson::json funDefJson; + funDefJson["name"] = nameFunDef.first; + funDefJson["type"] = buildTypeDescription(funDef.getType()); + std::vector parameterDeclarations; + std::unordered_set parameterNames; + for (auto const& p : funDef.getParameters()) { + modernjson::json parDefJson; + parDefJson["name"] = p.getName(); + parameterNames.insert(p.getName()); + parDefJson["type"] = buildTypeDescription(p.getType()); + parameterDeclarations.push_back(parDefJson); + } + funDefJson["parameters"] = parameterDeclarations; + funDefJson["body"] = buildExpression(funDef.getFunctionBody(), constants, globalVariables, localVariables, parameterNames); + functionDeclarations.push_back(funDefJson); + } + return modernjson::json(functionDeclarations); } modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { @@ -868,7 +924,7 @@ namespace storm { assignmentEntry["comment"] = assignment.getVariable().getName() + " <- " + assignment.getAssignedExpression().toString(); } } - return modernjson::json(assignmentDeclarations); + return modernjson::json(std::move(assignmentDeclarations)); } modernjson::json buildLocationsArray(std::vector const& locations, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { @@ -882,7 +938,7 @@ namespace storm { } locationDeclarations.push_back(locEntry); } - return modernjson::json(locationDeclarations); + return modernjson::json(std::move(locationDeclarations)); } modernjson::json buildInitialLocations(storm::jani::Automaton const& automaton) { @@ -916,7 +972,7 @@ namespace storm { } destDeclarations.push_back(destEntry); } - return modernjson::json(destDeclarations); + return modernjson::json(std::move(destDeclarations)); } modernjson::json buildEdges(std::vector const& edges , std::map const& actionNames, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { @@ -950,7 +1006,7 @@ namespace storm { edgeDeclarations.push_back(edgeEntry); } - return modernjson::json(edgeDeclarations); + return modernjson::json(std::move(edgeDeclarations)); } modernjson::json buildAutomataArray(std::vector const& automata, std::map const& actionNames, std::vector const& constants, VariableSet const& globalVariables, bool commentExpressions) { @@ -967,7 +1023,7 @@ namespace storm { autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables, automaton.getVariables(), commentExpressions); automataDeclarations.push_back(autoEntry); } - return modernjson::json(automataDeclarations); + return modernjson::json(std::move(automataDeclarations)); } void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) { diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index ce95a2c0f..1e6eefb50 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -19,7 +19,7 @@ namespace storm { class ExpressionToJson : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { public: - static modernjson::json translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables); + static modernjson::json translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables); virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data); @@ -34,13 +34,15 @@ namespace storm { virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data); private: - ExpressionToJson(std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) : constants(constants), globalVariables(globalVariables), localVariables(localVariables) {} + ExpressionToJson(std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables) : constants(constants), globalVariables(globalVariables), localVariables(localVariables), auxiliaryVariables(auxiliaryVariables) {} std::vector const& constants; VariableSet const& globalVariables; VariableSet const& localVariables; + std::unordered_set auxiliaryVariables; }; class FormulaToJaniJson : public storm::logic::FormulaVisitor { diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index d84762fc7..e983cccab 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -82,6 +82,7 @@ namespace storm { this->automatonToIndex = other.automatonToIndex; this->composition = other.composition; this->initialStatesRestriction = other.initialStatesRestriction; + this->globalFunctions = other.globalFunctions; // Now that we have copied all the data, we need to fix all assignments as they contain references to the old model. std::map> remapping; @@ -725,6 +726,20 @@ namespace storm { return false; } + FunctionDefinition const& Model::addFunctionDefinition(FunctionDefinition const& functionDefinition) { + auto insertionRes = globalFunctions.emplace(functionDefinition.getName(), functionDefinition); + STORM_LOG_THROW(insertionRes.second, storm::exceptions::InvalidOperationException, " a function with the name " << functionDefinition.getName() << " already exists in this model."); + return insertionRes.first->second; + } + + std::unordered_map const& Model::getGlobalFunctionDefinitions() const { + return globalFunctions; + } + + std::unordered_map Model::getGlobalFunctionDefinitions() { + return globalFunctions; + } + storm::expressions::ExpressionManager& Model::getExpressionManager() const { return *expressionManager; } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 274d17490..2f0bbaa72 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -12,6 +12,7 @@ #include "storm/storage/jani/Constant.h" #include "storm/storage/jani/Composition.h" #include "storm/storage/jani/Edge.h" +#include "storm/storage/jani/FunctionDefinition.h" #include "storm/storage/jani/Location.h" #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/ModelFeatures.h" @@ -248,6 +249,21 @@ namespace storm { */ bool hasNonGlobalTransientVariable() const; + /*! + * Adds the given function definition + */ + FunctionDefinition const& addFunctionDefinition(FunctionDefinition const& functionDefinition); + + /*! + * Retrieves all global function definitions + */ + std::unordered_map const& getGlobalFunctionDefinitions() const; + + /*! + * Retrieves all global function definitions + */ + std::unordered_map getGlobalFunctionDefinitions(); + /*! * Retrieves the manager responsible for the expressions in the JANI model. */ @@ -564,6 +580,9 @@ namespace storm { /// The global variables of the model. VariableSet globalVariables; + /// A mapping from names to function definitions + std::unordered_map globalFunctions; + /// The list of automata. std::vector automata; diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp index ada96c565..205b7cfc3 100644 --- a/src/storm/storage/jani/ModelFeatures.cpp +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -11,6 +11,8 @@ namespace storm { return "arrays"; case ModelFeature::DerivedOperators: return "derived-operators"; + case ModelFeature::Functions: + return "functions"; case ModelFeature::StateExitRewards: return "state-exit-rewards"; } @@ -40,6 +42,10 @@ namespace storm { return features.count(ModelFeature::DerivedOperators) > 0; } + bool ModelFeatures::hasFunctions() const { + return features.count(ModelFeature::Functions) > 0; + } + bool ModelFeatures::hasStateExitRewards() const { return features.count(ModelFeature::StateExitRewards) > 0; } diff --git a/src/storm/storage/jani/ModelFeatures.h b/src/storm/storage/jani/ModelFeatures.h index 363ee236c..32b4d3db3 100644 --- a/src/storm/storage/jani/ModelFeatures.h +++ b/src/storm/storage/jani/ModelFeatures.h @@ -6,7 +6,7 @@ namespace storm { namespace jani { - enum class ModelFeature {Arrays, DerivedOperators, StateExitRewards}; + enum class ModelFeature {Arrays, DerivedOperators, Functions, StateExitRewards}; std::string toString(ModelFeature const& modelFeature); @@ -16,6 +16,7 @@ namespace storm { std::string toString() const; bool hasArrays() const; + bool hasFunctions() const; bool hasDerivedOperators() const; bool hasStateExitRewards() const; diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.cpp b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp new file mode 100644 index 000000000..4ab6d64b4 --- /dev/null +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp @@ -0,0 +1,75 @@ +#include "storm/storage/jani/expressions/FunctionCallExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + FunctionCallExpression::FunctionCallExpression(ExpressionManager const& manager, Type const& type, std::string const& functionIdentifier, std::vector> const& arguments) : BaseExpression(manager, type), identifier(functionIdentifier), arguments(arguments) { + // Intentionally left empty + } + + void FunctionCallExpression::gatherVariables(std::set& variables) const { + for (auto const& a : arguments) { + a->gatherVariables(variables); + } + } + + bool FunctionCallExpression::containsVariables() const { + for (auto const& a : arguments) { + if (a->containsVariables()) { + return true; + } + } + return false; + } + + std::shared_ptr FunctionCallExpression::simplify() const { + std::vector> simplifiedArguments; + simplifiedArguments.reserve(arguments.size()); + for (auto const& a : arguments) { + simplifiedArguments.push_back(a->simplify()); + } + return std::shared_ptr(new FunctionCallExpression(getManager(), getType(), identifier, simplifiedArguments)); + } + + boost::any FunctionCallExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void FunctionCallExpression::printToStream(std::ostream& stream) const { + stream << identifier; + if (getNumberOfArguments() > 0) { + stream << "("; + bool first = true; + for (auto const& a : arguments) { + stream << *a; + if (!first) { + stream << ", "; + } + first = false; + } + stream << ")"; + } + } + + std::string const& FunctionCallExpression::getFunctionIdentifier() const { + return identifier; + } + + uint64_t FunctionCallExpression::getNumberOfArguments() const { + return arguments.size(); + } + + std::shared_ptr FunctionCallExpression::getArgument(uint64_t i) const { + STORM_LOG_THROW(i < arguments.size(), storm::exceptions::InvalidArgumentException, "Tried to access the argument with index " << i << " of a function call with " << arguments.size() << " arguments."); + return arguments[i]; + } + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.h b/src/storm/storage/jani/expressions/FunctionCallExpression.h new file mode 100644 index 000000000..75949247a --- /dev/null +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.h @@ -0,0 +1,42 @@ +#pragma once + +#include "storm/storage/expressions/BaseExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array with a given list of elements. + */ + class FunctionCallExpression : public BaseExpression { + public: + + FunctionCallExpression(ExpressionManager const& manager, Type const& type, std::string const& functionIdentifier, std::vector> const& arguments); + + + // Instantiate constructors and assignments with their default implementations. + FunctionCallExpression(FunctionCallExpression const& other) = default; + FunctionCallExpression& operator=(FunctionCallExpression const& other) = delete; + FunctionCallExpression(FunctionCallExpression&&) = default; + FunctionCallExpression& operator=(FunctionCallExpression&&) = delete; + + virtual ~FunctionCallExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const override; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + std::string const& getFunctionIdentifier() const; + uint64_t getNumberOfArguments() const; + std::shared_ptr getArgument(uint64_t i) const; + + + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::string identifier; + std::vector> arguments; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp index cfd421c59..6b17ba50c 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -60,6 +60,15 @@ namespace storm { } } + template + boost::any JaniExpressionSubstitutionVisitor::visit(FunctionCallExpression const& expression, boost::any const& data) { + std::vector> newArguments; + newArguments.reserve(expression.getNumberOfArguments()); + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + newArguments.push_back(boost::any_cast>(expression.getArgument(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new FunctionCallExpression(expression.getManager(), expression.getType(), expression.getIdentifier(), newArguments))); + } // Explicitly instantiate the class with map and unordered_map. template class JaniExpressionSubstitutionVisitor>; diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h index ab196acee..07867be28 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h @@ -25,6 +25,7 @@ namespace storm { virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override; virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override; virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override; + virtual boost::any visit(FunctionCallExpression const& expression, boost::any const& data) override; }; } } \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h index 61808bb0d..99a45f2c5 100644 --- a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h +++ b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h @@ -11,6 +11,7 @@ namespace storm { virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) = 0; virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) = 0; virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(FunctionCallExpression const& expression, boost::any const& data) = 0; }; } } diff --git a/src/storm/storage/jani/expressions/JaniExpressions.h b/src/storm/storage/jani/expressions/JaniExpressions.h index a48ec5119..209d6edd7 100644 --- a/src/storm/storage/jani/expressions/JaniExpressions.h +++ b/src/storm/storage/jani/expressions/JaniExpressions.h @@ -2,3 +2,4 @@ #include "storm/storage/jani/expressions/ArrayAccessExpression.h" #include "storm/storage/jani/expressions/ConstructorArrayExpression.h" #include "storm/storage/jani/expressions/ValueArrayExpression.h" +#include "storm/storage/jani/expressions/FunctionCallExpression.h" diff --git a/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp index f9c80a36a..8e5d11a92 100644 --- a/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp +++ b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp @@ -71,6 +71,15 @@ namespace storm { virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { return true; } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + if (boost::any_cast(expression.getArgument(i)->accept(*this, data))) { + return true; + } + } + return false; + } }; class ArrayExpressionFinderTraverser : public ConstJaniTraverser { From bb92be14dc1b4ffe667b0da938c145e4d2862ce7 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 09:28:21 +0200 Subject: [PATCH 558/647] fixes for array translation --- src/storm/storage/jani/ArrayEliminator.cpp | 29 ++++++++++++++----- .../ConstructorArrayExpression.cpp | 4 ++- .../expressions/ConstructorArrayExpression.h | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp index e733c295e..e04d20d13 100644 --- a/src/storm/storage/jani/ArrayEliminator.cpp +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -23,7 +23,7 @@ namespace storm { MaxArraySizeExpressionVisitor() = default; virtual ~MaxArraySizeExpressionVisitor() = default; - std::size_t getMaxSize(storm::expressions::Expression const& expression, std::unordered_map arrayVariableSizeMap) { + std::size_t getMaxSize(storm::expressions::Expression const& expression, std::unordered_map const& arrayVariableSizeMap) { return boost::any_cast(expression.accept(*this, &arrayVariableSizeMap)); } @@ -51,7 +51,7 @@ namespace storm { } virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { - std::unordered_map* arrayVariableSizeMap = boost::any_cast*>(data); + std::unordered_map const* arrayVariableSizeMap = boost::any_cast const*>(data); if (expression.getType().isArrayType()) { auto varIt = arrayVariableSizeMap->find(expression.getVariable()); if (varIt != arrayVariableSizeMap->end()) { @@ -90,7 +90,7 @@ namespace storm { if (!expression.size()->containsVariables()) { return static_cast(expression.size()->evaluateAsInt()); } else { - auto vars = expression.toExpression().getVariables(); + auto vars = expression.size()->toExpression().getVariables(); std::string variables = ""; for (auto const& v : vars) { if (variables != "") { @@ -99,11 +99,11 @@ namespace storm { variables += v.getName(); } if (vars.size() == 1) { - variables = "variable "; + variables = "variable " + variables; } else { - variables = "variables "; + variables = "variables " + variables; } - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unable to get determine array size: Size of ConstructorArrayExpression still contains the " << variables << "."); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unable to determine array size: Size of ConstructorArrayExpression '" << expression << "' still contains the " << variables << "."); } } @@ -111,6 +111,12 @@ namespace storm { STORM_LOG_WARN("Found Array access expression within an array expression. This is not expected since nested arrays are currently not supported."); return 0; } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Found Function call expression within an array expression. This is not expected since functions are expected to be eliminated at this point."); + return 0; + } + }; class ArrayExpressionEliminationVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { @@ -122,6 +128,7 @@ namespace storm { storm::expressions::Expression eliminate(storm::expressions::Expression const& expression) { // here, data is the accessed index of the most recent array access expression. Initially, there is none. + std::cout << "Eliminating arrays in expression " << expression << std::endl; auto res = storm::expressions::Expression(boost::any_cast(expression.accept(*this, boost::any()))); STORM_LOG_ASSERT(!containsArrayExpression(res), "Expression still contains array expressions. Before: " << std::endl << expression << std::endl << "After:" << std::endl << res); return res.simplify(); @@ -189,6 +196,7 @@ namespace storm { STORM_LOG_ASSERT(index < arrayVarReplacements.size(), "No replacement for array variable, since index " << index << " is out of bounds."); return arrayVarReplacements[index]->getExpressionVariable().getExpression().getBaseExpressionPointer(); } else { + STORM_LOG_ASSERT(data.empty(), "VariableExpression of non-array variable should not be a subexpressions of array access expressions. However, the expression " << expression << " is."); return expression.getSharedPointer(); } } @@ -235,7 +243,7 @@ namespace storm { uint64_t index = boost::any_cast(data); STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); STORM_LOG_THROW(index < static_cast(expression.size()->evaluateAsInt()), storm::exceptions::UnexpectedException, "Out of bounds array access occured while accessing index " << index << " of expression " << expression); - return expression.at(index); + return boost::any_cast(expression.at(index)->accept(*this, boost::any())); } virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { @@ -246,7 +254,7 @@ namespace storm { } else { STORM_LOG_THROW(index < static_cast(expression.size()->evaluateAsInt()), storm::exceptions::UnexpectedException, "Out of bounds array access occured while accessing index " << index << " of expression " << expression); } - return expression.at(index); + return boost::any_cast(expression.at(index)->accept(*this, boost::any())); } virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { @@ -271,6 +279,11 @@ namespace storm { } } + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Found Function call expression while eliminating array expressions. This is not expected since functions are expected to be eliminated at this point."); + return false; + } + private: std::unordered_map> const& replacements; std::unordered_map const& arraySizes; diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp index 2eb778800..eb014a70d 100644 --- a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/expressions/ConstructorArrayExpression.h" #include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -55,7 +56,8 @@ namespace storm { std::shared_ptr ConstructorArrayExpression::at(uint64_t i) const { std::map substitution; substitution.emplace(indexVar, this->getManager().integer(i)); - return elementExpression->toExpression().substitute(substitution).getBaseExpressionPointer(); + + return storm::jani::substituteJaniExpression(elementExpression->toExpression(), substitution).getBaseExpressionPointer(); } std::shared_ptr const& ConstructorArrayExpression::getElementExpression() const { diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h index 7c5d93c9e..262c6d68e 100644 --- a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h @@ -41,7 +41,7 @@ namespace storm { private: std::shared_ptr sizeExpression; storm::expressions::Variable indexVar; - std::shared_ptr const& elementExpression; + std::shared_ptr elementExpression; }; } } \ No newline at end of file From c739f0befa6a2393f5a292f0f93ca3bb255d9cb5 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 15:38:05 +0200 Subject: [PATCH 559/647] elimination of jani function --- src/storm-cli-utilities/model-handling.h | 20 +- src/storm-conv/api/storm-conv.cpp | 6 +- src/storm/storage/jani/Automaton.cpp | 5 +- src/storm/storage/jani/Automaton.h | 2 +- src/storm/storage/jani/FunctionDefinition.cpp | 19 + src/storm/storage/jani/FunctionDefinition.h | 8 + src/storm/storage/jani/FunctionEliminator.cpp | 403 ++++++++++++++++++ src/storm/storage/jani/FunctionEliminator.h | 19 + src/storm/storage/jani/LValue.cpp | 7 +- src/storm/storage/jani/LValue.h | 1 + src/storm/storage/jani/Model.cpp | 16 +- src/storm/storage/jani/Model.h | 11 +- .../expressions/FunctionCallExpression.cpp | 5 + .../jani/expressions/FunctionCallExpression.h | 1 + .../FunctionCallExpressionFinder.cpp | 124 ++++++ .../traverser/FunctionCallExpressionFinder.h | 20 + .../storage/jani/traverser/JaniTraverser.cpp | 20 + .../storage/jani/traverser/JaniTraverser.h | 2 + 18 files changed, 676 insertions(+), 13 deletions(-) create mode 100644 src/storm/storage/jani/FunctionEliminator.cpp create mode 100644 src/storm/storage/jani/FunctionEliminator.h create mode 100644 src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp create mode 100644 src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index 057f3f436..f0dfc5e6e 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -154,11 +154,23 @@ namespace storm { } } + // Check whether transformations on the jani model are required if (output.model && output.model.get().isJaniModel()) { - // Check if arrays need to be eliminated - if (coreSettings.getEngine() != storm::settings::modules::CoreSettings::Engine::Sparse || buildSettings.isJitSet()) { - output.preprocessedProperties = output.properties; - output.model.get().asJaniModel().eliminateArrays(output.preprocessedProperties.get()); + auto& janiModel = output.model.get().asJaniModel(); + // Check if functions need to be eliminated + if (janiModel.getModelFeatures().hasFunctions()) { + if (!output.preprocessedProperties) { + output.preprocessedProperties = output.properties; + } + janiModel.substituteFunctions(output.preprocessedProperties.get()); + } + + // Check if arrays need to be eliminated. This should be done after! eliminating the functions + if (janiModel.getModelFeatures().hasArrays() && (coreSettings.getEngine() != storm::settings::modules::CoreSettings::Engine::Sparse || buildSettings.isJitSet())) { + if (!output.preprocessedProperties) { + output.preprocessedProperties = output.properties; + } + janiModel.eliminateArrays(output.preprocessedProperties.get()); } } return output; diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index 9a965fb65..c0e7252bd 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -39,9 +39,9 @@ namespace storm { janiModel.eliminateArrays(properties); } - //if (!options.allowFunctions && janiModel.getModelFeatures().hasFunctions()) { - //janiModel = janiModel.substituteFunctions(); - //} + if (!options.allowFunctions && janiModel.getModelFeatures().hasFunctions()) { + janiModel = janiModel.substituteFunctions(properties); + } if (options.modelName) { janiModel.setName(options.modelName.get()); diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index c1b375b2b..e8c3555a9 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -95,7 +95,7 @@ namespace storm { return functionDefinitions; } - std::unordered_map Automaton::getFunctionDefinitions() { + std::unordered_map& Automaton::getFunctionDefinitions() { return functionDefinitions; } @@ -396,6 +396,9 @@ namespace storm { } void Automaton::substitute(std::map const& substitution) { + for (auto& functionDefinition : this->getFunctionDefinitions()) { + functionDefinition.second.substitute(substitution); + } for (auto& variable : this->getVariables().getBoundedIntegerVariables()) { variable.substitute(substitution); } diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index ed67d2efc..980fbaca7 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -112,7 +112,7 @@ namespace storm { /*! * Retrieves all function definitions of this automaton */ - std::unordered_map getFunctionDefinitions(); + std::unordered_map& getFunctionDefinitions(); /*! * Retrieves whether the automaton has a location with the given name. diff --git a/src/storm/storage/jani/FunctionDefinition.cpp b/src/storm/storage/jani/FunctionDefinition.cpp index 2bac96f91..8be6beac6 100644 --- a/src/storm/storage/jani/FunctionDefinition.cpp +++ b/src/storm/storage/jani/FunctionDefinition.cpp @@ -1,4 +1,9 @@ #include "storm/storage/jani/FunctionDefinition.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace jani { @@ -23,6 +28,20 @@ namespace storm { return functionBody; } + storm::expressions::Expression FunctionDefinition::call(std::vector> const& arguments ) const { + // substitute the parameters in the function body + STORM_LOG_THROW(arguments.size() == parameters.size(), storm::exceptions::InvalidArgumentException, "The number of arguments does not match the number of parameters."); + std::unordered_map parameterSubstitution; + for (uint64_t i = 0; i < arguments.size(); ++i) { + parameterSubstitution.emplace(parameters[i], arguments[i]); + } + return substituteJaniExpression(functionBody, parameterSubstitution); + } + + void FunctionDefinition::substitute(std::map const& substitution) { + this->setFunctionBody(substituteJaniExpression(this->getFunctionBody(), substitution)); + } + void FunctionDefinition::setFunctionBody(storm::expressions::Expression const& body) { functionBody = body; } diff --git a/src/storm/storage/jani/FunctionDefinition.h b/src/storm/storage/jani/FunctionDefinition.h index 51eabf937..4a46bb663 100644 --- a/src/storm/storage/jani/FunctionDefinition.h +++ b/src/storm/storage/jani/FunctionDefinition.h @@ -43,6 +43,14 @@ namespace storm { */ void setFunctionBody(storm::expressions::Expression const& body); + /*! + * Calls the function with the given arguments + */ + storm::expressions::Expression call(std::vector> const& arguments ) const; + + void substitute(std::map const& substitution); + + private: // The name of the function. std::string name; diff --git a/src/storm/storage/jani/FunctionEliminator.cpp b/src/storm/storage/jani/FunctionEliminator.cpp new file mode 100644 index 000000000..50d5deb95 --- /dev/null +++ b/src/storm/storage/jani/FunctionEliminator.cpp @@ -0,0 +1,403 @@ +#include "storm/storage/jani/FunctionEliminator.h" + +#include + +#include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/traverser/FunctionCallExpressionFinder.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + + + + namespace jani { + namespace detail { + + class FunctionEliminationExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + + typedef std::shared_ptr BaseExprPtr; + + FunctionEliminationExpressionVisitor(std::unordered_map const* globalFunctions, std::unordered_map const* localFunctions = nullptr) : globalFunctions(globalFunctions), localFunctions(localFunctions) {} + + virtual ~FunctionEliminationExpressionVisitor() = default; + + FunctionEliminationExpressionVisitor setLocalFunctions(std::unordered_map const* localFunctions) { + return FunctionEliminationExpressionVisitor(this->globalFunctions, localFunctions); + } + + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression) { + auto res = storm::expressions::Expression(boost::any_cast(expression.accept(*this, boost::any()))); + return res.simplify(); + } + + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + BaseExprPtr conditionExpression = boost::any_cast(expression.getCondition()->accept(*this, data)); + BaseExprPtr thenExpression = boost::any_cast(expression.getThenExpression()->accept(*this, data)); + BaseExprPtr elseExpression = boost::any_cast(expression.getElseExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::IfThenElseExpression(expression.getManager(), thenExpression->getType(), conditionExpression, thenExpression, elseExpression))); + } + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); + } + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + uint64_t size = expression.size()->evaluateAsInt(); + std::vector elements; + bool changed = false; + for (uint64_t i = 0; i(expression.at(i)->accept(*this, data)); + if (element.get() != expression.at(i).get()) { + changed = true; + } + elements.push_back(element); + } + if (changed) { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ValueArrayExpression(expression.getManager(), expression.getType(), elements))); + } else { + return expression.getSharedPointer(); + } + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + BaseExprPtr sizeExpression = boost::any_cast(expression.size()->accept(*this, data)); + BaseExprPtr elementExpression = boost::any_cast(expression.getElementExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (sizeExpression.get() == expression.size().get() && elementExpression.get() == expression.getElementExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ConstructorArrayExpression(expression.getManager(), expression.getType(), sizeExpression, expression.getIndexVar(), elementExpression))); + } + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ArrayAccessExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression))); + } + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + // Find the associated function definition + FunctionDefinition const* funDef = nullptr; + if (localFunctions != nullptr) { + auto funDefIt = localFunctions->find(expression.getIdentifier()); + if (funDefIt != localFunctions->end()) { + funDef = &(funDefIt->second); + } + } + if (globalFunctions != nullptr) { + auto funDefIt = globalFunctions->find(expression.getIdentifier()); + if (funDefIt != globalFunctions->end()) { + funDef = &(funDefIt->second); + } + } + + STORM_LOG_THROW(funDef != nullptr, storm::exceptions::UnexpectedException, "Unable to find function definition for function call " << expression << "."); + + return boost::any_cast(funDef->call(expression.getArguments()).getBaseExpression().accept(*this, data)); + } + + private: + std::unordered_map const* globalFunctions; + std::unordered_map const* localFunctions; + }; + + class FunctionEliminatorTraverser : public JaniTraverser { + public: + + FunctionEliminatorTraverser() = default; + + virtual ~FunctionEliminatorTraverser() = default; + + void eliminate(Model& model, std::vector& properties) { + + // Replace all function calls by the function definition + traverse(model, boost::any()); + + // Replace function definitions in properties + if (!model.getGlobalFunctionDefinitions().empty()) { + FunctionEliminationExpressionVisitor v(&model.getGlobalFunctionDefinitions()); + for (auto& property : properties) { + property = property.substitute([&v](storm::expressions::Expression const& exp) {return v.eliminate(exp);}); + } + } + + // Erase function definitions in model and automata + model.getGlobalFunctionDefinitions().clear(); + for (auto& automaton : model.getAutomata()) { + automaton.getFunctionDefinitions().clear(); + } + + // Clear the model feature 'functions' + model.getModelFeatures().remove(ModelFeature::Functions); + + // finalize the model + model.finalize(); + } + + + + // To detect cyclic dependencies between function bodies, we need to eliminate the functions in a topological order + enum class FunctionDefinitionStatus {Unprocessed, Current, Processed}; + void eliminateFunctionsInFunctionBodies(FunctionEliminationExpressionVisitor& eliminationVisitor, std::unordered_map& functions, std::unordered_map& status, std::string const& current) { + status[current] = FunctionDefinitionStatus::Current; + FunctionDefinition& funDef = functions.find(current)->second; + auto calledFunctions = getOccurringFunctionCalls(funDef.getFunctionBody()); + for (auto const& calledFunction : calledFunctions) { + STORM_LOG_THROW(calledFunction != current, storm::exceptions::NotSupportedException, "Function '" << calledFunction << "' calls itself. This is not supported."); + auto calledStatus = status.find(calledFunction); + // Check whether the called function belongs to the ones that actually needed processing + if (calledStatus != status.end()) { + STORM_LOG_THROW(calledStatus->second != FunctionDefinitionStatus::Current, storm::exceptions::NotSupportedException, "Found cyclic dependencies between functions '" << calledFunction << "' and '" << current << "'. This is not supported."); + if (calledStatus->second == FunctionDefinitionStatus::Unprocessed) { + eliminateFunctionsInFunctionBodies(eliminationVisitor, functions, status, calledFunction); + } + } + } + // At this point, all called functions are processed already. So we can finally process this one. + funDef.setFunctionBody(eliminationVisitor.eliminate(funDef.getFunctionBody())); + status[current] = FunctionDefinitionStatus::Processed; + } + void eliminateFunctionsInFunctionBodies(FunctionEliminationExpressionVisitor& eliminationVisitor, std::unordered_map& functions) { + + std::unordered_map status; + for (auto const& f : functions) { + status.emplace(f.first, FunctionDefinitionStatus::Unprocessed); + } + for (auto const& f : functions) { + if (status[f.first] == FunctionDefinitionStatus::Unprocessed) { + eliminateFunctionsInFunctionBodies(eliminationVisitor, functions, status, f.first); + } + } + } + + virtual void traverse(Model& model, boost::any const& data) override { + + // First we need to apply functions called in function bodies + FunctionEliminationExpressionVisitor globalFunctionEliminationVisitor(&model.getGlobalFunctionDefinitions()); + eliminateFunctionsInFunctionBodies(globalFunctionEliminationVisitor, model.getGlobalFunctionDefinitions()); + + // Now run through the remaining components + for (auto& c : model.getConstants()) { + traverse(c, &globalFunctionEliminationVisitor); + } + JaniTraverser::traverse(model.getGlobalVariables(), &globalFunctionEliminationVisitor); + for (auto& aut : model.getAutomata()) { + traverse(aut, &globalFunctionEliminationVisitor); + } + if (model.hasInitialStatesRestriction()) { + model.setInitialStatesRestriction(globalFunctionEliminationVisitor.eliminate(model.getInitialStatesRestriction())); + } + } + + void traverse(Automaton& automaton, boost::any const& data) override { + // First we need to apply functions called in function bodies + auto functionEliminationVisitor = boost::any_cast(data)->setLocalFunctions(&automaton.getFunctionDefinitions()); + eliminateFunctionsInFunctionBodies(functionEliminationVisitor, automaton.getFunctionDefinitions()); + + // Now run through the remaining components + JaniTraverser::traverse(automaton.getVariables(), &functionEliminationVisitor); + for (auto& loc : automaton.getLocations()) { + JaniTraverser::traverse(loc, &functionEliminationVisitor); + } + JaniTraverser::traverse(automaton.getEdgeContainer(), &functionEliminationVisitor); + if (automaton.hasInitialStatesRestriction()) { + automaton.setInitialStatesRestriction(functionEliminationVisitor.eliminate(automaton.getInitialStatesRestriction())); + } + } + + void traverse(Constant& constant, boost::any const& data) override { + if (constant.isDefined()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + constant.define(functionEliminationVisitor->eliminate(constant.getExpression())); + } + } + + void traverse(BooleanVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(BoundedIntegerVariable& variable, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (variable.hasInitExpression()) { + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + variable.setLowerBound(functionEliminationVisitor->eliminate(variable.getLowerBound())); + variable.setUpperBound(functionEliminationVisitor->eliminate(variable.getUpperBound())); + } + + void traverse(UnboundedIntegerVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(RealVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(ArrayVariable& variable, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (variable.hasInitExpression()) { + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + if (variable.hasElementTypeBounds()) { + variable.setElementTypeBounds(functionEliminationVisitor->eliminate(variable.getElementTypeBounds().first), functionEliminationVisitor->eliminate(variable.getElementTypeBounds().second)); + } + } + + void traverse(TemplateEdge& templateEdge, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + templateEdge.setGuard(functionEliminationVisitor->eliminate(templateEdge.getGuard())); + for (auto& dest : templateEdge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + JaniTraverser::traverse(templateEdge.getAssignments(), data); + } + + void traverse(Edge& edge, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (edge.hasRate()) { + edge.setRate(functionEliminationVisitor->eliminate(edge.getRate())); + } + for (auto& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void traverse(EdgeDestination& edgeDestination, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + edgeDestination.setProbability(functionEliminationVisitor->eliminate(edgeDestination.getProbability())); + } + + void traverse(Assignment& assignment, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + assignment.setAssignedExpression(functionEliminationVisitor->eliminate(assignment.getAssignedExpression())); + traverse(assignment.getLValue(), data); + } + + void traverse(LValue& lValue, boost::any const& data) override { + if (lValue.isArrayAccess()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + lValue.setArrayIndex(functionEliminationVisitor->eliminate(lValue.getArrayIndex())); + } + } + + void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { + STORM_LOG_THROW(getOccurringFunctionCalls(expression).empty(), storm::exceptions::UnexpectedException, "Did not translate functions in expression " << expression); + } + }; + } // namespace detail + + + void eliminateFunctions(Model& model, std::vector& properties) { + detail::FunctionEliminatorTraverser().eliminate(model, properties); + STORM_LOG_ASSERT(!containsFunctionCallExpression(model), "The model still seems to contain function calls."); + } + + } +} + diff --git a/src/storm/storage/jani/FunctionEliminator.h b/src/storm/storage/jani/FunctionEliminator.h new file mode 100644 index 000000000..791884aed --- /dev/null +++ b/src/storm/storage/jani/FunctionEliminator.h @@ -0,0 +1,19 @@ +#pragma once + + +#include + + +namespace storm { + namespace jani { + class Model; + class Property; + + /*! + * Eliminates all function references in the given model and the given properties by replacing them with their corresponding definitions. + */ + void eliminateFunctions(Model& model, std::vector& properties); + + } +} + diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp index 7ae2b3e42..57d80bfdd 100644 --- a/src/storm/storage/jani/LValue.cpp +++ b/src/storm/storage/jani/LValue.cpp @@ -35,10 +35,15 @@ namespace storm { } storm::expressions::Expression const& LValue::getArrayIndex() const { - STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array index of an LValue, that is not an array access."); + STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array index of an LValue that is not an array access."); return arrayIndex; } + void LValue::setArrayIndex(storm::expressions::Expression const& newIndex) { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to set the array index of an LValue that is not an array access."); + arrayIndex = newIndex; + } + bool LValue::isTransient() const { return variable->isTransient(); } diff --git a/src/storm/storage/jani/LValue.h b/src/storm/storage/jani/LValue.h index 0e8126bcd..1c6fa32c7 100644 --- a/src/storm/storage/jani/LValue.h +++ b/src/storm/storage/jani/LValue.h @@ -20,6 +20,7 @@ namespace storm { bool isArrayAccess() const; storm::jani::ArrayVariable const& getArray() const; storm::expressions::Expression const& getArrayIndex() const; + void setArrayIndex(storm::expressions::Expression const& newIndex); bool isTransient() const; bool operator< (LValue const& other) const; diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index e983cccab..5b3464ed4 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -17,6 +17,7 @@ #include "storm/storage/jani/Compositions.h" #include "storm/storage/jani/JSONExporter.h" #include "storm/storage/jani/ArrayEliminator.h" +#include "storm/storage/jani/FunctionEliminator.h" #include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -736,7 +737,7 @@ namespace storm { return globalFunctions; } - std::unordered_map Model::getGlobalFunctionDefinitions() { + std::unordered_map& Model::getGlobalFunctionDefinitions() { return globalFunctions; } @@ -927,6 +928,10 @@ namespace storm { } } + for (auto& functionDefinition : result.getGlobalFunctionDefinitions()) { + functionDefinition.second.substitute(constantSubstitution); + } + // Substitute constants in all global variables. for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { variable.substitute(constantSubstitution); @@ -958,6 +963,15 @@ namespace storm { return result; } + void Model::substituteFunctions() { + std::vector emptyPropertyVector; + substituteFunctions(emptyPropertyVector); + } + + void Model::substituteFunctions(std::vector& properties) { + eliminateFunctions(*this, properties); + } + bool Model::containsArrayVariables() const { if (getGlobalVariables().containsArrayVariables()) { return true; diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index 2f0bbaa72..24faf8d76 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -262,7 +262,7 @@ namespace storm { /*! * Retrieves all global function definitions */ - std::unordered_map getGlobalFunctionDefinitions(); + std::unordered_map& getGlobalFunctionDefinitions(); /*! * Retrieves the manager responsible for the expressions in the JANI model. @@ -386,6 +386,13 @@ namespace storm { */ std::map getConstantsSubstitution() const; + /*! + * Substitutes all function calls with the corresponding function definition + * @param properties also eliminates function call expressions in the given properties + */ + void substituteFunctions(); + void substituteFunctions(std::vector& properties); + /*! * Returns true if at least one array variable occurs in the model. */ @@ -396,7 +403,7 @@ namespace storm { * @param keepNonTrivialArrayAccess if set, array access expressions in LValues and expressions are only replaced, if the index expression is constant. * @return data from the elimination. If non-trivial array accesses are kept, pointers to remaining array variables point to this data. */ - ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess); + ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess = false); /*! * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.cpp b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp index 4ab6d64b4..783811461 100644 --- a/src/storm/storage/jani/expressions/FunctionCallExpression.cpp +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp @@ -71,5 +71,10 @@ namespace storm { STORM_LOG_THROW(i < arguments.size(), storm::exceptions::InvalidArgumentException, "Tried to access the argument with index " << i << " of a function call with " << arguments.size() << " arguments."); return arguments[i]; } + + std::vector> const& FunctionCallExpression::getArguments() const { + return arguments; + } + } } \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.h b/src/storm/storage/jani/expressions/FunctionCallExpression.h index 75949247a..66ab8dacd 100644 --- a/src/storm/storage/jani/expressions/FunctionCallExpression.h +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.h @@ -29,6 +29,7 @@ namespace storm { std::string const& getFunctionIdentifier() const; uint64_t getNumberOfArguments() const; std::shared_ptr getArgument(uint64_t i) const; + std::vector> const& getArguments() const; protected: diff --git a/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp new file mode 100644 index 000000000..f9f8b22ac --- /dev/null +++ b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp @@ -0,0 +1,124 @@ +#include "storm/storage/jani/traverser/FunctionCallExpressionFinder.h" + +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + + namespace detail { + class FunctionCallExpressionFinderExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + expression.getCondition()->accept(*this, data); + expression.getThenExpression()->accept(*this, data); + expression.getElseExpression()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::VariableExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + expression.getOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + expression.getOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + uint64_t size = expression.size()->evaluateAsInt(); + for (uint64_t i = 0; i < size; ++i) { + expression.at(i)->accept(*this, data); + } + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + expression.getElementExpression()->accept(*this, data); + expression.size()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + auto& set = *boost::any_cast*>(data); + set.insert(expression.getIdentifier()); + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + expression.getArgument(i)->accept(*this, data); + } + return boost::any(); + } + }; + + class FunctionCallExpressionFinderTraverser : public ConstJaniTraverser { + public: + virtual void traverse(Model const& model, boost::any const& data) override { + ConstJaniTraverser::traverse(model, data); + } + + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { + auto& res = *boost::any_cast(data); + res = res || !getOccurringFunctionCalls(expression).empty(); + } + }; + } + + + bool containsFunctionCallExpression(Model const& model) { + bool result = false; + detail::FunctionCallExpressionFinderTraverser().traverse(model, &result); + return result; + } + + std::unordered_set getOccurringFunctionCalls(storm::expressions::Expression const& expression) { + detail::FunctionCallExpressionFinderExpressionVisitor v; + std::unordered_set result; + expression.accept(v, &result); + return result; + } + } +} + diff --git a/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h new file mode 100644 index 000000000..e191eee4a --- /dev/null +++ b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace storm { + + namespace expressions { + class Expression; + } + + namespace jani { + + class Model; + + bool containsFunctionCallExpression(Model const& model); + std::unordered_set getOccurringFunctionCalls(storm::expressions::Expression const& expr); + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp index 787682ede..ae912a3a8 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.cpp +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -11,6 +11,9 @@ namespace storm { for (auto& c : model.getConstants()) { traverse(c, data); } + for (auto& f : model.getGlobalFunctionDefinitions()) { + traverse(f.second, data); + } traverse(model.getGlobalVariables(), data); for (auto& aut : model.getAutomata()) { traverse(aut, data); @@ -26,6 +29,9 @@ namespace storm { void JaniTraverser::traverse(Automaton& automaton, boost::any const& data) { traverse(automaton.getVariables(), data); + for (auto& f : automaton.getFunctionDefinitions()) { + traverse(f.second, data); + } for (auto& loc : automaton.getLocations()) { traverse(loc, data); } @@ -41,6 +47,10 @@ namespace storm { } } + void JaniTraverser::traverse(FunctionDefinition& functionDefinition, boost::any const& data) { + traverse(functionDefinition.getFunctionBody(), data); + } + void JaniTraverser::traverse(VariableSet& variableSet, boost::any const& data) { for (auto& v : variableSet.getBooleanVariables()) { traverse(v, data); @@ -162,6 +172,9 @@ namespace storm { for (auto const& c : model.getConstants()) { traverse(c, data); } + for (auto const& f : model.getGlobalFunctionDefinitions()) { + traverse(f.second, data); + } traverse(model.getGlobalVariables(), data); for (auto const& aut : model.getAutomata()) { traverse(aut, data); @@ -177,6 +190,9 @@ namespace storm { void ConstJaniTraverser::traverse(Automaton const& automaton, boost::any const& data) { traverse(automaton.getVariables(), data); + for (auto const& f : automaton.getFunctionDefinitions()) { + traverse(f.second, data); + } for (auto const& loc : automaton.getLocations()) { traverse(loc, data); } @@ -192,6 +208,10 @@ namespace storm { } } + void ConstJaniTraverser::traverse(FunctionDefinition const& functionDefinition, boost::any const& data) { + traverse(functionDefinition.getFunctionBody(), data); + } + void ConstJaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) { for (auto const& v : variableSet.getBooleanVariables()) { traverse(v, data); diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h index 685c76a85..a7da8bc6f 100644 --- a/src/storm/storage/jani/traverser/JaniTraverser.h +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -16,6 +16,7 @@ namespace storm { virtual void traverse(Action const& action, boost::any const& data); virtual void traverse(Automaton& automaton, boost::any const& data); virtual void traverse(Constant& constant, boost::any const& data); + virtual void traverse(FunctionDefinition& functionDefinition, boost::any const& data); virtual void traverse(VariableSet& variableSet, boost::any const& data); virtual void traverse(Location& location, boost::any const& data); virtual void traverse(BooleanVariable& variable, boost::any const& data); @@ -43,6 +44,7 @@ namespace storm { virtual void traverse(Action const& action, boost::any const& data); virtual void traverse(Automaton const& automaton, boost::any const& data); virtual void traverse(Constant const& constant, boost::any const& data); + virtual void traverse(FunctionDefinition const& functionDefinition, boost::any const& data); virtual void traverse(VariableSet const& variableSet, boost::any const& data); virtual void traverse(Location const& location, boost::any const& data); virtual void traverse(BooleanVariable const& variable, boost::any const& data); From e119131f78194b89a0fb69dbc959b202cdd59461 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 16:34:37 +0200 Subject: [PATCH 560/647] storm-conv compiles --- src/storm-conv-cli/storm-conv.cpp | 4 +++- src/storm-conv/api/storm-conv.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp index 72cba3e3d..043b27bb9 100644 --- a/src/storm-conv-cli/storm-conv.cpp +++ b/src/storm-conv-cli/storm-conv.cpp @@ -187,7 +187,9 @@ namespace storm { boost::optional> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter()); properties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), janiModel, propertyFilter); } else { - properties.insert(properties.end(), janiModelProperties.second.begin(), janiModelProperties.second.end()); + for (auto const& p : janiModelProperties.second) { + properties.push_back(p.second); + } } // Substitute constant definitions in program and properties. diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp index c0e7252bd..7b7f4d806 100644 --- a/src/storm-conv/api/storm-conv.cpp +++ b/src/storm-conv/api/storm-conv.cpp @@ -40,7 +40,7 @@ namespace storm { } if (!options.allowFunctions && janiModel.getModelFeatures().hasFunctions()) { - janiModel = janiModel.substituteFunctions(properties); + janiModel.substituteFunctions(properties); } if (options.modelName) { From 78d98655f6b5d4ba1449efc2049598011f746bf2 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 16:35:07 +0200 Subject: [PATCH 561/647] gspn and pgcl jani model builders now correctly add the model feature 'derived-operators' --- src/storm-gspn/builder/JaniGSPNBuilder.cpp | 2 ++ src/storm-pgcl/builder/JaniProgramGraphBuilder.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index 744b76eb4..fa01450de 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -25,6 +25,8 @@ namespace storm { if (buildStandardProperties) { buildProperties(model); } + model->getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + model->finalize(); return model; } diff --git a/src/storm-pgcl/builder/JaniProgramGraphBuilder.h b/src/storm-pgcl/builder/JaniProgramGraphBuilder.h index ad5feb8a4..08edb3220 100644 --- a/src/storm-pgcl/builder/JaniProgramGraphBuilder.h +++ b/src/storm-pgcl/builder/JaniProgramGraphBuilder.h @@ -76,6 +76,8 @@ namespace storm { addEdges(mainAutomaton); model->addAutomaton(mainAutomaton); model->setStandardSystemComposition(); + model->getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + model->finalize(); return model; } From 6d5af2d41430f07ba3d64525e1368f17a8cfdaf1 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 16:38:13 +0200 Subject: [PATCH 562/647] fixed exporting model-features --- src/storm/storage/jani/ModelFeatures.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp index 205b7cfc3..8bb8d6475 100644 --- a/src/storm/storage/jani/ModelFeatures.cpp +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -21,7 +21,7 @@ namespace storm { } std::string ModelFeatures::toString() const { - std::string res = "["; + std::string res; bool first = true; for (auto const& f : features) { if (!first) { @@ -30,7 +30,6 @@ namespace storm { res += storm::jani::toString(f); first = false; } - res += "]"; return res; } From ea76f6d0bee62ea52a4066cba5cc6ec638241c52 Mon Sep 17 00:00:00 2001 From: TimQu Date: Fri, 14 Sep 2018 16:40:18 +0200 Subject: [PATCH 563/647] prism parser no longer inserts formula definitions directly. Note that these have to be eliminated afterwards --- src/storm-parsers/parser/PrismParser.cpp | 27 ++++++++-- src/storm/storage/prism/Formula.cpp | 13 +++-- src/storm/storage/prism/Formula.h | 13 +++-- src/storm/storage/prism/Program.cpp | 66 +++++++++++++++--------- src/storm/storage/prism/Program.h | 17 +++++- src/storm/utility/prism.cpp | 1 - 6 files changed, 98 insertions(+), 39 deletions(-) diff --git a/src/storm-parsers/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp index 5d76736f7..6d3e7b239 100644 --- a/src/storm-parsers/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -428,13 +428,30 @@ namespace storm { } storm::prism::Formula PrismParser::createFormula(std::string const& formulaName, storm::expressions::Expression expression) { - // Only register formula in second run. This prevents the parser from accepting formulas that depend on future - // formulas. + // Only register formula in second run. + // This is necessary because the resulting type of the formula is only known in the second run. + // This prevents the parser from accepting formulas that depend on future formulas. + storm::expressions::Variable variable; if (this->secondRun) { - STORM_LOG_THROW(this->identifiers_.find(formulaName) == nullptr, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Duplicate identifier '" << formulaName << "'."); - this->identifiers_.add(formulaName, expression); + try { + if (expression.hasIntegerType()) { + variable = manager->declareIntegerVariable(formulaName); + } else if (expression.hasBooleanType()) { + variable = manager->declareBooleanVariable(formulaName); + } else { + STORM_LOG_ASSERT(expression.hasNumericalType(), "Unexpected type for formula expression of formula " << formulaName); + variable = manager->declareRationalVariable(formulaName); + } + this->identifiers_.add(formulaName, variable.getExpression()); + } catch (storm::exceptions::InvalidArgumentException const& e) { + if (manager->hasVariable(formulaName)) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Duplicate identifier '" << formulaName << "'."); + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": illegal identifier '" << formulaName << "'."); + } + } } - return storm::prism::Formula(formulaName, expression, this->getFilename()); + return storm::prism::Formula(variable, expression, this->getFilename()); } storm::prism::Label PrismParser::createLabel(std::string const& labelName, storm::expressions::Expression expression) const { diff --git a/src/storm/storage/prism/Formula.cpp b/src/storm/storage/prism/Formula.cpp index 3134bc033..1f1e7f09a 100644 --- a/src/storm/storage/prism/Formula.cpp +++ b/src/storm/storage/prism/Formula.cpp @@ -2,12 +2,16 @@ namespace storm { namespace prism { - Formula::Formula(std::string const& name, storm::expressions::Expression const& expression, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), name(name), expression(expression) { + Formula::Formula(storm::expressions::Variable const& variable, storm::expressions::Expression const& expression, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), variable(variable), expression(expression) { // Intentionally left empty. } std::string const& Formula::getName() const { - return this->name; + return this->variable.getName(); + } + + storm::expressions::Variable const& Formula::getExpressionVariable() const { + return this->variable; } storm::expressions::Expression const& Formula::getExpression() const { @@ -15,11 +19,12 @@ namespace storm { } storm::expressions::Type const& Formula::getType() const { - return this->getExpression().getType(); + assert(this->getExpressionVariable().getType() == this->getExpression().getType()); + return this->getExpressionVariable().getType(); } Formula Formula::substitute(std::map const& substitution) const { - return Formula(this->getName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); + return Formula(this->getExpressionVariable(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); } std::ostream& operator<<(std::ostream& stream, Formula const& formula) { diff --git a/src/storm/storage/prism/Formula.h b/src/storm/storage/prism/Formula.h index 17d2f0cbd..656361111 100644 --- a/src/storm/storage/prism/Formula.h +++ b/src/storm/storage/prism/Formula.h @@ -15,12 +15,12 @@ namespace storm { /*! * Creates a formula with the given name and expression. * - * @param name The name of the formula. + * @param placeholder The placeholder variable that is used in expressions to represent this formula. * @param expression The expression associated with this formula. * @param filename The filename in which the transition reward is defined. * @param lineNumber The line number in which the transition reward is defined. */ - Formula(std::string const& name, storm::expressions::Expression const& expression, std::string const& filename = "", uint_fast64_t lineNumber = 0); + Formula(storm::expressions::Variable const& variable, storm::expressions::Expression const& expression, std::string const& filename = "", uint_fast64_t lineNumber = 0); // Create default implementations of constructors/assignment. Formula() = default; @@ -36,6 +36,13 @@ namespace storm { */ std::string const& getName() const; + /*! + * Retrieves the placeholder variable that is used in expressions to represent this formula. + * + * @return The placeholder variable that is used in expressions to represent this formula. + */ + storm::expressions::Variable const& getExpressionVariable() const; + /*! * Retrieves the expression that is associated with this formula. * @@ -62,7 +69,7 @@ namespace storm { private: // The name of the formula. - std::string name; + storm::expressions::Variable variable; // A predicate that needs to be satisfied by states for the label to be attached. storm::expressions::Expression expression; diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index 45a4f5a1c..c0913257d 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -787,63 +787,79 @@ namespace storm { } Program Program::substituteConstants() const { + return substituteConstantsFormulas(true, false); + } + + Program Program::substituteFormulas() const { + return substituteConstantsFormulas(false, true); + } + + Program Program::substituteConstantsFormulas(bool substituteConstants, bool substituteFormulas) const { + // We start by creating the appropriate substitution. - std::map constantSubstitution; - std::vector newConstants(this->getConstants()); - for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) { - auto const& constant = newConstants[constantIndex]; + std::map substitution; + + // Start with substituting constants. In a sane model, constant definitions do not contain formulas. + std::vector newConstants; + newConstants.reserve(this->getNumberOfConstants()); + for (auto const& oldConstant : this->getConstants()) { + // apply the substitutions gathered so far to the constant definition *before* adding it to the substitution. + newConstants.push_back(oldConstant.substitute(substitution)); - // Put the corresponding expression in the substitution. - if (constant.isDefined()) { - constantSubstitution.emplace(constant.getExpressionVariable(), constant.getExpression().simplify()); - - // If there is at least one more constant to come, we substitute the constants we have so far. - if (constantIndex + 1 < newConstants.size()) { - newConstants[constantIndex + 1] = newConstants[constantIndex + 1].substitute(constantSubstitution); - } + // Put the corresponding expression in the substitution (if requested). + auto const& constant = newConstants.back(); + if (substituteConstants && constant.isDefined()) { + substitution.emplace(constant.getExpressionVariable(), constant.getExpression().simplify()); } } - // Now we can substitute the constants in all expressions appearing in the program. + // Secondly, handle the formulas. These might contain constants + std::vector newFormulas; + newFormulas.reserve(this->getNumberOfFormulas()); + for (auto const& oldFormula : this->getFormulas()) { + // apply the currently gathered substitutions on the formula definition *before* adding it to the substitution. + newFormulas.emplace_back(oldFormula.substitute(substitution)); + // Put the corresponding expression in the substitution (if requested). + auto const& formula = newFormulas.back(); + if (substituteFormulas) { + substitution.emplace(formula.getExpressionVariable(), formula.getExpression().simplify()); + } + } + + // Now we can substitute the constants/formulas in all expressions appearing in the program. std::vector newBooleanVariables; newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables()); for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { - newBooleanVariables.emplace_back(booleanVariable.substitute(constantSubstitution)); + newBooleanVariables.emplace_back(booleanVariable.substitute(substitution)); } std::vector newIntegerVariables; newBooleanVariables.reserve(this->getNumberOfGlobalIntegerVariables()); for (auto const& integerVariable : this->getGlobalIntegerVariables()) { - newIntegerVariables.emplace_back(integerVariable.substitute(constantSubstitution)); - } - - std::vector newFormulas; - newFormulas.reserve(this->getNumberOfFormulas()); - for (auto const& formula : this->getFormulas()) { - newFormulas.emplace_back(formula.substitute(constantSubstitution)); + newIntegerVariables.emplace_back(integerVariable.substitute(substitution)); } std::vector newModules; newModules.reserve(this->getNumberOfModules()); for (auto const& module : this->getModules()) { - newModules.emplace_back(module.substitute(constantSubstitution)); + newModules.emplace_back(module.substitute(substitution)); } std::vector newRewardModels; newRewardModels.reserve(this->getNumberOfRewardModels()); for (auto const& rewardModel : this->getRewardModels()) { - newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution)); + newRewardModels.emplace_back(rewardModel.substitute(substitution)); } boost::optional newInitialConstruct; if (this->hasInitialConstruct()) { - newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution); + newInitialConstruct = this->getInitialConstruct().substitute(substitution); } std::vector