Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
DftNextStateGenerator.cpp
Go to the documentation of this file.
2
9
10namespace storm::dft {
11namespace generator {
12
13template<typename ValueType, typename StateType>
15 storm::dft::storage::DFTStateGenerationInfo const& stateGenerationInfo)
16 : mDft(dft), mStateGenerationInfo(stateGenerationInfo), state(nullptr), uniqueFailedState(false) {
17 deterministicModel = !mDft.canHaveNondeterminism();
18 mTakeFirstDependency = storm::settings::getModule<storm::dft::settings::modules::FaultTreeSettings>().isTakeFirstDependency();
19}
20
21template<typename ValueType, typename StateType>
23 return deterministicModel;
24}
25
26template<typename ValueType, typename StateType>
27typename DftNextStateGenerator<ValueType, StateType>::DFTStatePointer DftNextStateGenerator<ValueType, StateType>::createInitialState() const {
28 DFTStatePointer initialState = std::make_shared<storm::dft::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
30 // Check whether constant failed BEs are present
31 if (mStateGenerationInfo.immediateFailedBE().size() > 0) {
32 STORM_LOG_THROW(mStateGenerationInfo.immediateFailedBE().size() < 2, storm::exceptions::NotSupportedException,
33 "DFTs with more than one constantly failed BE are not supported. Transform DFT to contain a unique failed BE.");
34 // Propagate the constant failure to reach the real initial state
35 auto constFailedBE = mDft.getBasicElement(mStateGenerationInfo.immediateFailedBE().front());
36 initialState = createSuccessorState(initialState, constFailedBE);
37 }
38
39 return initialState;
40}
41
42template<typename ValueType, typename StateType>
44 DFTStatePointer initialState = createInitialState();
45 // Register initial state
46 auto [id, shouldStop] = getNewStateId(initialState, stateToIdCallback);
47 initialState->setId(id);
48 STORM_LOG_THROW(!shouldStop, storm::exceptions::InvalidModelException, "Initial state is already invalid due to a restriction.");
49 return {id};
50}
51
52template<typename ValueType, typename StateType>
54 // Load the state from bitvector
55 StateType id = 0; // TODO: set correct id
56 this->state = std::make_shared<storm::dft::storage::DFTState<ValueType>>(state, mDft, mStateGenerationInfo, id);
57}
58
59template<typename ValueType, typename StateType>
60void DftNextStateGenerator<ValueType, StateType>::load(DFTStatePointer const& state) {
61 // Store a pointer to the state itself, because we need to be able to access it when expanding it.
62 this->state = state;
63}
64
65template<typename ValueType, typename StateType>
67 STORM_LOG_DEBUG("Explore state: " << mDft.getStateString(state));
68 // Initialization
69 bool hasDependencies = this->state->getFailableElements().hasDependencies();
70 return exploreState(stateToIdCallback, hasDependencies, mTakeFirstDependency);
71}
72
73template<typename ValueType, typename StateType>
74storm::generator::StateBehavior<ValueType, StateType> DftNextStateGenerator<ValueType, StateType>::exploreState(StateToIdCallback const& stateToIdCallback,
75 bool exploreDependencies,
76 bool takeFirstDependency) {
77 // Prepare the result, in case we return early.
79
80 STORM_LOG_TRACE("Currently failable: " << state->getFailableElements().getCurrentlyFailableString(!exploreDependencies));
81 auto iterFailable = this->state->getFailableElements().begin(!exploreDependencies);
82
83 // Check for absorbing state:
84 // - either no relevant event remains (i.e., all relevant events have failed already), or
85 // - no BE can fail
86 if (!this->state->hasOperationalRelevantEvent() || iterFailable == this->state->getFailableElements().end(!exploreDependencies)) {
88 // Add self loop
89 choice.addProbability(this->state->getId(), storm::utility::one<ValueType>());
90 STORM_LOG_TRACE("Added self loop for " << state->getId());
91 // No further exploration required
92 result.addChoice(std::move(choice));
93 result.setExpanded();
94 return result;
95 }
96
97 storm::generator::Choice<ValueType, StateType> choice(0, !exploreDependencies);
99 // Let BE fail
100 for (; iterFailable != this->state->getFailableElements().end(!exploreDependencies); ++iterFailable) {
101 DFTStatePointer newState;
102 if (iterFailable.isFailureDueToDependency()) {
103 // Next failure due to dependency
104 STORM_LOG_ASSERT(exploreDependencies, "Failure should be due to dependency.");
105 std::shared_ptr<storm::dft::storage::elements::DFTDependency<ValueType> const> dependency = iterFailable.asDependency(mDft);
106 // Obtain successor state by propagating dependency failure to dependent BE
107 newState = createSuccessorState(this->state, dependency, true);
108
109 auto [newStateId, shouldStop] = getNewStateId(newState, stateToIdCallback);
110 if (shouldStop) {
111 continue;
112 }
113 STORM_LOG_ASSERT(newStateId != this->state->getId(),
114 "Self loop was added for " << newStateId << " and successful trigger of " << dependency->name());
115
116 // Add non-deterministic choice if necessary
117 ValueType probability = dependency->probability();
118 choice.addProbability(newStateId, probability);
119 STORM_LOG_TRACE("Added transition to " << newStateId << " with probability " << probability);
120
121 if (!storm::utility::isOne(probability)) {
122 // Add transition to state where dependency was unsuccessful
123 DFTStatePointer unsuccessfulState = createSuccessorState(this->state, dependency, false);
124 // Add state
125 StateType unsuccessfulStateId = stateToIdCallback(unsuccessfulState);
126 ValueType remainingProbability = storm::utility::one<ValueType>() - probability;
127 choice.addProbability(unsuccessfulStateId, remainingProbability);
128 STORM_LOG_TRACE("Added transition to " << unsuccessfulStateId << " with remaining probability " << remainingProbability);
129 STORM_LOG_ASSERT(unsuccessfulStateId != this->state->getId(),
130 "Self loop was added for " << unsuccessfulStateId << " and unsuccessful trigger of " << dependency->name());
131 }
132 result.addChoice(std::move(choice));
133 // Start a fresh choice for the next conflicting dependency.
134 choice = storm::generator::Choice<ValueType, StateType>(0, !exploreDependencies);
135
136 // Handle premature stop for dependencies
137 if (!iterFailable.isConflictingDependency()) {
138 // We only explore the first non-conflicting dependency because we can fix an order.
139 break;
140 }
141 if (takeFirstDependency) {
142 // We discard further exploration as we already chose one dependent event
143 break;
144 }
145 } else {
146 STORM_LOG_ASSERT(!exploreDependencies, "Failure due to dependency should not be possible.");
147
148 // Next failure due to BE failing on its own
149 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const> nextBE = iterFailable.asBE(mDft);
150 // Obtain successor state by propagating failure of BE
151 newState = createSuccessorState(this->state, nextBE);
152
153 auto [newStateId, shouldStop] = getNewStateId(newState, stateToIdCallback);
154 if (shouldStop) {
155 continue;
156 }
157 STORM_LOG_ASSERT(newStateId != this->state->getId(), "Self loop was added for " << newStateId << " and failure of " << nextBE->name());
158
159 // Set failure rate according to activation
160 ValueType rate = this->state->getBERate(nextBE->id());
161 STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Failure rate should not be zero.");
162 choice.addProbability(newStateId, rate);
163 STORM_LOG_TRACE("Added transition to " << newStateId << " with failure rate " << rate);
164 }
165
166 } // end iteration of failing BE
167
168 if (exploreDependencies) {
169 if (result.empty()) {
170 // Dependencies might have been prevented from sequence enforcer -> explore BEs now instead of dependencies
171 return exploreState(stateToIdCallback, false, takeFirstDependency);
172 }
173 } else {
174 if (choice.size() == 0) {
175 // No transition was generated
176 STORM_LOG_TRACE("No transitions were generated.");
177 // Add self loop
178 choice.addProbability(this->state->getId(), storm::utility::one<ValueType>());
179 STORM_LOG_TRACE("Added self loop for " << state->getId());
180 }
181 STORM_LOG_ASSERT(choice.size() > 0, "At least one choice should have been generated.");
182 // Add all rates as one choice
183 result.addChoice(std::move(choice));
184 }
185
186 STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
187 result.setExpanded();
188 return result;
189}
190
191template<typename ValueType, typename StateType>
192std::pair<StateType, bool> DftNextStateGenerator<ValueType, StateType>::getNewStateId(DFTStatePointer newState,
193 StateToIdCallback const& stateToIdCallback) const {
194 if (newState->isInvalid() || newState->isTransient()) {
195 STORM_LOG_TRACE("State is ignored because " << (newState->isInvalid() ? "it is invalid" : "the transient fault is ignored"));
196 return std::make_pair(0, true);
197 }
198
199 if (newState->hasFailed(mDft.getTopLevelIndex()) && uniqueFailedState) {
200 // Use unique failed state
201 return std::make_pair(0, false);
202 } else {
203 // Add new state
204 return std::make_pair(stateToIdCallback(newState), false);
205 }
206}
207
208template<typename ValueType, typename StateType>
209typename DftNextStateGenerator<ValueType, StateType>::DFTStatePointer DftNextStateGenerator<ValueType, StateType>::createSuccessorState(
210 DFTStatePointer const origState, std::shared_ptr<storm::dft::storage::elements::DFTDependency<ValueType> const> dependency,
211 bool dependencySuccessful) const {
212 // Construct new state as copy from original one
213 DFTStatePointer newState = origState->copy();
214
215 if (dependencySuccessful) {
216 // Dependency was successful -> dependent BE fails
217 STORM_LOG_TRACE("With the successful triggering of PDEP " << dependency->name() << " [" << dependency->id() << "]" << " in "
218 << mDft.getStateString(origState));
219 newState->letDependencyTrigger(dependency, true);
220 STORM_LOG_ASSERT(dependency->dependentEvents().size() == 1, "Dependency " << dependency->name() << " does not have unique dependent event.");
221 STORM_LOG_ASSERT(dependency->dependentEvents().front()->isBasicElement(),
222 "Trigger event " << dependency->dependentEvents().front()->name() << " is not a BE.");
223 auto trigger = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<ValueType> const>(dependency->dependentEvents().front());
224 return createSuccessorState(newState, trigger);
225 } else {
226 // Dependency was unsuccessful -> no BE fails
227 STORM_LOG_TRACE("With the unsuccessful triggering of PDEP " << dependency->name() << " [" << dependency->id() << "]" << " in "
228 << mDft.getStateString(origState));
229 newState->letDependencyTrigger(dependency, false);
230 return newState;
231 }
232}
233
234template<typename ValueType, typename StateType>
235typename DftNextStateGenerator<ValueType, StateType>::DFTStatePointer DftNextStateGenerator<ValueType, StateType>::createSuccessorState(
236 DFTStatePointer const origState, std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const> be) const {
237 // Construct new state as copy from original one
238 DFTStatePointer newState = origState->copy();
239
240 STORM_LOG_TRACE("With the failure of " << be->name() << " [" << be->id() << "]" << " in " << mDft.getStateString(origState));
241 newState->letBEFail(be);
242
243 // Propagate
245 propagateFailure(newState, be, queues);
246
247 // Check whether transient failure lead to TLE failure
248 // TODO handle for all types of BEs.
250 auto beExp = std::static_pointer_cast<storm::dft::storage::elements::BEExponential<ValueType> const>(be);
251 if (beExp->isTransient() && !newState->hasFailed(mDft.getTopLevelIndex())) {
252 newState->markAsTransient();
253 }
254 }
255
256 // Check whether failsafe propagation can be discarded
257 bool discardFailSafe = false;
258 discardFailSafe |= newState->isInvalid();
259 discardFailSafe |= newState->isTransient();
260 discardFailSafe |= (newState->hasFailed(mDft.getTopLevelIndex()) && uniqueFailedState);
261
262 // Propagate failsafe (if necessary)
263 if (!discardFailSafe) {
264 propagateFailsafe(newState, be, queues);
265
266 // Update failable dependencies
267 newState->updateFailableDependencies(be->id());
268 newState->updateDontCareDependencies(be->id());
269 newState->updateFailableInRestrictions(be->id());
270 }
271 return newState;
272}
273
274template<typename ValueType, typename StateType>
276 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const>& nextBE,
278 // Propagate failure
279 for (DFTGatePointer parent : nextBE->parents()) {
280 if (newState->isOperational(parent->id())) {
281 queues.propagateFailure(parent);
282 }
283 }
284 // Propagate failures
285 while (!queues.failurePropagationDone()) {
286 DFTGatePointer next = queues.nextFailurePropagation();
287 next->checkFails(*newState, queues);
288 newState->updateFailableDependencies(next->id());
289 newState->updateFailableInRestrictions(next->id());
290 }
291
292 // Check restrictions
293 for (DFTRestrictionPointer restr : nextBE->restrictions()) {
294 queues.checkRestrictionLater(restr);
295 }
296 // Check restrictions
297 while (!queues.restrictionChecksDone()) {
298 DFTRestrictionPointer next = queues.nextRestrictionCheck();
299 next->checkFails(*newState, queues);
300 newState->updateFailableDependencies(next->id());
301 newState->updateFailableInRestrictions(next->id());
302 }
303}
304
305template<typename ValueType, typename StateType>
307 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const>& nextBE,
309 // Propagate failsafe
310 while (!queues.failsafePropagationDone()) {
311 DFTGatePointer next = queues.nextFailsafePropagation();
312 next->checkFailsafe(*newState, queues);
313 }
314
315 // Propagate dont cares
316 // Relevance is considered for each element independently
317 while (!queues.dontCarePropagationDone()) {
318 DFTElementPointer next = queues.nextDontCarePropagation();
319 next->checkDontCareAnymore(*newState, queues);
320 }
321}
322
323template<typename ValueType, typename StateType>
325 StateToIdCallback const& stateToIdCallback) {
326 this->uniqueFailedState = true;
327 // Introduce explicit fail state with id 0
328 DFTStatePointer failedState = std::make_shared<storm::dft::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
329 [[maybe_unused]] StateType failedStateId = stateToIdCallback(failedState);
330 STORM_LOG_ASSERT(failedStateId == 0, "Unique failed state has not id 0.");
331 STORM_LOG_TRACE("Introduce fail state with id 0.");
332
333 // Add self loop
336
337 // No further exploration required
339 result.addChoice(std::move(choice));
340 result.setExpanded();
341 return result;
342}
343
344template class DftNextStateGenerator<double>;
346
347} // namespace generator
348} // namespace storm::dft
void propagateFailure(DFTStatePointer newState, std::shared_ptr< storm::dft::storage::elements::DFTBE< ValueType > const > &nextBE, storm::dft::storage::DFTStateSpaceGenerationQueues< ValueType > &queues) const
Propagate the failures in a given state if the given BE fails.
storm::generator::StateBehavior< ValueType, StateType > expand(StateToIdCallback const &stateToIdCallback)
Expand and explore current state.
DftNextStateGenerator(storm::dft::storage::DFT< ValueType > const &dft, storm::dft::storage::DFTStateGenerationInfo const &stateGenerationInfo)
DFTStatePointer createSuccessorState(DFTStatePointer const origState, std::shared_ptr< storm::dft::storage::elements::DFTBE< ValueType > const > be) const
void load(storm::storage::BitVector const &state)
storm::generator::StateBehavior< ValueType, StateType > createMergeFailedState(StateToIdCallback const &stateToIdCallback)
Create unique failed state.
std::vector< StateType > getInitialStates(StateToIdCallback const &stateToIdCallback)
DFTStatePointer createInitialState() const
Create initial state.
std::function< StateType(DFTStatePointer const &)> StateToIdCallback
void propagateFailsafe(DFTStatePointer newState, std::shared_ptr< storm::dft::storage::elements::DFTBE< ValueType > const > &nextBE, storm::dft::storage::DFTStateSpaceGenerationQueues< ValueType > &queues) const
Propagate the failsafe state in a given state if the given BE fails.
Represents a Dynamic Fault Tree.
Definition DFT.h:49
void checkRestrictionLater(DFTRestrictionPointer const &restr)
Abstract base class for basic events (BEs) in DFTs.
Definition DFTBE.h:14
Dependency gate with probability p.
void addChoice(Choice< ValueType, StateType > &&choice)
Adds the given choice to the behavior of the state.
bool empty() const
Retrieves whether the behavior is empty in the sense that there are no available choices.
void setExpanded(bool newValue=true)
Sets whether the state was expanded.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
#define STORM_LOG_DEBUG(message)
Definition logging.h:21
#define STORM_LOG_TRACE(message)
Definition logging.h:15
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
SettingsType const & getModule()
Get module.
bool isOne(ValueType const &a)
Definition constants.cpp:37
bool isZero(ValueType const &a)
Definition constants.cpp:42
ValueType one()
Definition constants.cpp:19
void addProbability(StateType const &state, ValueType const &value)
Adds the given probability value to the given state in the underlying distribution.
Definition Choice.cpp:158