Storm
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>
75 bool exploreDependencies,
76 bool takeFirstDependency) {
77 // Prepare the result, in case we return early.
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
134 // Handle premature stop for dependencies
135 if (!iterFailable.isConflictingDependency()) {
136 // We only explore the first non-conflicting dependency because we can fix an order.
137 break;
138 }
139 if (takeFirstDependency) {
140 // We discard further exploration as we already chose one dependent event
141 break;
142 }
143 } else {
144 STORM_LOG_ASSERT(!exploreDependencies, "Failure due to dependency should not be possible.");
145
146 // Next failure due to BE failing on its own
147 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const> nextBE = iterFailable.asBE(mDft);
148 // Obtain successor state by propagating failure of BE
149 newState = createSuccessorState(this->state, nextBE);
150
151 auto [newStateId, shouldStop] = getNewStateId(newState, stateToIdCallback);
152 if (shouldStop) {
153 continue;
154 }
155 STORM_LOG_ASSERT(newStateId != this->state->getId(), "Self loop was added for " << newStateId << " and failure of " << nextBE->name());
156
157 // Set failure rate according to activation
158 ValueType rate = this->state->getBERate(nextBE->id());
159 STORM_LOG_ASSERT(!storm::utility::isZero(rate), "Failure rate should not be zero.");
160 choice.addProbability(newStateId, rate);
161 STORM_LOG_TRACE("Added transition to " << newStateId << " with failure rate " << rate);
162 }
163
164 } // end iteration of failing BE
165
166 if (exploreDependencies) {
167 if (result.empty()) {
168 // Dependencies might have been prevented from sequence enforcer -> explore BEs now instead of dependencies
169 return exploreState(stateToIdCallback, false, takeFirstDependency);
170 }
171 } else {
172 if (choice.size() == 0) {
173 // No transition was generated
174 STORM_LOG_TRACE("No transitions were generated.");
175 // Add self loop
176 choice.addProbability(this->state->getId(), storm::utility::one<ValueType>());
177 STORM_LOG_TRACE("Added self loop for " << state->getId());
178 }
179 STORM_LOG_ASSERT(choice.size() > 0, "At least one choice should have been generated.");
180 // Add all rates as one choice
181 result.addChoice(std::move(choice));
182 }
183
184 STORM_LOG_TRACE("Finished exploring state: " << mDft.getStateString(state));
185 result.setExpanded();
186 return result;
187}
188
189template<typename ValueType, typename StateType>
190std::pair<StateType, bool> DftNextStateGenerator<ValueType, StateType>::getNewStateId(DFTStatePointer newState,
191 StateToIdCallback const& stateToIdCallback) const {
192 if (newState->isInvalid() || newState->isTransient()) {
193 STORM_LOG_TRACE("State is ignored because " << (newState->isInvalid() ? "it is invalid" : "the transient fault is ignored"));
194 return std::make_pair(0, true);
195 }
196
197 if (newState->hasFailed(mDft.getTopLevelIndex()) && uniqueFailedState) {
198 // Use unique failed state
199 return std::make_pair(0, false);
200 } else {
201 // Add new state
202 return std::make_pair(stateToIdCallback(newState), false);
203 }
204}
205
206template<typename ValueType, typename StateType>
207typename DftNextStateGenerator<ValueType, StateType>::DFTStatePointer DftNextStateGenerator<ValueType, StateType>::createSuccessorState(
208 DFTStatePointer const origState, std::shared_ptr<storm::dft::storage::elements::DFTDependency<ValueType> const> dependency,
209 bool dependencySuccessful) const {
210 // Construct new state as copy from original one
211 DFTStatePointer newState = origState->copy();
212
213 if (dependencySuccessful) {
214 // Dependency was successful -> dependent BE fails
215 STORM_LOG_TRACE("With the successful triggering of PDEP " << dependency->name() << " [" << dependency->id() << "]" << " in "
216 << mDft.getStateString(origState));
217 newState->letDependencyTrigger(dependency, true);
218 STORM_LOG_ASSERT(dependency->dependentEvents().size() == 1, "Dependency " << dependency->name() << " does not have unique dependent event.");
219 STORM_LOG_ASSERT(dependency->dependentEvents().front()->isBasicElement(),
220 "Trigger event " << dependency->dependentEvents().front()->name() << " is not a BE.");
221 auto trigger = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<ValueType> const>(dependency->dependentEvents().front());
222 return createSuccessorState(newState, trigger);
223 } else {
224 // Dependency was unsuccessful -> no BE fails
225 STORM_LOG_TRACE("With the unsuccessful triggering of PDEP " << dependency->name() << " [" << dependency->id() << "]" << " in "
226 << mDft.getStateString(origState));
227 newState->letDependencyTrigger(dependency, false);
228 return newState;
229 }
230}
231
232template<typename ValueType, typename StateType>
233typename DftNextStateGenerator<ValueType, StateType>::DFTStatePointer DftNextStateGenerator<ValueType, StateType>::createSuccessorState(
234 DFTStatePointer const origState, std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const> be) const {
235 // Construct new state as copy from original one
236 DFTStatePointer newState = origState->copy();
237
238 STORM_LOG_TRACE("With the failure of " << be->name() << " [" << be->id() << "]" << " in " << mDft.getStateString(origState));
239 newState->letBEFail(be);
240
241 // Propagate
243 propagateFailure(newState, be, queues);
244
245 // Check whether transient failure lead to TLE failure
246 // TODO handle for all types of BEs.
248 auto beExp = std::static_pointer_cast<storm::dft::storage::elements::BEExponential<ValueType> const>(be);
249 if (beExp->isTransient() && !newState->hasFailed(mDft.getTopLevelIndex())) {
250 newState->markAsTransient();
251 }
252 }
253
254 // Check whether failsafe propagation can be discarded
255 bool discardFailSafe = false;
256 discardFailSafe |= newState->isInvalid();
257 discardFailSafe |= newState->isTransient();
258 discardFailSafe |= (newState->hasFailed(mDft.getTopLevelIndex()) && uniqueFailedState);
259
260 // Propagate failsafe (if necessary)
261 if (!discardFailSafe) {
262 propagateFailsafe(newState, be, queues);
263
264 // Update failable dependencies
265 newState->updateFailableDependencies(be->id());
266 newState->updateDontCareDependencies(be->id());
267 newState->updateFailableInRestrictions(be->id());
268 }
269 return newState;
270}
271
272template<typename ValueType, typename StateType>
274 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const>& nextBE,
276 // Propagate failure
277 for (DFTGatePointer parent : nextBE->parents()) {
278 if (newState->isOperational(parent->id())) {
279 queues.propagateFailure(parent);
280 }
281 }
282 // Propagate failures
283 while (!queues.failurePropagationDone()) {
284 DFTGatePointer next = queues.nextFailurePropagation();
285 next->checkFails(*newState, queues);
286 newState->updateFailableDependencies(next->id());
287 newState->updateFailableInRestrictions(next->id());
288 }
289
290 // Check restrictions
291 for (DFTRestrictionPointer restr : nextBE->restrictions()) {
292 queues.checkRestrictionLater(restr);
293 }
294 // Check restrictions
295 while (!queues.restrictionChecksDone()) {
296 DFTRestrictionPointer next = queues.nextRestrictionCheck();
297 next->checkFails(*newState, queues);
298 newState->updateFailableDependencies(next->id());
299 newState->updateFailableInRestrictions(next->id());
300 }
301}
302
303template<typename ValueType, typename StateType>
305 std::shared_ptr<storm::dft::storage::elements::DFTBE<ValueType> const>& nextBE,
307 // Propagate failsafe
308 while (!queues.failsafePropagationDone()) {
309 DFTGatePointer next = queues.nextFailsafePropagation();
310 next->checkFailsafe(*newState, queues);
311 }
312
313 // Propagate dont cares
314 // Relevance is considered for each element independently
315 while (!queues.dontCarePropagationDone()) {
316 DFTElementPointer next = queues.nextDontCarePropagation();
317 next->checkDontCareAnymore(*newState, queues);
318 }
319}
320
321template<typename ValueType, typename StateType>
323 StateToIdCallback const& stateToIdCallback) {
324 this->uniqueFailedState = true;
325 // Introduce explicit fail state with id 0
326 DFTStatePointer failedState = std::make_shared<storm::dft::storage::DFTState<ValueType>>(mDft, mStateGenerationInfo, 0);
327 StateType failedStateId = stateToIdCallback(failedState);
328 STORM_LOG_ASSERT(failedStateId == 0, "Unique failed state has not id 0.");
329 STORM_LOG_TRACE("Introduce fail state with id 0.");
330
331 // Add self loop
333 choice.addProbability(0, storm::utility::one<ValueType>());
334
335 // No further exploration required
337 result.addChoice(std::move(choice));
338 result.setExpanded();
339 return result;
340}
341
342template class DftNextStateGenerator<double>;
344
345} // namespace generator
346} // 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
Create successor state from given state by letting the given BE fail next.
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:52
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:18
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SettingsType const & getModule()
Get module.
bool isOne(ValueType const &a)
Definition constants.cpp:36
bool isZero(ValueType const &a)
Definition constants.cpp:41
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