Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SymmetryFinder.cpp
Go to the documentation of this file.
1#include "SymmetryFinder.h"
2
6
7namespace storm::dft {
8namespace utility {
9
10template<typename ValueType>
12 // Colour the DFT elements to find candidates for symmetries
14
15 std::vector<size_t> subDftIndices(storm::utility::vector::buildVectorForRange(size_t(0), dft.nrElements()));
16 storm::dft::storage::BijectionCandidates<ValueType> completeCategories = colouring.colourSubdft(subDftIndices);
17 std::map<size_t, std::vector<std::vector<size_t>>> res;
18
19 // Find symmetries for gates
20 for (auto const& colourClass : completeCategories.gateCandidates) {
21 findSymmetriesHelper(dft, colourClass.second, colouring, res);
22 }
23
24 // Find symmetries for BEs
25 for (auto const& colourClass : completeCategories.beCandidates) {
26 findSymmetriesHelper(dft, colourClass.second, colouring, res);
27 }
28
30}
31
32template<typename ValueType>
33std::map<size_t, size_t> SymmetryFinder<ValueType>::findBijection(storm::dft::storage::DFT<ValueType> const& dft, size_t index1, size_t index2,
34 storm::dft::storage::DFTColouring<ValueType> const& colouring, bool sparesAsLeaves) {
35 STORM_LOG_TRACE("Considering ids " << index1 << ", " << index2 << " for isomorphism.");
36 bool sharedSpareMode = false;
37 std::map<size_t, size_t> bijection;
38
39 if (dft.getElement(index1)->isRelevant() || dft.getElement(index2)->isRelevant()) {
40 // Relevant events need to be uniquely identified and cannot be symmetric.
41 return {};
42 }
43
44 if (dft.isBasicElement(index1)) {
45 if (!dft.isBasicElement(index2)) {
46 return {};
47 }
48 if (colouring.hasSameColour(index1, index2)) {
49 bijection[index1] = index2;
50 return bijection;
51 } else {
52 return {};
53 }
54 }
55
56 STORM_LOG_ASSERT(dft.isGate(index1), "Element is no gate.");
57 STORM_LOG_ASSERT(dft.isGate(index2), "Element is no gate.");
58 std::vector<size_t> isubdft1 = dft.getGate(index1)->independentSubDft(false);
59 std::vector<size_t> isubdft2 = dft.getGate(index2)->independentSubDft(false);
60 if (isubdft1.empty() || isubdft2.empty() || isubdft1.size() != isubdft2.size()) {
61 if (isubdft1.empty() && isubdft2.empty() && sparesAsLeaves) {
62 // Check again for shared spares
63 sharedSpareMode = true;
64 isubdft1 = dft.getGate(index1)->independentSubDft(false, true);
65 isubdft2 = dft.getGate(index2)->independentSubDft(false, true);
66 if (isubdft1.empty() || isubdft2.empty() || isubdft1.size() != isubdft2.size()) {
67 return {};
68 }
69 } else {
70 return {};
71 }
72 }
73 STORM_LOG_TRACE("Checking subdfts from " << index1 << ", " << index2 << " for isomorphism.");
74 auto LHS = colouring.colourSubdft(isubdft1);
75 auto RHS = colouring.colourSubdft(isubdft2);
76 auto IsoCheck = storm::dft::storage::DFTIsomorphismCheck<ValueType>(LHS, RHS, dft);
77
78 while (IsoCheck.findNextIsomorphism()) {
79 bijection = IsoCheck.getIsomorphism();
80 if (sharedSpareMode) {
81 bool bijectionSpareCompatible = true;
82 for (size_t elementId : isubdft1) {
83 if (dft.getElement(elementId)->isSpareGate()) {
84 auto spareLeft = std::static_pointer_cast<storm::dft::storage::elements::DFTSpare<ValueType> const>(dft.getElement(elementId));
85 auto spareRight =
86 std::static_pointer_cast<storm::dft::storage::elements::DFTSpare<ValueType> const>(dft.getElement(bijection.at(elementId)));
87
88 if (spareLeft->nrChildren() != spareRight->nrChildren()) {
89 bijectionSpareCompatible = false;
90 break;
91 }
92 // Check bijection for spare children
93 for (size_t i = 0; i < spareLeft->nrChildren(); ++i) {
94 size_t childLeftId = spareLeft->children().at(i)->id();
95 size_t childRightId = spareRight->children().at(i)->id();
96
97 STORM_LOG_ASSERT(bijection.count(childLeftId) == 0, "Child already part of bijection.");
98 if (childLeftId == childRightId) {
99 // Ignore shared child
100 continue;
101 }
102
103 // TODO generalize for more than one parent
104 if (spareLeft->children().at(i)->nrParents() != 1 || spareRight->children().at(i)->nrParents() != 1) {
105 bijectionSpareCompatible = false;
106 break;
107 }
108
109 std::map<size_t, size_t> tmpBijection = findBijection(dft, childLeftId, childRightId, colouring, false);
110 if (!tmpBijection.empty()) {
111 bijection.insert(tmpBijection.begin(), tmpBijection.end());
112 } else {
113 bijectionSpareCompatible = false;
114 break;
115 }
116 }
117 if (!bijectionSpareCompatible) {
118 break;
119 }
120 }
121 }
122 if (bijectionSpareCompatible) {
123 return bijection;
124 }
125 } else {
126 return bijection;
127 }
128 } // end while
129 return {};
130}
131
132template<typename ValueType>
133void SymmetryFinder<ValueType>::findSymmetriesHelper(storm::dft::storage::DFT<ValueType> const& dft, std::vector<size_t> const& candidates,
135 std::map<size_t, std::vector<std::vector<size_t>>>& result) {
136 if (candidates.size() <= 0) {
137 return;
138 }
139
140 std::set<size_t> foundEqClassFor;
141 for (auto it1 = candidates.cbegin(); it1 != candidates.cend(); ++it1) {
142 std::vector<std::vector<size_t>> symClass;
143 if (foundEqClassFor.count(*it1) > 0) {
144 // This item is already in a class.
145 continue;
146 }
147 auto elem1 = dft.getElement(*it1);
148 if (!elem1->hasOnlyStaticParents()) {
149 continue;
150 }
151 if (hasSeqRestriction(elem1)) {
152 continue;
153 }
154
155 std::tuple<std::vector<size_t>, std::vector<size_t>, std::vector<size_t>, std::vector<size_t>> influencedElem1Ids = getInfluencedIds(dft, *it1);
156 auto it2 = it1;
157 for (++it2; it2 != candidates.cend(); ++it2) {
158 auto elem2 = dft.getElement(*it2);
159 if (!elem2->hasOnlyStaticParents()) {
160 continue;
161 }
162 if (hasSeqRestriction(elem2)) {
163 continue;
164 }
165
166 if (influencedElem1Ids == getInfluencedIds(dft, *it2)) {
167 std::map<size_t, size_t> bijection = findBijection(dft, *it1, *it2, colouring, true);
168 if (!bijection.empty()) {
169 STORM_LOG_TRACE("Subdfts are symmetric");
170 foundEqClassFor.insert(*it2);
171 if (symClass.empty()) {
172 for (auto const& i : bijection) {
173 symClass.push_back(std::vector<size_t>({i.first}));
174 }
175 }
176 auto symClassIt = symClass.begin();
177 for (auto const& i : bijection) {
178 symClassIt->emplace_back(i.second);
179 ++symClassIt;
180 }
181 }
182 }
183 }
184
185 if (!symClass.empty()) {
186 result.emplace(*it1, symClass);
187 }
188 }
189}
190
191template<typename ValueType>
192bool SymmetryFinder<ValueType>::hasSeqRestriction(std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> elem) {
193 for (auto const& restr : elem->restrictions()) {
194 if (restr->isSeqEnforcer()) {
195 return true;
196 }
197 }
198 return false;
199}
200
201template<typename ValueType>
202std::tuple<std::vector<size_t>, std::vector<size_t>, std::vector<size_t>, std::vector<size_t>> SymmetryFinder<ValueType>::getInfluencedIds(
203 storm::dft::storage::DFT<ValueType> const& dft, size_t index) {
204 // Parents
205 std::vector<size_t> parents = dft.getElement(index)->parentIds();
206 std::sort(parents.begin(), parents.end());
207 // Ingoing dependencies
208 std::vector<size_t> ingoingDeps;
209 if (dft.isBasicElement(index)) {
210 for (auto const& dep : dft.getBasicElement(index)->ingoingDependencies()) {
211 ingoingDeps.push_back(dep->id());
212 }
213 std::sort(ingoingDeps.begin(), ingoingDeps.end());
214 }
215 // Outgoing dependencies
216 std::vector<size_t> outgoingDeps;
217 for (auto const& dep : dft.getElement(index)->outgoingDependencies()) {
218 outgoingDeps.push_back(dep->id());
219 }
220 std::sort(outgoingDeps.begin(), outgoingDeps.end());
221 std::vector<size_t> restrictions;
222 for (auto const& restr : dft.getElement(index)->restrictions()) {
223 restrictions.push_back(restr->id());
224 }
225 return std::make_tuple(parents, ingoingDeps, outgoingDeps, restrictions);
226}
227
228template class SymmetryFinder<double>;
229template class SymmetryFinder<storm::RationalFunction>;
230
231} // namespace utility
232} // namespace storm::dft
bool hasSameColour(size_t index1, size_t index2) const
BijectionCandidates< ValueType > colourSubdft(std::vector< size_t > const &subDftIndices) const
Represents a Dynamic Fault Tree.
Definition DFT.h:52
DFTElementCPointer getElement(size_t index) const
Get a pointer to an element in the DFT.
Definition DFT.h:189
size_t nrElements() const
Definition DFT.h:95
std::shared_ptr< storm::dft::storage::elements::DFTGate< ValueType > const > getGate(size_t index) const
Definition DFT.h:219
bool isGate(size_t index) const
Definition DFT.h:198
bool isBasicElement(size_t index) const
Definition DFT.h:194
Saves isomorphism between subtrees.
Abstract base class for DFT elements.
Definition DFTElement.h:38
static storm::dft::storage::DftSymmetries findSymmetries(storm::dft::storage::DFT< ValueType > const &dft)
Find symmetries in the given DFT.
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
std::vector< T > buildVectorForRange(T min, T max)
Constructs a vector [min, min+1, ...., max-1].
Definition vector.h:133
std::unordered_map< size_t, std::vector< size_t > > gateCandidates
std::unordered_map< BEColourClass< ValueType >, std::vector< size_t > > beCandidates