#include "src/generator/DftNextStateGenerator.h" #include "src/utility/constants.h" #include "src/utility/macros.h" #include "src/exceptions/NotImplementedException.h" namespace storm { namespace generator { template DftNextStateGenerator::DftNextStateGenerator(storm::storage::DFT const& dft, storm::storage::DFTStateGenerationInfo const& stateGenerationInfo, bool enableDC, bool mergeFailedStates) : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), enableDC(enableDC), mergeFailedStates(mergeFailedStates), comparator() { deterministicModel = !mDft.canHaveNondeterminism(); } template bool DftNextStateGenerator::isDeterministicModel() const { return deterministicModel; } template std::vector DftNextStateGenerator::getInitialStates(StateToIdCallback const& stateToIdCallback) { DFTStatePointer initialState = std::make_shared>(mDft, mStateGenerationInfo, 0); // Register initial state StateType id = stateToIdCallback(initialState); initialState->setId(id); return {id}; } template void DftNextStateGenerator::load(DFTStatePointer const& state) { // TODO Matthias load state from bitvector // Store a pointer to the state itself, because we need to be able to access it when expanding it. this->state = &state; } template bool DftNextStateGenerator::satisfies(storm::expressions::Expression const& expression) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The method 'satisfies' is not yet implemented."); } template StateBehavior DftNextStateGenerator::expand(StateToIdCallback const& stateToIdCallback) { DFTStatePointer currentState = *state; STORM_LOG_TRACE("Explore state: " << mDft.getStateString(currentState)); // Prepare the result, in case we return early. StateBehavior result; // Initialization bool hasDependencies = currentState->nrFailableDependencies() > 0; size_t failableCount = hasDependencies ? currentState->nrFailableDependencies() : currentState->nrFailableBEs(); size_t currentFailable = 0; Choice choice(0, !hasDependencies); // Check for absorbing state if (mDft.hasFailed(currentState) || mDft.isFailsafe(currentState) || currentState->nrFailableBEs() == 0) { // Add self loop choice.addProbability(currentState->getId(), storm::utility::one()); STORM_LOG_TRACE("Added self loop for " << currentState->getId()); // No further exploration required result.addChoice(std::move(choice)); result.setExpanded(); return result; } // Let BE fail while (currentFailable < failableCount) { STORM_LOG_ASSERT(!mDft.hasFailed(currentState), "Dft has failed."); // Construct new state as copy from original one DFTStatePointer newState = std::make_shared>(*currentState); std::pair const>, bool> nextBEPair = newState->letNextBEFail(currentFailable); std::shared_ptr const>& nextBE = nextBEPair.first; STORM_LOG_ASSERT(nextBE, "NextBE is null."); STORM_LOG_ASSERT(nextBEPair.second == hasDependencies, "Failure due to dependencies does not match."); STORM_LOG_TRACE("With the failure of: " << nextBE->name() << " [" << nextBE->id() << "] in " << mDft.getStateString(currentState)); /*if (storm::settings::getModule().computeApproximation()) { if (!storm::utility::isZero(exitRate)) { ValueType rate = nextBE->activeFailureRate(); ValueType div = rate / exitRate; if (!storm::utility::isZero(exitRate) && belowThreshold(div)) { // Set transition directly to failed state auto resultFind = outgoingRates.find(failedIndex); if (resultFind != outgoingRates.end()) { // Add to existing transition resultFind->second += rate; STORM_LOG_TRACE("Updated transition to " << resultFind->first << " with rate " << rate << " to new rate " << resultFind->second); } else { // Insert new transition outgoingRates.insert(std::make_pair(failedIndex, rate)); STORM_LOG_TRACE("Added transition to " << failedIndex << " with rate " << rate); } exitRate += rate; std::cout << "IGNORE: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate << std::endl; //STORM_LOG_TRACE("Ignore: " << nextBE->name() << " [" << nextBE->id() << "] with rate " << rate); continue; } } }*/ // Propagate storm::storage::DFTStateSpaceGenerationQueues queues; // Propagate failure for (DFTGatePointer parent : nextBE->parents()) { if (newState->isOperational(parent->id())) { queues.propagateFailure(parent); } } // Propagate failures while (!queues.failurePropagationDone()) { DFTGatePointer next = queues.nextFailurePropagation(); next->checkFails(*newState, queues); newState->updateFailableDependencies(next->id()); } // Check restrictions for (DFTRestrictionPointer restr : nextBE->restrictions()) { queues.checkRestrictionLater(restr); } // Check restrictions while(!queues.restrictionChecksDone()) { DFTRestrictionPointer next = queues.nextRestrictionCheck(); next->checkFails(*newState, queues); newState->updateFailableDependencies(next->id()); } if(newState->isInvalid()) { // Continue with next possible state ++currentFailable; continue; } StateType newStateId; if (newState->hasFailed(mDft.getTopLevelIndex()) && mergeFailedStates) { // Use unique failed state newStateId = mergeFailedStateId; } else { // Propagate failsafe while (!queues.failsafePropagationDone()) { DFTGatePointer next = queues.nextFailsafePropagation(); next->checkFailsafe(*newState, queues); } // Propagate dont cares while (enableDC && !queues.dontCarePropagationDone()) { DFTElementPointer next = queues.nextDontCarePropagation(); next->checkDontCareAnymore(*newState, queues); } // Update failable dependencies newState->updateFailableDependencies(nextBE->id()); newState->updateDontCareDependencies(nextBE->id()); // Add new state newStateId = stateToIdCallback(newState); } // Set transitions if (hasDependencies) { // Failure is due to dependency -> add non-deterministic choice std::shared_ptr const> dependency = mDft.getDependency(currentState->getDependencyId(currentFailable)); choice.addProbability(newStateId, dependency->probability()); STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << dependency->probability()); if (!storm::utility::isOne(dependency->probability())) { // Add transition to state where dependency was unsuccessful DFTStatePointer unsuccessfulState = std::make_shared>(*currentState); unsuccessfulState->letDependencyBeUnsuccessful(currentFailable); // Add state StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState); ValueType remainingProbability = storm::utility::one() - dependency->probability(); choice.addProbability(unsuccessfulStateId, remainingProbability); STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability); } result.addChoice(std::move(choice)); } else { // Failure is due to "normal" BE failure // Set failure rate according to activation bool isActive = true; if (mDft.hasRepresentant(nextBE->id())) { // Active must be checked for the state we are coming from as this state is responsible for the // rate and not the new state we are going to isActive = currentState->isActive(mDft.getRepresentant(nextBE->id())->id()); } ValueType rate = isActive ? nextBE->activeFailureRate() : nextBE->passiveFailureRate(); STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Rate is 0."); choice.addProbability(newStateId, rate); STORM_LOG_TRACE("Added transition to " << newStateId << " with " << (isActive ? "active" : "passive") << " rate " << rate); } ++currentFailable; } // end while failing BE if (!hasDependencies) { // Add all rates as one choice result.addChoice(std::move(choice)); } STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(currentState)); result.setExpanded(); return result; } template StateBehavior DftNextStateGenerator::createMergeFailedState(StateToIdCallback const& stateToIdCallback) { STORM_LOG_ASSERT(mergeFailedStates, "No unique failed state used."); // Introduce explicit fail state DFTStatePointer failedState = std::make_shared>(mDft, mStateGenerationInfo, 0); mergeFailedStateId = stateToIdCallback(failedState); STORM_LOG_TRACE("Introduce fail state with id: " << mergeFailedStateId); // Add self loop Choice choice(0, true); choice.addProbability(mergeFailedStateId, storm::utility::one()); // No further exploration required StateBehavior result; result.addChoice(std::move(choice)); result.setExpanded(); return result; } template class DftNextStateGenerator; template class DftNextStateGenerator; } }