LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mdd_reachset.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_MDD_MDD_REACHSET_H
6#define LINE_API_MDD_MDD_REACHSET_H
7
8/**
9 * @file
10 * @ingroup api_mdd
11 * Reachability set generation into a decision diagram.
12 *
13 * Port of matlab/src/api/mdd/mdd_reachset.m, jline.api.mdd.Mdd_reachset and
14 * python/line_solver/api/mdd/reachset.py, after A.S. Miner, G. Ciardo,
15 * "Efficient Reachability Set Generation and Storage Using Decision Diagrams",
16 * ICATPN 1999, LNCS 1639, pp.6-25.
17 *
18 * This is the basic (explicit-frontier) realisation: a breadth-first search
19 * enumerates successors while the MDD provides the O(K) membership test that
20 * replaces the usual explicit visited hash. The stored set lives entirely in
21 * the MDD (`O(#nodes)` memory); only the transient BFS frontier is held
22 * explicitly. Symbolic image computation / saturation, which removes the
23 * explicit frontier too, is the natural next step but is out of scope here and
24 * is what caps the wall-clock saving -- the storage saving is real regardless.
25 */
26
27#include <cstddef>
28#include <vector>
29
30#include "line/api/mdd/mdd.h"
32
33namespace line {
34namespace mdd {
35
36/**
37 * Generate and store the reachability set into a quasi-reduced ordered MDD.
38 *
39 * @param domain per-level local-state counts, values 0..domain[k]-1
40 * @param init the initial global state, 0-based local values
41 * @param nextfun the next-state function
42 * @return an MDD holding every state reachable from init
43 */
44inline MDD mdd_reachset(const std::vector<int>& domain, const std::vector<int>& init,
45 const MddNextState& nextfun) {
46 MDD diagram(domain);
47 diagram.insert(init);
48
49 std::vector<std::vector<int>> frontier;
50 frontier.push_back(init);
51 std::size_t head = 0;
52 while (head < frontier.size()) {
53 const std::vector<int> s = frontier[head];
54 ++head;
55 if (nextfun) {
56 const std::vector<std::vector<int>> successors = nextfun(s);
57 for (std::size_t r = 0; r < successors.size(); ++r) {
58 if (!diagram.member(successors[r])) {
59 diagram.insert(successors[r]);
60 frontier.push_back(successors[r]);
61 }
62 }
63 }
64 // drop already-expanded rows periodically to bound frontier memory
65 if (head > 1024 && 2 * head > frontier.size()) {
66 frontier.erase(frontier.begin(), frontier.begin() + static_cast<long>(head));
67 head = 0;
68 }
69 }
70 diagram.compact(); // reclaim the dead nodes left by the append-only inserts
71 return diagram;
72}
73
74} // namespace mdd
75} // namespace line
76
77#endif // LINE_API_MDD_MDD_REACHSET_H
The diagram: insert / member / index / enumerate / cardinality.
Definition mdd.h:97
void insert(const std::vector< int > &state)
Add a K-tuple of 0-based local values to the set.
Definition mdd.h:128
void compact()
Reclaim dead nodes left by the append-only build.
Definition mdd.h:202
bool member(const std::vector< int > &state) const
True iff state is in the set; O(K).
Definition mdd.h:135
Quasi-reduced ordered Multi-valued Decision Diagram.
The rate side of the decision-diagram domain: local matrices, events, the Kronecker descriptor,...
std::function< std::vector< std::vector< int > >(const std::vector< int > &)> MddNextState
Successor function over local indices, for mdd_reachset.
Definition mdd_types.h:155
MDD mdd_reachset(const std::vector< int > &domain, const std::vector< int > &init, const MddNextState &nextfun)
Generate and store the reachability set into a quasi-reduced ordered MDD.