Discrete variables
Copula models operate on the probability scale, and for a discrete variable that scale has atoms: the model needs both and the left limit . Declaring which variables are discrete is done through var_types, a vector of "c" and "d" strings.
The data layout
For an all-continuous model, every data-taking method uses the usual matrix: its d columns contain in the model's variable order. In particular, Bicop methods take an matrix by default.
Extra columns are needed only when variables are discrete. In that case, the expanded layout has columns: its first d columns hold and its next d columns hold in the same order.
For continuous variables , so their columns in the second block are duplicates. These duplicates may be omitted: if k of the d variables are discrete, the compact layout appends only their k left-limits, ordered by their positions in the first block.
Both discrete-data layouts are accepted throughout the library. The expanded layout has a fixed shape independent of var_types; the compact layout avoids storing duplicate continuous columns.
Bivariate copulas
Bicop's var_types defaults to {"c", "c"}. Pass it to the constructor, or set it later with set_var_types(); the density then dispatches to the mixed-discrete expressions (pdf_c_d, pdf_d_d internally).
// A discrete model uses an F(x) block followed by an F(x-) block. auto continuous = tools_stats::simulate_uniform(500, 2, false, { 1 }); auto disc = discretize(continuous.col(0), 5); Eigen::MatrixXd data(500, 4); data.col(0) = disc.first; // F(x) of the discrete variable data.col(1) = continuous.col(1); data.col(2) = disc.second; // F(x-) of the discrete variable data.col(3) = data.col(1); // F(x-) = F(x) for a continuous variable // Declare the types, then fit as usual. FitControlsBicop controls({ BicopFamily::gaussian, BicopFamily::clayton }); Bicop model(data, controls, { "d", "c" }); std::cout << "family: " << model.get_family_name() << ", var_types: " << model.get_var_types()[0] << model.get_var_types()[1] << std::endl; // Evaluation takes data in the same layout. auto pdf = model.pdf(data); std::cout << "loglik: " << model.loglik(data) << std::endl;
Vine copulas
The same conventions apply to Vinecop, whose var_types has one entry per variable. simulate() returns the d columns only.
set_var_types() on an existing model re-types the pair copulas according to their position in the vine: a pair copula is discrete in an argument when the corresponding variable is discrete and that argument has not yet been integrated out by an h-function.
The Rosenblatt transform of a discrete variable is not unique — the value falls in the interval — so rosenblatt() randomizes within that interval by default. Pass randomize_discrete = false for the deterministic upper endpoint, and seeds to make the randomization reproducible.
// Same convention for vines: discrete data uses two d-column blocks. size_t d = 4; auto continuous = tools_stats::simulate_uniform(500, d, false, { 2 }); auto disc0 = discretize(continuous.col(0), 4); auto disc2 = discretize(continuous.col(2), 6); Eigen::MatrixXd data(500, 2 * d); data.col(0) = disc0.first; data.col(1) = continuous.col(1); data.col(2) = disc2.first; data.col(3) = continuous.col(3); data.rightCols(d) = data.leftCols(d); data.col(d) = disc0.second; data.col(d + 2) = disc2.second; Vinecop model(data, RVineStructure(), { "d", "c", "d", "c" }); std::cout << "loglik: " << model.get_loglik() << std::endl; // simulate() returns the d "F(x)" columns only auto sim = model.simulate(10, false, 1, { 3 }); std::cout << "simulated: " << sim.rows() << " x " << sim.cols() << std::endl; // set_var_types can also change the types of an existing model; the pair // copulas are re-typed to match their position in the vine. Vinecop continuous_model(continuous); continuous_model.set_var_types({ "d", "c", "d", "c" });