NAME

Math::Histo - Fast, memory-safe C histogramming and statistical computing for Perl

SYNOPSIS

use Math::Histo;

# Uniform 1D histogram (50 bins in [0, 100], tracking sum(w^2))
my $h = Math::Histo->new(bins => 50, min => 0.0, max => 100.0, sumw2 => 1);

# Variable-width binning
my $h_var = Math::Histo->new(edges => [0.0, 1.0, 5.0, 10.0, 50.0, 100.0]);

# Ingestion: scalar, batch arrayref, or packed binary doubles
$h->fill(42.5);
$h->fill(84.0, 2.5); # with weight 2.5
$h->fill_n([10.5, 20.2, 30.8, 42.1]);
$h->fill_packed_f64($packed_doubles_scalar);

# Statistical summaries
printf("Entries: %d, Total Weight: %.2f\n", $h->num_entries, $h->total_weight);
printf("Mean: %.4f +/- %.4f\n", $h->mean, $h->std_dev);
printf("Median: %.4f (IQR: %.4f, MAD: %.4f)\n", $h->median, $h->iqr, $h->mad);
printf("Skewness: %.4f, Excess Kurtosis: %.4f\n", $h->skewness, $h->excess_kurtosis);

# Continuous peak detection
my $mode = $h->mode;
printf("Continuous Mode: %.4f (FWHM: %.4f, RMS: %.4f)\n", $mode, $h->fwhm, $h->rms);

# Non-linear curve fitting (Levenberg-Marquardt)
my $fit = $h->fit(model => 'gaussian');
print $fit->summary;

# Operator overloading
my $h2 = $h * 2.0;
my $sum = $h + $h2;
print "$h\n"; # stringification

# Two-sample hypothesis testing & distance metrics
my ($chi2, $ndf) = $h->chi2_test($h2);
my $ks   = $h->kolmogorov_smirnov($h2);
my $w1   = $h->wasserstein_distance($h2);
my $bhat = $h->bhattacharyya_distance($h2);
my $kl   = $h->kl_divergence($h2);

# Zero-loss binary wire format and JSON serialization
my $blob = $h->serialize_binary;
my $restored = Math::Histo->from_binary($blob);
$h->write_file('data.histo', format => 'binary');

DESCRIPTION

Math::Histo is a high-performance Perl XS wrapper for the libhisto C library. It provides SIMD-accelerated 1D and 2D histogramming, online Welford statistical moments, non-linear curve fitting (Levenberg-Marquardt), and streaming dynamic quantile sketches (DDSketch).

CONSTRUCTORS

new(%options)

Creates a new 1D histogram.

Uniform binning options: bins => $count (or nbins => $count) min => $min_val (default: 0.0) max => $max_val (default: 100.0)

Variable binning options: edges => [ $e0, $e1, $e2, ... ] (strictly monotonically increasing)

Feature flags: sumw2 => 1 (track per-bin sum of weights squared for error propagation) exact_moments => 1 (track running mean/variance during fill operations)

clone()

Creates an exact deep copy of the histogram.

from_binary($byte_string)

Deserializes a histogram from canonical Little-Endian binary format.

from_json($json_string)

Deserializes a histogram from a JSON string.

from_file($filename)

Autodetects format (binary wire format or JSON) and loads the histogram from disk.

INGESTION METHODS

fill($x, [$weight=1.0])

Fills a single coordinate with optional weight. Returns 1 on success, 0 on non-finite rejection.

fill_n(\@x, [\@weights])

Batch fills an arrayref of coordinates and optional weights.

fill_packed_f64($packed_x, [$packed_w]) (or fill_packed)

High-performance zero-copy batch fill from raw packed 64-bit IEEE double scalars (e.g. pack("d*", ...) or PDL::get_dataref).

reset()

Resets all bin contents, moments, and out-of-range counters to zero.

BIN ACCESS & GEOMETRY

nbins(): Number of bins.
min(): Lower range boundary.
max(): Upper range boundary.
is_uniform(): Returns 1 if uniform binning, 0 if variable-width binning.
bin_content($idx): Accumulated weight in bin $idx (0-indexed).
bin_error($idx): Standard error in bin $idx (sqrt(sum_w2) or sqrt(content)).
bin_sum_w2($idx): Sum of weights squared in bin $idx.
bin_low_edge($idx): Lower edge coordinate of bin $idx.
bin_high_edge($idx): Upper edge coordinate of bin $idx.
bin_center($idx): Geometric center coordinate of bin $idx.
bin_width($idx): Width of bin $idx.
bin_contents(): Returns an arrayref of all bin contents.
bin_edges(): Returns an arrayref of all bin edges (length nbins + 1).
find_bin($x): Returns the 0-indexed bin index for coordinate $x (-1 for underflow, nbins for overflow).
underflow_weight(): Total weight accumulated below min.
overflow_weight(): Total weight accumulated above max.
nan_count(): Total count of non-finite (NaN) samples rejected.

STATISTICAL ANALYSIS

num_entries(): Total number of in-range fill operations.
total_weight(): Total accumulated in-range weight sum.
mean(): Sample mean.
variance(): Sample variance.
std_dev(): Sample standard deviation.
skewness(): Distribution skewness (gamma_1).
kurtosis(): Distribution kurtosis (beta_2).
excess_kurtosis(): Excess kurtosis (gamma_2 = beta_2 - 3).
central_moment($order): Central statistical moment of given order.
median(): Estimated median (50th percentile).
quantile($p): Continuous piecewise linear quantile for $p in [0, 1].
iqr(): Interquartile Range (Q75 - Q25).
mad(): Median Absolute Deviation from median.
mode(): Continuous mode peak coordinate estimated via parabolic interpolation.
fwhm(): Full Width at Half Maximum of dominant peak.
rms(): Root Mean Square: sqrt(M2 + mean^2).
trimmed_mean($fraction): Trimmed mean excluding tails.
winsorized_mean($fraction): Winsorized mean replacing tails with quantile thresholds.
integral(): Total integrated sum of bin weights.
cdf([$prenormalization=1.0]): Returns a new Math::Histo object representing the cumulative distribution function.
stats(): Returns a hashref containing complete summary statistics.

ARITHMETIC & TRANSFORMATIONS

scale($factor): In-place scalar multiplication.
normalize([$target_area=1.0]): In-place normalization.
rebin($factor): Returns a new histogram with adjacent uniform bins combined.
add($other), subtract($other), multiply($other), divide($other): In-place element-wise arithmetic.
Overloaded operators: +, -, *, /, "".

TWO-SAMPLE DISTANCE METRICS

chi2_test($other): Returns ($chi2, $ndf).
kolmogorov_smirnov($other): Two-sample Kolmogorov-Smirnov supremum distance.
wasserstein_distance($other): 1D Earth Mover's Distance (L1 CDF integral).
kl_divergence($other): Kullback-Leibler divergence D_KL(self || other).
bhattacharyya_distance($other): Bhattacharyya distance between distributions.

CURVE FITTING

fit(%args)

Fits a parametric model to the histogram using the Levenberg-Marquardt non-linear optimizer.

Parameters: model => 'gaussian' | 'exponential' | 'polynomial' | 'breit_wigner' | 'power_law' initial => [ ... ] (optional initial guesses, auto-estimated if omitted) lower => [ ... ] (optional lower parameter bounds) upper => [ ... ] (optional upper parameter bounds) fixed => [ 0, 1, ... ] (optional boolean flags to freeze specific parameters) max_iter => 200 (maximum iterations) tol => 1e-8 (relative tolerance) mle => 1 (use Poisson MLE deviance instead of Chi2)

Returns a Math::Histo::Fit::Result object.

SERIALIZATION

serialize_binary(): Returns scalar byte string in canonical Little-Endian wire format.
serialize_json([$pretty=0]): Returns JSON string representation.
write_file($path, [format = 'binary'|'json'])>: Writes histogram directly to disk.

PERFORMANCE & BENCHMARKS

Math::Histo leverages C99 core algorithms, cache-conscious memory layout, and runtime-detected AVX2 / AVX-512 / ARM NEON vector instructions. While individual method invocations incur standard Perl XS sub-call overhead (~50 ns), bulk ingestion methods (fill_n and fill_packed_f64) bypass Perl interpreter loop overhead to achieve throughput exceeding 450+ Million operations/second.

Benchmark measured on an Intel(R) Core(TM) Ultra 7 255HX (Linux x86_64, Perl 5.40):

+---------------------------------+--------------+------------+----------------+------------+
| Benchmark Operation             | Count        | Time       | Throughput     | Latency    |
+=================================+==============+============+================+============+
| 1D Uniform Fill (method call)   |  2,000,000 ops|    0.099 s |   20.28 Mops/s | 49.3 ns/op |
| 1D Weighted Fill + sumw2        |  2,000,000 ops|    0.103 s |   19.35 Mops/s | 51.7 ns/op |
| 1D Variable Bins (100 bins)     |  2,000,000 ops|    0.156 s |   12.79 Mops/s | 78.2 ns/op |
| 1D Batch Arrayref (fill_n)      |  2,000,000 ops|    0.033 s |   61.02 Mops/s | 16.4 ns/op |
| 1D Packed f64 Buffer (SIMD)     |  5,000,000 ops|    0.011 s |  454.46 Mops/s |  2.20 ns/op|
| 2D Uniform Fill (method call)   |  2,000,000 ops|    0.109 s |   18.38 Mops/s | 54.4 ns/op |
| 2D Packed f64 Buffer (SIMD)     |  5,000,000 ops|    0.018 s |  281.26 Mops/s |  3.56 ns/op|
| DDSketch Dynamic Insert         |  2,000,000 ops|    0.121 s |   16.47 Mops/s | 60.7 ns/op |
| DDSketch Packed Buffer          |  5,000,000 ops|    0.067 s |   74.21 Mops/s | 13.48 ns/op|
+---------------------------------+--------------+------------+----------------+------------+

To run the benchmark suite on your machine:

perl -Iblib/lib -Iblib/arch bench/bench_fill.pl

IN-DEPTH DOCUMENTATION & ALGORITHMIC COMPLEXITY

For detailed documentation on underlying algorithms, mathematical proofs, IEEE-754 numerical behavior, SIMD vectorization kernels, and asymptotic time/space complexity tables, please refer to the main C library manual:

SEE ALSO

AUTHOR

Steffen Mueller <cpan@steffen-mueller.net>

LICENSE

MIT License. Copyright (c) 2026 Steffen Mueller and libhisto contributors.