Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
FailureBoundFinder.cpp
Go to the documentation of this file.
2
3namespace storm::dft {
4namespace utility {
5
6uint64_t FailureBoundFinder::correctLowerBound(std::shared_ptr<storm::dft::modelchecker::DFTASFChecker> smtchecker, uint64_t bound, uint_fast64_t timeout) {
7 STORM_LOG_DEBUG("Lower bound correction - try to correct bound " << std::to_string(bound));
8 uint64_t boundCandidate = bound;
9 uint64_t nrDepEvents = 0;
10 uint64_t nrNonMarkovian = 0;
11 auto dft = smtchecker->getDFT();
12
13 // Count dependent events
14 for (size_t i = 0; i < dft.nrElements(); ++i) {
15 std::shared_ptr<storm::dft::storage::elements::DFTElement<double> const> element = dft.getElement(i);
16 if (element->isBasicElement()) {
17 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
18 if (be->hasIngoingDependencies()) {
19 ++nrDepEvents;
20 }
21 }
22 }
23
24 // Only need to check as long as bound candidate + nr of non-Markovians to check is smaller than number of dependent events
25 while (nrNonMarkovian <= nrDepEvents && boundCandidate >= 0) {
26 if (nrNonMarkovian == 0 and boundCandidate == 0) {
27 nrNonMarkovian = 1;
28 }
29 STORM_LOG_TRACE("Lower bound correction - check possible bound " << std::to_string(boundCandidate) << " with " << std::to_string(nrNonMarkovian)
30 << " non-Markovian states");
31 // The uniqueness transformation for constantly failed BEs guarantees that a DFT never fails
32 // in step 0 without intermediate non-Markovians, thus forcibly set nrNonMarkovian
33 smtchecker->setSolverTimeout(timeout * 1000);
34 storm::solver::SmtSolver::CheckResult tmp_res = smtchecker->checkFailsLeqWithEqNonMarkovianState(boundCandidate + nrNonMarkovian, nrNonMarkovian);
35 smtchecker->unsetSolverTimeout();
36 switch (tmp_res) {
38 /* If SAT, there is a sequence where only boundCandidate-many BEs fail directly and rest is nonMarkovian.
39 * Bound candidate is vaild, therefore check the next one */
40 STORM_LOG_TRACE("Lower bound correction - SAT");
41 // Prevent integer underflow
42 if (boundCandidate == 0) {
43 STORM_LOG_DEBUG("Lower bound correction - corrected bound to 0");
44 return 0;
45 }
46 --boundCandidate;
47 break;
49 // If any query returns unknown, we cannot be sure about the bound and fall back to the naive one
50 STORM_LOG_DEBUG("Lower bound correction - Solver returned 'Unknown', corrected to 1");
51 return 1;
52 default:
53 // if query is UNSAT, increase number of non-Markovian states and try again
54 STORM_LOG_TRACE("Lower bound correction - UNSAT");
55 ++nrNonMarkovian;
56 break;
57 }
58 }
59 // if for one candidate all queries are UNSAT, it is not valid. Return last valid candidate
60 STORM_LOG_DEBUG("Lower bound correction - corrected bound to " << std::to_string(boundCandidate + 1));
61 return boundCandidate + 1;
62}
63
64uint64_t FailureBoundFinder::correctUpperBound(std::shared_ptr<storm::dft::modelchecker::DFTASFChecker> smtchecker, uint64_t bound, uint_fast64_t timeout) {
65 STORM_LOG_DEBUG("Upper bound correction - try to correct bound " << std::to_string(bound));
66 uint64_t boundCandidate = bound;
67 uint64_t nrDepEvents = 0;
68 uint64_t nrNonMarkovian = 0;
69 uint64_t currentTimepoint = 0;
70 auto dft = smtchecker->getDFT();
71 // Count dependent events
72 for (size_t i = 0; i < dft.nrElements(); ++i) {
73 std::shared_ptr<storm::dft::storage::elements::DFTElement<double> const> element = dft.getElement(i);
74 if (element->isBasicElement()) {
75 auto be = std::static_pointer_cast<storm::dft::storage::elements::DFTBE<double> const>(element);
76 if (be->hasIngoingDependencies()) {
77 ++nrDepEvents;
78 }
79 }
80 }
81 while (boundCandidate >= 0) {
82 currentTimepoint = bound + 1;
83 while (currentTimepoint - boundCandidate > 0) {
84 --currentTimepoint;
85 nrNonMarkovian = currentTimepoint - boundCandidate;
86 STORM_LOG_TRACE("Upper bound correction - candidate " << std::to_string(boundCandidate) << " check split " << std::to_string(currentTimepoint)
87 << "|" << std::to_string(nrNonMarkovian));
88 smtchecker->setSolverTimeout(timeout * 1000);
89 storm::solver::SmtSolver::CheckResult tmp_res = smtchecker->checkFailsAtTimepointWithEqNonMarkovianState(currentTimepoint, nrNonMarkovian);
90 smtchecker->unsetSolverTimeout();
91 switch (tmp_res) {
93 STORM_LOG_TRACE("Upper bound correction - SAT");
94 STORM_LOG_DEBUG("Upper bound correction - corrected to bound " << boundCandidate << " (TLE can fail at sequence point "
95 << std::to_string(currentTimepoint) << " with "
96 << std::to_string(nrNonMarkovian) << " non-Markovian states)");
97 return boundCandidate;
99 // If any query returns unknown, we cannot be sure about the bound and fall back to the naive one
100 STORM_LOG_DEBUG("Upper bound correction - Solver returned 'Unknown', corrected to bound " << bound);
101 return bound;
102 default:
103 // if query is UNSAT, increase number of non-Markovian states and try again
104 STORM_LOG_TRACE("Lower bound correction - UNSAT");
105 break;
106 }
107 }
108 --boundCandidate;
109 }
110
111 // if for one candidate all queries are UNSAT, it is not valid. Return last valid candidate
112 STORM_LOG_DEBUG("Upper bound correction - corrected bound to " << std::to_string(boundCandidate));
113 return boundCandidate;
114}
115
116uint64_t FailureBoundFinder::getLeastFailureBound(storm::dft::storage::DFT<double> const &dft, bool useSMT, uint_fast64_t timeout) {
117 if (useSMT) {
118 STORM_LOG_TRACE("Compute lower bound for number of BE failures necessary for the DFT to fail");
119
121 smtchecker.toSolver();
122
123 uint64_t bound = 0;
124 while (bound < dft.nrBasicElements() + 1) {
125 smtchecker.setSolverTimeout(timeout * 1000);
127 smtchecker.unsetSolverTimeout();
128 switch (tmp_res) {
130 if (!dft.getDependencies().empty()) {
131 return correctLowerBound(std::make_shared<storm::dft::modelchecker::DFTASFChecker>(smtchecker), bound, timeout);
132 } else {
133 return bound;
134 }
136 STORM_LOG_DEBUG("Lower bound: Solver returned 'Unknown'");
137 return bound;
138 default:
139 ++bound;
140 break;
141 }
142 }
143
144 return bound;
145 } else {
146 // naive bound
147 return 1;
148 }
149}
150
151uint64_t FailureBoundFinder::getLeastFailureBound(storm::dft::storage::DFT<RationalFunction> const &dft, bool useSMT, uint_fast64_t timeout) {
152 if (useSMT) {
153 STORM_LOG_WARN("SMT encoding does not support rational functions");
154 }
155 return 1;
156}
157
158uint64_t FailureBoundFinder::getAlwaysFailedBound(storm::dft::storage::DFT<double> const &dft, bool useSMT, uint_fast64_t timeout) {
159 STORM_LOG_TRACE("Compute bound for number of BE failures such that the DFT always fails");
160 if (useSMT) {
162 smtchecker.toSolver();
163
165 return dft.nrBasicElements() + 1;
166 }
167 uint64_t bound = dft.nrBasicElements();
168 while (bound >= 0) {
169 smtchecker.setSolverTimeout(timeout * 1000);
171 smtchecker.unsetSolverTimeout();
172 switch (tmp_res) {
174 if (!dft.getDependencies().empty()) {
175 return correctUpperBound(std::make_shared<storm::dft::modelchecker::DFTASFChecker>(smtchecker), bound, timeout);
176 } else {
177 return bound;
178 }
180 STORM_LOG_DEBUG("Upper bound: Solver returned 'Unknown'");
181 return bound;
182 default:
183 --bound;
184 break;
185 }
186 }
187 return bound;
188 } else {
189 // naive bound
190 return dft.nrBasicElements() + 1;
191 }
192}
193
194uint64_t FailureBoundFinder::getAlwaysFailedBound(storm::dft::storage::DFT<RationalFunction> const &dft, bool useSMT, uint_fast64_t timeout) {
195 if (useSMT) {
196 STORM_LOG_WARN("SMT encoding does not support rational functions");
197 }
198 return dft.nrBasicElements() + 1;
199}
200
202
203} // namespace utility
204} // namespace storm::dft
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.
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 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
size_t nrBasicElements() const
Definition DFT.h:99
std::vector< size_t > const & getDependencies() const
Definition DFT.h:154
static uint64_t getLeastFailureBound(storm::dft::storage::DFT< double > const &dft, bool useSMT=false, uint_fast64_t timeout=10)
Get the minimal number of BEs necessary for the TLE to fail (lower bound for number of failures to ch...
static uint64_t getAlwaysFailedBound(storm::dft::storage::DFT< double > const &dft, bool useSMT=false, uint_fast64_t timeout=10)
Get the number of BE failures for which the TLE always fails (upper bound for number of failures to c...
CheckResult
possible check results
Definition SmtSolver.h:25
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_DEBUG(message)
Definition logging.h:23
#define STORM_LOG_TRACE(message)
Definition logging.h:17