dcvar 0.9.3
Bug fixes and maintenance
- Fit constructors now preserve Stan file and cache metadata
consistently across constant, dynamic, HMM, covariate, multilevel, and
SEM fits.
- Extractor probability arguments are validated consistently before
posterior summaries are computed.
- Removed unused internal helpers superseded by the unified dynamic
engine, the content-hash Stan cache, the current multilevel simulator
behavior, and the scale-aware simulation path.
Tests
- Retargeted regression coverage from deleted internals to the live
routing, extractor, Stan cache, and simulation helpers.
dcvar 0.9.2
New features
applicability_check() screens a fitted constant
copula-VAR for the floor/ceiling pile-up pathology, combining a
boundary-atom signal, a dynamics-collapse signal (fitted self-lags
against an OLS VAR(1) anchor and an optional normal-margin reference
fit), and slant/convergence flags into a
suitable/caution/unsuitable
verdict with a recommendation. Has a print method.
Convergence problems (divergences, elevated split-Rhat) block a
suitable verdict; the boundary atom requires a genuine tie
at the bound; and the dynamics-collapse anchor is sign-agnostic.
dcvar 0.9.1
Bug fixes
- SEM and multilevel simulators now use and record the same residual
scale for skew-normal and gamma innovations when a non-default
sigma is supplied.
sigma_trajectory() now reports skew-normal time-varying
scales on the residual-SD scale, matching simulation truth and the gamma
convention.
- Gaussian-copula exponential posterior-predictive draws now clamp
inverse-CDF uniforms before applying
log1m(), matching the
Clayton guard.
- Missing-data diagnostics now report the number of interior missing
rows, rather than the total number of incomplete rows.
- The README HMM switching example now uses the valid lowercase
phi selector.
Tests
- Strengthened multilevel TV
fitted()/predict() tests so they exercise
time-varying unit-level Phi paths and sigma_t intervals
away from t = 1.
- Added regression tests for skew-normal/gamma simulator scale
conventions and skew-normal
sigma_trajectory() scale
reporting.
dcvar 0.9.0
Time-varying SEM and
multilevel extensions
dcvar_sem(method = "indicator") gains
tv_phi and tv_sigma, using a new
sem_tv_mixed.stan engine with optional masked random walks
for latent VAR coefficients, log-scale scale paths, and time-varying
Gaussian-copula correlation. The naive score method now rejects TV SEM
options explicitly.
dcvar_multilevel() gains tv_phi and
tv_sigma, using a new multilevel_tv_mixed.stan
engine. To reduce the main identifiability risk, time-varying Phi is
implemented as a shared population drift around unit-specific random
baselines rather than independent per-unit random walks.
- SEM and multilevel simulators now accept time-varying Phi, scale,
and correlation paths where supported. New
dcvar_sem_tv_fit
and dcvar_multilevel_tv_fit subclasses expose
phi_trajectory(), sigma_trajectory(),
rho_trajectory(), dependence_summary(),
coef(), and var_params() methods; multilevel
TV fits also use the per-unit-time Phi path in fitted() and
predict().
dcvar 0.8.0
Margins: full
SEM and multilevel family support
dcvar_sem() (indicator and naive score methods) and
dcvar_multilevel() now accept homogeneous
"skew_normal" and "gamma" margins in addition
to "normal" and "exponential". These fits
route through the existing generic mixed-margin Stan engines
(sem_mixed.stan, sem_naive_mixed.stan, and
multilevel_mixed.stan) by passing the same family code for
both dimensions.
- Data preparation, default initial values,
coef(),
var_params(), diagnostics, and diagnostic plots understand
the mixed-engine parameter layout for these homogeneous fits, including
per-dimension shape_gam[d] outputs for gamma margins.
dcvar 0.7.0
New feature: full
Markov-switching HMM
dcvar_hmm() gains a switch argument that
lets the VAR(1) intercepts (mu), the VAR coefficients
(Phi, with
"ar"/"cross"/coefficient-name granularity),
and the residual scales become state-specific, in addition to the always
state-specific copula correlation. switch = "rho" (the
default) reproduces the previous regime-switching-correlation model
exactly. The copula correlation is the label-switching anchor
(ordered z_rho), so rho must
remain in switch whenever other components switch; states
are reported in increasing-correlation order.
- The marginal distribution family can now switch by
state:
margins accepts a length-K list of per-state family
specifications, for example
margins = list(c("normal", "normal"), c("exponential", "gamma")),
with a matching skew_direction (a length-2 vector recycled
across states, or a length-K list). The list is consumed in
increasing-rho order, and a warning is emitted when
families differ across states so the ordering can be verified.
- These richer configurations are served by a new internal Stan
engine,
inst/stan/hmm_switching.stan, selected
automatically; the default dcvar_hmm() keeps routing to the
specialised legacy files, so existing fits and posteriors are unchanged.
dcvar_stan_path("hmm") is unchanged; pass
stan_file = dcvar_stan_path("hmm_switching") to request the
engine explicitly.
- New
hmm_state_params() returns the per-state
intercepts, effective VAR(1) coefficient matrices, margin scales, and
family labels. coef(), var_params(),
print(), and summary() report state-indexed
parameters for switching fits; fitted() returns the
gamma-weighted one-step prediction. Marginal prediction intervals, PIT,
and posterior-predictive plots are not yet available for state-specific
fits and abort with a pointer to hmm_state_params().
dcvar 0.6.0
Internal: unified dynamic
Stan engine
- The time-varying DC-VAR path (
dcvar() with
tv_phi / tv_sigma) and the drift covariate
model (dcvar_covariate(drift = TRUE)) are now served by a
single generic Stan engine, inst/stan/dcvar_dynamic.stan.
It extends the time-varying mixed-margin model with a covariate
predictor on the Fisher-z correlation and the covariate model’s
residual-drift convention, unifying the two model families behind one
Fisher-z predictor
z_rho[t] = z_rho_init + X[t+1]' beta + drift[t].
- This is an internal consolidation with no change to the public
interface:
dcvar() and dcvar_covariate() keep
their signatures, defaults, S3 classes, and model strings, and the
posteriors are unchanged. The plain (non time-varying)
dcvar() and the no-drift
dcvar_covariate(drift = FALSE) model continue to use their
specialised Stan files unchanged, so no refit is needed. The covariate
model exposes its intercept as beta_0 exactly as before
(now a transformed-parameter alias of the sampled
z_rho_init).
dcvar_stan_path() continues to return the Stan file
matching each exported prepare_*() data contract
(e.g. dcvar_stan_path("dcvar_covariate") still returns the
legacy covariate model). The unified engine is selected internally by
the fit wrappers; pass
stan_file = dcvar_stan_path("dcvar_dynamic") to request it
explicitly.
- For an all-normal, constant-scale fit (the covariate model) the
engine uses the z-score Gaussian-copula form on the standardized
residuals, reproducing the legacy covariate likelihood term-by-term; an
independent recomputation of the log-likelihood is checked in the test
suite. The copula fast path is guarded so it never applies to a
time-varying scale.
dcvar 0.5.0
New feature: fully
time-varying DC-VAR
dcvar() gains tv_phi and
tv_sigma flags. With tv_phi = TRUE the four
VAR(1) coefficients (the AR effects phi11/phi22 and the cross-lagged
effects phi12/phi21) evolve as independent non-centered random walks
around the constant baseline Phi; with
tv_sigma = TRUE the residual scales of normal and
skew-normal dimensions evolve as log-scale random walks around their
baselines. Combined with the always time-varying copula correlation
rho(t) and per-variable (mixed) margins, every model component except
the intercepts can now vary over time. Both flags default to
FALSE, which reproduces the previous behavior exactly (same
Stan models, same draws).
tv_phi also accepts a character selector so that only a
subset of the VAR coefficients varies: "ar" (the
autoregressive effects phi11, phi22 – e.g. for changing emotional
inertia / critical slowing down), "cross" (the cross-lagged
effects phi12, phi21), or specific names such as
c("phi11", "phi22"). Only the selected coefficients get
random-walk parameters (the others stay at their constant baseline),
which improves identifiability on short series and lets you test a sharp
hypothesis. phi_trajectory() still returns all four
coefficients (the fixed ones as constant paths);
coef()/var_params() label tau_phi
by coefficient name.
- Flag-on fits use one generic Stan model
(
dcvar_tv_mixed.stan) for all margin specifications,
dispatching on per-dimension family codes; with both flags off in that
model the target density is identical term-by-term to
dcvar_mixed_ncp.stan, so the TV model exactly nests the
classic DC-VAR. New walk priors prior_tau_phi_rate (default
0.025) and prior_tau_sigma_rate (default 0.05) shrink
toward the constant model; see the new “Recommended workflow” section in
?dcvar for the model ladder.
- New fit subclass
dcvar_tv_fit (inherits
dcvar_fit, so rho_trajectory(),
plot_rho(), and loo() work unchanged) with new
extractors phi_trajectory() and
sigma_trajectory() (flag-agnostic: constants are tiled over
time), plots plot_phi_trajectory() /
plot_sigma_trajectory(),
fitted()/predict() using the per-time
coefficients and scales, per-time plug-in PIT values, and per-time
spectral-radius monitoring in the Stan generated quantities.
simulate_dcvar() gains optional
phi_trajectory and sigma_trajectory arguments
(matrix, list of per-coefficient vectors — the rho_*
generators can be reused — or constants). The marginal quantile
transform is now scale-aware, so exponential/gamma dimensions can be
simulated with any constant scale; regression tests pin the copula
orientation under time-varying scales for every
skew_direction combination.
- Time-varying scales (
tv_sigma) apply to
all margin families. Normal and skew-normal dimensions
use a multiplicative log-scale random walk; exponential and gamma
dimensions use a soft-barrier transform
x = softplus_k(m_t + skew * eps) (sharpness
tv_sigma_k, default 8) so the scale m_t can
vary freely without the hard support boundary coupling it to the
residuals. The soft-barrier matches the exact shifted margin in the
interior and rounds the boundary smoothly (a small residual-mean bias in
the lower tail; larger tv_sigma_k tightens it at the cost
of stiffer geometry). simulate_dcvar() gains
tv_sigma_k to generate matching data for an exp/gamma
time-varying-scale fit.
- In the generic TV model
shape_gam is per-dimension
(mixed-model convention), unlike the shared scalar in the specialised
gamma models. dcvar_compare() warns when a TV fit is
compared against less heavily latent-conditioned fits.
dcvar 0.4.0
Breaking /
scientifically relevant fixes
- Simulators no longer negate the dependence for left-skewed
margins. The Stan likelihoods treat the copula uniform on a
skew_direction = -1 exponential/gamma dimension as
u = 1 - F(x_shifted), but simulate_dcvar()
(and the shared mixed-margin helper used by
simulate_dcvar_multilevel() and
simulate_dcvar_sem(), plus the homogeneous exponential SEM
path) negated the quantile-transformed variable after applying
the copula. Data simulated with exactly one negative
skew_direction therefore implied copula correlation
-rho while true_params recorded
+rho, so simulate-then-fit studies silently recovered the
negated dependence trajectory. Simulations that used
c(1, 1) or c(-1, -1) are unaffected (the flips
cancel); any results generated with asymmetric skew directions should be
re-run.
- The
eps_rep posterior-predictive blocks in seven Stan
models had the mirror-image inversion bug and replicated negated
dependence on left-skewed dimensions; they now invert at the flipped
uniform.
dependence_summary() for HMM fits now averages
Kendall’s tau over states per draw
(sum_k gamma[t,k] * (2/pi) asin(rho_state[k])) instead of
applying asin to the gamma-weighted mean rho, which
understated tau during regime transitions.
hmm_states()$viterbi is now a genuine Viterbi (MAP)
decoding on posterior-mean emission/transition log-probabilities. The
previous most-frequent-sampled-path estimator degenerated to an
arbitrary (lexicographically first) single draw’s path whenever
parameter uncertainty made nearly all sampled paths unique.
- HMM posterior predictive replicates (
eps_rep) are now
drawn from the regime mixture (a state sampled from the smoothed
probabilities, then that state’s rho) instead of the gamma-weighted mean
rho.
.relative_bias() (used by
compute_rho_metrics() /
compute_param_metrics()) now normalizes the mean error by
the mean true value (by the mean absolute true value for mixed-sign
trajectories, which preserves the conventional sign for negative
parameters). The previous pointwise form exploded to ~1e12 % when any
true value was near zero (e.g. null-dependence conditions), silently
corrupting aggregated summaries. It returns NA with a
warning when all true values are near zero, and
aggregate_metrics() now tolerates that NA (its
summaries already used na.rm = TRUE).
Bug fixes
hmm_EG.stan now exposes sigma_exp (plus
b_gq and rate_exp) as saved generated
quantities. Previously they were brace-local, so summary(),
var_params(), coef(), and
plot_diagnostics() errored and pit_values()
silently returned all-NA for exponential-margin HMM fits.
- Tibble input no longer breaks multilevel fits: per-unit time-grid
validation was silently skipped and the stored time axis corrupted,
crashing
rho_trajectory(), fitted(), and
predict() downstream. All preparation functions now coerce
to a plain data frame up front.
- Character and unordered-factor time columns are now rejected: they
sort lexicographically (“T10” before “T2”), silently scrambling the
VAR(1) ordering while making the spacing checks vacuous.
- Leading/trailing runs of two or more missing rows are now treated as
edge trims rather than adjacency-breaking interior gaps, so they no
longer abort (or warn misleadingly) when removing them preserves
adjacency.
loo() and dcvar_compare() now support all
multilevel fits: multilevel_copula_var.stan stores
per-observation log_lik like its EG and mixed siblings, and
the margin-based whitelist was removed. dcvar_compare()
warns when an HMM fit (state-marginalized predictive density) is
compared against a dynamic fit (conditioned on the smoothed latent rho
trajectory), which can systematically favor the dynamic model.
- The
seed argument now makes fits reproducible: default
per-chain initial values are generated under a deterministic RNG
(previously they came from the unseeded global R RNG, so two fits with
the same seed differed).
- cmdstanr fits now survive
saveRDS() and an R restart:
posterior draws are eagerly read into the fit object after sampling
instead of being lazily re-read from CSVs in the session tempdir.
interpret_rho_trajectory() no longer errors on Clayton
constant fits; it interprets the dependence via Kendall’s tau.
- The Clayton copula log-density is computed in log space, avoiding
overflow to
-Inf (with NaN gradients) for
theta greater than about 34 during warmup.
- PIT helpers abort with a clear message when a margin parameter group
is missing from the Stan output instead of silently returning all-NA
values.
simulate_dcvar_sem(n_time = 1) no longer crashes with a
subscript error; prepare_multilevel_data() requires at
least 3 occasions per unit; .safe_cor() handles length-1
inputs; Y[cc, ] row removal keeps the matrix shape with a
single remaining row.
print() for constant-fit summaries no longer swaps the
CI bounds when probs are not passed in ascending
order.
draws() validates its format argument
instead of silently returning a draws_array.
- Divergence/treedepth counts are reported as
NA
(unknown) rather than 0 for fits without sampler diagnostics.
plot_hmm_states() pins the state factor levels so
Viterbi point colors match the fill colors when the MAP path skips a
state; plot_trajectories() forwards ... only
to the scenario generators that accept each argument.
- Warnings are emitted for prior arguments that a configuration
ignores (
prior_sigma_eps_rate with no normal margin;
prior_z_rho_sd with the Clayton copula;
prior_sigma_omega_rate and zero_init_eta with
dcvar_covariate(drift = FALSE)), and the recorded
priors list omits unused entries.
interpret_rho_trajectory() classifies Clayton
dependence strength on the rho-equivalent scale
(sin(pi * tau / 2)), so the labels are comparable with the
Gaussian branch for equivalent dependence.
- Per-chain init seeds are derived in double arithmetic, so seeds near
.Machine$integer.max no longer overflow and abort the
fit.
Validation
- All bivariate Stan models now declare
int<lower=2, upper=2> D, rejecting D > 2 data that
the hard-wired bivariate copula code would silently mishandle.
Documentation
- Documented the plug-in nature of
predict() intervals,
the raw-data scale of simulator true_params (fit with
standardize = FALSE for round-trip comparisons), the
lognormal scale prior for exponential/gamma multilevel margins, and
prior_rho_init_sd as the covariate-model dependence
intercept (beta_0) prior.
- Added the covariate model family to the README table and the pkgdown
reference index (which previously failed to build due to missing
topics).
Tests
- New regression tests pin the simulator copula orientation for every
skew_direction combination, seed reproducibility, tibble
input, time column validation, and edge-gap handling. The Clayton-normal
constant model and dcvar_covariate() (drift and no-drift)
now get real MCMC smoke fits in CI.
dcvar 0.3.1
Bug fixes
summary() printouts for HMM and multilevel fits now
include the marginal scale/shape parameters
(e.g. sigma_exp, omega, delta,
sigma_gam, shape_gam) for non-normal and
per-variable (mixed) margins. Previously the HMM summary omitted all
margin scale parameters, and the multilevel summary dropped them for
mixed margins.
simulate_breakpoint_data() now records the breakpoint
specification (type, plus breakpoint or
breakpoints) in true_params, so the documented
access no longer returns NULL.
Validation
rho_decreasing() and rho_increasing() now
validate that rho_start and rho_end are single
finite values in [-1, 1], matching the other rho trajectory
generators.
Documentation
- Extensive roxygen, vignette, README, and CITATION updates so the
documentation reflects per-variable (mixed) margin support across all
model families (including the Clayton-copula constant model) and the
correct
coef() / fitted() / data-preparation
contracts.
Internal
- Removed unused helper code, made the exponential-margin diagnostic
generated quantity (
b_gq) report the clamped lower bound
consistently across the exponential models (inference-neutral), and
corrected Stan prior-hyperparameter comments. The Clayton-normal
constant model’s sigma_eps prior is left unchanged and its
intentional divergence from the other constant models is now
documented.
dcvar 0.3.0
Per-variable (mixed) margins
- All copula VAR model families now accept a length-2
margins vector so each variable can use its own marginal
family, e.g. margins = c("normal", "exponential"). This
exploits the copula’s separation of the marginal distributions from the
dependence structure. Supported across dcvar_constant(),
dcvar(), dcvar_hmm(),
dcvar_multilevel(), and dcvar_sem() (both the
indicator and naive methods).
- Added generic mixed-margins Stan models that dispatch each dimension
to its own marginal family and apply the copula on the CDF scale:
constant_mixed.stan, dcvar_mixed_ncp.stan,
hmm_mixed.stan, multilevel_mixed.stan,
sem_mixed.stan, and sem_naive_mixed.stan.
- Mixed margins are also available with the Clayton
copula for the constant model
(
constant_mixed_clayton.stan), previously limited to normal
margins.
simulate_dcvar(),
simulate_dcvar_multilevel(), and
simulate_dcvar_sem() accept the same per-variable
margins vector so mixed-family data can be generated (for
example for parameter-recovery studies).
coef(), var_params(),
pit_values(), and the diagnostics/plots report each
dimension under its own family for mixed fits across all model
families.
Backward compatibility
- A single
margins string is unchanged, and an
all-identical margins vector (such as
c("normal", "normal")) routes to the existing specialised
single-family model, so prior results, tests, and the gamma shared-shape
parameterisation are preserved exactly.
- The mixed multilevel and SEM models support all four families per
dimension. Single-family multilevel and SEM fits keep their existing
normal/exponential-only restriction (there is no specialised gamma or
skew-normal model for those structures); request the other families
through a per-variable
margins vector instead.
dcvar 0.2.0
Simulation model parity
- Added a constant Clayton-copula DC-VAR for normal margins via
dcvar_constant(copula = "clayton").
- Added exponential-margin support for
dcvar_multilevel().
- Added naive SEM score models via
dcvar_sem(method = "naive") for normal and exponential
margins.
- Added
dependence_summary() for Kendall’s tau summaries
across Gaussian and Clayton copula fits.
Infrastructure
- Added copula-family dispatch alongside the existing margin
dispatch.
- Added bundled Stan models for the new Clayton, multilevel
exponential, and naive SEM variants.
- Updated extractors, summaries, diagnostics, LOO support, and tests
for the new model variants.
dcvar 0.1.0
Scope and documentation
- Clarified that the package currently implements Gaussian-copula
models only.
- Marked the multilevel and SEM variants as experimental extensions
with narrower diagnostic support than the core single-level models.
- Documented PIT diagnostics as posterior-mean plug-in diagnostics and
made the unsupported multilevel and SEM paths explicit in the help
pages.
- Clarified the current scope of
loo() support across
model classes.
Build and submission hygiene
- Excluded local
*-test-local.log artifacts from source
builds.
- Added package citation metadata.
Testing
- Added skew-normal fit coverage for
dcvar() and
dcvar_hmm().
- Added PIT smoke coverage for gamma and skew-normal margins.