/** @file  psMinimize.c
 *  \brief basic minimization functions
 *  @ingroup Math
 *
 *  This file will contain function prototypes for various minimization,
 *  chi-squared minimization, and 1-D polynomial fitting routines.
 *
 *  @author GLG, MHPCC
 *
 *  @version $Revision: 1.57 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-09-11 22:18:40 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 *
 */

#ifndef PS_MINIMIZE_H
#define PS_MINIMIZE_H

/** \file psMinimize.h
 *  \brief minimization operations
 *  \ingroup Stats
 */
/** \addtogroup Stats
 *  \{
 */

#include "psVector.h"
#include "psMemory.h"
#include "psArray.h"
#include "psImage.h"
#include "psMatrix.h"
#include "psPolynomial.h"
#include "psSpline.h"
#include "psStats.h"
#include "psTrace.h"
#include "psError.h"
#include "psConstants.h"

/** A data structure for minimization routines.
 *
 *  Contains numerical analysis parameters/values
 */
typedef struct
{
    const int maxIter;                 ///< Convergence limit
    const float tol;                   ///< Error Tolerance
    float value;                       ///< Value of function at minimum
    int iter;                          ///< Number of iterations to date
    float lastDelta;                   ///< The last difference for the fit
}
psMinimization;

/** Allocates a psMinimization structure.
 *
 *  @return psMinimization* :   a new psMinimization struct
*/
psMinimization *psMinimizationAlloc(
    int maxIter,                       ///< Number of minimization iterations to perform.
    float tol                          ///< Requested error tolerance
);

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


/** Derive a polynomial fit.
 *
 *  psVectorFitPolynomial1d returns the polynomial that best fits the
 *  observations. The input parameters are a polynomial that specifies the
 *  fit order, myPoly, which will be altered and returned with the best-fit
 *  coefficients; and the observations, x, y and yErr. The independent
 *  variable list, x may be NULL, in which case the vector index is used.
 *  The dependent variable error, yErr may be null, in which case the solution
 *  is determined in the assumption that all data errors are equal. This
 *  function must be valid only for types psF32, psF64.
 *
 *  @return psPolynomial1D*    polynomial fit
 */

psPolynomial1D *psVectorFitPolynomial1D(
    psPolynomial1D *poly,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x
);

psPolynomial2D *psVectorFitPolynomial2D(
    psPolynomial2D *poly,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y
);

psPolynomial3D *psVectorFitPolynomial3D(
    psPolynomial3D *poly,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y,
    const psVector *z
);

psPolynomial4D *psVectorFitPolynomial4D(
    psPolynomial4D *poly,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y,
    const psVector *z,
    const psVector *t
);


psPolynomial1D *psVectorClipFitPolynomial1D(
    psPolynomial1D *poly,
    psStats *stats,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x
);

psPolynomial2D *psVectorClipFitPolynomial2D(
    psPolynomial2D *poly,
    psStats *stats,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y
);

psPolynomial3D *psVectorClipFitPolynomial3D(
    psPolynomial3D *poly,
    psStats *stats,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y,
    const psVector *z
);

psPolynomial4D *psVectorClipFitPolynomial4D(
    psPolynomial4D *poly,
    psStats *stats,
    const psVector *mask,
    psMaskType maskValue,
    const psVector *f,
    const psVector *fErr,
    const psVector *x,
    const psVector *y,
    const psVector *z,
    const psVector *t
);

/** Specifies the format of a user-defined function that the general Levenberg-
 *  Marquardt minimizer routine will accept.
 *
 *  @return float:   the single float value of the function given the parameters,
 *       positions, and derivatives.
 */
typedef
float (*psMinimizeLMChi2Func)(
    psVector *deriv,                   ///< derivatives of the function
    const psVector *params,            ///< the parameters used to evaluate the function
    const psVector *x                  ///< positions for evaluation
);

/** Minimizes a specified function based on the Levenberg-Marquardt method.
 *
 *  @return bool:   True if successful.
 */
bool psMinimizeLMChi2(
    psMinimization *min,               ///< Minimization specification
    psImage *covar,                    ///< Covariance matrix
    psVector *params,                  ///< "Best Guess" for the parameters that minimize func
    const psVector *paramMask,         ///< Parameters to be held fixed by the minimizer
    const psArray *x,                  ///< Measurement ordinates of multiple vectors
    const psVector *y,                 ///< Measurement coordinates
    const psVector *yErr,              ///< Errors in the measurement coordinates
    psMinimizeLMChi2Func func          ///< Specified function
);

bool psMinimizeGaussNewtonDelta (
    psVector *delta,
    const psVector *params,
    const psVector *paramMask,
    const psArray  *x,
    const psVector *y,
    const psVector *yErr,
    psMinimizeLMChi2Func func
);

/** Use specified alpha, beta, params to generate a new guess for Alpha, Beta, Params
 *
 *  @return psBool:   True if successful.
 */
psBool p_psMinLM_GuessABP(
    psImage  *Alpha,                   ///< New Alpha guess
    psVector *Beta,                    ///< New Beta guess
    psVector *Params,                  ///< New Params guess
    const psImage  *alpha,             ///< Old Alpha guess
    const psVector *beta,              ///< Old Beta guess
    const psVector *params,            ///< Old Params guess
    const psVector *paramMask,         ///< Param Mask
    psF64 lambda                       ///< Factor used in update
    //XXX Got Better Desc?
);

/** Function used to set parameters for generating "best guess" in minimizing Chi-Squared value.
 *
 *  @return psF64:    Chi-squared value for new guess
 */
psF64 p_psMinLM_SetABX (
    psImage  *alpha,                   ///< alpha guess
    psVector *beta,                    ///< beta guess
    const psVector *params,            ///< params guess
    const psVector *paramMask,         ///< param mask
    const psArray  *x,                 ///< Measurement ordinates
    const psVector *y,                 ///< Measurement coordinates
    const psVector *dy,                ///< Weights calculated from y-errors
    psMinimizeLMChi2Func func          ///< Specified function
);


/** Specifies the format of a user-defined function that the general Powell
 *  minimizer routine will accept.
 *
 *  @return float:   the single float value of the function given the parameters
 *      and coordinate vectors.
*/
typedef
float (*psMinimizePowellFunc)(
    const psVector *params,            ///< Parameters used to evaluate the function
    const psArray *coords              ///< Coordinates at which to evaluate
);

/** Minimizes a specified function based on the Powell method.
 *
 *  @return bool:   True if successful.
 */
bool psMinimizePowell(
    psMinimization *min,               ///< Minimization specification
    psVector *params,                  ///< "Best guess" for parameters that minimize func
    const psVector *paramMask,         ///< Parameters to be held fixed by minimizer
    const psArray *coords,             ///< Measurement coordinates
    psMinimizePowellFunc func          ///< Specified function
);

/** Specifies the format of a user-defined function that the general Powell chi-
 *  squared minimizer routine will accept.
 *
 *  @return psVector*:    Calculated values given the parameters and coordinates.
*/
typedef
psVector *(*psMinimizeChi2PowellFunc)(
    const psVector *params,            ///< Parameters used to evaluate the function
    const psArray *coords              ///< Coordinates at which to evaluate
);

/** Minimizes a specified function based on the Powell chi-squared method.
 *
 *  @return bool:   True is successful.
 */
bool psMinimizeChi2Powell(
    psMinimization *min,               ///< Minimization specification
    psVector *params,                  ///< "Best guess" for parameters that minimize func
    const psVector *paramMask,         ///< Parameters to be held fixed by minimizer
    const psArray *coords,             ///< Measurement coordinates
    const psVector *value,             ///< Measured values at the coordinates
    const psVector *error,             ///< Errors in the measure values (or NULL)
    psMinimizeChi2PowellFunc model     ///< Specified function
);

/** Gauss-Jordan numerical solver.
 *
 *  @return bool:   True if successful.
 */
bool psGaussJordan(
    psImage *a,                        ///< Matrix to be solved
    psVector *b                        ///< Vector of values
);

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




#endif // #ifndef PS_MINIMIZE_H

