Class TrainedDagSimulatorGNM
- All Implemented Interfaces:
TetradSerializable, Serializable
Trained DAG simulator (GNM): learn local mechanisms with non-additive noise and resimulate
This class is a “train-then-resimulate” simulator: given an observed DataSet and a
user-supplied acyclic Graph (treated as a DAG), it learns a local conditional mechanism
for each node and then generates new samples by running the DAG forward in topological order.
Primary motivation. The purpose is to construct realistic-looking synthetic datasets anchored to an observed dataset while making the assumed causal structure explicit. Because the mechanisms are learned from real data and noise is bootstrapped, substantially different DAGs can yield resimulated data with similar marginals and pairwise structure; however, scoring the resulting data with the wrong graph should degrade in a systematic way. This helps separate “looks plausible” from “fits the causal structure.”
Model family (GNM)
For each node Y with parents Pa(Y), the fitted mechanism is a general-noise model
Y = g(Pa(Y), e)
where e is a bootstrapped noise term and g is learned by a small neural network that
allows the noise to enter non-additively. One simple realization is a two-stage fit:
- Fit
μ(x) ≈ E[Y | x]using an MLP on parent featuresx. - Compute residuals
e = y - μ(x)on the training rows, bootstrape, and train a second network to predictyfrom(x, e).
At simulation time, sample e by bootstrap and generate y = g(x, e).
Mixed data support
- Continuous child: uses the general-noise mechanism described above; noise values are bootstrapped
(optionally stratified by discrete-parent signatures) and injected as an explicit input to
g. - Discrete child: uses a softmax classifier; optionally mixes unconditional base rates with parent-conditional probabilities to “turn down” parent influence.
Parent encoding
- Continuous parents enter as z-scored scalars.
- Discrete parents enter as one-hot blocks (with a configurable maximum number of levels).
Missingness
Training is done node-by-node using only rows where the child and all of its parents are observed.
Rows with any missing among {Y} ∪ Pa(Y) are skipped for that node. Simulation produces complete
samples given the learned mechanisms.
Notes and limitations
- This is intentionally a lightweight, dependency-minimal mechanism learner (single hidden layer, SGD, L2 decay), intended for simulation fidelity and portability rather than best-in-class predictive modeling.
- Because the simulator runs forward under the supplied DAG, unrealistic samples may occur when simulated parent configurations leave the support of the training data (extrapolation). Optional diagnostics may warn when parent z-scores become extreme.
- The GNM is strictly more expressive than the ANM: it can represent non-additive effects of noise on the child given parents, while still using bootstrapped noise anchored to the observed dataset.
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classRepresents a report for a single node in a trained directed acyclic graph (DAG) structure.static final classRepresents a configuration class containing various hyperparameters and settings used for the simulation and training of a directed acyclic graph (DAG) model.static final classRepresents the result of a simulation, containing continuous and discrete data for variables, metadata about the simulation, and support for generating reports. -
Constructor Summary
ConstructorsConstructorDescriptionTrainedDagSimulatorGNM(DataSet data, Graph dag, TrainedDagSimulatorGNM.Params params) Constructs a new instance of the TrainedDagSimulatorGNM class. -
Method Summary
Modifier and TypeMethodDescriptiondouble[]childProbsGiven(int childIdx, double[] contRow, int[] discRow) For a discrete child, the generative class distribution p(Y | pa) given the parent values incontRow/discRow: exactly the distributiongenerateChild(int, double[], int[], Random)samples from, including anylambdaParentsmixing with base rates.voidfillRowFromData(DataSet source, int row, double[] contRow, int[] discRow) Copies one observed row into the parallel continuous / discrete row arrays used by the mechanisms, so a child can be generated conditional on an observed parent configuration.voidfit()Fit one mechanism per node given its parents in the supplied DAG.voidgenerateChild(int childIdx, double[] contRow, int[] discRow, Random rng) Generates one value of nodechildIdxfrom its fitted mechanism, reading the parents fromcontRow/discRowand writing the result into the child's slot of the same arrays.Human-readable report (one block per node).Structured per-node reports.intReturns the number of variables.booleanisDiscreteVariable(int idx) Reports whether a variable is discrete.static booleanisMissingCell(DataSet data, int row, int col) True if the cell holds a missing value: NaN or an infinity for a continuous variable, or a negative category code for a discrete variable.doublepredictNode(int nodeIndex, DataSet data, int row) Returns the predicted value for the given node at the given row of the supplied dataset, using the already-fitted mechanism for that node.double[]predictNodeProbs(int nodeIndex, DataSet data, int row) Returns the predicted probability distribution for the given node at the given row of the supplied dataset.static intsafeGetInt(DataSet data, int row, int col) Safely retrieves an integer value from the specified row and column of a DataSet.simulate(int nSamples) Simulates data by generating continuous and discrete values for all variables in the trained directed acyclic graph (DAG) model.simulate(int nSamples, long seed) Simulates data by generating continuous and discrete values for all variables in the trained directed acyclic graph (DAG) model.withReducedParents(int nodeIndex, int[] reducedParentIndices, long seed) Returns a new simulator that is identical to this one except that the mechanism fornodeIndexhas been retrained using only the specified reduced parent set.voidwriteFitReportTxt(File file) Writes a human-readable textual representation of the fit report to the specified file.
-
Constructor Details
-
TrainedDagSimulatorGNM
Constructs a new instance of the TrainedDagSimulatorGNM class. This simulator utilizes a directed acyclic graph (DAG) representation and corresponding data to model variable relationships and simulate values based on learned mechanisms.- Parameters:
data- ADataSetobject containing the variables and observations to be utilized in the simulation. Must not benull.dag- AGraphobject representing the structure of the DAG to be used. The DAG must be acyclic and must also not benull.params- An optionalParamsobject containing additional configuration parameters for the simulator. If this parameter isnull, default parameters will be used.- Throws:
NullPointerException- Ifdataordagisnull.IllegalArgumentException- Ifdagcontains cycles (i.e., is not a valid DAG).
-
-
Method Details
-
withReducedParents
public TrainedDagSimulatorGNM withReducedParents(int nodeIndex, int[] reducedParentIndices, long seed) Returns a new simulator that is identical to this one except that the mechanism fornodeIndexhas been retrained using only the specified reduced parent set. All other node mechanisms are reused unchanged from this instance — they are not refitted.This is the correct way to isolate the contribution of a single edge: hold all other mechanisms constant and retrain only the affected child, rather than refitting the whole graph on a modified DAG.
fit()must have been called on this instance before calling this method.- Parameters:
nodeIndex- dataset column index of the node to retrainreducedParentIndices- dataset column indices of the parents to use (a strict subset of the node's current parents)seed- random seed for retraining- Returns:
- a new
TrainedDagSimulatorGNMwith the hybrid mechanism array - Throws:
IllegalStateException- iffit()has not been called
-
isMissingCell
True if the cell holds a missing value: NaN or an infinity for a continuous variable, or a negative category code for a discrete variable. Tetrad encodes discrete missing values asDiscreteVariable.MISSING_VALUE(−99); since valid category codes are non-negative, any negative code is treated as missing.- Parameters:
data- the datasetrow- the row indexcol- the column index- Returns:
- whether the cell is missing
-
safeGetInt
Safely retrieves an integer value from the specified row and column of a DataSet. Attempts to retrieve the value as an integer, falling back to processing it as a double if an exception occurs. If the value is not finite, it returns -1.- Parameters:
data- the DataSet from which the value is to be retrievedrow- the row index from which the value is to be extractedcol- the column index from which the value is to be extracted- Returns:
- the integer value at the specified row and column, or -1 if the value is non-finite or an error occurs
-
getFitReportText
Human-readable report (one block per node).- Returns:
- A string containing
-
getNodeReports
Structured per-node reports.- Returns:
- An unmodifiable list of node reports, each containing fit metrics for a node.
-
writeFitReportTxt
Writes a human-readable textual representation of the fit report to the specified file. The report contains information about the trained DAG simulator, including parameters and per-node reports on training fit metrics.- Parameters:
file- The target file where the fit report will be written. Must be writable and notnull.- Throws:
IOException- If an error occurs while writing to the file.
-
predictNode
Returns the predicted value for the given node at the given row of the supplied dataset, using the already-fitted mechanism for that node. The dataset does not need to be the training data — this is intended for OOS evaluation on held-out folds.- Parameters:
nodeIndex- dataset column index of the node to predictdata- the dataset containing the row to predictrow- the row index- Returns:
- predicted value, or NaN for root nodes
- Throws:
IllegalStateException- if fit() has not been called
-
predictNodeProbs
Returns the predicted probability distribution for the given node at the given row of the supplied dataset. For discrete nodes this is the full softmax distribution. For continuous nodes this is a single-element array containing the conditional mean prediction. Returns null for root nodes. Intended for OOS cross-entropy evaluation in k-fold CV.- Parameters:
nodeIndex- dataset column index of the nodedata- the held-out datasetrow- row index within that dataset- Returns:
- probability array, or null for root nodes
- Throws:
IllegalStateException- if fit() has not been called
-
fit
public void fit()Fit one mechanism per node given its parents in the supplied DAG. -
simulate
Simulates data by generating continuous and discrete values for all variables in the trained directed acyclic graph (DAG) model. It performs the simulation using a specified number of samples and a seed for random number generation.- Parameters:
nSamples- The number of samples to generate during the simulation. Must be a positive integer.- Returns:
- A
SimResultobject containing the simulated continuous and discrete values, along with additional metadata related to the DAG and variables used in the simulation.
-
fillRowFromData
Copies one observed row into the parallel continuous / discrete row arrays used by the mechanisms, so a child can be generated conditional on an observed parent configuration.- Parameters:
source- the dataset to read from (any dataset over these variables)row- the row index insourcecontRow- output array of lengthgetNumVariables()discRow- output array of lengthgetNumVariables()
-
generateChild
Generates one value of nodechildIdxfrom its fitted mechanism, reading the parents fromcontRow/discRowand writing the result into the child's slot of the same arrays. Other slots are untouched. Safe to call concurrently from multiple threads.- Parameters:
childIdx- index of the child in the variable listcontRow- continuous slots (parents read; child written if continuous)discRow- discrete slots (parents read; child written if discrete)rng- source of noise / categorical draws- Throws:
IllegalStateException- iffit()has not been called
-
childProbsGiven
public double[] childProbsGiven(int childIdx, double[] contRow, int[] discRow) For a discrete child, the generative class distribution p(Y | pa) given the parent values incontRow/discRow: exactly the distributiongenerateChild(int, double[], int[], Random)samples from, including anylambdaParentsmixing with base rates.- Parameters:
childIdx- index of a discrete childcontRow- continuous parent slotsdiscRow- discrete parent slots- Returns:
- a fresh probability array over the child's categories
- Throws:
IllegalArgumentException- if the child is not discreteIllegalStateException- iffit()has not been called
-
getNumVariables
public int getNumVariables()Returns the number of variables.- Returns:
- the length of the row arrays used by
fillRowFromData(DataSet, int, double[], int[])andgenerateChild(int, double[], int[], Random)
-
isDiscreteVariable
public boolean isDiscreteVariable(int idx) Reports whether a variable is discrete.- Parameters:
idx- variable index- Returns:
- true if the variable at
idxis discrete
-
simulate
Simulates data by generating continuous and discrete values for all variables in the trained directed acyclic graph (DAG) model. The simulation uses a specified number of samples and a seed for random number generation, ensuring reproducibility.- Parameters:
nSamples- The number of samples to generate during the simulation. Must be a positive integer greater than or equal to 1.seed- A long value representing the seed for the random number generator. Provides deterministic simulation results when the same seed is used.- Returns:
- A
SimResultobject containing the simulated continuous and discrete values, along with metadata about the DAG and the set of variables used in the simulation. - Throws:
IllegalArgumentException- IfnSamplesis less than 1.
-