From e1761fa774c68b84f91c361cc868fe8418db03b0 Mon Sep 17 00:00:00 2001 From: dehnert Date: Wed, 8 Apr 2015 23:08:59 +0200 Subject: [PATCH] Enabled hybrid CTMC model checker in cli. Further work on hybrid CTMC model checker (not yet working). Fixed some minor issues in sparse CTMC model checker. Former-commit-id: f9c0f976e187c4e39a96dacfe2291e23ddf13172 --- examples/ctmc/tandem/tandem.sm | 6 +- .../csl/HybridCtmcCslModelChecker.cpp | 37 +-- .../csl/HybridCtmcCslModelChecker.h | 4 +- .../csl/SparseCtmcCslModelChecker.cpp | 82 +++--- .../csl/SparseCtmcCslModelChecker.h | 2 + .../prctl/HybridDtmcPrctlModelChecker.cpp | 4 +- .../prctl/SparseDtmcPrctlModelChecker.cpp | 2 +- .../SymbolicPropositionalModelChecker.cpp | 2 + .../results/HybridQuantitativeCheckResult.cpp | 2 +- src/storage/BitVector.h | 21 ++ src/utility/cli.h | 7 + .../GmmxxCtmcCslModelCheckerTest.cpp | 19 +- .../GmmxxHybridCtmcCslModelCheckerTest.cpp | 261 ++++++++++++++++++ 13 files changed, 383 insertions(+), 66 deletions(-) create mode 100644 test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp diff --git a/examples/ctmc/tandem/tandem.sm b/examples/ctmc/tandem/tandem.sm index 439d33813..c35246e1a 100644 --- a/examples/ctmc/tandem/tandem.sm +++ b/examples/ctmc/tandem/tandem.sm @@ -35,4 +35,8 @@ endmodule // reward - number of customers in network rewards "customers" true : sc + sm; -endrewards \ No newline at end of file +endrewards + +label "network_full" = sc=c&sm=c&ph=2; +label "first_queue_full" = sc=c; +label "second_queue_full" = sm=c; diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp index a8c088aeb..67578184e 100644 --- a/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp +++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.cpp @@ -10,6 +10,7 @@ #include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" #include "src/modelchecker/results/SymbolicQuantitativeCheckResult.h" #include "src/modelchecker/results/HybridQuantitativeCheckResult.h" +#include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "src/exceptions/InvalidStateException.h" #include "src/exceptions/InvalidPropertyException.h" @@ -33,7 +34,7 @@ namespace storm { template storm::dd::Add HybridCtmcCslModelChecker::computeProbabilityMatrix(storm::models::symbolic::Model const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector) { - return rateMatrix / exitRateVector.swapVariables(model.getRowColumnMetaVariablePairs()); + return rateMatrix / exitRateVector; } template @@ -68,9 +69,10 @@ namespace storm { // Now perform the uniformization. uniformizedMatrix = uniformizedMatrix / model.getManager().getConstant(uniformizationRate); - storm::dd::Add diagonalOffset = model.getRowColumnIdentity(); - diagonalOffset -= model.getRowColumnIdentity() * (exitRateVector / model.getManager().getConstant(uniformizationRate)); - uniformizedMatrix = uniformizedMatrix + diagonalOffset; + storm::dd::Add diagonal = model.getRowColumnIdentity() * maybeStates.toAdd(); + storm::dd::Add diagonalOffset = diagonal; + diagonalOffset -= diagonal * (exitRateVector / model.getManager().getConstant(uniformizationRate)); + uniformizedMatrix += diagonalOffset; return uniformizedMatrix; } @@ -82,7 +84,7 @@ namespace storm { boost::optional> modifiedStateRewardVector; if (this->getModel().hasStateRewards()) { - modifiedStateRewardVector = this->getModel().getStateRewardVector() / this->getModel().getTransitionMatrix().sumAbstract(this->getModel().getColumnVariables()); + modifiedStateRewardVector = this->getModel().getStateRewardVector() / this->getModel().getExitRateVector(); } return HybridDtmcPrctlModelChecker::computeReachabilityRewardsHelper(this->getModel(), this->computeProbabilityMatrix(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()), modifiedStateRewardVector, this->getModel().getOptionalTransitionRewardMatrix(), subResult.getTruthValuesVector(), *linearEquationSolverFactory, qualitative); @@ -171,7 +173,7 @@ namespace storm { std::unique_ptr statesWithValuesGreaterZero = unboundedResult->asQuantitativeCheckResult().compareAgainstBound(storm::logic::ComparisonType::Greater, storm::utility::zero()); // And use it to compute the set of relevant states. - storm::dd::Bdd relevantStates = storm::utility::graph::performProbGreater0(this->getModel(), this->getModel().getTransitionMatrix(), phiStates, statesWithValuesGreaterZero->asSymbolicQualitativeCheckResult().getTruthValuesVector()); + storm::dd::Bdd relevantStates = storm::utility::graph::performProbGreater0(this->getModel(), this->getModel().getTransitionMatrix().notZero(), phiStates, statesWithValuesGreaterZero->asSymbolicQualitativeCheckResult().getTruthValuesVector()); // Filter the unbounded result such that it only contains values for the relevant states. unboundedResult->filter(SymbolicQualitativeCheckResult(this->getModel().getReachableStates(), relevantStates)); @@ -185,7 +187,7 @@ namespace storm { result = std::move(explicitUnboundedResult->asExplicitQuantitativeCheckResult().getValueVector()); } else { STORM_LOG_THROW(unboundedResult->isSymbolicQuantitativeCheckResult(), storm::exceptions::InvalidStateException, "Expected check result of different type."); - result = unboundedResult->asSymbolicQuantitativeCheckResult().getValueVector().toVector(odd); + result = unboundedResult->asSymbolicQuantitativeCheckResult().getValueVector().template toVector(odd); } // Determine the uniformization rate for the transient probability computation. @@ -196,9 +198,9 @@ namespace storm { storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); // Compute the transient probabilities. - std::vector subResult = SparseCtmcCslModelChecker::computeTransientProbabilities(explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, subResult, *this->linearEquationSolverFactory); + result = SparseCtmcCslModelChecker::computeTransientProbabilities(explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result, *this->linearEquationSolverFactory); - return std::unique_ptr(new HybridQuantitativeCheckResult(this->getModel().getReachableStates(), !relevantStates && this->getModel().getReachableStates(), this->getModel().getManager().getAddZero(), relevantStates, odd, subResult)); + return std::unique_ptr(new HybridQuantitativeCheckResult(this->getModel().getReachableStates(), !relevantStates && this->getModel().getReachableStates(), this->getModel().getManager().getAddZero(), relevantStates, odd, result)); } else { // In this case, the interval is of the form [t, t'] with t != 0 and t' != inf. @@ -223,9 +225,9 @@ namespace storm { storm::dd::Add b = (statesWithProbabilityGreater0NonPsi.toAdd() * this->getModel().getTransitionMatrix() * psiStates.swapVariables(this->getModel().getRowColumnMetaVariablePairs()).toAdd()).sumAbstract(this->getModel().getColumnVariables()) / this->getModel().getManager().getConstant(uniformizationRate); // Build an ODD for the relevant states and translate the symbolic parts to their explicit representation. - odd(statesWithProbabilityGreater0NonPsi); + odd = storm::dd::Odd(statesWithProbabilityGreater0NonPsi); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - std::vector explicitB = b.toVector(odd); + std::vector explicitB = b.template toVector(odd); // Compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); @@ -234,16 +236,16 @@ namespace storm { // Transform the explicit result to a hybrid check result, so we can easily convert it to // a symbolic qualitative format. HybridQuantitativeCheckResult hybridResult(this->getModel().getReachableStates(), psiStates || (!statesWithProbabilityGreater0 && this->getModel().getReachableStates()), - psiStates.toAdd(), statesWithProbabilityGreater0NonPsi, subResult); + psiStates.toAdd(), statesWithProbabilityGreater0NonPsi, odd, subResult); // Determine the set of states that achieved a strictly positive probability. std::unique_ptr statesWithValuesGreaterZero = hybridResult.compareAgainstBound(storm::logic::ComparisonType::Greater, storm::utility::zero()); // And use it to compute the set of relevant states. - storm::dd::Bdd relevantStates = storm::utility::graph::performProbGreater0(this->getModel(), this->getModel().getTransitionMatrix(), phiStates, statesWithValuesGreaterZero->asSymbolicQualitativeCheckResult().getTruthValuesVector()); + storm::dd::Bdd relevantStates = storm::utility::graph::performProbGreater0(this->getModel(), this->getModel().getTransitionMatrix().notZero(), phiStates, statesWithValuesGreaterZero->asSymbolicQualitativeCheckResult().getTruthValuesVector()); // Filter the unbounded result such that it only contains values for the relevant states. - hybridResult->filter(SymbolicQualitativeCheckResult(this->getModel().getReachableStates(), relevantStates)); + hybridResult.filter(SymbolicQualitativeCheckResult(this->getModel().getReachableStates(), relevantStates)); // Build an ODD for the relevant states. odd = storm::dd::Odd(relevantStates); @@ -261,7 +263,8 @@ namespace storm { // If the lower and upper bounds coincide, we have only determined the relevant states at this // point, but we still need to construct the starting vector. if (lowerBound == upperBound) { - newSubresult = psiStates.toAdd().toVector(odd); std::vector(relevantStates.getNonZeroCount()); + odd = storm::dd::Odd(relevantStates); + newSubresult = psiStates.toAdd().template toVector(odd); } // Finally, we compute the second set of transient probabilities. @@ -270,11 +273,11 @@ namespace storm { newSubresult = SparseCtmcCslModelChecker::computeTransientProbabilities(explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, *this->linearEquationSolverFactory); - return std::unique_ptr(new HybridQuantitativeCheckResult(this->getModel().getReachableStates(), !relevantStates && this->getModel().getReachableStates(), this->getModel().getManager().getAddZero(), relevantStates, newSubresult)); + return std::unique_ptr(new HybridQuantitativeCheckResult(this->getModel().getReachableStates(), !relevantStates && this->getModel().getReachableStates(), this->getModel().getManager().getAddZero(), relevantStates, odd, newSubresult)); } } } else { - return std::unique_ptr(new SymbolicQuantitativeCheckResult>(this->getModel().getReachableStates(), psiStates.toAdd())); + return std::unique_ptr(new SymbolicQuantitativeCheckResult(this->getModel().getReachableStates(), psiStates.toAdd())); } } diff --git a/src/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/modelchecker/csl/HybridCtmcCslModelChecker.h index ffc2d2694..331e12152 100644 --- a/src/modelchecker/csl/HybridCtmcCslModelChecker.h +++ b/src/modelchecker/csl/HybridCtmcCslModelChecker.h @@ -20,8 +20,8 @@ namespace storm { virtual std::unique_ptr computeBoundedUntilProbabilities(storm::logic::BoundedUntilFormula const& pathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; virtual std::unique_ptr computeNextProbabilities(storm::logic::NextFormula const& pathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; virtual std::unique_ptr computeUntilProbabilities(storm::logic::UntilFormula const& pathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; - virtual std::unique_ptr computeInstantaneousRewards(storm::logic::InstantaneousRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; - virtual std::unique_ptr computeCumulativeRewards(storm::logic::CumulativeRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; +// virtual std::unique_ptr computeInstantaneousRewards(storm::logic::InstantaneousRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; +// virtual std::unique_ptr computeCumulativeRewards(storm::logic::CumulativeRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; virtual std::unique_ptr computeReachabilityRewards(storm::logic::ReachabilityRewardFormula const& rewardPathFormula, bool qualitative = false, boost::optional const& optimalityType = boost::optional()) override; protected: diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp index 0a1a71c42..898993437 100644 --- a/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -138,8 +138,7 @@ namespace storm { result = this->computeUntilProbabilitiesHelper(this->getModel().getTransitionMatrix(), backwardTransitions, phiStates, psiStates, qualitative, *this->linearEquationSolverFactory); // Determine the set of states that must be considered further. - storm::storage::BitVector relevantStates = storm::utility::vector::filterGreaterZero(result); - relevantStates = storm::utility::graph::performProbGreater0(backwardTransitions, phiStates, relevantStates & phiStates); + storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; std::vector subResult(relevantStates.getNumberOfSetBits()); storm::utility::vector::selectVectorValues(subResult, relevantStates, result); @@ -163,14 +162,11 @@ namespace storm { // In this case, the interval is of the form [t, t'] with t != 0 and t' != inf. // Prepare some variables that are used by the two following blocks. - storm::storage::BitVector relevantStates; ValueType uniformizationRate = 0; storm::storage::SparseMatrix uniformizedMatrix; std::vector newSubresult; - if (lowerBound == upperBound) { - relevantStates = statesWithProbabilityGreater0; - } else { + if (lowerBound != upperBound) { // Find the maximal rate of all 'maybe' states to take it as the uniformization rate. uniformizationRate = 0; for (auto const& state : statesWithProbabilityGreater0NonPsi) { @@ -192,38 +188,51 @@ namespace storm { std::vector values(statesWithProbabilityGreater0NonPsi.getNumberOfSetBits(), storm::utility::zero()); std::vector subresult = computeTransientProbabilities(uniformizedMatrix, &b, upperBound - lowerBound, uniformizationRate, values, *this->linearEquationSolverFactory); - // Determine the set of states that must be considered further. - relevantStates = storm::utility::vector::filterGreaterZero(subresult); - relevantStates = storm::utility::graph::performProbGreater0(uniformizedMatrix.transpose(), phiStates % statesWithProbabilityGreater0NonPsi, relevantStates & (phiStates % statesWithProbabilityGreater0NonPsi)); - - newSubresult = std::vector(relevantStates.getNumberOfSetBits()); - storm::utility::vector::selectVectorValues(newSubresult, relevantStates, subresult); - } - - // 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 = 0; - for (auto const& state : relevantStates) { - uniformizationRate = std::max(uniformizationRate, exitRates[state]); - } - uniformizationRate *= 1.02; - STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); - - // If the lower and upper bounds coincide, we have only determined the relevant states at this - // point, but we still need to construct the starting vector. - if (lowerBound == upperBound) { + storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; newSubresult = std::vector(relevantStates.getNumberOfSetBits()); + storm::utility::vector::selectVectorValues(newSubresult, statesWithProbabilityGreater0NonPsi % relevantStates, subresult); storm::utility::vector::setVectorValues(newSubresult, psiStates % relevantStates, storm::utility::one()); + + // 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 = 0; + for (auto const& state : relevantStates) { + uniformizationRate = std::max(uniformizationRate, exitRates[state]); + } + uniformizationRate *= 1.02; + STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); + + // Finally, we compute the second set of transient probabilities. + uniformizedMatrix = this->computeUniformizedMatrix(this->getModel().getTransitionMatrix(), relevantStates, uniformizationRate, exitRates); + newSubresult = computeTransientProbabilities(uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, *this->linearEquationSolverFactory); + + // Fill in the correct values. + result = std::vector(this->getModel().getNumberOfStates(), storm::utility::zero()); + storm::utility::vector::setVectorValues(result, ~relevantStates, storm::utility::zero()); + storm::utility::vector::setVectorValues(result, relevantStates, newSubresult); + } else { + newSubresult = std::vector(statesWithProbabilityGreater0.getNumberOfSetBits()); + storm::utility::vector::setVectorValues(newSubresult, psiStates % statesWithProbabilityGreater0, storm::utility::one()); + + // 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 = 0; + for (auto const& state : statesWithProbabilityGreater0) { + uniformizationRate = std::max(uniformizationRate, exitRates[state]); + } + uniformizationRate *= 1.02; + STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); + + // Finally, we compute the second set of transient probabilities. + uniformizedMatrix = this->computeUniformizedMatrix(this->getModel().getTransitionMatrix(), statesWithProbabilityGreater0, uniformizationRate, exitRates); + newSubresult = computeTransientProbabilities(uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, *this->linearEquationSolverFactory); + + // Fill in the correct values. + result = std::vector(this->getModel().getNumberOfStates(), storm::utility::zero()); + storm::utility::vector::setVectorValues(result, ~statesWithProbabilityGreater0, storm::utility::zero()); + storm::utility::vector::setVectorValues(result, statesWithProbabilityGreater0, newSubresult); + } - - // Finally, we compute the second set of transient probabilities. - uniformizedMatrix = this->computeUniformizedMatrix(this->getModel().getTransitionMatrix(), relevantStates, uniformizationRate, exitRates); - newSubresult = computeTransientProbabilities(uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, *this->linearEquationSolverFactory); - - // Fill in the correct values. - result = std::vector(this->getModel().getNumberOfStates(), storm::utility::zero()); - storm::utility::vector::setVectorValues(result, ~relevantStates, storm::utility::zero()); - storm::utility::vector::setVectorValues(result, relevantStates, newSubresult); } } } @@ -337,7 +346,7 @@ namespace storm { weight = std::get<3>(foxGlynnResult)[index - std::get<0>(foxGlynnResult)]; storm::utility::vector::applyPointwise(result, values, result, addAndScale); } - + return result; } @@ -438,6 +447,7 @@ namespace storm { boost::optional> modifiedStateRewardVector; if (this->getModel().hasStateRewards()) { modifiedStateRewardVector = std::vector(this->getModel().getStateRewardVector()); + typename std::vector::const_iterator it2 = this->getModel().getExitRateVector().begin(); for (typename std::vector::iterator it1 = modifiedStateRewardVector.get().begin(), ite1 = modifiedStateRewardVector.get().end(); it1 != ite1; ++it1, ++it2) { *it1 /= *it2; diff --git a/src/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/modelchecker/csl/SparseCtmcCslModelChecker.h index ffa89f904..5108a183f 100644 --- a/src/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -16,6 +16,8 @@ namespace storm { template class SparseCtmcCslModelChecker : public SparsePropositionalModelChecker { public: + friend class HybridCtmcCslModelChecker; + explicit SparseCtmcCslModelChecker(storm::models::sparse::Ctmc const& model); explicit SparseCtmcCslModelChecker(storm::models::sparse::Ctmc const& model, std::unique_ptr>&& linearEquationSolverFactory); diff --git a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 231c17a94..25a02adff 100644 --- a/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -231,7 +231,7 @@ namespace storm { std::unique_ptr HybridDtmcPrctlModelChecker::computeReachabilityRewards(storm::logic::ReachabilityRewardFormula const& rewardPathFormula, bool qualitative, boost::optional const& optimalityType) { std::unique_ptr subResultPointer = this->check(rewardPathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return this->computeReachabilityRewardsHelper(this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory, qualitative); + return this->computeReachabilityRewardsHelper(this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getOptionalStateRewardVector(), this->getModel().getOptionalTransitionRewardMatrix(), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory, qualitative); } template @@ -247,7 +247,7 @@ namespace storm { STORM_LOG_INFO("Found " << infinityStates.getNonZeroCount() << " 'infinity' states."); STORM_LOG_INFO("Found " << targetStates.getNonZeroCount() << " 'target' states."); STORM_LOG_INFO("Found " << maybeStates.getNonZeroCount() << " 'maybe' states."); - + // Check whether we need to compute exact rewards for some states. if (qualitative) { // Set the values for all maybe-states to 1 to indicate that their reward values diff --git a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index a7775139a..179e82f42 100644 --- a/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -248,7 +248,7 @@ namespace storm { // Converting the matrix from the fixpoint notation to the form needed for the equation // system. That is, we go from x = A*x + b to (I-A)x = b. submatrix.convertToEquationSystem(); - + // Initialize the x vector with 1 for each element. This is the initial guess for // the iterative solvers. std::vector x(submatrix.getColumnCount(), storm::utility::one()); diff --git a/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp index 1552235d9..4fa0dbafe 100644 --- a/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp +++ b/src/modelchecker/propositional/SymbolicPropositionalModelChecker.cpp @@ -1,6 +1,7 @@ #include "src/modelchecker/propositional/SymbolicPropositionalModelChecker.h" #include "src/models/symbolic/Dtmc.h" +#include "src/models/symbolic/Ctmc.h" #include "src/models/symbolic/Mdp.h" #include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -48,6 +49,7 @@ namespace storm { // Explicitly instantiate the template class. template storm::models::symbolic::Dtmc const& SymbolicPropositionalModelChecker::getModelAs() const; + template storm::models::symbolic::Ctmc const& SymbolicPropositionalModelChecker::getModelAs() const; template storm::models::symbolic::Mdp const& SymbolicPropositionalModelChecker::getModelAs() const; template class SymbolicPropositionalModelChecker; } diff --git a/src/modelchecker/results/HybridQuantitativeCheckResult.cpp b/src/modelchecker/results/HybridQuantitativeCheckResult.cpp index 7019786ad..abf56e163 100644 --- a/src/modelchecker/results/HybridQuantitativeCheckResult.cpp +++ b/src/modelchecker/results/HybridQuantitativeCheckResult.cpp @@ -150,7 +150,7 @@ namespace storm { template double HybridQuantitativeCheckResult::getMax() const { - double max = this->symbolicValues.getMin(); + double max = this->symbolicValues.getMax(); if (!explicitStates.isZero()) { for (auto const& element : explicitValues) { max = std::max(max, element); diff --git a/src/storage/BitVector.h b/src/storage/BitVector.h index ec4cce693..5072d71cf 100644 --- a/src/storage/BitVector.h +++ b/src/storage/BitVector.h @@ -277,6 +277,27 @@ namespace storm { */ BitVector operator%(BitVector const& filter) const; +// /*! +// * Computes a bit vector that is as long as the number of set bits in the given filter that has bit i is set +// * iff the i-th set bit of the current bit vector is set in the filter. Note: this functionality is exactly +// * the same as operator%. +// * +// * @param filter A reference the bit vector to use as the filter. +// * @return A bit vector that is as long as the number of set bits in the given filter that has bit i is set +// * iff the i-th set bit of the current bit vector is set in the filter. +// */ +// BitVector operator<<(BitVector const& filter) const; +// +// /*! +// * Computes a bit vector that is as long as the number of set bits in the given filter that has bit i is set +// * iff the i-th set bit of the current bit vector is set in the filter. +// * +// * @param filter A reference the bit vector to use as the filter. +// * @return A bit vector that is as long as the number of set bits in the given filter that has bit i is set +// * iff the i-th set bit of the current bit vector is set in the filter. +// */ +// BitVector operator>>(BitVector const& filter) const; + /*! * Performs a logical "not" on the bit vector. * diff --git a/src/utility/cli.h b/src/utility/cli.h index 780201cf3..b46867be0 100644 --- a/src/utility/cli.h +++ b/src/utility/cli.h @@ -68,6 +68,7 @@ log4cplus::Logger printer; #include "src/modelchecker/prctl/SparseMdpPrctlModelChecker.h" #include "src/modelchecker/csl/SparseCtmcCslModelChecker.h" #include "src/modelchecker/prctl/HybridDtmcPrctlModelChecker.h" +#include "src/modelchecker/csl/HybridCtmcCslModelChecker.h" #include "src/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" @@ -503,6 +504,12 @@ namespace storm { if (modelchecker.canHandle(*formula.get())) { result = modelchecker.check(*formula.get()); } + } else if (model->getType() == storm::models::ModelType::Ctmc) { + std::shared_ptr> ctmc = model->template as>(); + storm::modelchecker::HybridCtmcCslModelChecker modelchecker(*ctmc); + if (modelchecker.canHandle(*formula.get())) { + result = modelchecker.check(*formula.get()); + } } else { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This functionality is not yet implemented."); } diff --git a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp index 6a814d63d..56c61da5a 100644 --- a/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxCtmcCslModelCheckerTest.cpp @@ -48,26 +48,33 @@ TEST(GmmxxCtmcCslModelCheckerTest, Cluster) { storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeCheckResult2 = checkResult->asExplicitQuantitativeCheckResult(); EXPECT_NEAR(2.3397873548343415E-6, quantitativeCheckResult2[initialState], storm::settings::generalSettings().getPrecision()); - formula = formulaParser.parseFromString("P=? [ \"minimum\" U<=10 \"premium\"]"); + formula = formulaParser.parseFromString("P=? [ F[100,2000] !\"minimum\"]"); checkResult = modelchecker.check(*formula); ASSERT_TRUE(checkResult->isExplicitQuantitativeCheckResult()); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeCheckResult3 = checkResult->asExplicitQuantitativeCheckResult(); - EXPECT_NEAR(1, quantitativeCheckResult3[initialState], storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0.001105335651650576, quantitativeCheckResult3[initialState], storm::settings::generalSettings().getPrecision()); - formula = formulaParser.parseFromString("P=? [ !\"minimum\" U[1,inf] \"minimum\"]"); + formula = formulaParser.parseFromString("P=? [ \"minimum\" U<=10 \"premium\"]"); checkResult = modelchecker.check(*formula); ASSERT_TRUE(checkResult->isExplicitQuantitativeCheckResult()); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeCheckResult4 = checkResult->asExplicitQuantitativeCheckResult(); - EXPECT_NEAR(0, quantitativeCheckResult4[initialState], storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(1, quantitativeCheckResult4[initialState], storm::settings::generalSettings().getPrecision()); - formula = formulaParser.parseFromString("R=? [C<=100]"); + formula = formulaParser.parseFromString("P=? [ !\"minimum\" U[1,inf] \"minimum\"]"); checkResult = modelchecker.check(*formula); ASSERT_TRUE(checkResult->isExplicitQuantitativeCheckResult()); storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeCheckResult5 = checkResult->asExplicitQuantitativeCheckResult(); - EXPECT_NEAR(0.8602815057967503, quantitativeCheckResult5[initialState], storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0, quantitativeCheckResult5[initialState], storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("R=? [C<=100]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isExplicitQuantitativeCheckResult()); + storm::modelchecker::ExplicitQuantitativeCheckResult quantitativeCheckResult6 = checkResult->asExplicitQuantitativeCheckResult(); + EXPECT_NEAR(0.8602815057967503, quantitativeCheckResult6[initialState], storm::settings::generalSettings().getPrecision()); } TEST(GmmxxCtmcCslModelCheckerTest, Embedded) { diff --git a/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp new file mode 100644 index 000000000..472547ba3 --- /dev/null +++ b/test/functional/modelchecker/GmmxxHybridCtmcCslModelCheckerTest.cpp @@ -0,0 +1,261 @@ +#include "gtest/gtest.h" +#include "storm-config.h" +#include "src/settings/SettingMemento.h" +#include "src/parser/PrismParser.h" +#include "src/parser/FormulaParser.h" +#include "src/logic/Formulas.h" +#include "src/builder/DdPrismModelBuilder.h" +#include "src/storage/dd/DdType.h" + +#include "src/utility/solver.h" +#include "src/modelchecker/csl/HybridCtmcCslModelChecker.h" +#include "src/modelchecker/results/HybridQuantitativeCheckResult.h" +#include "src/modelchecker/results/SymbolicQualitativeCheckResult.h" +#include "src/modelchecker/results/SymbolicQuantitativeCheckResult.h" + +#include "src/settings/SettingsManager.h" + +TEST(GmmxxHybridCtmcCslModelCheckerTest, Cluster) { + // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. + std::unique_ptr enablePrismCompatibility = storm::settings::mutableGeneralSettings().overridePrismCompatibilityMode(true); + + // Parse the model description. + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/cluster2.sm"); + storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); + std::shared_ptr formula(nullptr); + + // Build the model. + typename storm::builder::DdPrismModelBuilder::Options options; + options.buildRewards = true; + options.rewardModelName = "num_repairs"; + std::shared_ptr> model = storm::builder::DdPrismModelBuilder::translateProgram(program, options); + ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); + std::shared_ptr> ctmc = model->as>(); + + // Create model checker. + storm::modelchecker::HybridCtmcCslModelChecker modelchecker(*ctmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); + + // Start checking properties. + formula = formulaParser.parseFromString("P=? [ F<=100 !\"minimum\"]"); + std::unique_ptr checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult1 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(5.5461254704419085E-5, quantitativeCheckResult1.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(5.5461254704419085E-5, quantitativeCheckResult1.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ F[100,100] !\"minimum\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult2 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(2.3397873548343415E-6, quantitativeCheckResult2.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(2.3397873548343415E-6, quantitativeCheckResult2.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ \"minimum\" U<=10 \"premium\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult3 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(1, quantitativeCheckResult3.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(1, quantitativeCheckResult3.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ !\"minimum\" U[1,inf] \"minimum\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult4 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(0, quantitativeCheckResult4.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0, quantitativeCheckResult4.getMax(), storm::settings::generalSettings().getPrecision()); + +// formula = formulaParser.parseFromString("R=? [C<=100]"); +// checkResult = modelchecker.check(*formula); +// +// ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); +// checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); +// storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult5 = checkResult->asHybridQuantitativeCheckResult(); +// EXPECT_NEAR(0.8602815057967503, quantitativeCheckResult5.getMin(), storm::settings::generalSettings().getPrecision()); +// EXPECT_NEAR(0.8602815057967503, quantitativeCheckResult5.getMax(), storm::settings::generalSettings().getPrecision()); +} + +TEST(GmmxxHybridCtmcCslModelCheckerTest, Embedded) { + // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. + std::unique_ptr enablePrismCompatibility = storm::settings::mutableGeneralSettings().overridePrismCompatibilityMode(true); + + // Parse the model description. + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/embedded2.sm"); + storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); + std::shared_ptr formula(nullptr); + + // Build the model. + typename storm::builder::DdPrismModelBuilder::Options options; + options.buildRewards = true; + options.rewardModelName = "up"; + std::shared_ptr> model = storm::builder::DdPrismModelBuilder::translateProgram(program, options); + ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); + std::shared_ptr> ctmc = model->as>(); + + // Create model checker. + storm::modelchecker::HybridCtmcCslModelChecker modelchecker(*ctmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); + + // Start checking properties. + formula = formulaParser.parseFromString("P=? [ F<=10000 \"down\"]"); + std::unique_ptr checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult1 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(0.0019216435246119591, quantitativeCheckResult1.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0.0019216435246119591, quantitativeCheckResult1.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ !\"down\" U<=10000 \"fail_actuators\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult2 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(3.7079151806696567E-6, quantitativeCheckResult2.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(3.7079151806696567E-6, quantitativeCheckResult2.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ !\"down\" U<=10000 \"fail_io\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult3 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(0.001556839327673734, quantitativeCheckResult3.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0.001556839327673734, quantitativeCheckResult3.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ !\"down\" U<=10000 \"fail_sensors\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult4 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(4.429620626755424E-5, quantitativeCheckResult4.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(4.429620626755424E-5, quantitativeCheckResult4.getMax(), storm::settings::generalSettings().getPrecision()); + +// formula = formulaParser.parseFromString("R=? [C<=10000]"); +// checkResult = modelchecker.check(*formula); +// +// ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); +// checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); +// storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult5 = checkResult->asHybridQuantitativeCheckResult(); +// EXPECT_NEAR(2.7720429852369946, quantitativeCheckResult5.getMin(), storm::settings::generalSettings().getPrecision()); +// EXPECT_NEAR(2.7720429852369946, quantitativeCheckResult5.getMax(), storm::settings::generalSettings().getPrecision()); +} + +TEST(GmmxxHybridCtmcCslModelCheckerTest, Polling) { + // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. + std::unique_ptr enablePrismCompatibility = storm::settings::mutableGeneralSettings().overridePrismCompatibilityMode(true); + + // Parse the model description. + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/polling2.sm"); + storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); + std::shared_ptr formula(nullptr); + + // Build the model. + std::shared_ptr> model = storm::builder::DdPrismModelBuilder::translateProgram(program); + ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); + std::shared_ptr> ctmc = model->as>(); + + // Create model checker. + storm::modelchecker::HybridCtmcCslModelChecker modelchecker(*ctmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); + + // Start checking properties. + formula = formulaParser.parseFromString("P=?[ F<=10 \"target\"]"); + std::unique_ptr checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult1 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(1, quantitativeCheckResult1.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(1, quantitativeCheckResult1.getMax(), storm::settings::generalSettings().getPrecision()); +} + +TEST(GmmxxHybridCtmcCslModelCheckerTest, Fms) { + // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. + std::unique_ptr enablePrismCompatibility = storm::settings::mutableGeneralSettings().overridePrismCompatibilityMode(true); + + // No properties to check at this point. +} + +TEST(GmmxxHybridCtmcCslModelCheckerTest, Tandem) { + // Set the PRISM compatibility mode temporarily. It is set to its old value once the returned object is destructed. + std::unique_ptr enablePrismCompatibility = storm::settings::mutableGeneralSettings().overridePrismCompatibilityMode(true); + + // Parse the model description. + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/tandem5.sm"); + storm::parser::FormulaParser formulaParser(program.getManager().getSharedPointer()); + std::shared_ptr formula(nullptr); + + // Build the model with the customers reward structure. + typename storm::builder::DdPrismModelBuilder::Options options; + options.buildRewards = true; + options.rewardModelName = "customers"; + std::shared_ptr> model = storm::builder::DdPrismModelBuilder::translateProgram(program, options); + ASSERT_EQ(storm::models::ModelType::Ctmc, model->getType()); + std::shared_ptr> ctmc = model->as>(); + + // Create model checker. + storm::modelchecker::HybridCtmcCslModelChecker modelchecker(*ctmc, std::unique_ptr>(new storm::utility::solver::GmmxxLinearEquationSolverFactory())); + + // Start checking properties. + formula = formulaParser.parseFromString("P=? [ F<=10 \"network_full\" ]"); + std::unique_ptr checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult1 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(0.015446370562428037, quantitativeCheckResult1.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0.015446370562428037, quantitativeCheckResult1.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [ F<=10 \"first_queue_full\" ]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult2 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(0.999999837225515, quantitativeCheckResult2.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(0.999999837225515, quantitativeCheckResult2.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("P=? [\"second_queue_full\" U<=1 !\"second_queue_full\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult3 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(1, quantitativeCheckResult3.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(1, quantitativeCheckResult3.getMax(), storm::settings::generalSettings().getPrecision()); + +// formula = formulaParser.parseFromString("R=? [I=10]"); +// checkResult = modelchecker.check(*formula); +// +// ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); +// checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); +// storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult4 = checkResult->asHybridQuantitativeCheckResult(); +// EXPECT_NEAR(5.679243850315877, quantitativeCheckResult4.getMin(), storm::settings::generalSettings().getPrecision()); +// EXPECT_NEAR(5.679243850315877, quantitativeCheckResult4.getMax(), storm::settings::generalSettings().getPrecision()); +// +// formula = formulaParser.parseFromString("R=? [C<=10]"); +// checkResult = modelchecker.check(*formula); +// +// ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); +// checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); +// storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult5 = checkResult->asHybridQuantitativeCheckResult(); +// EXPECT_NEAR(55.44792186036232, quantitativeCheckResult5.getMin(), storm::settings::generalSettings().getPrecision()); +// EXPECT_NEAR(55.44792186036232, quantitativeCheckResult5.getMax(), storm::settings::generalSettings().getPrecision()); + + formula = formulaParser.parseFromString("R=? [F \"first_queue_full\"&\"second_queue_full\"]"); + checkResult = modelchecker.check(*formula); + + ASSERT_TRUE(checkResult->isHybridQuantitativeCheckResult()); + checkResult->filter(storm::modelchecker::SymbolicQualitativeCheckResult(ctmc->getReachableStates(), ctmc->getInitialStates())); + storm::modelchecker::HybridQuantitativeCheckResult quantitativeCheckResult6 = checkResult->asHybridQuantitativeCheckResult(); + EXPECT_NEAR(262.85103498583413, quantitativeCheckResult6.getMin(), storm::settings::generalSettings().getPrecision()); + EXPECT_NEAR(262.85103498583413, quantitativeCheckResult6.getMax(), storm::settings::generalSettings().getPrecision()); +}