GSL 6.0.0

A rust binding for the GSL (the GNU scientific library)
Documentation
//
// A rust binding for the GSL library by Guillaume Gomez (guillaume1.gomez@gmail.com)
//

/*!
# Histograms

This chapter describes functions for creating histograms. Histograms provide a convenient way of summarizing the distribution of a set of data.
A histogram consists of a set of bins which count the number of events falling into a given range of a continuous variable x. In GSL the bins
of a histogram contain floating-point numbers, so they can be used to record both integer and non-integer distributions. The bins can use arbitrary
sets of ranges (uniformly spaced bins are the default). Both one and two-dimensional histograms are supported.

Once a histogram has been created it can also be converted into a probability distribution function. The library provides efficient routines
for selecting random samples from probability distributions. This can be useful for generating simulations based on real data.

## Resampling from histograms

A histogram made by counting events can be regarded as a measurement of a probability distribution. Allowing for statistical error, the height
of each bin represents the probability of an event where the value of x falls in the range of that bin. The probability distribution function
has the one-dimensional form p(x)dx where,

p(x) = n_i/ (N w_i)
In this equation n_i is the number of events in the bin which contains x, w_i is the width of the bin and N is the total number of events.
The distribution of events within each bin is assumed to be uniform.
!*/

use crate::Value;
use ffi::FFI;
use std::io::{self, Write};

ffi_wrapper!(Histogram, *mut sys::gsl_histogram, gsl_histogram_free);

impl Histogram {
    /// This function allocates memory for a histogram with n bins, and returns a pointer to a newly created gsl_histogram struct. If insufficient
    /// memory is available a null pointer is returned and the error handler is invoked with an error code of Value::NoMem. The bins and ranges are
    /// not initialized, and should be prepared using one of the range-setting functions below in order to make the histogram ready for use.
    #[doc(alias = "gsl_histogram_alloc")]
    pub fn new(n: usize) -> Option<Histogram> {
        let tmp = unsafe { sys::gsl_histogram_alloc(n) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    /// This function sets the ranges of the existing histogram h using the array range of size size. The values of the histogram bins are reset
    /// to zero. The range array should contain the desired bin limits. The ranges can be arbitrary, subject to the restriction that they are
    /// monotonically increasing.
    ///
    /// The following example shows how to create a histogram with logarithmic bins with ranges [1,10), [10,100) and [100,1000).
    ///
    /// ```C
    /// gsl_histogram * h = gsl_histogram_alloc (3);
    ///
    /// /* bin[0] covers the range 1 <= x < 10 */
    /// /* bin[1] covers the range 10 <= x < 100 */
    /// /* bin[2] covers the range 100 <= x < 1000 */
    ///
    /// double range[4] = { 1.0, 10.0, 100.0, 1000.0 };
    ///
    /// gsl_histogram_set_ranges (h, range, 4);
    /// ```
    ///
    /// Note that the size of the range array should be defined to be one element bigger than the number of bins. The additional element is
    /// required for the upper value of the final bin.
    #[doc(alias = "gsl_histogram_set_ranges")]
    pub fn set_ranges(&mut self, range: &[f64]) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram_set_ranges(self.unwrap_unique(), range.as_ptr(), range.len() as _)
        })
    }

    /// This function sets the ranges of the existing histogram h to cover the range xmin to xmax uniformly. The values of the histogram bins
    /// are reset to zero. The bin ranges are shown in the table below,
    ///
    /// `bin[0]` corresponds to xmin <= x < xmin + d
    /// `bin[1]` corresponds to xmin + d <= x < xmin + 2 d
    /// ......
    /// bin[n-1] corresponds to xmin + (n-1)d <= x < xmax
    /// where d is the bin spacing, d = (xmax-xmin)/n.
    #[doc(alias = "gsl_histogram_set_ranges_uniform")]
    pub fn set_ranges_uniform(&mut self, xmin: f64, xmax: f64) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram_set_ranges_uniform(self.unwrap_unique(), xmin, xmax)
        })
    }

    /// This function copies the self histogram into the pre-existing histogram dest, making dest into an exact copy of self. The two histograms
    /// must be of the same size.
    #[doc(alias = "gsl_histogram_memcpy")]
    pub fn copy(&self, dest: &mut Histogram) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram_memcpy(dest.unwrap_unique(), self.unwrap_shared())
        })
    }

    /// This function returns a pointer to a newly created histogram which is an exact copy of the self histogram.
    #[doc(alias = "gsl_histogram_clone")]
    pub fn clone(&self) -> Option<Histogram> {
        let tmp = unsafe { sys::gsl_histogram_clone(self.unwrap_shared()) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    /// This function updates the self histogram by adding one (1.0) to the bin whose range contains the coordinate x.
    ///
    /// If x lies in the valid range of the histogram then the function returns zero to indicate success. If x is less than the lower limit of
    /// the histogram then the function returns Value::Dom, and none of bins are modified. Similarly, if the value of x is greater than or equal
    /// to the upper limit of the histogram then the function returns Value::Dom, and none of the bins are modified. The error handler is not
    /// called, however, since it is often necessary to compute histograms for a small range of a larger dataset, ignoring the values outside
    /// the range of interest.
    #[doc(alias = "gsl_histogram_increment")]
    pub fn increment(&mut self, x: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram_increment(self.unwrap_unique(), x) })
    }

    /// This function is similar to gsl_histogram_increment but increases the value of the appropriate bin in the histogram h by the floating-point
    /// number weight.
    #[doc(alias = "gsl_histogram_accumulate")]
    pub fn accumulate(&mut self, x: f64, weight: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram_accumulate(self.unwrap_unique(), x, weight) })
    }

    /// This function returns the contents of the i-th bin of the histogram h. If i lies outside the valid range of indices for the histogram then
    /// the error handler is called with an error code of Value::Dom and the function returns 0.
    #[doc(alias = "gsl_histogram_get")]
    pub fn get(&self, i: usize) -> f64 {
        unsafe { sys::gsl_histogram_get(self.unwrap_shared(), i) }
    }

    /// This function finds the upper and lower range limits of the i-th bin of the self histogram.
    /// If the index i is valid then the corresponding range limits are stored in lower and upper.
    /// The lower limit is inclusive (i.e. events with this coordinate are included in the bin) and
    /// the upper limit is exclusive (i.e. events with the coordinate of the upper limit are
    /// excluded and fall in the neighboring higher bin, if it exists). The function returns 0 to
    /// indicate success. If i lies outside the valid range of indices for the histogram then
    /// the error handler is called and the function returns an error code of Value::Dom.
    ///
    /// Returns `(Value, lower, upper)`.
    #[doc(alias = "gsl_histogram_get_range")]
    pub fn range(&self, i: usize) -> (Value, f64, f64) {
        let mut lower = 0.;
        let mut upper = 0.;
        let ret = unsafe {
            sys::gsl_histogram_get_range(self.unwrap_shared(), i, &mut lower, &mut upper)
        };
        (Value::from(ret), lower, upper)
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins of the self histogram. They provide a way
    /// of determining these values without accessing the gsl_histogram struct directly.
    #[doc(alias = "gsl_histogram_max")]
    pub fn max(&self) -> f64 {
        unsafe { sys::gsl_histogram_max(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins of the self histogram. They provide a way
    /// of determining these values without accessing the gsl_histogram struct directly.
    #[doc(alias = "gsl_histogram_min")]
    pub fn min(&self) -> f64 {
        unsafe { sys::gsl_histogram_min(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins of the self histogram. They provide a way
    /// of determining these values without accessing the gsl_histogram struct directly.
    #[doc(alias = "gsl_histogram_bins")]
    pub fn bins(&self) -> usize {
        unsafe { sys::gsl_histogram_bins(self.unwrap_shared()) }
    }

    /// This function resets all the bins in the self histogram to zero.
    #[doc(alias = "gsl_histogram_reset")]
    pub fn reset(&mut self) {
        unsafe { sys::gsl_histogram_reset(self.unwrap_unique()) }
    }

    /// This function finds and sets the index i to the bin number which covers the coordinate x in
    /// the self histogram. The bin is located using a binary search. The search includes an
    /// optimization for histograms with uniform range, and will return the correct bin immediately
    /// in this case. If x is found in the range of the histogram then the function sets the index i
    /// and returns ::Value::Success. If x lies outside the valid range of the histogram then the
    /// function returns Value::Dom and the error handler is invoked.
    ///
    /// Returns `(Value, i)`.
    #[doc(alias = "gsl_histogram_find")]
    pub fn find(&self, x: f64) -> (Value, usize) {
        let mut i = 0;
        let ret = unsafe { sys::gsl_histogram_find(self.unwrap_shared(), x, &mut i) };
        (Value::from(ret), i)
    }

    /// This function returns the maximum value contained in the histogram bins.
    #[doc(alias = "gsl_histogram_max_val")]
    pub fn max_val(&self) -> f64 {
        unsafe { sys::gsl_histogram_max_val(self.unwrap_shared()) }
    }

    /// This function returns the index of the bin containing the maximum value. In the case where several bins contain the same maximum value
    /// the smallest index is returned.
    #[doc(alias = "gsl_histogram_max_bin")]
    pub fn max_bin(&self) -> usize {
        unsafe { sys::gsl_histogram_max_bin(self.unwrap_shared()) }
    }

    /// This function returns the minimum value contained in the histogram bins.
    #[doc(alias = "gsl_histogram_min_val")]
    pub fn min_val(&self) -> f64 {
        unsafe { sys::gsl_histogram_min_val(self.unwrap_shared()) }
    }

    /// This function returns the index of the bin containing the minimum value. In the case where several bins contain the same maximum value
    /// the smallest index is returned.
    #[doc(alias = "gsl_histogram_min_bin")]
    pub fn min_bin(&self) -> usize {
        unsafe { sys::gsl_histogram_min_bin(self.unwrap_shared()) }
    }

    /// This function returns the mean of the histogrammed variable, where the histogram is regarded as a probability distribution. Negative
    /// bin values are ignored for the purposes of this calculation. The accuracy of the result is limited by the bin width.
    #[doc(alias = "gsl_histogram_mean")]
    pub fn mean(&self) -> f64 {
        unsafe { sys::gsl_histogram_mean(self.unwrap_shared()) }
    }

    /// This function returns the standard deviation of the histogrammed variable, where the histogram is regarded as a probability distribution.
    /// Negative bin values are ignored for the purposes of this calculation. The accuracy of the result is limited by the bin width.
    #[doc(alias = "gsl_histogram_sigma")]
    pub fn sigma(&self) -> f64 {
        unsafe { sys::gsl_histogram_sigma(self.unwrap_shared()) }
    }

    /// This function returns the sum of all bin values. Negative bin values are included in the sum.
    #[doc(alias = "gsl_histogram_sum")]
    pub fn sum(&self) -> f64 {
        unsafe { sys::gsl_histogram_sum(self.unwrap_shared()) }
    }

    /// This function returns true if the all of the individual bin ranges of the two histograms are identical, and false otherwise.
    #[doc(alias = "gsl_histogram_equal_bins_p")]
    pub fn equal_bins_p(&self, other: &Histogram) -> bool {
        unsafe { sys::gsl_histogram_equal_bins_p(self.unwrap_shared(), other.unwrap_shared()) != 0 }
    }

    /// This function adds the contents of the bins in histogram other to the corresponding bins of self histogram, i.e. h'_1(i) = h_1(i) + h_2(i).
    /// The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram_add")]
    pub fn add(&mut self, other: &Histogram) -> Value {
        Value::from(unsafe { sys::gsl_histogram_add(self.unwrap_unique(), other.unwrap_shared()) })
    }

    /// This function subtracts the contents of the bins in histogram other from the corresponding bins of self histogram, i.e. h'_1(i) = h_1(i) - h_2(i).
    /// The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram_sub")]
    pub fn sub(&mut self, other: &Histogram) -> Value {
        Value::from(unsafe { sys::gsl_histogram_sub(self.unwrap_unique(), other.unwrap_shared()) })
    }

    /// This function multiplies the contents of the bins of self histogram by the contents of the corresponding bins in other histogram, i.e. h'_1(i) =
    /// h_1(i) * h_2(i). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram_mul")]
    pub fn mul(&mut self, other: &Histogram) -> Value {
        Value::from(unsafe { sys::gsl_histogram_mul(self.unwrap_unique(), other.unwrap_shared()) })
    }

    /// This function divides the contents of the bins of self histogram by the contents of the corresponding bins in other histogram, i.e. h'_1(i) = h_1(i)
    /// / h_2(i). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram_div")]
    pub fn div(&mut self, other: &Histogram) -> Value {
        Value::from(unsafe { sys::gsl_histogram_div(self.unwrap_unique(), other.unwrap_shared()) })
    }

    /// This function multiplies the contents of the bins of self histogram by the constant scale, i.e. h'_1(i) = h_1(i) * scale.
    #[doc(alias = "gsl_histogram_scale")]
    pub fn scale(&mut self, scale: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram_scale(self.unwrap_unique(), scale) })
    }

    /// This function shifts the contents of the bins of self histogram by the constant offset, i.e. h'_1(i) = h_1(i) + offset.
    #[doc(alias = "gsl_histogram_shift")]
    pub fn shift(&mut self, offset: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram_shift(self.unwrap_unique(), offset) })
    }

    #[allow(unused_must_use)]
    pub fn print<W: Write>(
        &self,
        stream: &mut W, /*, range_format: &str, bin_format: &str*/
    ) -> io::Result<Value> {
        unsafe {
            let n = (*self.unwrap_shared()).n as isize;

            for i in 0isize..n {
                writeln!(
                    stream,
                    "{} {} {}",
                    *(*self.unwrap_shared()).range.offset(i),
                    *(*self.unwrap_shared()).range.offset(i + 1),
                    *(*self.unwrap_shared()).range.offset(i),
                )?;
            }

            Ok(::Value::Success)
        }
    }
}

ffi_wrapper!(HistogramPdf, *mut sys::gsl_histogram_pdf, gsl_histogram_pdf_free,
"The probability distribution function for a histogram consists of a set of bins which measure the \
probability of an event falling into a given range of a continuous variable x. A probability \
distribution function is defined by the following struct, which actually stores the cumulative \
probability distribution function. This is the natural quantity for generating samples via the \
inverse transform method, because there is a one-to-one mapping between the cumulative probability \
distribution and the range [0,1]. It can be shown that by taking a uniform random number in this \
range and finding its corresponding coordinate in the cumulative probability distribution we obtain \
samples with the desired probability distribution.");

impl HistogramPdf {
    /// This function allocates memory for a probability distribution with n bins and returns a pointer to a newly initialized gsl_histogram_pdf
    /// struct. If insufficient memory is available a null pointer is returned and the error handler is invoked with an error code of Value::NoMem.
    #[doc(alias = "gsl_histogram_pdf_alloc")]
    pub fn new(n: usize) -> Option<HistogramPdf> {
        let tmp = unsafe { sys::gsl_histogram_pdf_alloc(n) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    /// This function initializes the probability distribution self with the contents of the histogram h. If any of the bins of h are negative then
    /// the error handler is invoked with an error code of Value::Dom because a probability distribution cannot contain negative values.
    #[doc(alias = "gsl_histogram_pdf_init")]
    pub fn init(&mut self, h: &Histogram) -> Value {
        Value::from(unsafe { sys::gsl_histogram_pdf_init(self.unwrap_unique(), h.unwrap_shared()) })
    }

    /// This function uses r, a uniform random number between zero and one, to compute a single random sample from the probability distribution
    /// self. The algorithm used to compute the sample s is given by the following formula,
    ///
    /// ```text
    /// s = range[i] + delta * (range[i+1] - range[i])
    /// ```
    ///
    /// where i is the index which satisfies `sum[i] <= r < sum[i+1]` and `delta` is
    /// `(r - sum[i])/(sum[i+1] - sum[i])`.
    #[doc(alias = "gsl_histogram_pdf_sample")]
    pub fn sample(&self, r: f64) -> f64 {
        unsafe { sys::gsl_histogram_pdf_sample(self.unwrap_shared(), r) }
    }
}

ffi_wrapper!(Histogram2D, *mut sys::gsl_histogram2d, gsl_histogram2d_free,
"A two dimensional histogram consists of a set of bins which count the number of events falling in \
a given area of the (x,y) plane. The simplest way to use a two dimensional histogram is to record \
two-dimensional position information, n(x,y). Another possibility is to form a joint distribution \
by recording related variables. For example a detector might record both the position of an event \
(x) and the amount of energy it deposited E. These could be histogrammed as the joint distribution \
n(x,E).");

impl Histogram2D {
    /// This function allocates memory for a two-dimensional histogram with nx bins in the x direction and ny bins in the y direction. The
    /// function returns a pointer to a newly created gsl_histogram2d struct. If insufficient memory is available a null pointer is returned
    /// and the error handler is invoked with an error code of Value::NoMem. The bins and ranges must be initialized with one of the
    /// functions below before the histogram is ready for use.
    #[doc(alias = "gsl_histogram2d_alloc")]
    pub fn new(nx: usize, ny: usize) -> Option<Histogram2D> {
        let tmp = unsafe { sys::gsl_histogram2d_alloc(nx, ny) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    /// This function sets the ranges of the existing histogram h using the arrays xrange and yrange of size xsize and ysize respectively.
    /// The values of the histogram bins are reset to zero.
    #[doc(alias = "gsl_histogram2d_set_ranges")]
    pub fn set_ranges(&mut self, xrange: &[f64], yrange: &[f64]) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_set_ranges(
                self.unwrap_unique(),
                xrange.as_ptr(),
                xrange.len() as _,
                yrange.as_ptr(),
                yrange.len() as _,
            )
        })
    }

    /// This function sets the ranges of the existing histogram h to cover the ranges xmin to xmax and ymin to ymax uniformly. The values
    /// of the histogram bins are reset to zero.
    #[doc(alias = "gsl_histogram2d_set_ranges_uniform")]
    pub fn set_ranges_uniform(&mut self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_set_ranges_uniform(self.unwrap_unique(), xmin, xmax, ymin, ymax)
        })
    }

    /// This function copies the histogram src into the pre-existing histogram dest, making dest into an exact copy of src. The two histograms
    /// must be of the same size.
    #[doc(alias = "gsl_histogram2d_memcpy")]
    pub fn copy(&self, dest: &mut Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_memcpy(dest.unwrap_unique(), self.unwrap_shared())
        })
    }

    /// his function returns a pointer to a newly created histogram which is an exact copy of the histogram self.
    #[doc(alias = "gsl_histogram2d_clone")]
    pub fn clone(&self) -> Option<Histogram2D> {
        let tmp = unsafe { sys::gsl_histogram2d_clone(self.unwrap_shared()) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    /// This function updates the histogram h by adding one (1.0) to the bin whose x and y ranges contain the coordinates (x,y).
    ///
    /// If the point (x,y) lies inside the valid ranges of the histogram then the function returns zero to indicate success. If (x,y) lies
    /// outside the limits of the histogram then the function returns Value::Dom, and none of the bins are modified. The error handler is not
    /// called, since it is often necessary to compute histograms for a small range of a larger dataset, ignoring any coordinates outside the
    /// range of interest.
    #[doc(alias = "gsl_histogram2d_increment")]
    pub fn increment(&mut self, x: f64, y: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram2d_increment(self.unwrap_unique(), x, y) })
    }

    /// This function is similar to gsl_histogram2d_increment but increases the value of the appropriate bin in the histogram h by the floating-point
    /// number weight.
    #[doc(alias = "gsl_histogram2d_accumulate")]
    pub fn accumulate(&mut self, x: f64, y: f64, weight: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram2d_accumulate(self.unwrap_unique(), x, y, weight) })
    }

    /// This function returns the contents of the (i,j)-th bin of the histogram h. If (i,j) lies outside the valid range of indices for the
    /// histogram then the error handler is called with an error code of Value::Dom and the function returns 0.
    #[doc(alias = "gsl_histogram2d_get")]
    pub fn get(&self, i: usize, j: usize) -> f64 {
        unsafe { sys::gsl_histogram2d_get(self.unwrap_shared(), i, j) }
    }

    /// This function finds the upper and lower range limits of the i-th and j-th bins in the x and
    /// y directions of the histogram h. The range limits are stored in xlower and xupper or ylower
    /// and yupper. The lower limits are inclusive (i.e. events with these coordinates are included
    /// in the bin) and the upper limits are exclusive (i.e. events with the value of the upper
    /// limit are not included and fall in the neighboring higher bin, if it exists). The functions
    /// return 0 to indicate success. If i or j lies outside the valid range of indices for the
    /// histogram then the error handler is called with an error code of Value::Dom.
    ///
    /// Returns `(Value, xlower, xupper)`.
    #[doc(alias = "gsl_histogram2d_get_xrange")]
    pub fn xrange(&self, i: usize) -> (Value, f64, f64) {
        let mut xlower = 0.;
        let mut xupper = 0.;
        let ret = unsafe {
            sys::gsl_histogram2d_get_xrange(self.unwrap_shared(), i, &mut xlower, &mut xupper)
        };
        (Value::from(ret), xlower, xupper)
    }

    /// This function finds the upper and lower range limits of the i-th and j-th bins in the x and
    /// y directions of the histogram h. The range limits are stored in xlower and xupper or ylower
    /// and yupper. The lower limits are inclusive (i.e. events with these coordinates are included
    /// in the bin) and the upper limits are exclusive (i.e. events with the value of the upper
    /// limit are not included and fall in the neighboring higher bin, if it exists). The functions
    /// return 0 to indicate success. If i or j lies outside the valid range of indices for the
    /// histogram then the error handler is called with an error code of Value::Dom.
    ///
    /// Returns `(Value, ylower, yupper)`.
    #[doc(alias = "gsl_histogram2d_get_yrange")]
    pub fn yrange(&self, j: usize) -> (Value, f64, f64) {
        let mut ylower = 0.;
        let mut yupper = 0.;
        let ret = unsafe {
            sys::gsl_histogram2d_get_yrange(self.unwrap_shared(), j, &mut ylower, &mut yupper)
        };
        (Value::from(ret), ylower, yupper)
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_xmax")]
    pub fn xmax(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_xmax(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_xmin")]
    pub fn xmin(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_xmin(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_nx")]
    pub fn nx(&self) -> usize {
        unsafe { sys::gsl_histogram2d_nx(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_ymax")]
    pub fn ymax(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_ymax(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_ymin")]
    pub fn ymin(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_ymin(self.unwrap_shared()) }
    }

    /// This function returns the maximum upper and minimum lower range limits and the number of bins for the x and y directions of the histogram h.
    /// They provide a way of determining these values without accessing the gsl_histogram2d struct directly.
    #[doc(alias = "gsl_histogram2d_ny")]
    pub fn ny(&self) -> usize {
        unsafe { sys::gsl_histogram2d_ny(self.unwrap_shared()) }
    }

    /// This function resets all the bins of the histogram h to zero.
    #[doc(alias = "gsl_histogram2d_reset")]
    pub fn reset(&mut self) {
        unsafe { sys::gsl_histogram2d_reset(self.unwrap_unique()) }
    }

    /// This function finds and sets the indices i and j to the bin which covers the coordinates
    /// (x,y). The bin is located using a binary search. The search includes an optimization for
    /// histograms with uniform ranges, and will return the correct bin immediately in this case. If
    /// (x,y) is found then the function sets the indices (i,j) and returns ::Value::Success. If
    /// (x,y) lies outside the valid range of the histogram then the function returns Value::Dom and
    /// the error handler is invoked.
    ///
    /// Returns `(Value, i, j)`.
    #[doc(alias = "gsl_histogram2d_find")]
    pub fn find(&self, x: f64, y: f64) -> (Value, usize, usize) {
        let mut i = 0;
        let mut j = 0;
        let ret = unsafe { sys::gsl_histogram2d_find(self.unwrap_shared(), x, y, &mut i, &mut j) };
        (Value::from(ret), i, j)
    }

    /// This function returns the maximum value contained in the histogram bins.
    #[doc(alias = "gsl_histogram2d_max_val")]
    pub fn max_val(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_max_val(self.unwrap_shared()) }
    }

    /// This function finds the indices of the bin containing the maximum value in the histogram h
    /// and stores the result in (i,j). In the case where several bins contain the same maximum
    /// value the first bin found is returned.
    ///
    /// Returns `(i, j)`.
    #[doc(alias = "gsl_histogram2d_max_bin")]
    pub fn max_bin(&self) -> (usize, usize) {
        let mut i = 0;
        let mut j = 0;
        unsafe { sys::gsl_histogram2d_max_bin(self.unwrap_shared(), &mut i, &mut j) };
        (i, j)
    }

    /// This function returns the minimum value contained in the histogram bins.
    #[doc(alias = "gsl_histogram2d_min_val")]
    pub fn min_val(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_min_val(self.unwrap_shared()) }
    }

    /// This function finds the indices of the bin containing the minimum value in the histogram h
    /// and stores the result in (i,j). In the case where several bins contain the same maximum
    /// value the first bin found is returned.
    ///
    /// Returns `(i, j)`.
    #[doc(alias = "gsl_histogram2d_min_bin")]
    pub fn min_bin(&self) -> (usize, usize) {
        let mut i = 0;
        let mut j = 0;
        unsafe { sys::gsl_histogram2d_min_bin(self.unwrap_shared(), &mut i, &mut j) };
        (i, j)
    }

    /// This function returns the mean of the histogrammed x variable, where the histogram is regarded as a probability distribution. Negative
    /// bin values are ignored for the purposes of this calculation.
    #[doc(alias = "gsl_histogram2d_xmean")]
    pub fn xmean(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_xmean(self.unwrap_shared()) }
    }

    /// This function returns the mean of the histogrammed y variable, where the histogram is regarded as a probability distribution. Negative
    /// bin values are ignored for the purposes of this calculation.
    #[doc(alias = "gsl_histogram2d_ymean")]
    pub fn ymean(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_ymean(self.unwrap_shared()) }
    }

    /// This function returns the standard deviation of the histogrammed x variable, where the histogram is regarded as a probability
    /// distribution. Negative bin values are ignored for the purposes of this calculation.
    #[doc(alias = "gsl_histogram2d_xsigma")]
    pub fn xsigma(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_xsigma(self.unwrap_shared()) }
    }

    /// This function returns the standard deviation of the histogrammed y variable, where the histogram is regarded as a probability
    /// distribution. Negative bin values are ignored for the purposes of this calculation.
    #[doc(alias = "gsl_histogram2d_ysigma")]
    pub fn ysigma(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_ysigma(self.unwrap_shared()) }
    }

    /// This function returns the covariance of the histogrammed x and y variables, where the histogram is regarded as a probability
    /// distribution. Negative bin values are ignored for the purposes of this calculation.
    #[doc(alias = "gsl_histogram2d_cov")]
    pub fn cov(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_cov(self.unwrap_shared()) }
    }

    /// This function returns the sum of all bin values. Negative bin values are included in the sum.
    #[doc(alias = "gsl_histogram2d_sum")]
    pub fn sum(&self) -> f64 {
        unsafe { sys::gsl_histogram2d_sum(self.unwrap_shared()) }
    }

    /// This function returns 1 if all the individual bin ranges of the two histograms are identical, and 0 otherwise.
    #[doc(alias = "gsl_histogram2d_equal_bins_p")]
    pub fn equal_bins_p(&self, other: &Histogram2D) -> bool {
        unsafe {
            sys::gsl_histogram2d_equal_bins_p(self.unwrap_shared(), other.unwrap_shared()) != 0
        }
    }

    /// This function adds the contents of the bins in histogram h2 to the corresponding bins of histogram h1, i.e. h'_1(i,j) = h_1(i,j)
    /// + h_2(i,j). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram2d_add")]
    pub fn add(&mut self, other: &Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_add(self.unwrap_unique(), other.unwrap_shared())
        })
    }

    /// This function subtracts the contents of the bins in histogram h2 from the corresponding bins of histogram h1, i.e. h'_1(i,j) = h_1(i,j)
    /// - h_2(i,j). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram2d_sub")]
    pub fn sub(&mut self, other: &Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_sub(self.unwrap_unique(), other.unwrap_shared())
        })
    }

    /// This function multiplies the contents of the bins of histogram h1 by the contents of the corresponding bins in histogram h2, i.e. h'_1(i,j)
    /// = h_1(i,j) * h_2(i,j). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram2d_mul")]
    pub fn mul(&mut self, other: &Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_mul(self.unwrap_unique(), other.unwrap_shared())
        })
    }

    /// This function divides the contents of the bins of histogram h1 by the contents of the corresponding bins in histogram h2, i.e. h'_1(i,j) =
    /// h_1(i,j) / h_2(i,j). The two histograms must have identical bin ranges.
    #[doc(alias = "gsl_histogram2d_div")]
    pub fn div(&mut self, other: &Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_div(self.unwrap_unique(), other.unwrap_shared())
        })
    }

    /// This function multiplies the contents of the bins of histogram h by the constant scale, i.e. h'_1(i,j) = h_1(i,j) scale.
    #[doc(alias = "gsl_histogram2d_scale")]
    pub fn scale(&mut self, scale: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram2d_scale(self.unwrap_unique(), scale) })
    }

    /// This function shifts the contents of the bins of histogram h by the constant offset, i.e. h'_1(i,j) = h_1(i,j) + offset.
    #[doc(alias = "gsl_histogram2d_shift")]
    pub fn shift(&mut self, offset: f64) -> Value {
        Value::from(unsafe { sys::gsl_histogram2d_shift(self.unwrap_unique(), offset) })
    }
}

ffi_wrapper!(
    Histogram2DPdf,
    *mut sys::gsl_histogram2d_pdf,
    gsl_histogram2d_pdf_free,
    "As in the one-dimensional case, a two-dimensional histogram made by counting events can be \
regarded as a measurement of a probability distribution. Allowing for statistical error, the \
height of each bin represents the probability of an event where (x,y) falls in the range of that \
bin. For a two-dimensional histogram the probability distribution takes the form p(x,y) dx dy \
where,

p(x,y) = n_{ij}/ (N A_{ij})

In this equation n_{ij} is the number of events in the bin which contains (x,y), A_{ij} is the \
area of the bin and N is the total number of events. The distribution of events within each bin is \
assumed to be uniform."
);

impl Histogram2DPdf {
    /// This function allocates memory for a two-dimensional probability distribution of size nx-by-ny and returns a pointer to a newly initialized
    /// gsl_histogram2d_pdf struct. If insufficient memory is available a null pointer is returned and the error handler is invoked with an error
    /// code of Value::NoMem.
    #[doc(alias = "gsl_histogram2d_pdf_alloc")]
    pub fn new(nx: usize, ny: usize) -> Option<Histogram2DPdf> {
        let tmp = unsafe { sys::gsl_histogram2d_pdf_alloc(nx, ny) };

        if tmp.is_null() {
            None
        } else {
            Some(Self::wrap(tmp))
        }
    }

    ///This function initializes the two-dimensional probability distribution calculated p from the histogram h. If any of the bins of h are
    /// negative then the error handler is invoked with an error code of GSL_EDOM because a probability distribution cannot contain negative
    /// values.
    #[doc(alias = "gsl_histogram2d_pdf_init")]
    pub fn init(&mut self, h: &Histogram2D) -> Value {
        Value::from(unsafe {
            sys::gsl_histogram2d_pdf_init(self.unwrap_unique(), h.unwrap_shared())
        })
    }

    /// This function uses two uniform random numbers between zero and one, r1 and r2, to compute a
    /// single random sample from the two-dimensional probability distribution p.
    ///
    /// Returns `(Value, x, y)`.
    #[doc(alias = "gsl_histogram2d_pdf_sample")]
    pub fn sample(&self, r1: f64, r2: f64) -> (Value, f64, f64) {
        let mut x = 0.;
        let mut y = 0.;
        let ret = unsafe {
            sys::gsl_histogram2d_pdf_sample(self.unwrap_shared(), r1, r2, &mut x, &mut y)
        };
        (Value::from(ret), x, y)
    }
}