#ifndef histogram_h_
#define histogram_h_
/* These are currently necessary for the malloc wrappers that perl defines.
* TODO: It probably warrants understanding to what extent they are important
* and useful in this code. */
#include "EXTERN.h"
#include "perl.h"
#include "hist_constants.h"
struct simple_histo_1d_struct {
/* parameters */
double min;
double max;
unsigned int nbins;
/* derived */
double width;
double binsize;
/* content */
unsigned int nfills;
double overflow;
double underflow;
/* derived content */
double total;
/* main data store */
double* data;
/* Exists with nbins+1 elements if we do not have constant binsize */
double* bins;
/* Optional ptr to cumulative histo.
* If this isn't 0, we need to deallocate in the parent
* object's DESTROY. This isn't serialized nor cloned
* ever since it can be recalculated.
* Needs to be invalidated using HS_INVALIDATE_CUMULATIVE
* on almost every operation on the histogram!
* Not currently invalidated when setting the under-/overflow.
*/
/* The stored cumulative hist MUST be normalized in such a way
* that the last bin content is == 1. This is like ->cumulative(1) */
struct simple_histo_1d_struct* cumulative_hist;
};
typedef struct simple_histo_1d_struct simple_histo_1d;
/* deallocates a histogram. Requires a THX */
#define HS_DEALLOCATE(hist) \
STMT_START { \
simple_histo_1d* histptr = (hist); \
Safefree( (void*)histptr->data ); \
if (histptr->bins != NULL) \
Safefree(histptr->bins); \
Safefree( (void*)histptr ); \
} STMT_END
/* deallocates the cumulative histogram of the given histogram
* IF NECESSARY. Requires a THX */
#define HS_INVALIDATE_CUMULATIVE(self) \
STMT_START { \
if ((self)->cumulative_hist) { \
HS_DEALLOCATE((self)->cumulative_hist); \
(self)->cumulative_hist = 0; \
} \
} STMT_END
/* allocates the cumulative histogram of the given histogram
* IF NECESSARY. Requires a THX */
#define HS_ASSERT_CUMULATIVE(self) \
STMT_START { \
simple_histo_1d* selfptr = (self); \
if (!(selfptr->cumulative_hist)) \
self->cumulative_hist = histo_cumulative(aTHX_ self, 1.); \
} STMT_END
/* Fetch the center of the given bin without range checking. */
#define HS_BIN_CENTER(self, ibin) \
((self)->bins == NULL) \
? (self)->min + ((double)(ibin) + 0.5) * (self)->binsize \
: 0.5*((self)->bins[ibin] + (self)->bins[(ibin)+1])
/* Fetch the lower boundary of the given bin without range checking. */
#define HS_BIN_LOWER_BOUNDARY(self, ibin) \
((self)->bins == NULL) \
? (self)->min + (double)(ibin) * (self)->binsize \
: (self)->bins[ibin]
/* Fetch the upper boundary of the given bin without range checking. */
#define HS_BIN_UPPER_BOUNDARY(self, ibin) \
((self)->bins == NULL) \
? (self)->min + ((double)((ibin) + 1)) * (self)->binsize \
: (self)->bins[(ibin)+1]
/* creates a new fixed-bin histogram */
simple_histo_1d*
histo_alloc_new_fixed_bins(pTHX_ unsigned int nbins, double min, double max);
/* Clones the given histogram, 'empty' indicates that the clone should
* be alike the original, but not contain the data. */
simple_histo_1d*
histo_clone(pTHX_ simple_histo_1d* src, bool empty);
/* Clones a given histogram while stripping off all bins below the input
* histogram's bin 'bin_start' and beyond bin 'bin_end'. */
simple_histo_1d*
histo_clone_from_bin_range(pTHX_ simple_histo_1d* src, bool empty,
unsigned int bin_start, unsigned int bin_end);
/* Returns the bin number where x would be filled into the given
* histogram abstracts away whether the given histogram uses
* constant or non-constant bin sizes. */
unsigned int
histo_find_bin(simple_histo_1d* self, double x);
/* Fill n values x_in into the histogram. If the weights array w_in is
* NULL, a weight of 1 will be used for all x. */
void
histo_fill(simple_histo_1d* self, const unsigned int n, const double* x_in, const double* w_in);
/* Same as histo_fill, but expects bin numbers instead of coordinates */
void
histo_fill_by_bin(simple_histo_1d* self, const unsigned int n, const int* ibin_in, const double* w_in);
/* Calculates the cumulative histogram of the source histogram.
* If the prenormalization is > 0, the output histogram will be
* normalized to that value before calculating the cumulative. */
simple_histo_1d*
histo_cumulative(pTHX_ simple_histo_1d* src, double prenormalization);
void
histo_multiply_constant(simple_histo_1d* self, double constant);
/* Add the contents of one histogram (to_add) to another (target).
* Works only if the histograms have exactly the same binning and
* are otherwise compatible. Returns whether the addition has been
* performed or not. */
bool
histo_add_histogram(simple_histo_1d* target, simple_histo_1d* to_add);
/* Symmetric to histo_add_histogram: h1_i -= h2_i. */
bool
histo_subtract_histogram(simple_histo_1d* target, simple_histo_1d* to_subtract);
/* Symmetric to histo_add_histogram: h1_i *= h2_i. */
bool
histo_multiply_histogram(simple_histo_1d* target, simple_histo_1d* to_multiply);
/* Symmetric to histo_add_histogram: h1_i /= h2_i. */
bool
histo_divide_histogram(simple_histo_1d* target, simple_histo_1d* to_divide);
/* Rebin a given histogram to have 1/Nth as many bins.
* rebin_factor must divide the number of bins in the histogram without
* remainder. Returns a modified clone of the input histogram or NULL if
* the rebin_factor does not divide the number of bins in the input
* histogram. */
simple_histo_1d*
histo_rebin(pTHX_ simple_histo_1d* self, unsigned int rebin_factor);
/* Implements the binary search logic for locating the bin that a given
* value falls into */
unsigned int
find_bin_nonconstant(double x, unsigned int nbins, double* bins);
#include "histogram_agg.h"
#endif