Skip to content

Releases: evandeilton/gkwdist

v1.1.5 — Numerical correctness fixes and componentwise derivative validation

Choose a tag to compare

@evandeilton evandeilton released this 11 Aug 18:09

This release corrects six numerical defects. The user-facing API is unchanged: no functions were added, removed or renamed.

Critical fixes

dgkw() returned 0 for every input. The internal helpers log1mexp() and log1pexp() collide with functions of the same name in R's public Rmath.h API, which use the convention log(1 - exp(-x)) for x >= 0. Where that macro was active the calls resolved to R's version, which returns NaN for the negative arguments used here, so every density evaluation failed its finiteness guard. The helpers are now gkw_log1mexp() and gkw_log1pexp(). The sub-family densities and llgkw() were unaffected.

EKw, KKw and BKw log-likelihoods were wrong for data near zero. These routines clamped 1 - x^alpha and 1 - (1 - x^alpha)^beta at 1e-10 instead of working in log space. For small x and moderate alpha those round to 1 and 0 in double precision, so the clamp substituted log(1e-10) = -23 for values near -53. Deviations reached 6,100 log-units, which corrupts AIC, BIC and likelihood ratio tests.

Mixed second derivatives were zeroed at degenerate parameter values. Guards of the form if (abs(p - 1) > eps) gated terms that do not carry the vanishing factor: differentiating (gamma-1)*log(w) once in gamma consumes the (gamma-1), so the term survives at gamma = 1. hsbkw() returned 0 where the correct value was 271.12; hsekw() and hskkw() had the same defect at beta = 1.

Also fixed: arbitrary min(., 1000) clamps in grkkw() and llkkw(); a skipped block in grkkw()/hskkw() at delta = 0; and check_beta_pars(), which rejected delta = 0, the valid Beta(gamma, 1) boundary.

Validation

Every gradient component and every Hessian entry of all seven sub-families is now checked individually against two independent references: the general GKw routines restricted to the constrained parameter point, and numDeriv Richardson extrapolation. Grids cover the degenerate values gamma = 1, beta = 1, lambda = 1 and delta = 0, and samples with observations near zero.

Family log-likelihood gradient Hessian
GKw 1.5e-11 1.5e-08 1.5e-07
BKw 1.6e-12 3.7e-08 3.6e-08
KKw 3.1e-13 3.5e-08 4.9e-08
EKw 5.4e-14 7.8e-09 2.7e-08
Mc 3.5e-13 2.5e-09 9.5e-10
Kw 4.1e-15 7.2e-10 1.2e-09
Beta 7.2e-15 4.6e-10 8.9e-11

Against the GKw reference all seven families agree to 1e-13; the residual error versus numDeriv is at the accuracy limit of Richardson extrapolation itself. Densities are additionally checked to integrate to one and to reproduce base R for the Beta and closed-form Kumaraswamy cases. Coverage rose from 70.8% to 74.2%.

Documentation

The JOSS manuscript was rewritten, CONTRIBUTING.md and CODE_OF_CONDUCT.md were added, and the README performance claim was corrected: the previous benchmark compared C++ against C++ plus R loop overhead. The real gain is in the derivatives, where the analytical score is about 9x faster than Richardson extrapolation and the analytical Hessian about 38x faster.

Full changelog: https://github.com/evandeilton/gkwdist/blob/main/NEWS.md

v1.1.4 — CRAN fix: skip timing-based tests on CRAN

Choose a tag to compare

@evandeilton evandeilton released this 27 May 19:49

Summary

Patch release fixing the CRAN check ERRORs reported on 2026-05-25 (deadline 2026-06-08). No functional changes; all user-facing code is unchanged.

Fix

All 4 CRAN failures were in tests/testthat/test-mle-performance.R (line 264). Those tests assert that analytical-gradient optimisation runs no more than 2× slower than numerical-only. On CRAN's loaded Linux hosts the numerical baseline ran anomalously fast, breaching the ratio even though the gradient code is correct.

Prof. Ripley's note: "The manual warned you about testing timings, and this fails quite often."

Change: added skip_on_cran() inside each test_that block in test-mle-performance.R. The benchmarks remain intact for local development — they are only skipped during CRAN checks.

R CMD check

0 errors | 0 warnings | 0 notes

Submitted to CRAN

Package submitted to CRAN on 2026-05-27 and is pending review.

v1.1.3 — Critical MLE Bug Fixes & Numerical Corrections

Choose a tag to compare

@evandeilton evandeilton released this 21 May 00:35

What's Changed

Critical Bug Fixes

  • llgkw() invalid parameter return — fixed returning R_NegInf instead of R_PosInf for invalid parameters. Gradient-based MLE optimizers treat −∞ as a global minimum, causing silent convergence to invalid boundaries.
  • gkwinit delta=0 rejectiongkw_pdf() incorrectly rejected delta = 0 (valid for EKw, Kw sub-families) due to a strict delta <= 0 guard that should have been delta < 0.
  • gkwinit EKw/Kw sub-family mappingekw_pdf() and kw_pdf() passed delta = 1 instead of the correct delta = 0, producing wrong starting values for MLE of these families.
  • hsbkw() Hessian error for β < 1 — ternary expression (beta > 1.0) ? v_beta/v : 1.0 returned 1.0 for all β ≤ 1, yielding wrong second derivatives and incorrect standard errors when β ∈ (0, 1).

Numerical Corrections

  • safe_exp() 10× scaling error — moderate-underflow branch computed 10 × exp(x) instead of exp(x) due to use of DBL_MIN_SAFE = 10 × DBL_MIN in the scaling expression.
  • dgkw() silent boundary truncation removed — a block silently returned density = 0 for valid data near x = 0 or x = 1 without warning; removed since log-space arithmetic handles these values correctly.
  • llekw() / grekw() lambda clamping removed — arbitrary min(lambda_factor, 1000) cap distorted gradients and Hessians for λ > 1000.

Code Quality

  • Hessian accumulation in hsgkw() / hsekw() refactored to build upper triangle only and symmetrize once with arma::symmatu().
  • Removed spurious try/catch blocks in grbkw() / hsbkw() around Rcpp::as<arma::vec> conversions that cannot throw.
  • Removed using namespace Rcpp; from gkwinit.cpp; added NA/NaN filtering before moment computation.
  • Added UB guard in vec_safe_pow() for static_cast<int> when exponent > INT_MAX.
  • Added SIMD-friendly fast path arma::exp(y * arma::log(x)) in vec_safe_pow() for the common case (y > 0, all x > 0).

Build

R CMD check --as-cran: 0 errors | 0 warnings | 0 notes
Tests: 342/342 pass

gkwdist 1.1.2

Choose a tag to compare

@evandeilton evandeilton released this 08 Jan 21:00

Code Cleanup and Testing Enhancement

C++ Code Cleanup

  • Removed legacy commented code: Cleaned up all C++ source files (gkw.cpp, bkw.cpp, kkw.cpp, ekw.cpp, kw.cpp, bpmc.cpp, beta_.cpp) by removing old commented-out implementations that were kept for reference.
  • Code formatting: Improved R wrapper formatting with consistent indentation and alignment in .Call() invocations and roxygen examples.

New Test Suites

  • Analytical derivatives validation (test-derivatives-validation.R):

    • 70 comprehensive tests validating gradient (gr*) and Hessian (hs*) functions
    • Compares analytical derivatives against numerical differentiation via numDeriv
    • Covers all 7 subfamilies: GKw, BKw, KKw, EKw, Mc, Kw, Beta
    • Multiple parameter configurations per subfamily for robustness
  • MLE performance benchmarks (test-mle-performance.R):

    • Compares optimization efficiency across three scenarios: numerical-only, analytical gradient, and analytical gradient + Hessian
    • Validates that analytical derivatives provide equivalent or better accuracy
    • Tests convergence rates and computational time across all distribution families

JOSS Paper

  • Added paper for JOSS submission (inst/paper/):
    • Complete manuscript describing the package's statistical framework
    • Comprehensive bibliography with foundational references
    • Compiled PDF ready for submission

gkwdist 1.1.1

Choose a tag to compare

@evandeilton evandeilton released this 26 Nov 23:18

Major Refactoring Release

This release represents a comprehensive refactoring of the entire package codebase, focusing on numerical stability, code consistency, and maintainability.

C++ Backend Overhaul

  • Unified utility functions: Introduced utils.h header providing numerically stable implementations of critical functions:

    • log1mexp(): Stable computation of log(1 - exp(x)) using Mächler (2012) methodology
    • log1pexp(): Overflow-protected computation of log(1 + exp(x))
    • safe_log(), safe_exp(), safe_pow(): Protected arithmetic operations with graceful handling of edge cases
    • Vectorized versions (vec_safe_log, vec_log1mexp, etc.) for efficient array operations
  • Consistent parameter validation: All distribution families now use dedicated parameter checkers (check_pars(), check_kw_pars(), check_ekw_pars(), etc.) that properly handle NaN, Inf, and boundary conditions.

  • Complete documentation: All C++ source files now include comprehensive Doxygen-style documentation headers describing:

    • Mathematical formulas for PDF, CDF, quantile, and random generation
    • Parameter constraints and special cases
    • Numerical stability considerations
    • Relationship to parent GKw distribution

Bug Fixes

  • Fixed critical bug in qgkw(): Corrected logic error where lower_tail transformation was incorrectly applied when log_p = TRUE. The probability is now properly converted to linear scale before tail adjustment.

  • Fixed gradient calculation in grkkw(): Resolved issue where log_z was not recomputed after clamping z to minimum threshold, causing corrupted gradient values near boundaries.

  • Fixed Hessian calculation in hsmc(): Corrected sign errors and formula for the lambda component of the Hessian matrix for the Beta-Power/McDonald distribution.

  • Fixed gradient signs in grmc(): Ensured consistent computation of log-likelihood gradient before negation for optimization.

Code Quality Improvements

  • Eliminated unused variables: Removed declared but unused constants (exp_threshold) and intermediate variables across all distribution files.

  • Removed redundant calculations: Streamlined computations, notably in pgkw() where logarithm was computed twice for the same quantity.

  • Simplified parameter recycling: Replaced double-modulo indexing pattern (idx = i % k; vec[idx % vec.n_elem]) with direct single-modulo access (vec[i % vec.n_elem]) in random generation functions.

  • Standardized function signatures: All distribution functions now follow consistent patterns for parameter order, validation, and return value handling.

R Wrapper Layer

  • Complete separation of R and C++ interfaces: All exported R functions now serve as wrappers around internal C++ implementations (.dgkw_cpp, .pgkw_cpp, etc.), providing:
    • Enhanced input validation with informative error messages
    • Consistent argument checking across all distribution families
    • Proper NA/NaN propagation
    • Documentation accessible via standard R help system

Distribution Families

All seven distribution families have been refactored with identical improvements:

Distribution Parameters File
Generalized Kumaraswamy (GKw) α, β, γ, δ, λ gkw.cpp
Kumaraswamy-Kumaraswamy (KKw) α, β, δ, λ kkw.cpp
Beta-Kumaraswamy (BKw) α, β, γ, δ bkw.cpp
Exponentiated Kumaraswamy (EKw) α, β, λ ekw.cpp
Beta-Power/McDonald (BP/Mc) γ, δ, λ bpmc.cpp
Kumaraswamy (Kw) α, β kw.cpp
Beta (GKw-style) γ, δ beta.cpp

Each family includes: density (d*), distribution (p*), quantile (q*), random generation (r*), negative log-likelihood (ll*), gradient (gr*), and Hessian (hs*) functions.

Technical Notes

  • Minimum supported R version remains 3.5.0
  • C++11 standard required (enabled via Rcpp plugin)
  • Depends on RcppArmadillo for efficient linear algebra operations

Acknowledgments

Special thanks to the thorough code review process that identified subtle numerical issues in edge cases, particularly for extreme parameter values and observations near distribution boundaries.

gkwdist 1.0.10

Choose a tag to compare

@evandeilton evandeilton released this 16 Nov 14:35
v1.0.10

Remove par() from examples and update Site