/** @file  psStats.h
 *  \brief basic statistical operations
 *  @ingroup Stats
 *
 *  This file will hold the definition of the histogram and stats data
 *  structures.  It also contains prototypes for procedures which operate
 *  on those data structures.
 *
 *  XXX: The following stats members are never used, or set in this code.
 *      stats->robustN50
 *      stats->clippedNvalues
 *      stats->binsize
 *
 *  @author GLG, MHPCC
 *
 *  @version $Revision: 1.48 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-08-30 01:14:13 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */
#ifndef PS_STATS_H
#define PS_STATS_H

#include "psVector.h"

/// @addtogroup Stats
/// @{

/******************************************************************************
    Statistical functions and data structures.
 *****************************************************************************/

/** enumeration of statistical calculation options
 *
 *  @see psStats, psVectorStats, psImageStats
 */
// XXX: Is PS_STAT_ROBUST_FOR_SAMPLE obsolete?
typedef enum {
    PS_STAT_SAMPLE_MEAN = 0x000001,         ///< Sample Mean
    PS_STAT_SAMPLE_MEDIAN = 0x000002,       ///< Sample Median
    PS_STAT_SAMPLE_STDEV = 0x000004,        ///< Sample Standard Deviation
    PS_STAT_SAMPLE_QUARTILE = 0x000008,     ///< Sample Quartile
    PS_STAT_ROBUST_MEAN = 0x000010,         ///< Robust Mean
    PS_STAT_ROBUST_MEDIAN = 0x000020,       ///< Robust Median
    PS_STAT_ROBUST_MODE = 0x000040,         ///< Robust Mode
    PS_STAT_ROBUST_STDEV = 0x000080,        ///< Robust Standarad Deviation
    PS_STAT_ROBUST_QUARTILE = 0x000100,     ///< Robust Quartile
    PS_STAT_CLIPPED_MEAN = 0x000200,        ///< Clipped Mean
    PS_STAT_CLIPPED_STDEV = 0x000400,       ///< Clipped Standard Deviation
    PS_STAT_MAX =  0x000800,                ///< Maximum
    PS_STAT_MIN =  0x001000,                ///< Minumum
    PS_STAT_USE_RANGE =  0x002000,          ///< Range
    PS_STAT_USE_BINSIZE = 0x004000,         ///< Binsize
} psStatsOptions;

/** This is the generic statistics structure.  It contails the data members
    for the various statistic values.  It also contains the options member to
    specifiy which statistics should be calculated. */
typedef struct
{
    double sampleMean;                 ///< formal mean of sample
    double sampleMedian;               ///< formal median of sample
    double sampleStdev;                ///< standard deviation of sample
    double sampleUQ;                   ///< upper quartile of sample
    double sampleLQ;                   ///< lower quartile of sample
    double robustMean;                 ///< robust mean of array
    double robustMedian;               ///< robust median of array
    double robustMode;                 ///< Robust mode of array
    double robustStdev;                ///< robust standard deviation of array
    double robustUQ;                   ///< robust upper quartile
    double robustLQ;                   ///< robust lower quartile
    int robustN50;                     ///< Number of points in Gaussian fit.  XXX: This is currently never set.
    int robustNfit;                    ///< The number of points between the quartiles.
    double clippedMean;                ///< Nsigma clipped mean
    double clippedStdev;               ///< standard deviation after clipping
    int clippedNvalues;                ///< Number of data points used for clipped mean:  This value is never used.
    double clipSigma;                  ///< Nsigma used for clipping; user input
    int clipIter;                      ///< Number of clipping iterations; user input
    double min;                        ///< minimum data value in array
    double max;                        ///< maximum data value in array
    double binsize;                    ///< binsize for robust fit (input/ouput)
    psStatsOptions options;            ///< bitmask of calculated values
}
psStats;

/** Performs statistical calculations on a vector.
 *
 *  @return psStats*    the statistical results as specified by stats->options
 */
psStats* psVectorStats(
    psStats* stats,                    ///< stats structure defines stats to be calculated and how
    const psVector* in,                ///< Vector to be analysed.
    const psVector* errors,            ///< Errors.
    const psVector* mask,              ///< Ignore elements where (maskVector & maskVal) != 0: must be INT or NULL
    psMaskType maskVal                 ///< Only mask elements with one of these bits set in maskVector
);

/** Allocator of the psStats structure.
 *
 *  @return psStats*    A new psStats struct with the options member set to the
 *                      value given.
 */
psStats* psStatsAlloc(
    psStatsOptions options             ///< Statistics to calculate
);


/** Checks the type of a particular pointer.
 *
 *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
 *
 *  @return bool:       True if the pointer matches a psStats structure, false otherwise.
 */
bool psMemCheckStats(
    psPtr ptr                          ///< the pointer whose type to check
);


/******************************************************************************
    Histogram functions and data structures.
 *****************************************************************************/

/** The basic histogram structure which contains bounds and bins.
 *
 *  In this structure, the vector bounds specifies the boundaries of the
 *  histogram bins, and must of type psF32, while nums specifies the number
 *  of entries in the bin, and must of type psU32. The value of bounds.n must
 *  therefore be 1 greater than than nums.n. The two values minNum and maxNum
 *  are the number of data values which fell below the lower limit bound or
 *  above the upper limit bound, respectively.
 */
typedef struct
{
    const psVector* bounds;            ///< Bounds for the bins (type F32)
    psVector* nums;                    ///< Number in each of the bins (INT)
    int minNum;                        ///< Number below the minimum
    int maxNum;                        ///< Number above the maximum
    bool uniform;                      ///< Is it a uniform distribution?
}
psHistogram;

/** Allocator for psHistogram where the bounds of the bins are implicitly
 *  specified through simply specifying an upper and lower limit along with
 *  the size of the bins.
 *
 *  @return psHistogram*    Newly allocated psHistogram
 */
psHistogram* psHistogramAlloc(
    float lower,                       ///< Lower limit for the bins
    float upper,                       ///< Upper limit for the bins
    int n                              ///< Number of bins
);


/** Checks the type of a particular pointer.
 *
 *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
 *
 *  @return bool:       True if the pointer matches a psHistogram structure, false otherwise.
 */
bool psMemCheckHistogram(
    psPtr ptr                          ///< the pointer whose type to check
);


/** Allocator for psHistogram where the bounds of the bins are explicitly
 *  specified.
 *
 *  @return psHistogram*    Newly allocated psHistogram
 */
psHistogram* psHistogramAllocGeneric(
    const psVector* bounds             ///< Bounds for the bins
);

/** Calculate a histogram
 *
 *  The following function populates the histogram bins from the specified
 *  vector (in). It alters and returns the histogram out structure. The input
 *  vector may be of types psU8, psU16, psF32, psF64.
 *
 *  @return psHistogram*   histogram result
 */
psHistogram* psVectorHistogram(
    psHistogram* out,                  ///< Histogram data
    const psVector* values,            ///< Vector to analyse
    const psVector* errors,            ///< Errors
    const psVector* mask,              ///< Mask dat for input vector
    psMaskType maskVal                 ///< Mask value
);

/** Extracts the statistic value specified by stats->options.
 *
 *  @return psBool    If more than one statistic result is set in stats->options,
 *                    false is returned and the value parameter is not set,
 *                    otherwise true is returned.
 */
psBool p_psGetStatValue(
    const psStats* stats, ///< the statistic struct to operate on

    psF64 *value ///< if return is true, this is set to the specified statistic value by stats->options
);

// XXX: Create a single, generic, version of the vector normalize function.
// XXX: Ask IfA for a public psLib function.

/** Normalize the range of a vector containing U8 values  */
void p_psNormalizeVectorRangeU8(
    psVector* myData,                  ///< Vector containing the U8 values
    psU8 low,                          ///< Minimum value
    psU8 high                          ///< Maximum value
);

/** Normalize the range of a vector containing U16 values  */
void p_psNormalizeVectorRangeU16(
    psVector* myData,                  ///< Vector containing the U16 values
    psU16 low,                         ///< Minimum value
    psU16 high                         ///< Maximum value
);

/** Normalize the range of a vector containing U32 values  */
void p_psNormalizeVectorRangeU32(
    psVector* myData,                  ///< Vector containing the U32 values
    psU32 low,                         ///< Minimum value
    psU32 high                         ///< Maximum value
);

/** Normalize the range of a vector containing U64 values  */
void p_psNormalizeVectorRangeU64(
    psVector* myData,                  ///< Vector containing the U64 values
    psU64 low,                         ///< Minimum value
    psU64 high                         ///< Maximum value
);

/** Normalize the range of a vector containing S8 values  */
void p_psNormalizeVectorRangeS8(
    psVector* myData,                  ///< Vector containing the S8 values
    psS8 low,                          ///< Minimum value
    psS8 high                          ///< Maximum value
);

/** Normalize the range of a vector containing S16 values  */
void p_psNormalizeVectorRangeS16(
    psVector* myData,                  ///< Vector containing the S16 values
    psS16 low,                         ///< Minimum value
    psS16 high                         ///< Maximum value
);

/** Normalize the range of a vector containing S32 values  */
void p_psNormalizeVectorRangeS32(
    psVector* myData,                  ///< Vector containing the S32 values
    psS32 low,                         ///< Minimum value
    psS32 high                         ///< Maximum value
);

/** Normalize the range of a vector containing S64 values  */
void p_psNormalizeVectorRangeS64(
    psVector* myData,                  ///< Vector containing the S64 values
    psS64 low,                         ///< Minimum value
    psS64 high                         ///< Maximum value
);

/** Normalize the range of a vector containing F32 values  */
void p_psNormalizeVectorRangeF32(
    psVector* myData,                  ///< Vector containing the F32 values
    psF32 low,                         ///< Minimum value
    psF32 high                         ///< Maximum value
);

/** Normalize the range of a vector containing F64 values  */
void p_psNormalizeVectorRangeF64(
    psVector* myData,                  ///< Vector containing the F64 values
    psF64 low,                         ///< Minimum value
    psF64 high                         ///< Maximum value
);

/// @}

#endif // #ifndef PS_STATS_H
