5#ifndef LINE_API_MDD_MDD_REC_H
6#define LINE_API_MDD_MDD_REC_H
65typedef std::vector<std::vector<bool>>
MddMask;
71T mdd_rec_node(
const MddStruct& mdds,
const std::vector<std::vector<T>>& g,
const MddMask& mask,
72 std::size_t l,
int id, std::vector<std::vector<T>>& memo,
73 std::vector<std::vector<bool>>& done) {
74 if (done[l][
id - 1])
return memo[l][
id - 1];
77 const std::vector<int>& a = mdds.
node[l][
id - 1];
78 for (
int v = 0; v < mdds.
domain[l]; ++v) {
79 if (!mask.empty() && !mask[l][
static_cast<std::size_t
>(v)])
continue;
80 const T gv = g[l][
static_cast<std::size_t
>(v)];
81 if (gv == zero)
continue;
84 if (l + 1 == mdds.
K) {
89 below = mdd_rec_node(mdds, g, mask, l + 1, ch, memo, done);
93 memo[l][
id - 1] = acc;
94 done[l][
id - 1] =
true;
99void mdd_rec_check(
const MddStruct& mdds,
const std::vector<std::vector<T>>& g,
100 const MddMask& mask,
const char* caller) {
101 if (g.size() != mdds.
K)
102 throw InputError(std::string(caller) +
": one g_l per level is required");
103 for (std::size_t l = 0; l < mdds.
K; ++l) {
104 if (g[l].size() !=
static_cast<std::size_t
>(mdds.
domain[l]))
105 throw InputError(std::string(caller) +
": g_l must have one entry per local state");
106 if (!mask.empty() && mask[l].size() !=
static_cast<std::size_t
>(mdds.
domain[l]))
107 throw InputError(std::string(caller) +
": the mask must have one entry per local state");
109 if (!mask.empty() && mask.size() != mdds.
K)
110 throw InputError(std::string(caller) +
": the mask must have one row per level");
125 detail::mdd_rec_check(mdds, g, mask,
"mdd_rec");
128 std::vector<std::vector<T>> memo(mdds.
K);
129 std::vector<std::vector<bool>> done(mdds.
K);
130 for (std::size_t l = 0; l < mdds.
K; ++l) {
131 memo[l].assign(
static_cast<std::size_t
>(mdds.
nnodes[l]), zero);
132 done[l].assign(
static_cast<std::size_t
>(mdds.
nnodes[l]),
false);
134 return detail::mdd_rec_node(mdds, g, mask, 0, mdds.
root, memo, done);
152 if (l >= mdds.
K)
throw InputError(
"mdd_rec_marginal: level index is out of range");
153 const std::size_t d =
static_cast<std::size_t
>(mdds.
domain[l]);
155 for (std::size_t k = 0; k < d; ++k) {
157 for (std::size_t j = 0; j < mdds.
K; ++j)
158 mask[j].assign(
static_cast<std::size_t
>(mdds.
domain[j]),
true);
159 for (std::size_t v = 0; v < d; ++v) mask[l][v] = (v == k);
The exception types the port throws.
Quasi-reduced ordered Multi-valued Decision Diagram.
std::vector< std::vector< bool > > MddMask
Per-level admissible local values, the restriction of Sec.
T mdd_rec(const MddStruct &mdds, const std::vector< std::vector< T > > &g)
The normalising constant G = sum_{s in S} prod_l g_l(s_l).
const int TERM_TRUE
Terminal node "1": a completed path is accepted.
T mdd_rec_masked(const MddStruct &mdds, const std::vector< std::vector< T > > &g, const MddMask &mask)
Unnormalised mass of the masked subset of the reachable set (Algorithm 1).
std::vector< T > mdd_rec_marginal(const MddStruct &mdds, const std::vector< std::vector< T > > &g, std::size_t l)
Unnormalised masses of {s in S : s_l = k}, one per local value k of level l.
const int TERM_FALSE
Terminal node "0": empty subgraph.
Number-type abstraction for the templated API port.
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.