67#include <unordered_map>
71 template < GUM_Numeric GUM_SCALAR >
76 template < GUM_Numeric GUM_SCALAR >
83 template < GUM_Numeric GUM_SCALAR >
88 template < GUM_Numeric GUM_SCALAR >
90 const std::string& name,
91 const std::unordered_set< std::string >& temporalSet) {
92 if (!name.empty() && name.back() ==
']') {
93 const auto p = name.rfind(
'[');
94 if (p != std::string::npos && p + 1 < name.size() - 1) {
95 const std::string base = name.substr(0, p);
96 const std::string digits = name.substr(p + 1, name.size() - p - 2);
97 if (temporalSet.contains(base)
98 && std::all_of(digits.begin(), digits.end(), [](
unsigned char c) {
99 return std::isdigit(c) != 0;
101 return {base, std::stoi(digits)};
107 template < GUM_Numeric GUM_SCALAR >
109 const std::unordered_set< std::string >& temporalSet = kdbn.temporalVarNames();
113 std::unordered_map< std::string, Idx > colByName;
115 for (
const std::string& base: temporalSet) {
117 colByName.emplace(base,
_nbVars_++);
119 for (
const std::string& base: kdbn.atemporalVarNames()) {
121 colByName.emplace(base,
_nbVars_++);
131 const int lastSlice = int(
_k_) - 1;
134 const Tensor< GUM_SCALAR >& cpt =
_template_.cpt(n);
135 const auto [base, slice] =
_decode_(v.
name(), temporalSet);
141 nr.
col = colByName[base];
143 for (
Idx i = 1; i < cpt.nbrDim(); ++i) {
145 const auto [pbase, pslice] =
_decode_(pv.
name(), temporalSet);
150 pr.
col = colByName[pbase];
153 nr.
parents.push_back(std::move(pr));
159 _nodes_.push_back(std::move(nr));
163 template < GUM_Numeric GUM_SCALAR >
165 const Tensor< GUM_SCALAR >& cpt,
166 double& log2likelihood) {
168 double cumulProb = 0.0;
171 if (cumulProb > threshold)
break;
174 log2likelihood += std::log2(cpt[
_inst_]);
178 template < GUM_Numeric GUM_SCALAR >
179 std::vector< double >
182 std::string_view dirPath,
183 std::string_view csvBaseName,
186 std::string csvSeparator) {
198 template < GUM_Numeric GUM_SCALAR >
199 std::vector< double >
201 std::string_view dirPath,
202 std::string_view csvBaseName,
205 std::string csvSeparator) {
227 template < GUM_Numeric GUM_SCALAR >
228 std::vector< double >
231 const std::vector< Size >* perTraj,
232 std::string_view dirPath,
233 std::string_view csvBaseName,
236 const std::string& csvSeparator) {
238 const auto lengthAt = [&](
Idx i) {
return perTraj ? (*perTraj)[i] : fixedLen; };
241 if (csvSeparator.find(
'\n') != std::string::npos)
243 for (
Idx i = 0; i < nbSamples; ++i)
244 if (lengthAt(i) <
_k_)
249 std::vector< Idx > colOrder;
257 const std::filesystem::path dir{dirPath};
258 const std::string stem{csvBaseName};
259 std::filesystem::create_directories(dir);
261 std::vector< double > log2Ls;
262 log2Ls.reserve(nbSamples);
264 const bool hasListener =
onProgress.hasListener();
265 std::optional< Timer > timer;
273 for (std::size_t i = 0; i < nbSamples; ++i) {
274 const Size T = lengthAt(i);
279 std::vector< Idx > traj(T *
_nbVars_);
291 for (
Size t = 0; t < T; ++t)
292 traj[t *
_nbVars_ + nr.col] = drawn;
293 else traj[nr.slice *
_nbVars_ + nr.col] = drawn;
297 for (
Size t =
_k_; t < T; ++t) {
308 log2Ls.push_back(log2L);
309 const std::filesystem::path file = dir / (stem + std::to_string(i + 1) +
".csv");
313 const int p = int((i * 100) / nbSamples);
322 std::stringstream ss;
323 ss << nbSamples <<
" trajectories generated in " << timer->step() <<
" s.";
330 template < GUM_Numeric GUM_SCALAR >
335 template < GUM_Numeric GUM_SCALAR >
340 template < GUM_Numeric GUM_SCALAR >
345 template < GUM_Numeric GUM_SCALAR >
360 template < GUM_Numeric GUM_SCALAR >
362 std::string_view csvFileURL,
363 const std::vector< Idx >& traj,
366 const std::string& csvSeparator,
367 const std::vector< Idx >& colOrder)
const {
368 std::ofstream os(std::filesystem::path{csvFileURL}, std::ofstream::out);
369 if (!os)
GUM_ERROR(
IOError,
"could not open '" << csvFileURL <<
"' for writing")
372 bool firstCol =
true;
373 for (
const Idx col: colOrder) {
374 if (!firstCol) os << csvSeparator;
380 for (
Size t = 0; t < nbTimeSlices; ++t) {
383 for (
const Idx col: colOrder) {
384 if (!firstCol) os << csvSeparator;
385 os << (useLabels ?
_label_(col, traj[base + col]) : std::to_string(traj[base + col]));
392 template < GUM_Numeric GUM_SCALAR >
394 std::vector< Idx >& colOrder)
const {
396 std::iota(colOrder.begin(), colOrder.end(), 0);
400 template < GUM_Numeric GUM_SCALAR >
402 std::vector< Idx >& colOrder)
const {
410 std::vector< std::vector< Idx > > children(
_nbVars_);
411 std::vector< int > indegree(
_nbVars_, 0);
412 std::vector< bool > isAtemporal(
_nbVars_,
false);
414 auto addEdge = [&](
Idx parent,
Idx child) {
415 children[parent].push_back(child);
420 const int lastSlice = int(
_k_) - 1;
423 isAtemporal[nf.col] =
true;
427 "temporal variable '"
428 <<
_baseCols_[pr.
col] <<
"' is a parent of atemporal variable '"
429 <<
_baseCols_[nf.col] <<
"' — violates the k-DBN invariant")
430 addEdge(pr.
col, nf.col);
432 }
else if (nf.slice == lastSlice) {
440 auto topoSortBlock = [&](
bool atempBlock) {
443 if (isAtemporal[c] == atempBlock && indegree[c] == 0) q.push(c);
445 const Idx cur = q.front();
447 colOrder.push_back(cur);
448 for (
const Idx ch: children[cur])
449 if (--indegree[ch] == 0) q.push(ch);
456 topoSortBlock(
false);
459 template < GUM_Numeric GUM_SCALAR >
461 std::vector< Idx >& colOrder)
const {
463 std::reverse(colOrder.begin(), colOrder.end());
A database generator for k-order dynamic Bayesian networks.
Base class for discrete random variable.
virtual double numerical(Idx indice) const =0
get a numerical representation of the indice-th value.
VarType varType() const override=0
returns the varType of variable
virtual std::string label(Idx i) const =0
get the indice-th label. This method is pure virtual.
Exception : fatal (unknown ?) error.
A base class for discretized variables, independent of the ticks type.
Exception : input/output problem.
Exception: at least one argument passed to a function is not what was expected.
static constexpr int ATEMPORAL
Conventional time-slice value denoting an atemporal (static) variable.
Exception : operation not allowed.
Signaler< std::string_view > onStop
with a possible explanation for stopping
Signaler< Size, double > onProgress
Progression (percent) and time.
const std::string & name() const
returns the name of the variable
Idx _drawVar_(const DiscreteVariable &var, const Tensor< GUM_SCALAR > &cpt, double &log2likelihood)
inverse-CDF draw of var given the parents already set in inst; accumulates log2(P(drawn value)) into ...
Size _k_
the order of the k-DBN
Size _nbVars_
number of base variable columns
std::vector< const DiscreteVariable * > _vars_
one representative variable per base column (same order as baseCols), pointing into template so it ou...
void setVarOrderAntiTopological(std::vector< Idx > &colOrder) const
builds the reverse of setVarOrderTopological()
void setVarOrderTopological(std::vector< Idx > &colOrder) const
builds a topological column order (transition-kernel projection)
void setDiscretizedLabelModeInterval()
set discretized-label rendering to the interval label "[min,max["
std::vector< std::string > _baseCols_
col index -> base name (canonical column numbering)
static std::pair< std::string, int > _decode_(const std::string &name, const std::unordered_set< std::string > &temporalSet)
decodes a template node name into (base, slice): "B[t]" with B a known temporal process -> (B,...
void _writeTrajectory_(std::string_view csvFileURL, const std::vector< Idx > &traj, Size nbTimeSlices, bool useLabels, const std::string &csvSeparator, const std::vector< Idx > &colOrder) const
writes one trajectory CSV (header + T rows) to csvFileURL. traj is the flat row-major buffer (T x nbV...
void setDiscretizedLabelModeRandom()
set discretized-label rendering to a uniform random draw in the interval (this is the default; each l...
std::vector< Idx > _kernel_
indices, in nodes, of the slice-(k-1) nodes (the transition kernel, drives Phase 2); already in topol...
std::vector< NodeRef > _nodes_
all template nodes in topological order (drives Phase 1, the bootstrap)
~KTBNDatabaseGenerator()
destructor
void setDiscretizedLabelModeMedian()
set discretized-label rendering to the (deterministic) interval median
std::vector< double > _drawSamples_(Size nbSamples, Size fixedLen, const std::vector< Size > *perTraj, std::string_view dirPath, std::string_view csvBaseName, VarOrderMode mode, bool useLabels, const std::string &csvSeparator)
the single worker behind both drawSamples() overloads. Trajectory i's horizon is read from perTraj (w...
void _build_(const KTBN< GUM_SCALAR > &kdbn)
one-shot initialisation called by the constructor: fills the column index (baseCols,...
Instantiation _inst_
a shared instantiation over all template variables, so we don't have to rebuild it for every draw
KTBNDatabaseGenerator(const KTBN< GUM_SCALAR > &kdbn)
Constructor.
std::string _label_(Idx col, Idx idx) const
renders the label of modality idx of base column col (taking the discretized-label mode into account)
BayesNet< GUM_SCALAR > _template_
the -slice template (a small copy, independent of the horizon)
VarOrderMode
column order used for the exported CSV
void setVarOrderRandomized(std::vector< Idx > &colOrder) const
builds a uniformly random column order
Size nbVars() const
returns the number of base variable columns
DiscretizedLabelMode _discretizedLabelMode_
rendering of discretized variables when labels are requested
std::vector< double > drawSamples(Size nbSamples, Size nbTimeSlices, std::string_view dirPath, std::string_view csvBaseName, VarOrderMode mode=VarOrderMode::RANDOM, bool useLabels=true, std::string csvSeparator=",")
Generates nbSamples independent trajectories, writing one CSV file per trajectory into dirPath.
#define GUM_ERROR(type, msg)
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Size Idx
Type for indexes.
Size NodeId
Type for node ids.
GUM_SHARED_PUBLIC std::mt19937 & randomGenerator()
define a random_engine with correct seed
GUM_SHARED_PUBLIC double randomProba()
Returns a random double between 0 and 1 included (i.e.
include the inlined functions if necessary
#define GUM_EMIT2(signal, arg1, arg2)
#define GUM_EMIT1(signal, arg1)
a template node, precompiled for fast sampling
Idx col
its base column index in baseCols
int slice
its template slice (ATEMPORAL if static)
const DiscreteVariable * var
the node variable (in template)
std::vector< ParentRef > parents
its parents (drives sampling and topology)
const Tensor< GUM_SCALAR > * cpt
its CPT (in template)
a parent of a template node, precompiled for fast sampling
bool isAtemporal
whether the parent is atemporal
const DiscreteVariable * var
the parent variable (in template)
Idx col
its base column index in baseCols
int lag
time steps back: parentTime = nodeTime - lag
Contains useful methods for random stuff.