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