Skip to content

Benchmarks

Benchmarks in VineCopulas.jl serve two different purposes:

  • correctness gates show that the Julia implementation agrees with an external reference on deterministic fixtures;

  • performance benchmarks explain where the Julia implementation is fast, where it is near parity, and where optimization work remains.

Correctness before timing

A faster result is not meaningful until both implementations are known to be evaluating or fitting the same model. Read correctness reports before interpreting speed tables.

Correctness against rvinecopulib

The external reference is R rvinecopulib, which wraps the C++ vinecopulib library. The correctness gate checks:

  • pair-copula log densities, h-functions, and inverse h-functions;

  • fixed general R-vine evaluation and transforms;

  • fixed-structure fitting;

  • automatic Dissmann-style structure selection.

Equivalent R-vine matrices can encode the same conditioned and conditioning sets, so the gate compares represented edges and numerical behavior rather than raw matrix text.

Run:

bash
PARITY_N=800 PARITY_FIT_MODE=common \
  bash benchmarks/correctness/run_correctness_gate.sh

PARITY_N=800 PARITY_FIT_MODE=default \
  bash benchmarks/correctness/run_correctness_gate.sh

The v0.1.1 release-candidate gate passed both supported parity modes:

ModeFitParametersStructureFamiliesFitted parameters
commonautomatic 10 / 10PASSPASSPASS
commonfixed 11 / 11PASSPASSPASS
defaultautomatic 11 / 11PASSPASSPASS
defaultfixed 11 / 11PASSPASSPASS

The fixed-model stage also passed all pair fixtures and both general R-vine fixtures. Representative fixed-vine discrepancies were around for log density and below   for inverse transforms.

Performance overview

The standard evaluation battery measures log density, Rosenblatt transform, inverse Rosenblatt transform, simulation, and numerical CDF behavior. It keeps evaluation separate from fitting because they stress different parts of the implementation.

Run:

bash
bash benchmarks/run_main.sh

Fitting benchmarks use a separate entry point:

bash
bash benchmarks/fitting/run_fit.sh

Tip

Use the benchmark reports to choose optimization targets. For example, standalone pair primitives and fused vine traversal can have different bottlenecks.

The reference evaluation campaign used   observations on an Apple Silicon macOS system with Julia 1.12.6, R 4.5.3, and rvinecopulib 0.7.3.1.0. These numbers are machine-specific, but the profile is useful:

FamilyJuliarvinecopulibInterpretation
Gaussian514.0 ms21.9 msJulia 1.56× faster
Gaussian1016.8 ms33.0 msJulia 1.96× faster
Gaussian2037.9 ms72.0 msJulia 1.90× faster
Clayton513.7 ms18.8 msJulia 1.38× faster
Clayton1017.1 ms27.6 msJulia 1.62× faster
Clayton2039.3 ms61.8 msJulia 1.57× faster
Gumbel531.0 ms30.1 msnear parity
Gumbel1038.4 ms45.3 msJulia 1.18× faster
Gumbel2085.3 ms100.1 msJulia 1.17× faster
Frank520.8 ms15.6 msR 1.33× faster
Frank1024.0 ms21.9 msR 1.10× faster
Frank2054.8 ms49.0 msR 1.12× faster

Gaussian and Clayton are consistently faster in this battery. Gumbel is close to parity, while Frank log density is modestly faster in rvinecopulib.

The fitting benchmark is currently the main performance gap:

TaskCommon model spaceDefault model space
Gaussian pair selectionR 3.40× fasterR 7.25× faster
Clayton pair selectionR 3.71× fasterR 8.45× faster
Fixed-structure R-vineR 3.16× fasterR 6.74× faster
Automatic R-vineR 3.31× fasterR 6.93× faster

This is not a correctness issue: the corresponding common and default correctness gates pass. It is the clearest performance target for future work.

Generic vs specialized pair conditionals

The architectural question is not simply whether hfunc1(C, u, v) is fast. It is whether the specialized vine spelling still adds value over the canonical Copulas.jl conditioning interface:

julia
hfunc1(C, u, v)
cdf(condition(C, 2, v), u)

hinv1(C, q, v)
quantile(condition(C, 2, v), q)

Focused diagnostics live in:

bash
julia --project=benchmarks benchmarks/diagnostics/condition_fallback.jl
julia --project=benchmarks benchmarks/diagnostics/fused_pair_kernels.jl
julia --project=benchmarks benchmarks/diagnostics/vine_engine_allocations.jl

The goal is to decide which optimized paths remain justified. Generic compatibility comes first; family-specific or fused methods should be retained when they are measurably faster, more stable, or avoid important allocations.

Reproducing results

Instantiate the benchmark environment:

bash
julia --project=benchmarks -e '
using Pkg
Pkg.develop(path=".")
Pkg.resolve()
Pkg.instantiate()
'

Install the R reference dependency once:

bash
Rscript -e 'install.packages("rvinecopulib", repos="https://cloud.r-project.org")'

Then run the correctness and performance commands above from the repository root. Generated reports are written under benchmarks/reports/ and benchmarks/correctness/results/.

Note

Benchmark numbers are local measurements. They are useful for tracking regressions and prioritizing engineering work, not as hardware-independent guarantees.