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