Skip to content

CDANs class

The top-level estimator. Most users should interact with the library through this class; the individual step functions are exposed under cdans.steps for finer-grained control.

CDANs

CDANs(
    tau_max: int = 2,
    alpha: float = 0.05,
    pc_alpha: float = 0.2,
    ci_test: str | CITest = "fisherz",
    surrogate: str | ndarray = "time",
    max_extra_conds: int = 2,
    use_independent_change: bool = True,
    independent_change_width: WidthSpec = AUTO,
    verbose: bool = False,
)

Temporal causal discovery from autocorrelated, nonstationary time series.

Implements the four-step algorithm from Ferdous, Hasan & Gani (2023):

  1. Identify lagged adjacencies via MCI tests.
  2. Build the partial undirected graph (lagged + contemporaneous + surrogate).
  3. Refine the contemporaneous skeleton and confirm changing modules using CI tests with lagged-parent conditioning sets.
  4. Orient contemporaneous edges via v-structures and Meek's rules.

Parameters:

Name Type Description Default
tau_max int

Maximum lag.

2
alpha float

Significance level for the final CI tests.

0.05
pc_alpha float

Significance level for the preliminary PC step inside Step 1 (typically larger than alpha).

0.2
ci_test str | CITest

CI test to use for Steps 1 and 3. Either a string ("fisherz" or "kci") or an object implementing :class:CITest.

'fisherz'
surrogate str | ndarray

Either "time" (use the time index, default) or an array of shape (n_samples,) to use as the distribution-shift surrogate.

'time'
max_extra_conds int

Cap on contemporaneous neighbors added to the lagged conditioning set in Step 3.

2
use_independent_change bool

Whether Step 4 should run the iterative independent-change-principle sink-finding sub-pass to orient undirected edges between two changing modules. Set to False to return only the Markov equivalence class.

True
independent_change_width WidthSpec

Bandwidth for the kernels inside the independent-change score. "auto" (default) picks per-call via the median heuristic on the standardized parents — robust across datasets, fast. "gp" learns the bandwidth via Gaussian-process marginal- likelihood optimization with an ARD-RBF kernel — adaptive across DGPs but ~10–50× slower than "auto" per score call; recommended when the skeleton is recovered correctly but contemp orientations between changing modules look wrong. A positive float forces a manual bandwidth (0.1 reproduces the MATLAB reference's hard-coded default).

AUTO
verbose bool

Print per-step progress.

False

Examples:

>>> from cdans import CDANs
>>> from cdans.utils import generate_synthetic_cdans
>>> ds = generate_synthetic_cdans(n_vars=4, n_samples=300, tau_max=2, seed=0)
>>> model = CDANs(tau_max=2, alpha=0.05, ci_test="fisherz")
>>> result = model.fit(ds.data)
>>> print(result.summary())

fit

fit(data: ndarray, var_names: list[str] | None = None) -> CDANsResult

Run the full four-step pipeline.

Parameters:

Name Type Description Default
data ndarray

Time series, shape (n_samples, n_vars).

required
var_names list[str] | None

Optional names for the variables (used in the result's summary).

None

Returns:

Type Description
CDANsResult

The discovered graph plus diagnostics.

CDANsResult dataclass

CDANsResult(
    graph: TimeSeriesGraph,
    timings: dict[str, float] = dict(),
    config: dict = dict(),
)

Container for the output of :meth:CDANs.fit.

Attributes:

Name Type Description
graph TimeSeriesGraph

The final :class:TimeSeriesGraph containing lagged edges, contemporaneous edges (oriented where possible), and changing modules.

timings dict[str, float]

Per-step wall-clock time in seconds.

config dict

The configuration used to produce this result.