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