Browse Source
Trying to refurbish the TopologicalValueIterationMdpPrctlModelChecker
Trying to refurbish the TopologicalValueIterationMdpPrctlModelChecker
Former-commit-id: 2963c774b0
main
5 changed files with 462 additions and 2 deletions
-
2src/modelchecker/prctl/TopologicalValueIterationMdpPrctlModelChecker.h
-
2src/solver/NativeNondeterministicLinearEquationSolver.h
-
39src/solver/TopologicalValueIterationNativeNondeterministicLinearEquationSolver.h
-
197src/solver/TopologicalValueIterationNondeterministicLinearEquationSolver.cpp
-
224test/functional/modelchecker/TopologicalValueIterationMdpPrctlModelCheckerTest.cpp
@ -0,0 +1,39 @@ |
|||||
|
#ifndef STORM_SOLVER_TOPOLOGICALVALUEITERATIONNONDETERMINISTICLINEAREQUATIONSOLVER_H_ |
||||
|
#define STORM_SOLVER_TOPOLOGICALVALUEITERATIONNONDETERMINISTICLINEAREQUATIONSOLVER_H_ |
||||
|
|
||||
|
#include "src/solver/NondeterministicLinearEquationSolver.h" |
||||
|
#include "src/solver/NativeNondeterministicLinearEquationSolver.h" |
||||
|
|
||||
|
namespace storm { |
||||
|
namespace solver { |
||||
|
|
||||
|
/*! |
||||
|
* A class that uses SCC Decompositions to solve a linear equation system |
||||
|
*/ |
||||
|
template<class ValueType> |
||||
|
class TopologicalValueIterationNondeterministicLinearEquationSolver : public NondeterministicLinearEquationSolver<ValueType> { |
||||
|
public: |
||||
|
/*! |
||||
|
* Constructs a nondeterministic linear equation solver with parameters being set according to the settings |
||||
|
* object. |
||||
|
*/ |
||||
|
TopologicalValueIterationNondeterministicLinearEquationSolver(); |
||||
|
|
||||
|
/*! |
||||
|
* Constructs a nondeterminstic linear equation solver with the given parameters. |
||||
|
* |
||||
|
* @param precision The precision to use for convergence detection. |
||||
|
* @param maximalNumberOfIterations The maximal number of iterations do perform before iteration is aborted. |
||||
|
* @param relative If set, the relative error rather than the absolute error is considered for convergence |
||||
|
* detection. |
||||
|
*/ |
||||
|
TopologicalValueIterationNondeterministicLinearEquationSolver(double precision, uint_fast64_t maximalNumberOfIterations, bool relative = true); |
||||
|
|
||||
|
virtual NondeterministicLinearEquationSolver<ValueType>* clone() const override; |
||||
|
|
||||
|
virtual void solveEquationSystem(bool minimize, storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<ValueType>* multiplyResult = nullptr, std::vector<ValueType>* newX = nullptr) const override; |
||||
|
}; |
||||
|
} // namespace solver |
||||
|
} // namespace storm |
||||
|
|
||||
|
#endif /* STORM_SOLVER_NATIVENONDETERMINISTICLINEAREQUATIONSOLVER_H_ */ |
@ -0,0 +1,197 @@ |
|||||
|
#include "src/solver/TopologicalValueIterationNativeNondeterministicLinearEquationSolver.h"
|
||||
|
|
||||
|
#include <utility>
|
||||
|
|
||||
|
#include "src/settings/Settings.h"
|
||||
|
#include "src/utility/vector.h"
|
||||
|
|
||||
|
namespace storm { |
||||
|
namespace solver { |
||||
|
|
||||
|
template<typename ValueType> |
||||
|
TopologicalValueIterationNondeterministicLinearEquationSolver<ValueType>::TopologicalValueIterationNondeterministicLinearEquationSolver() { |
||||
|
// // Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template<typename ValueType> |
||||
|
TopologicalValueIterationNondeterministicLinearEquationSolver<ValueType>::TopologicalValueIterationNondeterministicLinearEquationSolver(double precision, uint_fast64_t maximalNumberOfIterations, bool relative) : NativeNondeterministicLinearEquationSolver<ValueType>(precision, maximalNumberOfIterations, relative) { |
||||
|
// Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template<typename ValueType> |
||||
|
TopologicalValueIterationNondeterministicLinearEquationSolver<ValueType>* TopologicalValueIterationNondeterministicLinearEquationSolver<ValueType>::clone() const { |
||||
|
return new NativeNondeterministicLinearEquationSolver<ValueType>(*this); |
||||
|
} |
||||
|
|
||||
|
template<typename ValueType> |
||||
|
void TopologicalValueIterationNondeterministicLinearEquationSolver<ValueType>::solveEquationSystem(bool minimize, storm::storage::SparseMatrix<ValueType> const& A, std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<uint_fast64_t> const& nondeterministicChoiceIndices, std::vector<ValueType>* multiplyResult, std::vector<ValueType>* newX) const { |
||||
|
|
||||
|
// Now, we need to determine the SCCs of the MDP and a topological sort.
|
||||
|
std::vector<std::vector<uint_fast64_t>> stronglyConnectedComponents = storm::utility::graph::performSccDecomposition(this->getModel(), stronglyConnectedComponents, stronglyConnectedComponentsDependencyGraph); |
||||
|
storm::storage::SparseMatrix<T> stronglyConnectedComponentsDependencyGraph = this->getModel().extractSccDependencyGraph(stronglyConnectedComponents); |
||||
|
std::vector<uint_fast64_t> topologicalSort = storm::utility::graph::getTopologicalSort(stronglyConnectedComponentsDependencyGraph); |
||||
|
|
||||
|
// Set up the environment for the power method.
|
||||
|
bool multiplyResultMemoryProvided = true; |
||||
|
if (multiplyResult == nullptr) { |
||||
|
multiplyResult = new std::vector<ValueType>(A.getRowCount()); |
||||
|
multiplyResultMemoryProvided = false; |
||||
|
} |
||||
|
std::vector<ValueType>* currentX = &x; |
||||
|
bool xMemoryProvided = true; |
||||
|
if (newX == nullptr) { |
||||
|
newX = new std::vector<ValueType>(x.size()); |
||||
|
xMemoryProvided = false; |
||||
|
} |
||||
|
std::vector<ValueType>* swap = nullptr; |
||||
|
uint_fast64_t currentMaxLocalIterations = 0; |
||||
|
uint_fast64_t localIterations = 0; |
||||
|
uint_fast64_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 = topologicalSort.begin(); sccIndexIt != topologicalSort.end() && converged; ++sccIndexIt) { |
||||
|
std::vector<uint_fast64_t> const& scc = stronglyConnectedComponents[*sccIndexIt]; |
||||
|
|
||||
|
// For the current SCC, we need to perform value iteration until convergence.
|
||||
|
localIterations = 0; |
||||
|
converged = false; |
||||
|
while (!converged && localIterations < maxIterations) { |
||||
|
// Compute x' = A*x + b.
|
||||
|
matrix.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.
|
||||
|
if (minimize) { |
||||
|
storm::utility::reduceVectorMin(*multiplyResult, *newX, scc, nondeterministicChoiceIndices); |
||||
|
} |
||||
|
else { |
||||
|
storm::utility::reduceVectorMax(*multiplyResult, *newX, scc, nondeterministicChoiceIndices); |
||||
|
} |
||||
|
|
||||
|
// 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::equalModuloPrecision(*currentX, *newX, precision, relative); |
||||
|
|
||||
|
// Update environment variables.
|
||||
|
swap = currentX; |
||||
|
currentX = newX; |
||||
|
newX = swap; |
||||
|
++localIterations; |
||||
|
++globalIterations; |
||||
|
} |
||||
|
|
||||
|
// 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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If we performed an odd number of global iterations, we need to swap the x and currentX, because the newest
|
||||
|
// result is currently stored in currentX, but x is the output vector.
|
||||
|
// TODO: Check whether this is correct or should be put into the for-loop over SCCs.
|
||||
|
if (globalIterations % 2 == 1) { |
||||
|
std::swap(x, *currentX); |
||||
|
} |
||||
|
|
||||
|
if (!xMemoryProvided) { |
||||
|
delete copyX; |
||||
|
} |
||||
|
|
||||
|
if (!multiplyResultMemoryProvided) { |
||||
|
delete multiplyResult; |
||||
|
} |
||||
|
|
||||
|
// Check if the solver converged and issue a warning otherwise.
|
||||
|
if (converged) { |
||||
|
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << currentMaxLocalIterations << " iterations."); |
||||
|
} |
||||
|
else { |
||||
|
LOG4CPLUS_WARN(logger, "Iterative solver did not converged after " << currentMaxLocalIterations << " iterations."); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
|
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
// Set up the environment for the power method. If scratch memory was not provided, we need to create it.
|
||||
|
bool multiplyResultMemoryProvided = true; |
||||
|
if (multiplyResult == nullptr) { |
||||
|
multiplyResult = new std::vector<ValueType>(A.getRowCount()); |
||||
|
multiplyResultMemoryProvided = false; |
||||
|
} |
||||
|
std::vector<ValueType>* currentX = &x; |
||||
|
bool xMemoryProvided = true; |
||||
|
if (newX == nullptr) { |
||||
|
newX = new std::vector<ValueType>(x.size()); |
||||
|
xMemoryProvided = false; |
||||
|
} |
||||
|
std::vector<ValueType>* swap = nullptr; |
||||
|
uint_fast64_t iterations = 0; |
||||
|
bool converged = false; |
||||
|
|
||||
|
// Keep track of which of the vectors for x is the auxiliary copy.
|
||||
|
std::vector<ValueType>* copyX = newX; |
||||
|
|
||||
|
// Proceed with the iterations as long as the method did not converge or reach the
|
||||
|
// user-specified maximum number of iterations.
|
||||
|
while (!converged && iterations < maximalNumberOfIterations) { |
||||
|
// Compute x' = A*x + b.
|
||||
|
A.multiplyWithVector(*currentX, *multiplyResult); |
||||
|
storm::utility::vector::addVectorsInPlace(*multiplyResult, b); |
||||
|
|
||||
|
// 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.
|
||||
|
if (minimize) { |
||||
|
storm::utility::vector::reduceVectorMin(*multiplyResult, *newX, nondeterministicChoiceIndices); |
||||
|
} else { |
||||
|
storm::utility::vector::reduceVectorMax(*multiplyResult, *newX, nondeterministicChoiceIndices); |
||||
|
} |
||||
|
|
||||
|
// Determine whether the method converged.
|
||||
|
converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative); |
||||
|
|
||||
|
// Update environment variables.
|
||||
|
std::swap(currentX, newX); |
||||
|
++iterations; |
||||
|
} |
||||
|
|
||||
|
// Check if the solver converged and issue a warning otherwise.
|
||||
|
if (converged) { |
||||
|
LOG4CPLUS_INFO(logger, "Iterative solver converged after " << iterations << " iterations."); |
||||
|
} else { |
||||
|
LOG4CPLUS_WARN(logger, "Iterative solver did not converge after " << iterations << " iterations."); |
||||
|
} |
||||
|
|
||||
|
// If we performed an odd number of iterations, we need to swap the x and currentX, because the newest result
|
||||
|
// is currently stored in currentX, but x is the output vector.
|
||||
|
if (currentX == copyX) { |
||||
|
std::swap(x, *currentX); |
||||
|
} |
||||
|
|
||||
|
if (!xMemoryProvided) { |
||||
|
delete copyX; |
||||
|
} |
||||
|
|
||||
|
if (!multiplyResultMemoryProvided) { |
||||
|
delete multiplyResult; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Explicitly instantiate the solver.
|
||||
|
template class TopologicalValueIterationNondeterministicLinearEquationSolver<double>; |
||||
|
} // namespace solver
|
||||
|
} // namespace storm
|
@ -0,0 +1,224 @@ |
|||||
|
#include "gtest/gtest.h"
|
||||
|
#include "storm-config.h"
|
||||
|
|
||||
|
#include "src/solver/NativeNondeterministicLinearEquationSolver.h"
|
||||
|
#include "src/settings/Settings.h"
|
||||
|
#include "src/modelchecker/prctl/SparseMdpPrctlModelChecker.h"
|
||||
|
#include "src/modelchecker/prctl/TopologicalValueIterationMdpPrctlModelChecker.h"
|
||||
|
#include "src/parser/AutoParser.h"
|
||||
|
|
||||
|
TEST(TopologicalValueIterationMdpPrctlModelCheckerTest, Dice) { |
||||
|
storm::settings::Settings* s = storm::settings::Settings::getInstance(); |
||||
|
storm::parser::AutoParser<double> parser(STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.tra", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.lab", "", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.flip.trans.rew"); |
||||
|
|
||||
|
ASSERT_EQ(parser.getType(), storm::models::MDP); |
||||
|
|
||||
|
std::shared_ptr<storm::models::Mdp<double>> mdp = parser.getModel<storm::models::Mdp<double>>(); |
||||
|
|
||||
|
ASSERT_EQ(mdp->getNumberOfStates(), 169ull); |
||||
|
ASSERT_EQ(mdp->getNumberOfTransitions(), 436ull); |
||||
|
|
||||
|
storm::modelchecker::prctl::TopologicalValueIterationMdpPrctlModelChecker<double> mc(*mdp); |
||||
|
|
||||
|
storm::property::prctl::Ap<double>* apFormula = new storm::property::prctl::Ap<double>("two"); |
||||
|
storm::property::prctl::Eventually<double>* eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
storm::property::prctl::ProbabilisticNoBoundOperator<double>* probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, true); |
||||
|
|
||||
|
std::vector<double> result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0277777612209320068), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("two"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0277777612209320068), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("three"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, true); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0555555224418640136), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("three"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0555555224418640136), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("four"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, true); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.083333283662796020508), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("four"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.083333283662796020508), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
storm::property::prctl::ReachabilityReward<double>* reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
storm::property::prctl::RewardNoBoundOperator<double>* rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, true); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*rewardFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 7.333329499), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*rewardFormula);; |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 7.333329499), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
storm::parser::AutoParser<double> stateRewardParser(STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.tra", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.lab", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.flip.state.rew", ""); |
||||
|
|
||||
|
ASSERT_EQ(stateRewardParser.getType(), storm::models::MDP); |
||||
|
|
||||
|
std::shared_ptr<storm::models::Mdp<double>> stateRewardMdp = stateRewardParser.getModel<storm::models::Mdp<double>>(); |
||||
|
|
||||
|
storm::modelchecker::prctl::SparseMdpPrctlModelChecker<double> stateRewardModelChecker(*stateRewardMdp, std::shared_ptr<storm::solver::NativeNondeterministicLinearEquationSolver<double>>(new storm::solver::NativeNondeterministicLinearEquationSolver<double>())); |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, true); |
||||
|
|
||||
|
result = stateRewardModelChecker.checkNoBoundOperator(*rewardFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 7.333329499), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, false); |
||||
|
|
||||
|
result = stateRewardModelChecker.checkNoBoundOperator(*rewardFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 7.333329499), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
storm::parser::AutoParser<double> stateAndTransitionRewardParser(STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.tra", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.lab", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.flip.state.rew", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.flip.trans.rew"); |
||||
|
|
||||
|
ASSERT_EQ(stateAndTransitionRewardParser.getType(), storm::models::MDP); |
||||
|
|
||||
|
std::shared_ptr<storm::models::Mdp<double>> stateAndTransitionRewardMdp = stateAndTransitionRewardParser.getModel<storm::models::Mdp<double>>(); |
||||
|
|
||||
|
storm::modelchecker::prctl::SparseMdpPrctlModelChecker<double> stateAndTransitionRewardModelChecker(*stateAndTransitionRewardMdp, std::shared_ptr<storm::solver::NativeNondeterministicLinearEquationSolver<double>>(new storm::solver::NativeNondeterministicLinearEquationSolver<double>())); |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, true); |
||||
|
|
||||
|
result = stateAndTransitionRewardModelChecker.checkNoBoundOperator(*rewardFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 14.666658998), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("done"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, false); |
||||
|
|
||||
|
result = stateAndTransitionRewardModelChecker.checkNoBoundOperator(*rewardFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 14.666658998), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
} |
||||
|
|
||||
|
TEST(TopologicalValueIterationMdpPrctlModelCheckerTest, AsynchronousLeader) { |
||||
|
storm::settings::Settings* s = storm::settings::Settings::getInstance(); |
||||
|
storm::parser::AutoParser<double> parser(STORM_CPP_BASE_PATH "/examples/mdp/asynchronous_leader/leader4.tra", STORM_CPP_BASE_PATH "/examples/mdp/asynchronous_leader/leader4.lab", "", STORM_CPP_BASE_PATH "/examples/mdp/asynchronous_leader/leader4.trans.rew"); |
||||
|
|
||||
|
ASSERT_EQ(parser.getType(), storm::models::MDP); |
||||
|
|
||||
|
std::shared_ptr<storm::models::Mdp<double>> mdp = parser.getModel<storm::models::Mdp<double>>(); |
||||
|
|
||||
|
ASSERT_EQ(mdp->getNumberOfStates(), 3172ull); |
||||
|
ASSERT_EQ(mdp->getNumberOfTransitions(), 7144ull); |
||||
|
|
||||
|
storm::modelchecker::prctl::TopologicalValueIterationMdpPrctlModelChecker<double> mc(*mdp); |
||||
|
|
||||
|
storm::property::prctl::Ap<double>* apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
storm::property::prctl::Eventually<double>* eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
storm::property::prctl::ProbabilisticNoBoundOperator<double>* probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, true); |
||||
|
|
||||
|
std::vector<double> result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 1), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
eventuallyFormula = new storm::property::prctl::Eventually<double>(apFormula); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(eventuallyFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 1), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
storm::property::prctl::BoundedEventually<double>* boundedEventuallyFormula = new storm::property::prctl::BoundedEventually<double>(apFormula, 25); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(boundedEventuallyFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0625), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
boundedEventuallyFormula = new storm::property::prctl::BoundedEventually<double>(apFormula, 25); |
||||
|
probFormula = new storm::property::prctl::ProbabilisticNoBoundOperator<double>(boundedEventuallyFormula, true); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*probFormula); |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 0.0625), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
|
||||
|
delete probFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
storm::property::prctl::ReachabilityReward<double>* reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
storm::property::prctl::RewardNoBoundOperator<double>* rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, true); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*rewardFormula);; |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 4.285689611), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
|
||||
|
apFormula = new storm::property::prctl::Ap<double>("elected"); |
||||
|
reachabilityRewardFormula = new storm::property::prctl::ReachabilityReward<double>(apFormula); |
||||
|
rewardFormula = new storm::property::prctl::RewardNoBoundOperator<double>(reachabilityRewardFormula, false); |
||||
|
|
||||
|
result = mc.checkNoBoundOperator(*rewardFormula);; |
||||
|
|
||||
|
ASSERT_LT(std::abs(result[0] - 4.285689611), s->getOptionByLongName("precision").getArgument(0).getValueAsDouble()); |
||||
|
delete rewardFormula; |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue