Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
DFTASFChecker.cpp
Go to the documentation of this file.
1#include "DFTASFChecker.h"
2#include <string>
3#include "SmtConstraint.cpp"
4
8#include "storm/io/file.h"
13
14namespace storm::dft {
15namespace modelchecker {
16
18 // Intentionally left empty.
19}
20
21uint64_t DFTASFChecker::getClaimVariableIndex(uint64_t spare, uint64_t child) const {
22 return claimVariables.at(SpareAndChildPair(spare, child));
23}
24
26 std::vector<uint64_t> beVariables;
27 uint64_t failedBeVariables;
28 std::vector<uint64_t> failsafeBeVariables;
29 bool failedBeIsSet = false;
30 notFailed = dft.nrBasicElements() + 1; // Value indicating the element is not failed
31
32 // Initialize variables
33 for (size_t i = 0; i < dft.nrElements(); ++i) {
34 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(i);
35 varNames.push_back("t_" + element->name());
36 timePointVariables.emplace(i, varNames.size() - 1);
37 switch (element->type()) {
39 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
40 switch (be->beType()) {
42 beVariables.push_back(varNames.size() - 1);
43 break;
45 STORM_LOG_WARN("Constant BEs are only experimentally supported in the SMT encoding");
46 // Constant BEs are initially either failed or failsafe, treat them differently
47 auto be = std::static_pointer_cast<storm::dft::storage::elements::BEConst<double> const>(element);
48 if (be->failed()) {
49 STORM_LOG_THROW(!failedBeIsSet, storm::exceptions::NotSupportedException,
50 "DFTs containing more than one constantly failed BE are not supported");
51 notFailed = dft.nrBasicElements();
52 failedBeVariables = varNames.size() - 1;
53 failedBeIsSet = true;
54 } else {
55 failsafeBeVariables.push_back(varNames.size() - 1);
56 }
57 break;
58 }
59 default:
60 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "BE type '" << be->beType() << "' not known.");
61 break;
62 }
63 break;
64 }
66 auto spare = std::static_pointer_cast<storm::dft::storage::elements::DFTSpare<double> const>(element);
67 for (auto const &spareChild : spare->children()) {
68 varNames.push_back("c_" + element->name() + "_" + spareChild->name());
69 claimVariables.emplace(SpareAndChildPair(element->id(), spareChild->id()), varNames.size() - 1);
70 }
71 break;
72 }
74 varNames.push_back("dep_" + element->name());
75 dependencyVariables.emplace(element->id(), varNames.size() - 1);
76 break;
77 }
78 default:
79 break;
80 }
81 }
82 // Initialize variables indicating Markovian states
83 for (size_t i = 0; i < dft.nrBasicElements(); ++i) {
84 varNames.push_back("m_" + std::to_string(i));
85 markovianVariables.emplace(i, varNames.size() - 1);
86 }
87
88 // Generate constraints
89
90 // All exponential BEs have to fail (first part of constraint 12)
91 for (auto const &beV : beVariables) {
92 constraints.push_back(std::make_shared<BetweenValues>(beV, 1, notFailed - 1));
93 }
94
95 // Constantly failsafe BEs may also be fail-safe
96 for (auto const &beV : failsafeBeVariables) {
97 constraints.push_back(std::make_shared<BetweenValues>(beV, 1, notFailed));
98 }
99
100 // Constantly failed BEs fail before other types
101 if (failedBeIsSet) {
102 constraints.push_back(std::make_shared<IsConstantValue>(failedBeVariables, 0));
103 }
104
105 std::vector<uint64_t> allBeVariables;
106 allBeVariables.insert(std::end(allBeVariables), std::begin(beVariables), std::end(beVariables));
107 allBeVariables.insert(std::end(allBeVariables), std::begin(failsafeBeVariables), std::end(failsafeBeVariables));
108
109 // No two exponential BEs fail at the same time (second part of constraint 12)
110 if (beVariables.size() > 1) {
111 constraints.push_back(std::make_shared<PairwiseDifferent>(beVariables));
112 constraints.back()->setDescription("No two BEs fail at the same time");
113 }
114
115 bool descFlag = true;
116 for (auto const &failsafeBe : failsafeBeVariables) {
117 std::vector<std::shared_ptr<SmtConstraint>> unequalConstraints;
118 for (auto const &otherBe : allBeVariables) {
119 if (otherBe != failsafeBe) {
120 unequalConstraints.push_back(std::make_shared<IsUnequal>(failsafeBe, otherBe));
121 }
122 }
123 constraints.push_back(
124 std::make_shared<Implies>(std::make_shared<IsNotConstantValue>(failsafeBe, notFailed), std::make_shared<And>(unequalConstraints)));
125 if (descFlag) {
126 constraints.back()->setDescription("Initially failsafe BEs don't fail at the same time as other BEs");
127 descFlag = false;
128 }
129 }
130
131 // Initialize claim variables in [1, |BE|+1]
132 for (auto const &claimVariable : claimVariables) {
133 constraints.push_back(std::make_shared<BetweenValues>(claimVariable.second, 0, notFailed));
134 }
135
136 // Encoding for gates
137 for (size_t i = 0; i < dft.nrElements(); ++i) {
138 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(i);
139 STORM_LOG_ASSERT(i == element->id(), "Id and index should match.");
140
141 // Get indices for gate children
142 std::vector<uint64_t> childVarIndices;
143 if (element->isGate()) {
144 std::shared_ptr<storm::dft::storage::elements::DFTGate<ValueType> const> gate = dft.getGate(i);
145 for (auto const &child : gate->children()) {
146 childVarIndices.push_back(timePointVariables.at(child->id()));
147 }
148 }
149
150 switch (element->type()) {
152 // BEs were already considered before
153 break;
155 generateAndConstraint(i, childVarIndices, element);
156 break;
158 generateOrConstraint(i, childVarIndices, element);
159 break;
161 generateVotConstraint(i, childVarIndices, element);
162 break;
164 generatePandConstraint(i, childVarIndices, element);
165 break;
167 generatePorConstraint(i, childVarIndices, element);
168 break;
170 generateSeqConstraint(childVarIndices, element);
171 break;
173 generateSpareConstraint(i, childVarIndices, element);
174 break;
176 generatePdepConstraint(i, childVarIndices, element);
177 break;
178 default:
179 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "SMT encoding for type '" << element->type() << "' is not supported.");
180 break;
181 }
182 }
183
184 // Constraint (8) intentionally commented out for testing purposes
185 // addClaimingConstraints();
186
187 // Handle dependencies
188 addMarkovianConstraints();
189
190 // Failsafe BEs may only fail in non-Markovian states (i.e. if they were triggered)
191 std::vector<std::shared_ptr<SmtConstraint>> failsafeNotIConstr;
192 for (uint64_t i = 0; i < dft.nrBasicElements(); ++i) {
193 failsafeNotIConstr.clear();
194 for (auto const &beV : failsafeBeVariables) {
195 failsafeNotIConstr.push_back(std::make_shared<IsNotConstantValue>(beV, i + 1));
196 }
197 // If state i+1 is Markovian (i.e. m_i = true), all failsafeBEVariables are not equal to i+1
198 constraints.push_back(
199 std::make_shared<Implies>(std::make_shared<IsBoolValue>(markovianVariables.at(i), true), std::make_shared<And>(failsafeNotIConstr)));
200 if (i == 0) {
201 constraints.back()->setDescription("Failsafe BEs fail only if they are triggered");
202 }
203 }
204
205 // A failsafe BE only stays failsafe if no trigger has been triggered
206 std::vector<std::shared_ptr<SmtConstraint>> triggerConstraints;
207 for (size_t i = 0; i < dft.nrElements(); ++i) {
208 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(i);
209 if (element->isBasicElement()) {
210 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
212 triggerConstraints.clear();
213 for (auto const &dependency : be->ingoingDependencies()) {
214 triggerConstraints.push_back(std::make_shared<IsConstantValue>(timePointVariables.at(dependency->triggerEvent()->id()), notFailed));
215 }
216 if (!triggerConstraints.empty()) {
217 constraints.push_back(std::make_shared<Implies>(std::make_shared<IsConstantValue>(timePointVariables.at(be->id()), notFailed),
218 std::make_shared<And>(triggerConstraints)));
219 constraints.back()->setDescription("Failsafe BE " + be->name() + " stays failsafe if no trigger fails");
220 }
221 }
222 }
223 }
224}
225
226// Constraint Generator Functions
227
228void DFTASFChecker::generateAndConstraint(size_t i, std::vector<uint64_t> childVarIndices,
229 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
230 // Constraint for AND gate (constraint 1)
231 constraints.push_back(std::make_shared<IsMaximum>(timePointVariables.at(i), childVarIndices));
232 constraints.back()->setDescription("AND gate " + element->name());
233}
234
235void DFTASFChecker::generateOrConstraint(size_t i, std::vector<uint64_t> childVarIndices,
236 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
237 // Constraint for OR gate (constraint 2)
238 constraints.push_back(std::make_shared<IsMinimum>(timePointVariables.at(i), childVarIndices));
239 constraints.back()->setDescription("OR gate " + element->name());
240}
241
242void DFTASFChecker::generateVotConstraint(size_t i, std::vector<uint64_t> childVarIndices,
243 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
244 auto vot = std::static_pointer_cast<storm::dft::storage::elements::DFTVot<double> const>(element);
245 // VOTs are implemented via OR over ANDs with all possible combinations
246 std::vector<uint64_t> tmpVars;
247 size_t k = 0;
248 // Generate all permutations of k out of n
249 uint64_t combination = smallestIntWithNBitsSet(static_cast<uint64_t>(vot->threshold()));
250 do {
251 // Construct selected children from combination
252 std::vector<uint64_t> combinationChildren;
253 STORM_LOG_ASSERT(vot->nrChildren() < 64, "Too many children of a VOT Gate.");
254 for (uint8_t j = 0; j < static_cast<uint8_t>(vot->nrChildren()); ++j) {
255 if (combination & (1ul << j)) {
256 combinationChildren.push_back(childVarIndices.at(j));
257 }
258 }
259 // Introduce temporary variable for this AND
260 varNames.push_back("v_" + vot->name() + "_" + std::to_string(k));
261 size_t index = varNames.size() - 1;
262 tmpVars.push_back(index);
263 tmpTimePointVariables.push_back(index);
264 // AND over the selected children
265 constraints.push_back(std::make_shared<IsMaximum>(index, combinationChildren));
266 constraints.back()->setDescription("VOT gate " + element->name() + ": AND no. " + std::to_string(k));
267 // Generate next permutation
268 combination = nextBitPermutation(combination);
269 ++k;
270 } while (combination < (1ul << vot->nrChildren()) && combination != 0);
271
272 // Constraint is OR over all possible combinations
273 constraints.push_back(std::make_shared<IsMinimum>(timePointVariables.at(i), tmpVars));
274 constraints.back()->setDescription("VOT gate " + element->name() + ": OR");
275}
276
277void DFTASFChecker::generatePandConstraint(size_t i, std::vector<uint64_t> childVarIndices,
278 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
279 // Constraint for PAND gate (constraint 3)
280 std::shared_ptr<SmtConstraint> ifC = std::make_shared<Sorted>(childVarIndices);
281 std::shared_ptr<SmtConstraint> thenC = std::make_shared<IsEqual>(timePointVariables.at(i), childVarIndices.back());
282 std::shared_ptr<SmtConstraint> elseC = std::make_shared<IsConstantValue>(timePointVariables.at(i), notFailed);
283 constraints.push_back(std::make_shared<IfThenElse>(ifC, thenC, elseC));
284 constraints.back()->setDescription("PAND gate " + element->name());
285}
286
287void DFTASFChecker::generatePorConstraint(size_t i, std::vector<uint64_t> childVarIndices,
288 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
289 // Constraint for POR gate
290 // First child fails before all others
291 std::vector<std::shared_ptr<SmtConstraint>> firstSmallestC;
292 uint64_t timeFirstChild = childVarIndices.front();
293 for (uint64_t i = 1; i < childVarIndices.size(); ++i) {
294 firstSmallestC.push_back(std::make_shared<IsLess>(timeFirstChild, childVarIndices.at(i)));
295 }
296 std::shared_ptr<SmtConstraint> ifC = std::make_shared<And>(firstSmallestC);
297 std::shared_ptr<SmtConstraint> thenC = std::make_shared<IsEqual>(timePointVariables.at(i), childVarIndices.front());
298 std::shared_ptr<SmtConstraint> elseC = std::make_shared<IsConstantValue>(timePointVariables.at(i), notFailed);
299 constraints.push_back(std::make_shared<IfThenElse>(ifC, thenC, elseC));
300 constraints.back()->setDescription("POR gate " + element->name());
301}
302
303void DFTASFChecker::generateSeqConstraint(std::vector<uint64_t> childVarIndices,
304 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
305 // Constraint for SEQ gate (constraint 4)
306 // As the restriction is not a gate we have to enumerate its children here
307 auto seq = std::static_pointer_cast<storm::dft::storage::elements::DFTRestriction<double> const>(element);
308 for (auto const &child : seq->children()) {
309 childVarIndices.push_back(timePointVariables.at(child->id()));
310 }
311
312 constraints.push_back(std::make_shared<Sorted>(childVarIndices));
313 constraints.back()->setDescription("SEQ gate " + element->name());
314}
315
316void DFTASFChecker::generateSpareConstraint(size_t i, std::vector<uint64_t> childVarIndices,
317 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
318 auto spare = std::static_pointer_cast<storm::dft::storage::elements::DFTSpare<double> const>(element);
319 auto const &children = spare->children();
320 uint64_t firstChild = children.front()->id();
321 uint64_t lastChild = children.back()->id();
322
323 // First child of each spare is claimed in the beginning
324 constraints.push_back(std::make_shared<IsConstantValue>(getClaimVariableIndex(spare->id(), firstChild), 0));
325 constraints.back()->setDescription("SPARE gate " + spare->name() + " claims first child");
326
327 // If last child is claimed before failure, then the spare fails when the last child fails (constraint 5)
328 std::shared_ptr<SmtConstraint> leftC = std::make_shared<IsLess>(getClaimVariableIndex(spare->id(), lastChild), childVarIndices.back());
329 constraints.push_back(std::make_shared<Implies>(leftC, std::make_shared<IsEqual>(timePointVariables.at(i), childVarIndices.back())));
330 constraints.back()->setDescription("Last child & claimed -> SPARE fails");
331
332 // Construct constraint for trying to claim next child
333 STORM_LOG_ASSERT(children.size() >= 2, "Spare has only one child");
334 for (uint64_t currChild = 0; currChild < children.size() - 1; ++currChild) {
335 uint64_t timeCurrChild = childVarIndices.at(currChild); // Moment when current child fails
336 // If i-th child fails after being claimed, then try to claim next child (constraint 6)
337 std::shared_ptr<SmtConstraint> tryClaimC = generateTryToClaimConstraint(spare, currChild + 1, timeCurrChild);
338 constraints.push_back(
339 std::make_shared<Iff>(std::make_shared<IsLess>(getClaimVariableIndex(spare->id(), children.at(currChild)->id()), timeCurrChild), tryClaimC));
340 constraints.back()->setDescription("Try to claim " + std::to_string(currChild + 2) + "th child");
341 }
342}
343
344std::shared_ptr<SmtConstraint> DFTASFChecker::generateTryToClaimConstraint(std::shared_ptr<storm::dft::storage::elements::DFTSpare<ValueType> const> spare,
345 uint64_t childIndex, uint64_t timepoint) const {
346 auto child = spare->children().at(childIndex);
347 uint64_t timeChild = timePointVariables.at(child->id()); // Moment when the child fails
348 uint64_t claimChild = getClaimVariableIndex(spare->id(), child->id()); // Moment the spare claims the child
349
350 std::vector<std::shared_ptr<SmtConstraint>> noClaimingPossible;
351 // Child cannot be claimed.
352 if (childIndex + 1 < spare->children().size()) {
353 // Consider next child for claiming (second case in constraint 7)
354 noClaimingPossible.push_back(generateTryToClaimConstraint(spare, childIndex + 1, timepoint));
355 } else {
356 // Last child: spare fails at same point as this child (third case in constraint 7)
357 noClaimingPossible.push_back(std::make_shared<IsEqual>(timePointVariables.at(spare->id()), timepoint));
358 }
359 std::shared_ptr<SmtConstraint> elseCaseC = std::make_shared<And>(noClaimingPossible);
360
361 // Check if next child is available (first case in constraint 7)
362 std::vector<std::shared_ptr<SmtConstraint>> claimingPossibleC;
363 // Next child is not yet failed
364 claimingPossibleC.push_back(std::make_shared<IsLess>(timepoint, timeChild));
365 // Child is not yet claimed by a different spare
366 for (auto const &otherSpare : child->parents()) {
367 if (otherSpare->id() == spare->id()) {
368 // not a different spare.
369 continue;
370 }
371 claimingPossibleC.push_back(std::make_shared<IsLess>(timepoint, getClaimVariableIndex(otherSpare->id(), child->id())));
372 }
373
374 // Claim child if available
375 std::shared_ptr<SmtConstraint> firstCaseC =
376 std::make_shared<IfThenElse>(std::make_shared<And>(claimingPossibleC), std::make_shared<IsEqual>(claimChild, timepoint), elseCaseC);
377 return firstCaseC;
378}
379
380void DFTASFChecker::addClaimingConstraints() {
381 // Only one spare can claim a child (constraint 8)
382 // and only not failed children can be claimed (addition to constrain 8)
383 for (size_t i = 0; i < dft.nrElements(); ++i) {
384 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(i);
385 if (element->isSpareGate()) {
386 auto spare = std::static_pointer_cast<storm::dft::storage::elements::DFTSpare<double> const>(element);
387 for (auto const &child : spare->children()) {
388 std::vector<std::shared_ptr<SmtConstraint>> additionalC;
389 uint64_t timeClaiming = getClaimVariableIndex(spare->id(), child->id());
390 std::shared_ptr<SmtConstraint> leftC = std::make_shared<IsLessConstant>(timeClaiming, notFailed);
391 // Child must be operational at time of claiming
392 additionalC.push_back(std::make_shared<IsLess>(timeClaiming, timePointVariables.at(child->id())));
393 // No other spare claims this child
394 for (auto const &parent : child->parents()) {
395 if (parent->isSpareGate() && parent->id() != spare->id()) {
396 // Different spare
397 additionalC.push_back(std::make_shared<IsConstantValue>(getClaimVariableIndex(parent->id(), child->id()), notFailed));
398 }
399 }
400 constraints.push_back(std::make_shared<Implies>(leftC, std::make_shared<And>(additionalC)));
401 constraints.back()->setDescription("Child " + child->name() + " must be operational at time of claiming by spare " + spare->name() +
402 " and can only be claimed by one spare.");
403 }
404 }
405 }
406}
407
408void DFTASFChecker::generatePdepConstraint(size_t i, std::vector<uint64_t> childVarIndices,
409 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element) {
410 auto dependency = std::static_pointer_cast<storm::dft::storage::elements::DFTDependency<double> const>(element);
411 auto const &dependentEvents = dependency->dependentEvents();
412 auto const &trigger = dependency->triggerEvent();
413 std::vector<uint64_t> dependentIndices;
414 for (size_t j = 0; j < dependentEvents.size(); ++j) {
415 dependentIndices.push_back(timePointVariables.at(dependentEvents[j]->id()));
416 }
417
418 constraints.push_back(std::make_shared<IsMaximum>(dependencyVariables.at(i), dependentIndices));
419 constraints.back()->setDescription("Dependency " + element->name() + ": Last element");
420 constraints.push_back(std::make_shared<IsEqual>(timePointVariables.at(i), timePointVariables.at(trigger->id())));
421 constraints.back()->setDescription("Dependency " + element->name() + ": Trigger element");
422}
423
424void DFTASFChecker::addMarkovianConstraints() {
425 uint64_t nrMarkovian = dft.nrBasicElements();
426 std::set<size_t> depElements;
427 // Vector containing (non-)Markovian constraints for each timepoint
428 std::vector<std::vector<std::shared_ptr<SmtConstraint>>> markovianC(nrMarkovian);
429 std::vector<std::vector<std::shared_ptr<SmtConstraint>>> nonMarkovianC(nrMarkovian);
430 std::vector<std::vector<std::shared_ptr<SmtConstraint>>> notColdC(nrMarkovian);
431
432 // All dependent events of a failed trigger have failed as well (constraint 9)
433 for (size_t j = 0; j < dft.nrElements(); ++j) {
434 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(j);
435 if (element->hasOutgoingDependencies()) {
436 for (uint64_t i = 0; i < nrMarkovian; ++i) {
437 std::shared_ptr<SmtConstraint> triggerFailed = std::make_shared<IsLessEqualConstant>(timePointVariables.at(j), i);
438 std::vector<std::shared_ptr<SmtConstraint>> depFailed;
439 for (auto const &dependency : element->outgoingDependencies()) {
440 for (auto const &depElement : dependency->dependentEvents()) {
441 depFailed.push_back(std::make_shared<IsLessEqualConstant>(timePointVariables.at(depElement->id()), i));
442 }
443 }
444 markovianC[i].push_back(std::make_shared<Implies>(triggerFailed, std::make_shared<And>(depFailed)));
445 }
446 }
447 }
448 for (uint64_t i = 0; i < nrMarkovian; ++i) {
449 constraints.push_back(std::make_shared<Iff>(std::make_shared<IsBoolValue>(markovianVariables.at(i), true), std::make_shared<And>(markovianC[i])));
450 constraints.back()->setDescription("Markovian (" + std::to_string(i) + ") iff all dependent events which trigger failed also failed.");
451 }
452
453 // In non-Markovian steps the next failed element is a dependent BE (constraint 10) + additions to specification in paper
454 for (size_t j = 0; j < dft.nrElements(); ++j) {
455 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(j);
456 if (element->isBasicElement()) {
457 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
458
459 if (be->hasIngoingDependencies()) {
460 depElements.emplace(j);
461 for (uint64_t i = 0; i < nrMarkovian - 1; ++i) {
462 std::shared_ptr<SmtConstraint> nextFailure = std::make_shared<IsConstantValue>(timePointVariables.at(j), i + 1);
463 std::vector<std::shared_ptr<SmtConstraint>> triggerFailed;
464 for (auto const &dependency : be->ingoingDependencies()) {
465 triggerFailed.push_back(std::make_shared<IsLessEqualConstant>(timePointVariables.at(dependency->triggerEvent()->id()), i));
466 }
467 nonMarkovianC[i].push_back(std::make_shared<Implies>(nextFailure, std::make_shared<Or>(triggerFailed)));
468 }
469 }
470 }
471 }
472 for (uint64_t i = 0; i < nrMarkovian; ++i) {
473 std::vector<std::shared_ptr<SmtConstraint>> dependentConstr;
474 for (auto dependentEvent : depElements) {
475 std::shared_ptr<SmtConstraint> nextFailure = std::make_shared<IsConstantValue>(timePointVariables.at(dependentEvent), i + 1);
476 dependentConstr.push_back(nextFailure);
477 }
478 // Add Constraint that any DEPENDENT event has to fail next
479 nonMarkovianC[i].push_back(std::make_shared<Or>(dependentConstr));
480 constraints.push_back(
481 std::make_shared<Implies>(std::make_shared<IsBoolValue>(markovianVariables.at(i), false), std::make_shared<And>(nonMarkovianC[i])));
482 constraints.back()->setDescription("Non-Markovian (" + std::to_string(i) + ") -> next failure is dependent BE.");
483 }
484
485 // In Markovian steps the failure rate is positive (constraint 11)
486 for (size_t j = 0; j < dft.nrElements(); ++j) {
487 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(j);
488 if (element->isBasicElement()) {
489 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
490 for (uint64_t i = 0; i < nrMarkovian; ++i) {
491 std::shared_ptr<SmtConstraint> nextFailure = std::make_shared<IsConstantValue>(timePointVariables.at(j), i + 1);
492 // BE is not cold
493 // TODO: implement use of activation variables here
494 notColdC[i].push_back(std::make_shared<Implies>(nextFailure, std::make_shared<IsTrue>(be->canFail())));
495 }
496 }
497 }
498 for (uint64_t i = 0; i < nrMarkovian; ++i) {
499 constraints.push_back(std::make_shared<Implies>(std::make_shared<IsBoolValue>(markovianVariables.at(i), true), std::make_shared<And>(notColdC[i])));
500 constraints.back()->setDescription("Markovian (" + std::to_string(i) + ") -> positive failure rate.");
501 }
502}
503
504void DFTASFChecker::toFile(std::string const &filename) {
505 std::ofstream stream;
506 storm::io::openFile(filename, stream);
507 stream << "; time point variables\n";
508 for (auto const &timeVarEntry : timePointVariables) {
509 stream << "(declare-fun " << varNames[timeVarEntry.second] << "() Int)\n";
510 }
511 stream << "; claim variables\n";
512 for (auto const &claimVarEntry : claimVariables) {
513 stream << "(declare-fun " << varNames[claimVarEntry.second] << "() Int)\n";
514 }
515 stream << "; Markovian variables\n";
516 for (auto const &markovianVarEntry : markovianVariables) {
517 stream << "(declare-fun " << varNames[markovianVarEntry.second] << "() Bool)\n";
518 }
519 stream << "; Dependency variables\n";
520 for (auto const &depVarEntry : dependencyVariables) {
521 stream << "(declare-fun " << varNames[depVarEntry.second] << "() Int)\n";
522 }
523 if (!tmpTimePointVariables.empty()) {
524 stream << "; Temporary variables\n";
525 for (auto const &tmpVar : tmpTimePointVariables) {
526 stream << "(declare-fun " << varNames[tmpVar] << "() Int)\n";
527 }
528 }
529 for (auto const &constraint : constraints) {
530 if (!constraint->description().empty()) {
531 stream << "; " << constraint->description() << '\n';
532 }
533 stream << "(assert " << constraint->toSmtlib2(varNames) << ")\n";
534 }
535 stream << "(check-sat)\n";
536 storm::io::closeFile(stream);
537}
538
540 // First convert the DFT
541 convert();
542
543 std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
545 // Add variables to manager
546 for (auto const &timeVarEntry : timePointVariables) {
547 manager->declareIntegerVariable(varNames[timeVarEntry.second]);
548 }
549 for (auto const &claimVarEntry : claimVariables) {
550 manager->declareIntegerVariable(varNames[claimVarEntry.second]);
551 }
552 for (auto const &markovianVarEntry : markovianVariables) {
553 manager->declareBooleanVariable(varNames[markovianVarEntry.second]);
554 }
555 if (!tmpTimePointVariables.empty()) {
556 for (auto const &tmpVar : tmpTimePointVariables) {
557 manager->declareIntegerVariable(varNames[tmpVar]);
558 }
559 }
560 for (auto const &depVarEntry : dependencyVariables) {
561 manager->declareIntegerVariable(varNames[depVarEntry.second]);
562 }
563 // Add constraints to solver
564 for (auto const &constraint : constraints) {
565 solver->add(constraint->toExpression(varNames, manager));
566 }
567}
568
570 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, call toSolver() before checking queries");
571
572 // Set backtracking marker to check several properties without reconstructing DFT encoding
573 solver->push();
574 // Constraint that toplevel element can fail with less or equal 'bound' failures
575 std::shared_ptr<SmtConstraint> tleFailedConstr = std::make_shared<IsConstantValue>(timePointVariables.at(dft.getTopLevelIndex()), bound);
576 std::shared_ptr<storm::expressions::ExpressionManager> manager = solver->getManager().getSharedPointer();
577 solver->add(tleFailedConstr->toExpression(varNames, manager));
578 storm::solver::SmtSolver::CheckResult res = solver->check();
579 solver->pop();
580 return res;
581}
582
584 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, call toSolver() before checking queries");
585
586 // Set backtracking marker to check several properties without reconstructing DFT encoding
587 solver->push();
588 // Constraint that toplevel element can fail with less or equal 'bound' failures
589 std::shared_ptr<SmtConstraint> tleNeverFailedConstr = std::make_shared<IsLessEqualConstant>(timePointVariables.at(dft.getTopLevelIndex()), bound);
590 std::shared_ptr<storm::expressions::ExpressionManager> manager = solver->getManager().getSharedPointer();
591 solver->add(tleNeverFailedConstr->toExpression(varNames, manager));
592 storm::solver::SmtSolver::CheckResult res = solver->check();
593 solver->pop();
594 return res;
595}
596
597void DFTASFChecker::setSolverTimeout(uint_fast64_t milliseconds) {
598 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, timeout cannot be set");
599 solver->setTimeout(milliseconds);
600}
601
603 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, timeout cannot be unset");
604 solver->unsetTimeout();
605}
606
608 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, call toSolver() before checking queries");
609 return checkTleFailsWithEq(notFailed);
610}
611
613 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, call toSolver() before checking queries");
614 std::vector<uint64_t> markovianIndices;
615 checkbound = std::min<int>(checkbound, markovianVariables.size());
616 // Get Markovian variable indices up until given timepoint
617 for (uint64_t i = 0; i < checkbound; ++i) {
618 markovianIndices.push_back(markovianVariables.at(i));
619 }
620 // Set backtracking marker to check several properties without reconstructing DFT encoding
621 solver->push();
622 // Constraint that TLE fails before or during given timepoint
623 std::shared_ptr<SmtConstraint> tleFailedConstr = std::make_shared<IsLessEqualConstant>(timePointVariables.at(dft.getTopLevelIndex()), checkbound);
624 std::shared_ptr<storm::expressions::ExpressionManager> manager = solver->getManager().getSharedPointer();
625 solver->add(tleFailedConstr->toExpression(varNames, manager));
626 // Constraint that a given number of non-Markovian states are visited
627 std::shared_ptr<SmtConstraint> nonMarkovianConstr = std::make_shared<FalseCountIsEqualConstant>(markovianIndices, nrNonMarkovian);
628 solver->add(nonMarkovianConstr->toExpression(varNames, manager));
629 storm::solver::SmtSolver::CheckResult res = solver->check();
630 solver->pop();
631 return res;
632}
633
635 STORM_LOG_ASSERT(solver, "SMT Solver was not initialized, call toSolver() before checking queries");
636 std::vector<uint64_t> markovianIndices;
637 timepoint = std::min<int>(timepoint, markovianVariables.size());
638 // Get Markovian variable indices up until given timepoint
639 for (uint64_t i = 0; i < timepoint; ++i) {
640 markovianIndices.push_back(markovianVariables.at(i));
641 }
642 // Set backtracking marker to check several properties without reconstructing DFT encoding
643 solver->push();
644 // Constraint that TLE fails before or during given timepoint
645 std::shared_ptr<SmtConstraint> tleFailedConstr = std::make_shared<IsConstantValue>(timePointVariables.at(dft.getTopLevelIndex()), timepoint);
646 std::shared_ptr<storm::expressions::ExpressionManager> manager = solver->getManager().getSharedPointer();
647 solver->add(tleFailedConstr->toExpression(varNames, manager));
648 // Constraint that a given number of non-Markovian states are visited
649 std::shared_ptr<SmtConstraint> nonMarkovianConstr = std::make_shared<FalseCountIsEqualConstant>(markovianIndices, nrNonMarkovian);
650 solver->add(nonMarkovianConstr->toExpression(varNames, manager));
651 storm::solver::SmtSolver::CheckResult res = solver->check();
652 solver->pop();
653 return res;
654}
655
656storm::solver::SmtSolver::CheckResult DFTASFChecker::checkDependencyConflict(uint64_t dep1Index, uint64_t dep2Index, uint64_t timeout) {
657 std::vector<std::shared_ptr<SmtConstraint>> andConstr;
658 std::vector<std::shared_ptr<SmtConstraint>> orConstr;
659 STORM_LOG_DEBUG("Check " << dft.getElement(dep1Index)->name() << " and " << dft.getElement(dep2Index)->name());
660 andConstr.clear();
661 // AND FDEP1 is triggered before FDEP2 is resolved
662 andConstr.push_back(std::make_shared<IsGreaterEqual>(timePointVariables.at(dep1Index), timePointVariables.at(dep2Index)));
663 andConstr.push_back(std::make_shared<IsLess>(timePointVariables.at(dep1Index), dependencyVariables.at(dep2Index)));
664 std::shared_ptr<SmtConstraint> betweenConstr1 = std::make_shared<And>(andConstr);
665
666 andConstr.clear();
667 // AND FDEP2 is triggered before FDEP1 is resolved
668 andConstr.push_back(std::make_shared<IsGreaterEqual>(timePointVariables.at(dep2Index), timePointVariables.at(dep1Index)));
669 andConstr.push_back(std::make_shared<IsLess>(timePointVariables.at(dep2Index), dependencyVariables.at(dep1Index)));
670 std::shared_ptr<SmtConstraint> betweenConstr2 = std::make_shared<And>(andConstr);
671
672 orConstr.clear();
673 // Either one of the above constraints holds
674 orConstr.push_back(betweenConstr1);
675 orConstr.push_back(betweenConstr2);
676
677 // Both FDEPs were triggered before dependent elements have failed
678 andConstr.clear();
679 andConstr.push_back(std::make_shared<IsLess>(timePointVariables.at(dep1Index), dependencyVariables.at(dep1Index)));
680 andConstr.push_back(std::make_shared<IsLess>(timePointVariables.at(dep2Index), dependencyVariables.at(dep2Index)));
681 andConstr.push_back(std::make_shared<Or>(orConstr));
682
683 std::shared_ptr<SmtConstraint> checkConstr = std::make_shared<And>(andConstr);
684
685 std::shared_ptr<storm::expressions::ExpressionManager> manager = solver->getManager().getSharedPointer();
686 solver->push();
687 solver->add(checkConstr->toExpression(varNames, manager));
688 setSolverTimeout(timeout * 1000);
689 storm::solver::SmtSolver::CheckResult res = solver->check();
691 solver->pop();
692 return res;
693}
694
695} // namespace modelchecker
696} // namespace storm::dft
uint64_t nextBitPermutation(uint64_t v)
The next bit permutation in a lexicographical sense.
uint64_t smallestIntWithNBitsSet(uint64_t n)
storm::solver::SmtSolver::CheckResult checkTleFailsWithLeq(uint64_t bound)
Check if there exists a sequence of BE failures of at least given length such that the TLE of the DFT...
void setSolverTimeout(uint_fast64_t milliseconds)
Set the timeout of the solver.
storm::solver::SmtSolver::CheckResult checkFailsAtTimepointWithEqNonMarkovianState(uint64_t timepoint, uint64_t nrNonMarkovian)
Helper function that checks if the DFT can fail at a timepoint while visiting a given number of Marko...
void convert()
Generate general variables and constraints for the DFT and store them in the corresponding maps and v...
DFTASFChecker(storm::dft::storage::DFT< ValueType > const &)
storm::solver::SmtSolver::CheckResult checkFailsLeqWithEqNonMarkovianState(uint64_t checkbound, uint64_t nrNonMarkovian)
Helper function to check if the TLE fails before or at a given timepoint while visiting exactly a giv...
void toSolver()
Generates a new solver instance and prepares it for SMT checking of the DFT.
void unsetSolverTimeout()
Unset the timeout for the solver.
storm::solver::SmtSolver::CheckResult checkTleNeverFailed()
Check if the TLE of the DFT never fails.
storm::solver::SmtSolver::CheckResult checkDependencyConflict(uint64_t dep1Index, uint64_t dep2Index, uint64_t timeout=10)
Check if two given dependencies are conflicting in their resolution, i.e.
storm::solver::SmtSolver::CheckResult checkTleFailsWithEq(uint64_t bound)
Check if there exists a sequence of BE failures of exactly given length such that the TLE of the DFT ...
Represents a Dynamic Fault Tree.
Definition DFT.h:52
Abstract base class for DFT elements.
Definition DFTElement.h:39
This class is responsible for managing a set of typed variables and all expressions using these varia...
CheckResult
possible check results
Definition SmtSolver.h:25
virtual std::unique_ptr< storm::solver::SmtSolver > create(storm::expressions::ExpressionManager &manager) const
Creates a new SMT solver instance.
Definition solver.cpp:124
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
void closeFile(std::ofstream &stream)
Close the given file after writing.
Definition file.h:47
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
Definition file.h:18