#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); /* 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