Browse Source

Implemented basis for handling invalid traces during simulation

tempestpy_adaptions
Matthias Volk 4 years ago
parent
commit
76afd5e3de
No known key found for this signature in database GPG Key ID: 83A57678F739FCD3
  1. 80
      src/storm-dft/simulator/DFTTraceSimulator.cpp
  2. 23
      src/storm-dft/simulator/DFTTraceSimulator.h
  3. 126
      src/test/storm-dft/simulator/DftSimulatorTest.cpp
  4. 8
      src/test/storm-dft/simulator/DftTraceGeneratorTest.cpp

80
src/storm-dft/simulator/DFTTraceSimulator.cpp

@ -85,25 +85,24 @@ namespace storm {
}
template<typename ValueType>
double DFTTraceSimulator<ValueType>::randomStep() {
std::pair<SimulationResult, double> DFTTraceSimulator<ValueType>::randomStep() {
auto retTuple = this->randomNextFailure();
storm::dft::storage::FailableElements::const_iterator nextFailable = std::get<0>(retTuple);
double time = std::get<1>(retTuple);
bool successful = std::get<2>(retTuple);
//double time = pairNextFailure.second;
if (time < 0) {
return -1;
return std::make_pair(SimulationResult::UNSUCCESSFUL, -1);
} else {
// Apply next failure
bool res = step(nextFailable, successful);
return res ? time : -1;
return std::make_pair(step(nextFailable, successful), time);
}
}
template<typename ValueType>
bool DFTTraceSimulator<ValueType>::step(storm::dft::storage::FailableElements::const_iterator nextFailElement, bool dependencySuccessful) {
SimulationResult DFTTraceSimulator<ValueType>::step(storm::dft::storage::FailableElements::const_iterator nextFailElement, bool dependencySuccessful) {
if (nextFailElement == state->getFailableElements().end()) {
return false;
// No next failure possible
return SimulationResult::UNSUCCESSFUL;
}
auto nextBEPair = nextFailElement.getFailBE(dft);
@ -111,40 +110,73 @@ namespace storm {
if(newState->isInvalid() || newState->isTransient()) {
STORM_LOG_TRACE("Step is invalid because new state " << (newState->isInvalid() ? "it is invalid" : "the transient fault is ignored"));
return false;
return SimulationResult::INVALID;
}
state = newState;
return true;
return SimulationResult::SUCCESSFUL;
}
template<typename ValueType>
bool DFTTraceSimulator<ValueType>::simulateCompleteTrace(double timebound) {
SimulationResult DFTTraceSimulator<ValueType>::simulateCompleteTrace(double timebound) {
resetToInitial();
// Check whether DFT is initially already failed.
if (state->hasFailed(dft.getTopLevelIndex())) {
STORM_LOG_TRACE("DFT is initially failed");
return SimulationResult::SUCCESSFUL;
}
double time = 0;
while (time <= timebound) {
// Check whether DFT failed within timebound
if (state->hasFailed(dft.getTopLevelIndex())) {
STORM_LOG_TRACE("DFT has failed after " << time);
return true;
// Generate next failure
auto retTuple = randomNextFailure();
storm::dft::storage::FailableElements::const_iterator nextFailable = std::get<0>(retTuple);
double addTime = std::get<1>(retTuple);
bool successfulDependency = std::get<2>(retTuple);
if (addTime < 0) {
// No next state can be reached, because no element can fail anymore.
STORM_LOG_TRACE("No next state possible in state " << dft.getStateString(state) << " because no element can fail anymore");
return SimulationResult::UNSUCCESSFUL;
}
// Generate next state
double res = randomStep();
// TODO: exit if time would be up after this failure
// This is only correct if no invalid states are possible! (no restrictors and no transient failures)
// Apply next failure
auto stepResult = step(nextFailable, successfulDependency);
STORM_LOG_TRACE("Current state: " << dft.getStateString(state));
if (res < 0) {
// No next state can be reached
STORM_LOG_TRACE("No next state possible in state " << dft.getStateString(state));
return false;
// Check whether state is invalid
if (stepResult != SimulationResult::SUCCESSFUL) {
STORM_LOG_ASSERT(stepResult == SimulationResult::INVALID, "Result of simulation step should be invalid.");
// No next state can be reached, because the state is invalid.
STORM_LOG_TRACE("No next state possible in state " << dft.getStateString(state) << " because simulation was invalid");
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Handling of invalid states is not supported for simulation");
return SimulationResult::INVALID;
}
// Check whether time is up
// Checking whether the time is up must be performed after checking if a state is invalid.
// Otherwise we would erroneously mark invalid traces as unsucessful.
time += addTime;
if (time > timebound) {
STORM_LOG_TRACE("Time limit" << timebound << " exceeded: " << time);
return SimulationResult::UNSUCCESSFUL;
}
// Check whether DFT is failed
if (state->hasFailed(dft.getTopLevelIndex())) {
STORM_LOG_TRACE("DFT has failed after " << time);
return SimulationResult::SUCCESSFUL;
}
time += res;
}
// Time is up
return false;
STORM_LOG_ASSERT(false, "Should not be reachable");
return SimulationResult::UNSUCCESSFUL;
}
template<>
bool DFTTraceSimulator<storm::RationalFunction>::simulateCompleteTrace(double timebound) {
SimulationResult DFTTraceSimulator<storm::RationalFunction>::simulateCompleteTrace(double timebound) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Simulation not support for parametric DFTs.");
}

23
src/storm-dft/simulator/DFTTraceSimulator.h

@ -10,6 +10,12 @@ namespace storm {
namespace dft {
namespace simulator {
/*!
* Simulation result.
*
*/
enum class SimulationResult { SUCCESSFUL, UNSUCCESSFUL, INVALID };
/*!
* Simulator for DFTs.
* A step in the simulation corresponds to the failure of one BE (either on its own or triggered by a dependency)
@ -19,6 +25,7 @@ namespace storm {
template<typename ValueType>
class DFTTraceSimulator {
using DFTStatePointer = std::shared_ptr<storm::storage::DFTState<ValueType>>;
public:
/*!
* Constructor.
@ -54,9 +61,9 @@ namespace storm {
* @param nextFailElement Iterator giving the next element which should fail.
* @param dependencySuccessful Whether the triggering dependency was successful.
* If the dependency is unsuccessful, no BE fails and only the depedendy is marked as failed.
* @return True iff step could be performed successfully.
* @return Successful if step could be performed, unsuccesful if no element can fail or invalid if the next state is invalid (due to a restrictor).
*/
bool step(storm::dft::storage::FailableElements::const_iterator nextFailElement, bool dependencySuccessful = true);
SimulationResult step(storm::dft::storage::FailableElements::const_iterator nextFailElement, bool dependencySuccessful = true);
/*!
* Randomly pick an element which fails next (either a BE or a dependency which triggers a BE) and the time after which it fails.
@ -70,20 +77,22 @@ namespace storm {
/*!
* Perform a random step by using the random number generator.
*
* @return double The time which progessed between the last step and this step.
* Returns -1 if no next step could be created.
* @return Pair of the simulation result (successful, unsuccesful, invalid) and the time which progessed between the last step and this step.
*/
double randomStep();
std::pair<SimulationResult, double> randomStep();
/*!
* Perform a complete simulation of a failure trace by using the random number generator.
* The simulation starts in the initial state and tries to reach a state where the top-level event of the DFT has failed.
* If this target state can be reached within the given timebound, the simulation was successful.
* If an invalid state (due to a restrictor) was reached, the simulated trace is invalid.
*
* @param timebound Time bound in which the system failure should occur.
* @return True iff a system failure occurred for the generated trace within the time bound.
* @return Simulation result is (1) successful if a system failure occurred for the generated trace within the time bound,
* (2) unsuccesfull, if no system failure occurred within the time bound, or
* (3) invalid, if an invalid state (due to a restrictor) was reached during the trace generation.
*/
bool simulateCompleteTrace(double timebound);
SimulationResult simulateCompleteTrace(double timebound);
protected:

126
src/test/storm-dft/simulator/DftSimulatorTest.cpp

@ -10,8 +10,8 @@
namespace {
// Helper function
double simulateDft(std::string const& file, double timebound, size_t noRuns) {
// Helper functions
std::pair<double, double> simulateDft(std::string const& file, double timebound, size_t noRuns) {
// Load, build and prepare DFT
storm::transformations::dft::DftTransformator<double> dftTransformator = storm::transformations::dft::DftTransformator<double>();
std::shared_ptr<storm::storage::DFT<double>> dft = dftTransformator.transformBinaryFDEPs(*(storm::api::loadDFTGalileoFile<double>(file)));
@ -27,104 +27,162 @@ namespace {
storm::storage::DFTStateGenerationInfo stateGenerationInfo(dft->buildStateGenerationInfo(symmetries));
// Init random number generator
//storm::utility::setLogLevel(l3pp::LogLevel::TRACE);
boost::mt19937 gen(5u);
storm::dft::simulator::DFTTraceSimulator<double> simulator(*dft, stateGenerationInfo, gen);
size_t count = 0;;
bool res;
size_t count = 0;
size_t invalid = 0;
storm::dft::simulator::SimulationResult res;
for (size_t i=0; i<noRuns; ++i) {
res = simulator.simulateCompleteTrace(timebound);
if (res) {
if (res == storm::dft::simulator::SimulationResult::SUCCESSFUL) {
++count;
} else if (res == storm::dft::simulator::SimulationResult::INVALID) {
// Discard invalid traces
++invalid;
}
}
return std::make_pair(count, invalid);
}
double simulateDftProb(std::string const& file, double timebound, size_t noRuns) {
size_t count;
size_t invalid;
std::tie(count, invalid) = simulateDft(file, timebound, noRuns);
EXPECT_EQ(invalid, 0);
return (double) count / noRuns;
}
TEST(DftSimulatorTest, AndUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/and.dft", 2, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/and.dft", 2, 10000);
EXPECT_NEAR(result, 0.3995764009, 0.01);
}
TEST(DftSimulatorTest, OrUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/or.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/or.dft", 1, 10000);
EXPECT_NEAR(result, 0.6321205588, 0.01);
}
TEST(DftSimulatorTest, VotingUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/voting.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/voting.dft", 1, 10000);
EXPECT_NEAR(result, 0.4511883639, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/voting2.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/voting2.dft", 1, 10000);
EXPECT_NEAR(result, 0.8173164759, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/voting3.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/voting3.dft", 1, 10000);
EXPECT_NEAR(result, 0.3496529873, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/voting4.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/voting4.dft", 1, 10000);
EXPECT_NEAR(result, 0.693568287, 0.01);
}
TEST(DftSimulatorTest, PandUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/pand.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/pand.dft", 1, 10000);
EXPECT_NEAR(result, 0.03087312562, 0.01);
}
TEST(DftSimulatorTest, PorUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/por.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/por.dft", 1, 10000);
EXPECT_NEAR(result, 0.2753355179, 0.01);
}
TEST(DftSimulatorTest, FdepUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep.dft", 1, 10000);
EXPECT_NEAR(result, 0.7768698399, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep2.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep2.dft", 1, 10000);
EXPECT_NEAR(result, 0.3934693403, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep3.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep3.dft", 1, 10000);
EXPECT_NEAR(result, 0.329679954, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep4.dft", 1, 10000);
EXPECT_NEAR(result, 0.601280086, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep5.dft", 1, 10000);
EXPECT_NEAR(result, 0.1548181217, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/fdep6.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/fdep6.dft", 1, 10000);
EXPECT_NEAR(result, 0.9985116987, 0.01);
}
TEST(DftSimulatorTest, PdepUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/pdep.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/pdep.dft", 1, 10000);
EXPECT_NEAR(result, 0.2017690905, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/pdep2.dft", 1, 10000);
EXPECT_NEAR(result, 0.2401091405, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/pdep3.dft", 1, 10000);
EXPECT_NEAR(result, 0.2259856274, 0.01);
// Examle pdep4 contains non-determinism which is not handled in simulation
//result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft", 1, 10000);
// Example pdep4 contains non-determinism which is not handled in simulation
//result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/pdep4.dft", 1, 10000);
//EXPECT_NEAR(result, 0.008122157897, 0.01);
}
TEST(DftSimulatorTest, SpareUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare.dft", 1, 10000);
EXPECT_NEAR(result, 0.1118530638, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare2.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare2.dft", 1, 10000);
EXPECT_NEAR(result, 0.2905027469, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare3.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare3.dft", 1, 10000);
EXPECT_NEAR(result, 0.4660673246, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare4.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare4.dft", 1, 10000);
EXPECT_NEAR(result, 0.01273070783, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare5.dft", 1, 10000);
EXPECT_NEAR(result, 0.2017690905, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare6.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare6.dft", 1, 10000);
EXPECT_NEAR(result, 0.4693712702, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare7.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare7.dft", 1, 10000);
EXPECT_NEAR(result, 0.06108774525, 0.01);
result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/spare8.dft", 1, 10000);
result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/spare8.dft", 1, 10000);
EXPECT_NEAR(result, 0.02686144489, 0.01);
}
TEST(DftSimulatorTest, SeqUnreliability) {
size_t count;
size_t invalid;
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
double result = (double) count / 10000;
EXPECT_NEAR(result, 0.09020401043, 0.01);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq2.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
result = (double) count / 10000;
EXPECT_NEAR(result, 0.01438767797, 0.01);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq3.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
result = (double) count / 10000;
EXPECT_NEAR(result, 0.01438767797, 0.01);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq4.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
result = (double) count / 10000;
EXPECT_NEAR(result, 0.01438767797, 0.01);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq5.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
result = (double) count / 10000;
EXPECT_FLOAT_EQ(result, 0);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/seq6.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
result = (double) count / 10000;
EXPECT_NEAR(result, 2.499875004e-09, 0.01);
}
TEST(DftSimulatorTest, MutexUnreliability) {
size_t count;
size_t invalid;
// Invalid states are currently not supported
EXPECT_THROW(simulateDft(STORM_TEST_RESOURCES_DIR "/dft/mutex.dft", 1, 10000), storm::exceptions::NotSupportedException);
//EXPECT_GE(invalid, 0);
//double result = (double) count / (10000 - invalid);
//EXPECT_NEAR(result, 0.8646647168, 0.01);
EXPECT_THROW(simulateDft(STORM_TEST_RESOURCES_DIR "/dft/mutex2.dft", 1, 10000), storm::exceptions::NotSupportedException);
//EXPECT_EQ(invalid, 10000);
//EXPECT_EQ(count, 0);
std::tie(count, invalid) = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/mutex3.dft", 1, 10000);
EXPECT_EQ(invalid, 0);
EXPECT_EQ(count, 0);
}
TEST(DftSimulatorTest, SymmetryUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/symmetry6.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/symmetry6.dft", 1, 10000);
EXPECT_NEAR(result, 0.3421934224, 0.01);
}
TEST(DftSimulatorTest, HecsUnreliability) {
double result = simulateDft(STORM_TEST_RESOURCES_DIR "/dft/hecs_2_2.dft", 1, 10000);
double result = simulateDftProb(STORM_TEST_RESOURCES_DIR "/dft/hecs_2_2.dft", 1, 10000);
EXPECT_NEAR(result, 0.00021997582, 0.001);
}

8
src/test/storm-dft/simulator/DftTraceGeneratorTest.cpp

@ -173,8 +173,11 @@ namespace {
auto state = simulator.getCurrentState();
EXPECT_FALSE(state->hasFailed(dft->getTopLevelIndex()));
storm::dft::simulator::SimulationResult res;
double timebound;
// First random step
double timebound = simulator.randomStep();
std::tie(res, timebound) = simulator.randomStep();
EXPECT_EQ(res, storm::dft::simulator::SimulationResult::SUCCESSFUL);
#if BOOST_VERSION > 106400
// Older Boost versions yield different value
EXPECT_FLOAT_EQ(timebound, 0.522079);
@ -182,7 +185,8 @@ namespace {
state = simulator.getCurrentState();
EXPECT_FALSE(state->hasFailed(dft->getTopLevelIndex()));
timebound = simulator.randomStep();
std::tie(res, timebound) = simulator.randomStep();
EXPECT_EQ(res, storm::dft::simulator::SimulationResult::SUCCESSFUL);
#if BOOST_VERSION > 106400
// Older Boost versions yield different value
EXPECT_FLOAT_EQ(timebound, 0.9497214);

Loading…
Cancel
Save