69#include <unordered_map>
77 template < GUM_Numeric GUM_SCALAR >
79 std::string_view dirPath,
80 std::string_view csvBaseName,
83 const std::unordered_set< std::string >& atemporalVars,
84 const std::vector< std::string >& missingSymbols,
97 namespace fs = std::filesystem;
98 const fs::path firstCSV = fs::path{dirPath} / (std::string{csvBaseName} +
"1.csv");
99 std::ifstream is(firstCSV, std::ifstream::in);
104 GUM_ERROR(
IOError,
"Empty trajectory file (no header row): " << firstCSV.string())
105 const std::vector< std::string >& header = parser.
current();
112 "atemporal variable '" << aname <<
"' not found in the CSV header")
117 template < GUM_Numeric GUM_SCALAR >
119 std::string_view dirPath,
120 std::string_view csvBaseName,
123 const std::vector< std::string >& missingSymbols,
142 template < GUM_Numeric GUM_SCALAR >
144 std::string_view dirPath,
145 std::string_view csvBaseName,
148 const std::vector< std::string >& missingSymbols) {
157 template < GUM_Numeric GUM_SCALAR >
159 std::string_view dirPath,
160 std::string_view csvBaseName,
163 const BayesNet< GUM_SCALAR >& bn,
164 const std::unordered_set< std::string >& atemporalVars,
165 const std::vector< std::string >& missingSymbols) :
176 for (
const NodeId node: bn.nodes())
183 "atemporal variable '" << aname <<
"' not found in the schema BN")
188 template < GUM_Numeric GUM_SCALAR >
197 template < GUM_Numeric GUM_SCALAR >
211 KTBN< GUM_SCALAR > best;
213 double bestScore = 0.0;
215 std::vector< std::pair< Size, double > > scores;
216 std::vector< std::pair< std::string, std::string > >
223 std::unique_ptr< KTBNLearner< GUM_SCALAR > > learnerPtr
232 : std::make_unique< KTBNLearner< GUM_SCALAR > >(
_dirPath_,
248 "the trajectories contain missing values. Neither aGrUM's structure learning "
249 "nor the cross-k order score can evaluate an incomplete window. Call "
250 "ignoreMissingSymbols() to learn and score on the fully observed data only "
251 "(see its warning: dropping skews the selection towards larger k).")
258 for (
const Size len: learner.nbRows())
260 logN = std::log2(nbObs);
266 KTBN< GUM_SCALAR > candidate = learner.learnKTBN();
275 scores.emplace_back(k, score);
276 if (
bestK == 0 || score > bestScore) {
278 best = std::move(candidate);
283 ? learner.latentVariables()
284 : std::vector< std::pair< std::string, std::string > >{};
298 template < GUM_Numeric GUM_SCALAR >
304 "bestK() is undefined: call learnKTBN() before querying the selected order.")
308 template < GUM_Numeric GUM_SCALAR >
309 const std::vector< std::pair< std::string, std::string > >&
317 template < GUM_Numeric GUM_SCALAR >
318 const std::vector< std::pair< Size, double > >&
324 "scorePerCandidateK() is undefined: call learnKTBN() before querying the per-k scores.")
332 template < GUM_Numeric GUM_SCALAR >
337 template < GUM_Numeric GUM_SCALAR >
363 template < GUM_Numeric GUM_SCALAR >
364 std::vector< std::tuple< std::string, std::string, std::string > >
366 std::vector< std::tuple< std::string, std::string, std::string > > vals;
367 const auto add = [&](std::string k, std::string v, std::string c =
"") {
368 vals.emplace_back(std::move(k), std::move(v), std::move(c));
371 const auto arcs = [](
const std::set< std::pair< std::string, std::string > >& s) {
374 for (
const auto& [a, b]: s) {
375 if (!first) r +=
", ";
381 const auto names = [](
const std::set< std::string >& s) {
384 for (
const auto& n: s) {
385 if (!first) r +=
", ";
392 const auto kernelArcs = [](
const std::set< std::tuple< std::string, std::string, int > >& s) {
395 for (
const auto& [a, b, lag]: s) {
396 if (!first) r +=
", ";
398 r += a +
"->" + b +
" (lag " + std::to_string(lag) +
")";
403 add(
"Candidate orders", std::to_string(
_kMin_) +
".." + std::to_string(
_kMax_));
404 add(
"Selected k",
_bestK_ == 0 ?
"not learned yet" : std::to_string(
_bestK_));
405 add(
"Base variables", std::to_string(
_baseNames_.size()));
411 add(
"Algorithm",
"Greedy Hill Climbing");
414 add(
"Algorithm",
"Extended Greedy Hill Climbing");
417 add(
"Algorithm",
"Local Search with Tabu List");
418 add(
"Tabu list size", std::to_string(
_tabuSize_));
421 default : add(
"Algorithm",
"(other)");
break;
429 add(
"Correction",
"No correction");
440 add(
"Structure score",
"Log2Likelihood");
443 default : add(
"Structure score",
"(other)");
break;
483 template < GUM_Numeric GUM_SCALAR >
486 const auto st =
state();
487 std::size_t maxkey = 0;
488 for (
const auto& t: st)
489 maxkey = std::max(maxkey, std::get< 0 >(t).length());
492 for (
const auto& t: st) {
493 s += std::format(
"{:<{}} : {}", std::get< 0 >(t), maxkey, std::get< 1 >(t));
494 if (!std::get< 2 >(t).empty()) s += std::format(
" ({})", std::get< 2 >(t));
504 template < GUM_Numeric GUM_SCALAR >
510 template < GUM_Numeric GUM_SCALAR >
516 template < GUM_Numeric GUM_SCALAR >
522 template < GUM_Numeric GUM_SCALAR >
528 template < GUM_Numeric GUM_SCALAR >
534 template < GUM_Numeric GUM_SCALAR >
540 template < GUM_Numeric GUM_SCALAR >
549 template < GUM_Numeric GUM_SCALAR >
555 template < GUM_Numeric GUM_SCALAR >
561 template < GUM_Numeric GUM_SCALAR >
571 template < GUM_Numeric GUM_SCALAR >
578 template < GUM_Numeric GUM_SCALAR >
587 template < GUM_Numeric GUM_SCALAR >
593 template < GUM_Numeric GUM_SCALAR >
600 template < GUM_Numeric GUM_SCALAR >
610 template < GUM_Numeric GUM_SCALAR >
620 template < GUM_Numeric GUM_SCALAR >
626 template < GUM_Numeric GUM_SCALAR >
632 template < GUM_Numeric GUM_SCALAR >
642 template < GUM_Numeric GUM_SCALAR >
654 template < GUM_Numeric GUM_SCALAR >
657 std::string_view headNode) {
658 const auto [tailBase, tailSlice] =
_determineNode_(std::string{tailNode});
659 const auto [headBase, headSlice] =
_determineNode_(std::string{headNode});
671 template < GUM_Numeric GUM_SCALAR >
675 std::string_view headBase,
684 template < GUM_Numeric GUM_SCALAR >
687 std::string_view headNode) {
688 const auto [tailBase, tailSlice] =
_determineNode_(std::string{tailNode});
689 const auto [headBase, headSlice] =
_determineNode_(std::string{headNode});
698 template < GUM_Numeric GUM_SCALAR >
702 std::string_view headBase,
711 template < GUM_Numeric GUM_SCALAR >
714 std::string_view headNode) {
715 const auto [tailBase, tailSlice] =
_determineNode_(std::string{tailNode});
716 const auto [headBase, headSlice] =
_determineNode_(std::string{headNode});
729 template < GUM_Numeric GUM_SCALAR >
733 std::string_view headBase,
742 template < GUM_Numeric GUM_SCALAR >
745 std::string_view headNode) {
746 const auto [tailBase, tailSlice] =
_determineNode_(std::string{tailNode});
747 const auto [headBase, headSlice] =
_determineNode_(std::string{headNode});
757 template < GUM_Numeric GUM_SCALAR >
761 std::string_view headBase,
774 template < GUM_Numeric GUM_SCALAR >
778 std::string_view headBase) {
785 template < GUM_Numeric GUM_SCALAR >
789 std::string_view headBase) {
796 template < GUM_Numeric GUM_SCALAR >
800 std::string_view headBase) {
810 template < GUM_Numeric GUM_SCALAR >
814 std::string_view headBase) {
821 template < GUM_Numeric GUM_SCALAR >
824 std::string_view headBase) {
836 template < GUM_Numeric GUM_SCALAR >
839 std::string_view headBase) {
848 template < GUM_Numeric GUM_SCALAR >
851 std::string_view headBase) {
860 template < GUM_Numeric GUM_SCALAR >
863 std::string_view headBase) {
870 template < GUM_Numeric GUM_SCALAR >
878 template < GUM_Numeric GUM_SCALAR >
888 template < GUM_Numeric GUM_SCALAR >
896 template < GUM_Numeric GUM_SCALAR >
906 template < GUM_Numeric GUM_SCALAR >
914 template < GUM_Numeric GUM_SCALAR >
924 template < GUM_Numeric GUM_SCALAR >
932 template < GUM_Numeric GUM_SCALAR >
942 template < GUM_Numeric GUM_SCALAR >
946 std::string_view headBase,
955 template < GUM_Numeric GUM_SCALAR >
958 std::string_view head) {
965 std::string first{tail}, second{head};
966 if (second < first) std::swap(first, second);
976 template < GUM_Numeric GUM_SCALAR >
980 std::string_view headBase,
989 template < GUM_Numeric GUM_SCALAR >
992 std::string_view head) {
999 std::string first{tail}, second{head};
1000 if (second < first) std::swap(first, second);
1006 template < GUM_Numeric GUM_SCALAR >
1013 template < GUM_Numeric GUM_SCALAR >
1020 template < GUM_Numeric GUM_SCALAR >
1027 template < GUM_Numeric GUM_SCALAR >
1038 template < GUM_Numeric GUM_SCALAR >
1039 const std::unordered_set< std::string >&
1044 template < GUM_Numeric GUM_SCALAR >
1053 template < GUM_Numeric GUM_SCALAR >
1057 "unknown base variable '" << base <<
"': it is not one of the data columns")
1063 "atemporal variable '" << base <<
"' cannot be given a time slice (got " << slice
1064 <<
"): use KTBN::ATEMPORAL")
1072 "negative time slice " << slice <<
" for '" << base
1073 <<
"': slices start at 0 (use KTBN::ATEMPORAL to address an "
1074 "atemporal variable)")
1075 if (slice >=
static_cast< int >(
_kMax_))
1077 "time slice " << slice <<
" for '" << base
1078 <<
"' is out of range: it must be < kMax (" <<
_kMax_ <<
")")
1081 template < GUM_Numeric GUM_SCALAR >
1083 std::string_view headBase,
1088 for (
const std::string_view base: {tailBase, headBase})
1095 if (lag >=
static_cast< int >(
_kMax_))
1097 "kernel lag " << lag <<
" is out of range: it must be < kMax (" <<
_kMax_
1098 <<
"), so some candidate k can place the tail at slice k-1-lag >= 0")
1105 template < GUM_Numeric GUM_SCALAR >
1111 template < GUM_Numeric GUM_SCALAR >
1150 template < GUM_Numeric GUM_SCALAR >
1155 bool scoreBased =
false;
1200 template < GUM_Numeric GUM_SCALAR >
1203 const int ik =
static_cast< int >(k);
1207 auto fits = [&](
const std::string& node) {
return _determineNode_(node).second < ik; };
1225 const int tailSlice = ik - 1 - lag;
1226 if (tailSlice >= 0) learner.
addForbiddenArc(tailBase, tailSlice, headBase, ik - 1);
1229 const int tailSlice = ik - 1 - lag;
1230 if (tailSlice >= 0) learner.
addMandatoryArc(tailBase, tailSlice, headBase, ik - 1);
1251 template < GUM_Numeric GUM_SCALAR >
1252 template <
typename PerInstance,
typename PerNodeFinal >
1254 PerInstance perInstance,
1255 PerNodeFinal perNodeFinal)
const {
1256 namespace fs = std::filesystem;
1257 const int k =
static_cast< int >(net.k());
1265 const Tensor< GUM_SCALAR >* cpt;
1267 std::vector< std::string > dimName;
1268 std::vector< std::pair< std::string, int > > dimNode;
1270 std::unordered_map< Size, double > counts;
1273 auto makeEval = [&](
const Tensor< GUM_SCALAR >& cpt) {
1277 e.selfDom = cpt.variable(0).domainSize();
1278 e.dimName.reserve(cpt.nbrDim());
1279 e.dimNode.reserve(cpt.nbrDim());
1280 for (
Idx d = 0; d < cpt.nbrDim(); ++d) {
1281 std::string name = cpt.variable(d).name();
1283 e.dimName.push_back(std::move(name));
1290 const auto& temporalBases = net.temporalVarNames();
1291 std::vector< std::vector< NodeEval > > temporalEvals(k);
1292 for (
int slice = 0; slice < k; ++slice) {
1293 temporalEvals[slice].reserve(temporalBases.size());
1294 for (
const auto& base: temporalBases)
1295 temporalEvals[slice].push_back(makeEval(net.cpt(base, slice)));
1299 std::vector< NodeEval > atemporalEvals;
1300 atemporalEvals.reserve(net.atemporalVarNames().size());
1301 for (
const auto& base: net.atemporalVarNames())
1307 std::vector< std::vector< std::string > > window(k);
1325 std::unordered_map< std::string, std::size_t > colOf;
1326 std::unordered_map< std::string, std::string > atempVal;
1328 std::ifstream pis(file, std::ifstream::in);
1332 const auto& header = pre.
current();
1333 for (std::size_t c = 0; c < header.size(); ++c)
1334 colOf[header[c]] = c;
1336 const std::size_t nbAtemp = net.atemporalVarNames().size();
1337 while (atempVal.size() < nbAtemp && pre.
next()) {
1338 const auto& row = pre.
current();
1339 for (
const auto& c: net.atemporalVarNames()) {
1340 if (atempVal.contains(c))
continue;
1341 const std::string& tok = row[colOf.at(c)];
1342 if (!missing.contains(tok)) atempVal[c] = tok;
1347 std::ifstream is(file, std::ifstream::in);
1359 auto labelOf = [&](
const std::string& varBase,
1362 int scoredSlice) ->
const std::string* {
1365 const auto it = atempVal.find(varBase);
1366 return (it == atempVal.end()) ? nullptr : &it->second;
1370 const int varTime = scoredTime - (scoredSlice - varSlice);
1372 const std::string& tok = window[varTime % k][colOf.at(varBase)];
1373 return missing.contains(tok) ? nullptr : &tok;
1377 while (parser.
next()) {
1378 const auto& cur = parser.
current();
1379 window[t % k].assign(cur.begin(), cur.end());
1383 const int childSlice = (t < k - 1) ? t : (k - 1);
1384 for (NodeEval& e: temporalEvals[childSlice]) {
1388 bool complete =
true;
1389 for (std::size_t d = 0; d < e.dimName.size(); ++d) {
1390 const auto& [vbase, vslice] = e.dimNode[d];
1391 const std::string* lbl = labelOf(vbase, vslice, t, childSlice);
1392 if (lbl ==
nullptr) {
1396 e.inst.chgVal(e.dimName[d], *lbl);
1398 if (complete) perInstance(e);
1408 for (NodeEval& e: atemporalEvals) {
1409 bool complete =
true;
1410 for (std::size_t d = 0; d < e.dimName.size(); ++d) {
1411 const auto it = atempVal.find(e.dimNode[d].first);
1412 if (it == atempVal.end()) {
1416 e.inst.chgVal(e.dimName[d], it->second);
1418 if (complete) perInstance(e);
1424 for (
auto& slice: temporalEvals)
1425 for (NodeEval& e: slice)
1427 for (NodeEval& e: atemporalEvals)
1431 template < GUM_Numeric GUM_SCALAR >
1438 [&logL](
auto& e) { logL += std::log2((*e.cpt)[e.inst]); },
1443 template < GUM_Numeric GUM_SCALAR >
1451 double logL = 0.0, penalty = 0.0;
1455 logL += std::log2((*e.cpt)[e.inst]);
1458 for (
Idx d = 1; d < e.cpt->nbrDim(); ++d)
1459 idx = idx * e.cpt->variable(d).domainSize() + e.inst.val(e.cpt->variable(d));
1460 e.counts[idx] += 1.0;
1462 [
this, &penalty](
auto& e) {
1463 for (
const auto& [cfg, n]: e.counts)
1464 penalty +=
_ctable_.log2Cnr(e.selfDom, n);
1466 return logL - penalty;
1469 template < GUM_Numeric GUM_SCALAR >
1476 for (
const auto& [base, slice]: net.nodes()) {
1477 double cell = net.variable(base, slice).domainSize() - 1.0;
1478 for (
const auto& [pbase, pslice]: net.parents(base, slice))
1479 cell *= net.variable(pbase, pslice).domainSize();
1485 template < GUM_Numeric GUM_SCALAR >
1487 double logN)
const {
Class for fast parsing of CSV file (never more than one line in application memory).
A k-TBN learner that also selects the order k from the data.
Class representing a Bayesian network.
Exception : input/output problem.
Class for assigning/browsing values to tuples of discrete variables.
Instantiation()
Default constructor: creates an empty tuple.
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.
Error: The database contains some missing values.
Exception : operation not allowed.
Class for fast parsing of CSV file (never more than one line in application memory).
bool next()
gets the next line of the csv stream and parses it
const std::vector< std::string > & current() const
returns the current parsed line
@ EXTENDED_GREEDY_HILL_CLIMBING
@ LOCAL_SEARCH_WITH_TABU_LIST
void _checkBaseIsTemporal_(std::string_view base, std::string_view context) const
Throw InvalidArgument unless base is a known temporal base. context completes "cannot appear in <cont...
void _checkArcTemporallyFeasible_(std::string_view tail, std::string_view head, std::string_view action) const
Reject an arc the k-TBN definition can never contain, so eraseForbiddenArc and addMandatoryArc both f...
static std::unordered_set< std::string > _scanConstantColumns_(std::string_view dirPath, std::string_view csvBaseName, Size nbSamples, const std::vector< std::string > &missingSymbols)
Scans every trajectory and returns the base names classified atemporal: those whose value never chang...
static void _checkMinimalOrder_(Size order, std::string_view label)
Throw InvalidArgument unless order is at least 2, label naming the offending parameter ("k" for the f...
std::string _encode_(std::string_view base, int slice) const
(base, slice) -> engine name ("A[1]" / atemporal engine name). Pure function, shared by every learner...
std::pair< std::string, int > _determineNode_(const std::string &name) const
engine name -> (base, slice); atemporal names map to KTBN::ATEMPORAL. Shared by every learner; only t...
Learns a k-TBN (order k + structure + parameters) from trajectory CSVs.
std::string toString() const
Human-readable summary of the recorded configuration (candidate order range, algorithm / score / corr...
KTBNAdaptiveLearner< GUM_SCALAR > & addForbiddenArcAllSlices(std::string_view tailBase, std::string_view headBase) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
bool _induceTypes_
whether numeric columns are retyped (see KTBNLearner); unused (and forced false) when a schema BN is ...
std::set< std::string > _noParentNodes_
root nodes (no parents), as engine names
KTBNAdaptiveLearner< GUM_SCALAR > & allowArcAdditions(bool allow=true) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
std::vector< std::string > _missingSymbols_
symbols in the CSVs to interpret as missing values
std::unordered_set< std::string > _atemporalVars_
base names of the atemporal (static) variables
bool _allowAdditions_
recorded graph-change permissions / indegree cap
void _verifyKernelArc_(std::string_view tailBase, std::string_view headBase, int lag) const
Throw InvalidArgument unless tailBase and headBase are known, temporal base variables (a kernel-relat...
KTBNAdaptiveLearner< GUM_SCALAR > & useOrderScoreBIC()
Select k by BIC (the default): keep the k whose learned model maximises .
std::unique_ptr< BayesNet< GUM_SCALAR > > _prior_bn_
optional variable-schema BN (set by the BN constructor): when present, each per-k KTBNLearner is buil...
Size _bestK_
k selected by the last learnKTBN() call, or 0 as a sentinel while no learning has happened yet....
std::string _dirPath_
directory holding the trajectory CSV files
Size _kMax_
largest order to explore (candidates are kMin..kMax)
KTBNAdaptiveLearner< GUM_SCALAR > & addMandatoryArc(std::string_view tailNode, std::string_view headNode) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
bool _isKnownBase_(std::string_view base) const override
whether base is one of this learner's variables; the base names read at construction,...
KTBNAdaptiveLearner< GUM_SCALAR > & eraseForbiddenArcAllSlices(std::string_view tailBase, std::string_view headBase) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & useNMLCorrection() override
void _applyConstraints_(KTBNLearner< GUM_SCALAR > &learner, Size k) const
Replay the recorded structural constraints onto learner (built for order k). Engine-name constraints ...
std::vector< std::pair< std::string, std::string > > _bestLatentVariables_
latent-variable arcs (engine-name pairs) reported by the winning candidate's MIIC run,...
IBNLearner::BNLearnerPriorType _prior_
recorded prior and its weight
double _orderSelectionScore_(const KTBN< GUM_SCALAR > &net, double logN) const
The cross-k order-selection score of net under the recorded orderScore criterion, given logN = log2 o...
const std::vector< std::pair< std::string, std::string > > & latentVariables() const
Engine-name (tail, head) pairs of arcs the selected model's MIIC run flagged as hiding a latent varia...
std::set< std::string > _noChildrenNodes_
leaf nodes (no children), as engine names
KTBNAdaptiveLearner< GUM_SCALAR > & useGreedyHillClimbing() override
double _fNMLScore_(const KTBN< GUM_SCALAR > &net) const
fNML order score of net over the recorded trajectories: , with the node's domain size and the count...
KTBNAdaptiveLearner< GUM_SCALAR > & eraseForbiddenIntraSliceArc(std::string_view tailBase, std::string_view headBase) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
void _forEachScoredNode_(const KTBN< GUM_SCALAR > &net, PerInstance perInstance, PerNodeFinal perNodeFinal) const
Stream every scored template-node instance of net over the recorded trajectories, driving both the li...
~KTBNAdaptiveLearner()
Constructor — the candidate orders are kMin..kMax.
KTBNAdaptiveLearner< GUM_SCALAR > & eraseMandatoryArc(std::string_view tailNode, std::string_view headNode) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
IBNLearner::AlgoType _algo_
recorded structure-learning algorithm
KTBNAdaptiveLearner< GUM_SCALAR > & addMandatoryKernelArc(std::string_view tailBase, int lag, std::string_view headBase)
Force an arc from tailBase, lag slices before the kernel, to headBase in the kernel....
OrderScoreType _orderScore_
recorded cross-k order-selection criterion (the outer score used by learnKTBN() to pick the best k; i...
Size kMax() const
Largest order explored (the kMax argument of the constructor).
KTBNAdaptiveLearner< GUM_SCALAR > & allowArcDeletions(bool allow=true) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & erasePossibleEdge(std::string_view tailBase, int tailSlice, std::string_view headBase, int headSlice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner(std::string_view dirPath, std::string_view csvBaseName, Size nbSamples, Size kMax, const std::unordered_set< std::string > &atemporalVars, const std::vector< std::string > &missingSymbols={"?"}, bool induceTypes=true)
Constructor — the candidate orders are kMin..kMax.
KTBNAdaptiveLearner< GUM_SCALAR > & useSmoothingPrior(double weight=1.0) override
bool _ignoreMissingSymbols_
whether incomplete rows/instances are dropped (see ignoreMissingSymbols())
KTBNAdaptiveLearner< GUM_SCALAR > & addNoChildrenNode(std::string_view base, int slice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & addPossibleEdge(std::string_view tailBase, int tailSlice, std::string_view headBase, int headSlice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
std::set< std::pair< std::string, std::string > > _forbiddenArcsAllSlices_
forbidden all-slices arcs, as (tailBase, headBase) pairs
KTBNAdaptiveLearner< GUM_SCALAR > & addForbiddenIntraSliceArc(std::string_view tailBase, std::string_view headBase) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
std::set< std::pair< std::string, std::string > > _mandatoryArcs_
mandatory arcs, as (tail, head) engine-name pairs
std::set< std::pair< std::string, std::string > > _possibleEdges_
MIIC candidate edges, as (tail, head) engine-name pairs.
const std::vector< std::pair< Size, double > > & scorePerCandidateK() const
Per-candidate cross-k scores from the last learnKTBN() call, as (k, score) pairs for k = kMin....
const std::unordered_set< std::string > & _atemporalVarNames_() const override
atemporal base names for IKTBNLearner's shared encode/_determineNode_; the set recorded at constructi...
IBNLearner::ScoreType _score_
recorded per-k structure score (the inner score, replayed on each candidate)
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreBDeu() override
std::set< std::pair< std::string, std::string > > _forbiddenArcs_
forbidden arcs, as (tail, head) engine-name pairs
std::set< std::pair< std::string, std::string > > _forbiddenIntraSliceArcs_
forbidden intra-slice arcs, as (tailBase, headBase) pairs
KTBNAdaptiveLearner< GUM_SCALAR > & addForbiddenArc(std::string_view tailNode, std::string_view headNode) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
Size bestK() const
Order k selected by the last learnKTBN() call.
bool isIgnoringMissingSymbols() const
Whether incomplete rows and instances are dropped. False by default.
Size _nbSamples_
number of CSV files to read
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreMDL() override
double _log2Likelihood_(const KTBN< GUM_SCALAR > &net) const
Factorized log2-likelihood of net over the recorded trajectories, comparable across candidate k (the ...
void useScorefNML() override
KTBNAdaptiveLearner< GUM_SCALAR > & eraseForbiddenKernelArc(std::string_view tailBase, int lag, std::string_view headBase)
Undo a previous addForbiddenKernelArc (same (tailBase, lag, headBase) triple).
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreAIC() override
void _applyConfig_(KTBNLearner< GUM_SCALAR > &learner) const
Apply the recorded score / algorithm / correction / prior onto a freshly-built learner....
KTBNAdaptiveLearner< GUM_SCALAR > & eraseMandatoryKernelArc(std::string_view tailBase, int lag, std::string_view headBase)
Undo a previous addMandatoryKernelArc (same (tailBase, lag, headBase) triple).
KTBNAdaptiveLearner< GUM_SCALAR > & useExtendedGreedyHillClimbing() override
Size _kMin_
smallest order worth exploring (candidates are kMin..kMax). Starts at 2 and is recomputed by recomput...
std::set< std::tuple< std::string, std::string, int > > _mandatoryKernelArcs_
mandatory kernel-relative arcs, same shape as forbiddenKernelArcs
log_2 where the penalty replaces BIC s KTBNAdaptiveLearner< GUM_SCALAR > & useOrderScorefNML()
by a sum of per-node, per-parent-configuration multinomial parametric complexities (regret) – data-de...
KTBNAdaptiveLearner< GUM_SCALAR > & eraseForbiddenArc(std::string_view tailNode, std::string_view headNode) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
void _recomputeKMin_()
Recompute kMin from scratch: max(2, 1 + the largest concrete slice named by any recorded forbidden/ma...
KTBNAdaptiveLearner< GUM_SCALAR > & useMDLCorrection() override
std::vector< std::pair< Size, double > > _scorePerCandidateK_
per-candidate (k, order-score) pairs from the last learnKTBN() run, in ascending k....
VariableLog2ParamComplexity _ctable_
cache of log2 of the multinomial parametric complexity C^r_n, used by the fNML order penalty....
double _countParameters_(const KTBN< GUM_SCALAR > &net) const
Number of free parameters of net's template: summed over every template node (all initial slices,...
KTBNAdaptiveLearner< GUM_SCALAR > & allowArcReversals(bool allow=true) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
std::vector< std::tuple< std::string, std::string, std::string > > state() const
The recorded configuration as (key, value, comment) tuples (mirrors KTBNLearner::state()); toString()...
KTBN< GUM_SCALAR > learnKTBN() override
Learns the best k in [kMin, kMax] together with the structure and the CPTs: one KTBNLearner is built ...
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreLog2Likelihood() override
std::unordered_set< std::string > _baseNames_
all base variable names (temporal + atemporal), read from the first trajectory CSV header at construc...
KTBNAdaptiveLearner< GUM_SCALAR > & eraseNoParentNode(std::string_view base, int slice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & ignoreMissingSymbols(bool ignore=true)
Learn and score on the fully observed data only, dropping every row and every scoring instance that c...
void _raiseKMinForSlice_(int slice)
Raise kMin, if needed, so that kMin > slice: a smaller candidate would silently drop a constraint nam...
KTBNAdaptiveLearner< GUM_SCALAR > & useOrderScoreAIC()
Select k by AIC: keep the k whose learned model maximises (a lighter, sample-size-independent comple...
void _verifyBase_(std::string_view base, int slice) const
Throw InvalidArgument unless base is a known base variable and slice is valid for it: base must be in...
std::string _csvBaseName_
stem of each trajectory file name
Size _tabuSize_
tabu-list parameters (meaningful when algo is LOCAL_SEARCH_WITH_TABU_LIST)
KTBNAdaptiveLearner< GUM_SCALAR > & useLocalSearchWithTabuList(Size tabu_size=100, Size nb_decrease=2) override
static std::unordered_set< std::string > _inferAtemporalVars_(std::string_view dirPath, std::string_view csvBaseName, Size nbSamples, Size kMax, const std::vector< std::string > &missingSymbols)
checks kMax >= 2 and nbSamples >= 1, then delegates to the shared IKTBNLearner::scanConstantColumns()...
KTBNAdaptiveLearner< GUM_SCALAR > & setMaxIndegree(Size max_indegree) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreBD() override
KTBNAdaptiveLearner< GUM_SCALAR > & addNoParentNode(std::string_view base, int slice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & useScoreBIC() override
CorrectedMutualInformation::KModeTypes _correction_
recorded MIIC correction
KTBNAdaptiveLearner< GUM_SCALAR > & addForbiddenKernelArc(std::string_view tailBase, int lag, std::string_view headBase)
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
KTBNAdaptiveLearner< GUM_SCALAR > & useNoCorrection() override
KTBNAdaptiveLearner< GUM_SCALAR > & useMIIC() override
KTBNAdaptiveLearner< GUM_SCALAR > & eraseNoChildrenNode(std::string_view base, int slice) override
Forbid an arc from tailBase, lag slices before the kernel, to headBase in the kernel: tailBase at sli...
std::set< std::tuple< std::string, std::string, int > > _forbiddenKernelArcs_
forbidden kernel-relative arcs, as (tailBase, headBase, lag) triples: tailBase at slice k-1-lag -> he...
std::string checkScorePriorCompatibility() const
Warning string if the recorded score and prior are incompatible, empty otherwise. Data-free: it evalu...
Learns a k-TBN (structure and/or parameters) from trajectory CSVs.
KTBNLearner< GUM_SCALAR > & useNMLCorrection() override
Engine-name pairs (tail, head) of arcs flagged as hiding a latent variable by MIIC (merged from all i...
KTBNLearner< GUM_SCALAR > & addForbiddenArc(std::string_view tailNode, std::string_view headNode) override
Forbid tailNode from ever parenting headNode (engine names, e.g. "X[1]", "C").
KTBNLearner< GUM_SCALAR > & useScoreAIC() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
KTBNLearner< GUM_SCALAR > & useGreedyHillClimbing() override
KTBNLearner< GUM_SCALAR > & useScoreLog2Likelihood() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
KTBNLearner< GUM_SCALAR > & addForbiddenArcAllSlices(std::string_view tailBase, std::string_view headBase) override
Forbid tailBase -> headBase at every causally-possible slice pair (every lag, not just matching slice...
KTBNLearner< GUM_SCALAR > & useScoreBD() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
KTBNLearner< GUM_SCALAR > & allowArcReversals(bool allow=true) override
Allow or forbid arc reversals during structure search.
KTBNLearner< GUM_SCALAR > & addNoChildrenNode(std::string_view base, int slice) override
Declare a single (base, slice) node as a leaf (no children).
KTBNLearner< GUM_SCALAR > & allowArcDeletions(bool allow=true) override
Allow or forbid arc deletions during structure search.
KTBNLearner< GUM_SCALAR > & useExtendedGreedyHillClimbing() override
KTBNLearner< GUM_SCALAR > & useNoCorrection() override
Engine-name pairs (tail, head) of arcs flagged as hiding a latent variable by MIIC (merged from all i...
KTBNLearner< GUM_SCALAR > & allowArcAdditions(bool allow=true) override
Allow or forbid arc additions during structure search.
KTBNLearner< GUM_SCALAR > & useScoreBIC() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
void useScorefNML() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
KTBNLearner< GUM_SCALAR > & useScoreMDL() override
Returns a warning string if the current score and prior are incompatible, empty string otherwise.
KTBNLearner< GUM_SCALAR > & addMandatoryArc(std::string_view tailNode, std::string_view headNode) override
Force tailNode to be a parent of headNode (engine names, e.g. "X[1]", "C").
KTBNLearner< GUM_SCALAR > & setMaxIndegree(Size max_indegree) override
Cap the number of parents of any single node.
KTBNLearner< GUM_SCALAR > & addForbiddenIntraSliceArc(std::string_view tailBase, std::string_view headBase) override
Forbid tailBase -> headBase at every intra-slice position (i.e. tailBase[t] -> headBase[t] for all t ...
KTBNLearner< GUM_SCALAR > & addPossibleEdge(std::string_view tailBase, int tailSlice, std::string_view headBase, int headSlice) override
Add a candidate edge for MIIC (only edges explicitly listed are explored).
KTBNLearner< GUM_SCALAR > & useSmoothingPrior(double weight=1.0) override
KTBNLearner< GUM_SCALAR > & addNoParentNode(std::string_view base, int slice) override
Declare a single (base, slice) node as a root (no parents).
KTBNLearner< GUM_SCALAR > & useLocalSearchWithTabuList(Size tabu_size=100, Size nb_decrease=2) override
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
std::string isPriorCompatible() const final
indicates whether the prior is compatible (meaningful) with the score
#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.
Header files of gum::Instantiation.
include the inlined functions if necessary
the base class for all a priori
the class for computing AIC scores
the class for computing Bayesian Dirichlet (BD) log2 scores
the class for computing BDeu scores
the class for computing BIC scores
the class for computing Log2-likelihood scores
the class for computing MDL scores
the class for computing fNML scores