24 : transitionMatrix(transitionMatrix),
27 initialStates(initialStates),
28 targetProbMap(targetProbMap),
29 matrixFormat(matrixFormat) {
30 computePredecessors();
35 computeSPSuccessors();
38 initializeShortestPaths();
40 candidatePaths.resize(numStates);
46 :
ShortestPathsGenerator<T>(transitionMatrix, vectorToMap(targetProbVector), initialStates, matrixFormat) {}
71 return kShortestPaths[metaTarget][k - 1].distance;
79 Path<T> currentPath = kShortestPaths[metaTarget][k - 1];
80 boost::optional<state_t> maybePredecessor = currentPath.
predecessorNode;
83 while (maybePredecessor) {
84 state_t predecessor = maybePredecessor.get();
85 stateSet.
set(predecessor,
true);
87 currentPath = kShortestPaths[predecessor][currentPath.
predecessorK - 1];
98 std::vector<state_t> backToFrontList;
100 Path<T> currentPath = kShortestPaths[metaTarget][k - 1];
101 boost::optional<state_t> maybePredecessor = currentPath.
predecessorNode;
104 while (maybePredecessor) {
105 state_t predecessor = maybePredecessor.get();
106 backToFrontList.push_back(predecessor);
108 currentPath = kShortestPaths[predecessor][currentPath.
predecessorK - 1];
112 return backToFrontList;
120 graphPredecessors.resize(numStates);
122 for (
state_t i = 0; i < numStates - 1; i++) {
123 for (
auto const& transition : transitionMatrix.getRowGroup(i)) {
126 if (!isMetaTargetPredecessor(i)) {
127 graphPredecessors[transition.getColumn()].push_back(i);
135 for (
auto targetProbPair : targetProbMap) {
136 graphPredecessors[metaTarget].push_back(targetProbPair.first);
141void ShortestPathsGenerator<T>::performDijkstra() {
145 T inftyDistance = zero<T>();
146 T zeroDistance = one<T>();
147 shortestPathDistances.resize(numStates, inftyDistance);
148 shortestPathPredecessors.resize(numStates, boost::optional<state_t>());
152 std::set<std::pair<T, state_t>, std::greater<std::pair<T, state_t>>> dijkstraQueue;
154 for (
state_t initialState : initialStates) {
155 shortestPathDistances[initialState] = zeroDistance;
156 dijkstraQueue.emplace(zeroDistance, initialState);
159 while (!dijkstraQueue.empty()) {
160 state_t currentNode = (*dijkstraQueue.begin()).second;
161 dijkstraQueue.erase(dijkstraQueue.begin());
163 if (!isMetaTargetPredecessor(currentNode)) {
165 for (
auto const& transition : transitionMatrix.getRowGroup(currentNode)) {
166 state_t otherNode = transition.getColumn();
169 T alternateDistance = shortestPathDistances[currentNode] * convertDistance(currentNode, otherNode, transition.getValue());
170 assert((zero<T>() <= alternateDistance) && (alternateDistance <= one<T>()));
171 if (alternateDistance > shortestPathDistances[otherNode]) {
172 shortestPathDistances[otherNode] = alternateDistance;
173 shortestPathPredecessors[otherNode] = boost::optional<state_t>(currentNode);
174 dijkstraQueue.emplace(alternateDistance, otherNode);
179 T alternateDistance = shortestPathDistances[currentNode] * targetProbMap[currentNode];
180 if (alternateDistance > shortestPathDistances[metaTarget]) {
181 shortestPathDistances[metaTarget] = alternateDistance;
182 shortestPathPredecessors[metaTarget] = boost::optional<state_t>(currentNode);
190void ShortestPathsGenerator<T>::computeSPSuccessors() {
191 shortestPathSuccessors.resize(numStates);
193 for (
state_t i = 0;
i < numStates;
i++) {
194 if (shortestPathPredecessors[i]) {
195 state_t predecessor = shortestPathPredecessors[
i].get();
196 shortestPathSuccessors[predecessor].push_back(i);
202void ShortestPathsGenerator<T>::initializeShortestPaths() {
203 kShortestPaths.resize(numStates);
206 std::queue<state_t> bfsQueue;
207 for (
state_t initialState : initialStates) {
208 bfsQueue.push(initialState);
211 while (!bfsQueue.empty()) {
212 state_t currentNode = bfsQueue.front();
215 if (!kShortestPaths[currentNode].empty()) {
219 for (
state_t successorNode : shortestPathSuccessors[currentNode]) {
220 bfsQueue.push(successorNode);
226 kShortestPaths[currentNode].push_back(Path<T>{shortestPathPredecessors[currentNode], 1, shortestPathDistances[currentNode]});
231T ShortestPathsGenerator<T>::getEdgeDistance(
state_t tailNode,
state_t headNode)
const {
233 if (headNode != metaTarget) {
236 for (
auto const& transition : transitionMatrix.getRowGroup(tailNode)) {
237 if (transition.getColumn() == headNode) {
238 return convertDistance(tailNode, headNode, transition.getValue());
244 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Should not happen.");
247 assert(isMetaTargetPredecessor(tailNode));
248 return targetProbMap.at(tailNode);
253void ShortestPathsGenerator<T>::computeNextPath(
state_t node,
unsigned long k) {
255 assert(kShortestPaths[node].size() == k - 1);
261 Path<T> shortestPathToNode = kShortestPaths[node][1 - 1];
263 for (
state_t predecessor : graphPredecessors[node]) {
265 Path<T> pathToPredecessorPlusEdge = {boost::optional<state_t>(predecessor), 1,
266 shortestPathDistances[predecessor] * getEdgeDistance(predecessor, node)};
267 candidatePaths[node].insert(pathToPredecessorPlusEdge);
270 auto it = std::find(candidatePaths[node].begin(), candidatePaths[node].end(), shortestPathToNode);
271 if (it != candidatePaths[node].end()) {
272 candidatePaths[node].erase(it);
277 if (not(k == 2 && isInitialState(node))) {
281 Path<T> previousShortestPath = kShortestPaths[node][k - 1 - 1];
284 state_t predecessor = previousShortestPath.predecessorNode.get();
286 unsigned long tailK = previousShortestPath.predecessorK;
291 if (kShortestPaths[predecessor].size() < tailK + 1) {
293 computeNextPath(predecessor, tailK + 1);
296 if (kShortestPaths[predecessor].size() >= tailK + 1) {
298 Path<T> pathToPredecessorPlusEdge = {boost::optional<state_t>(predecessor), tailK + 1,
299 kShortestPaths[predecessor][tailK + 1 - 1].distance * getEdgeDistance(predecessor, node)};
300 candidatePaths[node].insert(pathToPredecessorPlusEdge);
306 if (!candidatePaths[node].empty()) {
307 Path<T> minDistanceCandidate = *(candidatePaths[node].begin());
308 for (
auto path : candidatePaths[node]) {
309 if (path.distance > minDistanceCandidate.distance) {
310 minDistanceCandidate = path;
314 candidatePaths[node].erase(std::find(candidatePaths[node].begin(), candidatePaths[node].end(), minDistanceCandidate));
315 kShortestPaths[node].push_back(minDistanceCandidate);
318 STORM_LOG_TRACE(
"KSP: no candidates, this will trigger nonexisting ksp after exiting these recursions. TODO: handle here");
323void ShortestPathsGenerator<T>::computeKSP(
unsigned long k) {
325 throw std::invalid_argument(
"Index 0 is invalid, since we use 1-based indices (sorry)!");
328 unsigned long alreadyComputedK = kShortestPaths[metaTarget].size();
330 for (
unsigned long nextK = alreadyComputedK + 1; nextK <= k; nextK++) {
331 computeNextPath(metaTarget, nextK);
332 if (kShortestPaths[metaTarget].size() < nextK) {
333 unsigned long lastExistingK = nextK - 1;
334 STORM_LOG_DEBUG(
"KSP throws (as expected) due to nonexistence -- maybe this is unhandled and causes the Python interface to segfault?");
335 STORM_LOG_DEBUG(
"last existing k-SP has k=" + std::to_string(lastExistingK));
336 STORM_LOG_DEBUG(
"maybe this is unhandled and causes the Python interface to segfault?");
337 throw std::invalid_argument(
"k-SP does not exist for k=" + std::to_string(k));
343void ShortestPathsGenerator<T>::printKShortestPath(
state_t targetNode,
unsigned long k,
bool head)
const {
345 Path<T> p = kShortestPaths[targetNode][k - 1];
348 std::cout <<
"Path (reversed";
349 if (targetNode == metaTarget) {
350 std::cout <<
", w/ meta-target";
352 std::cout <<
"), dist (prob)=" << p.distance <<
": [";
355 std::cout <<
" " << targetNode;
357 if (p.predecessorNode) {
358 printKShortestPath(p.predecessorNode.get(), p.predecessorK,
false);
367std::ostream& operator<<(std::ostream& out,
Path<T> const& p) {
372template std::ostream& operator<<(std::ostream& out,
Path<double> const& p);