/** @file psPolynomial.h
 *  @brief Standard Mathematical Functions.
 *  @ingroup Stats
 *
 *  This file will hold the prototypes for procedures which allocate, free,
 *  and evaluate various polynomials.  Those polynomial structures are also
 *  defined here.
 *
 *  @ingroup Stats
 *
 *  @author GLG, MHPCC
 *
 *  @version $Revision: 1.58 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-10-12 21:02:20 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PS_POLYNOMIAL_H
#define PS_POLYNOMIAL_H

#include <stdio.h>
#include <stdbool.h>
#include <float.h>
#include <math.h>

#include "psVector.h"
#include "psScalar.h"

/** \addtogroup Stats
 *  \{
 */

/** Evaluate a non-normalized Gaussian with the given mean and sigma at the
 *  given coordianate.
 *
 *  Note that this is not a Gaussian deviate.  The evaluated Gaussian is:
 *        \f[ exp(-\frac{(x-mean)^2}{2\sigma^2}) \f]
 *
 *  @return float      value on the gaussian curve given the input parameters
 */
float psGaussian(
    float x,                           ///< Value at which to evaluate
    float mean,                        ///< Mean for the Gaussian
    float sigma,                       ///< Standard deviation for the Gaussian
    bool normal                        ///< Indicates whether result should be normalized
);

/** Produce a vector of random numbers from a Gaussian distribution with
 *  the specified mean and sigma
 *
 *  @return psVector*    vector of random numbers
 *
 */
psVector* p_psGaussianDev(
    psF32 mean,                        ///< The mean of the Gaussian
    psF32 sigma,                       ///< The sigma of the Gaussian
    unsigned int Npts                  ///< The size of the vector
);

/** Polynomial Type.
 *
 *  Enumeration for Polynomial types.
 */
typedef enum {
    PS_POLYNOMIAL_ORD,                  ///< Ordinary Polynomial
    PS_POLYNOMIAL_CHEB                  ///< Chebyshev Polynomial
}
psPolynomialType;

// XXX: These are incorrect names for the order of the polynomial.  We
// keep them here temporarily so we can later sed replace them with the
// correct names.
/** One-dimensional polynomial */
typedef struct
{
    psPolynomialType type;              ///< Polynomial type
    unsigned int nX;             ///< Polynomial order
    psF64 *coeff;                       ///< Coefficients
    psF64 *coeffErr;                    ///< Error in coefficients
    psMaskType *mask;                   ///< Coefficient mask
}
psPolynomial1D;

// XXX: These are incorrect names for the order of the polynomial.  We
// keep them here temporarily so we can later sed replace them with the
// correct names.
/** Two-dimensional polynomial */
typedef struct
{
    psPolynomialType type;              ///< Polynomial type
    unsigned int nX;            ///< Polynomial order in x
    unsigned int nY;            ///< Polynomial order in y
    psF64 **coeff;                      ///< Coefficients
    psF64 **coeffErr;                   ///< Error in coefficients
    psMaskType **mask;                  ///< Coefficients mask
}
psPolynomial2D;

// XXX: These are incorrect names for the order of the polynomial.  We
// keep them here temporarily so we can later sed replace them with the
// correct names.
/** Three-dimensional polynomial */
typedef struct
{
    psPolynomialType type;              ///< Polynomial type
    unsigned int nX;            ///< Polynomial order in x
    unsigned int nY;            ///< Polynomial order in y
    unsigned int nZ;            ///< Polynomial order in z
    psF64 ***coeff;                     ///< Coefficients
    psF64 ***coeffErr;                  ///< Error in coefficients
    psMaskType ***mask;                 ///< Coefficients mask
}
psPolynomial3D;

// XXX: These are incorrect names for the order of the polynomial.  We
// keep them here temporarily so we can later sed replace them with the
// correct names.
/** Four-dimensional polynomial */
typedef struct
{
    psPolynomialType type;              ///< Polynomial type
    unsigned int nX;            ///< Polynomial order in x
    unsigned int nY;            ///< Polynomial order in y
    unsigned int nZ;            ///< Polynomial order in z
    unsigned int nT;            ///< Polynomial order in t
    psF64 ****coeff;                    ///< Coefficients
    psF64 ****coeffErr;                 ///< Error in coefficients
    psMaskType ****mask;                ///< Coefficients mask
}
psPolynomial4D;


/** Allocates a psPolynomial1D structure with n terms
 *
 *  @return  psPolynomial1D*    new 1-D polynomial struct
 */
psPolynomial1D* psPolynomial1DAlloc(
    unsigned int n,                    ///< Number of terms
    psPolynomialType type              ///< Polynomial Type
);

/** Allocates a 2-D polynomial structure
 *
 *  @return  psPolynomial2D*    new 2-D polynomial struct
 */
psPolynomial2D* psPolynomial2DAlloc(
    unsigned int nX,                   ///< Number of terms in x
    unsigned int nY,                   ///< Number of terms in y
    psPolynomialType type              ///< Polynomial Type
);

/** Allocates a 3-D polynomial structure
 *
 *  @return  psPolynomial3D*    new 3-D polynomial struct
 */
psPolynomial3D* psPolynomial3DAlloc(
    unsigned int nX,                   ///< Number of terms in x
    unsigned int nY,                   ///< Number of terms in y
    unsigned int nZ,                   ///< Number of terms in z
    psPolynomialType type              ///< Polynomial Type
);

/** Allocates a 4-D polynomial structure
 *
 *  @return  psPolynomial4D*    new 4-D polynomial struct
 */
psPolynomial4D* psPolynomial4DAlloc(
    unsigned int nX,                   ///< Number of terms in x
    unsigned int nY,                   ///< Number of terms in y
    unsigned int nZ,                   ///< Number of terms in z
    unsigned int nT,                   ///< Number of terms in t
    psPolynomialType type              ///< Polynomial Type
);

/** Evaluates a 1-D polynomial at specific coordinates.
 *
 *  @return psF64    result of polynomial at given location
 */
psF64 psPolynomial1DEval(
    const psPolynomial1D* poly,        ///< Coefficients for the polynomial
    psF64 x                            ///< location at which to evaluate
);

/** Evaluates a 2-D polynomial at specific coordinates.
 *
 *  @return psF64    result of polynomial at given location
 */
psF64 psPolynomial2DEval(
    const psPolynomial2D* poly,        ///< Coefficients for the polynomial
    psF64 x,                           ///< x location at which to evaluate
    psF64 y                            ///< y location at which to evaluate
);

/** Evaluates a 3-D polynomial at specific coordinates.
 *
 *  @return psF64    result of polynomial at given location
 */
psF64 psPolynomial3DEval(
    const psPolynomial3D* poly,        ///< Coefficients for the polynomial
    psF64 x,                           ///< x location at which to evaluate
    psF64 y,                           ///< y location at which to evaluate
    psF64 z                            ///< z location at which to evaluate
);

/** Evaluates a 4-D polynomial at specific coordinates.
 *
 *  @return psF64    result of polynomial at given location
 */
psF64 psPolynomial4DEval(
    const psPolynomial4D* poly,        ///< Coefficients for the polynomial
    psF64 x,                           ///< x location at which to evaluate
    psF64 y,                           ///< y location at which to evaluate
    psF64 z,                           ///< z location at which to evaluate
    psF64 t                            ///< t location at which to evaluate
);

/** Evaluates a 1-D polynomial at specific sets of coordinates
 *
 *  @return psVector*    results of polynomials at given locations
 */
psVector *psPolynomial1DEvalVector(
    const psPolynomial1D *poly,        ///< Coefficients for the polynomial
    const psVector *x                  ///< x locations at which to evaluate
);

/** Evaluates a 2-D polynomial at specific sets of coordinates
 *
 *  @return psVector*    results of polynomial at given locations
 */
psVector *psPolynomial2DEvalVector(
    const psPolynomial2D *poly,        ///< Coefficients for the polynomial
    const psVector *x,                 ///< x locations at which to evaluate
    const psVector *y                  ///< y locations at which to evaluate
);

/** Evaluates a 3-D polynomial at specific sets of coordinates
 *
 *  @return psVector*    results of polynomial at given locations
 */
psVector *psPolynomial3DEvalVector(
    const psPolynomial3D *poly,        ///< Coefficients for the polynomial
    const psVector *x,                 ///< x locations at which to evaluate
    const psVector *y,                 ///< y locations at which to evaluate
    const psVector *z                  ///< z locations at which to evaluate
);

/** Evaluates a 4-D polynomial at specific sets of coordinates
 *
 *  @return psVector*    results of polynomial at given locations
 */
psVector *psPolynomial4DEvalVector(
    const psPolynomial4D *poly,        ///< Coefficients for the polynomial
    const psVector *x,                 ///< x locations at which to evaluate
    const psVector *y,                 ///< y locations at which to evaluate
    const psVector *z,                 ///< z locations at which to evaluate
    const psVector *t                  ///< t locations at which to evaluate
);

/** 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 psPolynomial1D structure, false otherwise.
 */
bool psMemCheckPolynomial1D(
    psPtr ptr                          ///< the pointer whose type to check
);

/** 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 psPolynomial2D structure, false otherwise.
 */
bool psMemCheckPolynomial2D(
    psPtr ptr                          ///< the pointer whose type to check
);

/** 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 psPolynomial3D structure, false otherwise.
 */
bool psMemCheckPolynomial3D(
    psPtr ptr                          ///< the pointer whose type to check
);

/** 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 psPolynomial4D structure, false otherwise.
 */
bool psMemCheckPolynomial4D(
    psPtr ptr                          ///< the pointer whose type to check
);

/** \} */ // End of MathGroup Functions

#endif // #ifndef PS_POLYNOMIAL_H

