5#ifndef LINE_API_MDD_MDD_H
6#define LINE_API_MDD_MDD_H
70 std::vector<std::vector<std::vector<int>>>
node;
92 return static_cast<double>(
explicit_ints) /
static_cast<double>(den);
102 for (std::size_t k = 0; k < K_; ++k) {
103 if (
domain[k] <= 0)
throw InputError(
"MDD: a level domain must be positive");
105 node_.assign(K_, std::vector<std::vector<int>>());
106 uniq_.assign(K_, std::map<std::vector<int>,
int>());
107 cnt_.assign(K_, std::vector<long long>());
112 const std::vector<std::vector<int>>& states) {
114 for (std::size_t i = 0; i < states.size(); ++i) obj.
insert(states[i]);
118 std::size_t
K()
const {
return K_; }
119 const std::vector<int>&
domain()
const {
return domain_; }
121 int root()
const {
return root_; }
123 int node_count(std::size_t k)
const {
return static_cast<int>(node_[k].size()); }
125 const std::vector<int>&
arcs(std::size_t k,
int id)
const {
return node_[k][
id - 1]; }
128 void insert(
const std::vector<int>& state) {
129 if (state.size() != K_)
throw InputError(
"MDD::insert: state has the wrong length");
130 root_ = add_state(0, root_, state);
135 bool member(
const std::vector<int>& state)
const {
137 for (std::size_t k = 0; k < K_; ++k) {
139 id = node_[k][
id - 1][state[k]];
147 return child_count(0, root_);
157 long long index(
const std::vector<int>& state)
const {
161 for (std::size_t k = 0; k < K_; ++k) {
163 const std::vector<int>& a = node_[k][
id - 1];
164 const int v = state[k];
165 for (
int vv = 0; vv < v; ++vv) idx += child_count(k + 1, a[vv]);
173 std::vector<std::vector<int>> out;
175 std::vector<int> prefix(K_, 0);
176 enum_below(0, root_, prefix, out);
187 s.
node.assign(K_, std::vector<std::vector<int>>());
188 for (std::size_t k = 0; k < K_; ++k) {
189 s.
nnodes[k] =
static_cast<int>(node_[k].size());
190 s.
node[k] = node_[k];
203 const std::vector<std::vector<bool>> vis = reachable_ids();
204 std::vector<std::vector<std::vector<int>>> newnode(K_);
205 std::vector<std::vector<int>> remap(K_);
206 for (std::size_t k = 0; k < K_; ++k) {
207 remap[k].assign(node_[k].size() + 1, 0);
208 for (std::size_t p = 0; p < node_[k].size(); ++p) {
210 newnode[k].push_back(node_[k][p]);
211 remap[k][p + 1] =
static_cast<int>(newnode[k].size());
215 for (std::size_t k = 0; k + 1 < K_; ++k) {
216 for (std::size_t p = 0; p < newnode[k].size(); ++p) {
217 for (
int v = 0; v < domain_[k]; ++v) {
218 if (newnode[k][p][v] > 0) newnode[k][p][v] = remap[k + 1][newnode[k][p][v]];
223 if (root_ !=
TERM_FALSE) root_ = remap[0][root_];
224 for (std::size_t k = 0; k < K_; ++k) {
226 for (std::size_t p = 0; p < node_[k].size(); ++p)
227 uniq_[k][node_[k][p]] =
static_cast<int>(p + 1);
234 const std::vector<std::vector<bool>> vis = reachable_ids();
238 for (std::size_t k = 0; k < K_; ++k) {
240 for (std::size_t p = 0; p < vis[k].size(); ++p)
244 s.
mdd_ints +=
static_cast<long long>(c) * domain_[k];
245 s.
table_nodes +=
static_cast<int>(node_[k].size());
254 int make_node(std::size_t k,
const std::vector<int>& arc_row) {
255 bool all_false =
true;
256 for (std::size_t v = 0; v < arc_row.size(); ++v)
262 const std::map<std::vector<int>,
int>::const_iterator it = uniq_[k].find(arc_row);
263 if (it != uniq_[k].end())
return it->second;
264 node_[k].push_back(arc_row);
265 const int id =
static_cast<int>(node_[k].size());
266 uniq_[k][arc_row] = id;
276 int add_state(std::size_t k,
int id,
const std::vector<int>& state) {
278 std::vector<int> arc_row;
282 arc_row = node_[k][
id - 1];
283 const int v = state[k];
284 if (v < 0 || v >= domain_[k])
285 throw InputError(
"MDD::insert: a local value is outside its level domain");
286 arc_row[v] = add_state(k + 1, arc_row[v], state);
287 return make_node(k, arc_row);
290 long long child_count(std::size_t k,
int child_id)
const {
291 if (k >= K_)
return child_id ==
TERM_TRUE ? 1 : 0;
293 return count_node(k, child_id);
296 long long count_node(std::size_t k,
int id)
const {
297 long long c = cnt_[k][
id - 1];
298 if (c >= 0)
return c;
299 const std::vector<int>& a = node_[k][
id - 1];
301 for (
int v = 0; v < domain_[k]; ++v) c += child_count(k + 1, a[v]);
306 void ensure_counts()
const {
307 bool sized = !dirty_;
309 for (std::size_t k = 0; k < K_; ++k)
310 if (cnt_[k].size() != node_[k].size()) {
316 for (std::size_t k = 0; k < K_; ++k) cnt_[k].assign(node_[k].size(), -1);
321 std::vector<std::vector<bool>> reachable_ids()
const {
322 std::vector<std::vector<bool>> vis(K_);
323 for (std::size_t k = 0; k < K_; ++k) vis[k].assign(node_[k].size(),
false);
325 vis[0][root_ - 1] =
true;
326 std::vector<std::pair<std::size_t, int>> stack;
327 stack.push_back(std::make_pair(
static_cast<std::size_t
>(0), root_));
328 while (!stack.empty()) {
329 const std::pair<std::size_t, int> top = stack.back();
331 const std::size_t k = top.first;
332 if (k + 1 == K_)
continue;
333 const std::vector<int>& a = node_[k][top.second - 1];
334 for (
int v = 0; v < domain_[k]; ++v) {
336 if (ch > 0 && !vis[k + 1][ch - 1]) {
337 vis[k + 1][ch - 1] =
true;
338 stack.push_back(std::make_pair(k + 1, ch));
345 void enum_below(std::size_t k,
int id, std::vector<int>& prefix,
346 std::vector<std::vector<int>>& out)
const {
347 const std::vector<int>& a = node_[k][
id - 1];
349 for (
int v = 0; v < domain_[k]; ++v)
352 out.push_back(prefix);
356 for (
int v = 0; v < domain_[k]; ++v) {
359 enum_below(k + 1, a[v], prefix, out);
364 std::vector<int> domain_;
367 std::vector<std::vector<std::vector<int>>> node_;
369 std::vector<std::map<std::vector<int>,
int>> uniq_;
372 mutable std::vector<std::vector<long long>> cnt_;
379 std::string out =
" MDD " + std::to_string(m.
K()) +
" levels, " +
380 std::to_string(s.
num_states) +
" states in " +
381 std::to_string(s.
num_nodes) +
" nodes, footprint " +
382 std::to_string(s.
mdd_ints) +
" ints vs " +
386 " dead nodes in tables; call compact() to reclaim)";
The diagram: insert / member / index / enumerate / cardinality.
static MDD from_states(const std::vector< int > &domain, const std::vector< std::vector< int > > &states)
Build from a set of 0-based state tuples.
long long cardinality() const
|S|, the number of stored states.
MddStruct to_struct() const
Export the diagram as plain arrays for downstream algorithms.
void insert(const std::vector< int > &state)
Add a K-tuple of 0-based local values to the set.
MDD(const std::vector< int > &domain)
An empty set over the given per-level domains.
const std::vector< int > & arcs(std::size_t k, int id) const
Arc row of level-k node id (1-based id).
void compact()
Reclaim dead nodes left by the append-only build.
bool member(const std::vector< int > &state) const
True iff state is in the set; O(K).
int node_count(std::size_t k) const
Number of live nodes at level k.
std::vector< std::vector< int > > enumerate() const
All stored states as rows, in index() order.
MddStats stats() const
Storage description of the current set; only reachable nodes are counted.
long long index(const std::vector< int > &state) const
0-based lexicographic rank of state among the stored set, level 0 most significant,...
int root() const
Id of the root node, or TERM_FALSE for the empty set.
const std::vector< int > & domain() const
The exception types the port throws.
const int TERM_TRUE
Terminal node "1": a completed path is accepted.
std::string mdd_to_string(const MDD &m)
Human-readable storage summary, the twin of MDD.toString.
const int TERM_FALSE
Terminal node "0": empty subgraph.
Storage description of the set held in an MDD.
int num_nodes
Reachable non-terminal nodes.
long long explicit_ints
Integers an explicit state list would need, |S| * K.
long long mdd_ints
Integers in the reachable arc arrays, the diagram footprint.
double compression() const
Explicit footprint divided by the diagram footprint.
int table_nodes
Nodes physically held in the tables, dead ones included.
std::vector< int > nodes_per_level
Reachable node count per level.
Plain-array export of an MDD, the input contract of mdd_mcd.
int root
Id of the top (level-0) node; TERM_FALSE for the empty set.
std::vector< std::vector< std::vector< int > > > node
node[k][p][v] is the child of arc v of level-k node id p+1: a level-(k+1) node id when k < K-1,...
std::vector< int > domain
domain[k] is the number of local states at level k.
std::vector< int > nnodes
nnodes[k] is the live node count at level k.
std::size_t K
Number of variable levels.