// @(#)root/minuit2:$Id$
// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005  

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
 *                                                                    *
 **********************************************************************/

#ifndef ROOT_Minuit2_FumiliChi2FCN
#define ROOT_Minuit2_FumiliChi2FCN

#include "FumiliFCNBase.h"
#include <vector>
#include "Minuit2/ParametricFunction.h"

namespace ROOT {

   namespace Minuit2 {



/** 

Extension of the FCNBase for the Fumili method. Fumili applies only to 
minimization problems used for fitting. The method is based on a 
linearization of the model function negleting second derivatives. 
User needs to provide the model function. The figure-of-merit describing
the difference between the model function and the actual measurements in
the case of chi-square is the sum of the squares of the figures-of-merit
calculated for each measurement point, which is implemented by the 
operator() member function. The user still has to implement the calculation
of the individual figures-of-merit (which in the majority of the cases
will be the (measured Value - the Value predicted by the model)/standard deviation
implemeted by the FumiliStandardChi2FCN;
however this form can become more complicated (see for an example Numerical Recipes'
section on "Straight-Line Data with Errors in Both Coordinates")).


@author Andras Zsenei and Lorenzo Moneta, Creation date: 24 Aug 2004

@see <A HREF="http://www.cern.ch/winkler/minuit/tutorial/mntutorial.pdf">MINUIT Tutorial</A> on function minimization, section 5

@see FumiliStandardChi2FCN

@ingroup Minuit

*/



class FumiliChi2FCN : public FumiliFCNBase {

public:

  FumiliChi2FCN() {}

  virtual ~FumiliChi2FCN() {}



  /**

  Sets the model function for the data (for example gaussian+linear for a peak)

  @param modelFunction a reference to the model function.

  */

  void SetModelFunction(const ParametricFunction& modelFCN) { fModelFunction = &modelFCN; }



  /**

  Returns the model function used for the data.

  @return Returns a pointer to the model function.

  */

  const ParametricFunction *  ModelFunction() const { return fModelFunction; }



  /**
     
  Evaluates the model function for the different measurement points and 
  the Parameter values supplied, calculates a figure-of-merit for each
  measurement and returns a vector containing the result of this
  evaluation.

  @param par vector of Parameter values to feed to the model function.

  @return A vector containing the figures-of-merit for the model function evaluated 
  for each set of measurements.

  */

  virtual std::vector<double> Elements(const std::vector<double>& par) const = 0;



  /**
     
  Accessor to the parameters of a given measurement. For example in the
  case of a chi-square fit with a one-dimensional Gaussian, the Parameter 
  characterizing the measurement will be the position. It is the Parameter
  that is feeded to the model function.

  @param Index Index of the measueremnt the parameters of which to return
  @return A reference to a vector containing the values characterizing a measurement

  */

  virtual const std::vector<double> &  GetMeasurement(int Index) const = 0;


  /**

  Accessor to the number of measurements used for calculating the 
  present figure of merit.

  @return the number of measurements

  */

  virtual int GetNumberOfMeasurements() const = 0;



  /**
 
  Calculates the sum of Elements squared, ie the chi-square. The user must 
  implement in a class which inherits from FumiliChi2FCN the member function
  Elements() which will supply the Elements for the sum.


  @param par vector containing the Parameter values for the model function
  
  @return The sum of Elements squared

  @see FumiliFCNBase#elements

  */
  
  double operator()(const std::vector<double>& par) const {

    double chiSquare = 0.0; 
    std::vector<double> vecElements =  Elements(par);
    unsigned int vecElementsSize = vecElements.size();

    for (unsigned int i = 0; i < vecElementsSize; ++i) 
      chiSquare += vecElements[i]*vecElements[i]; 

    return chiSquare; 
  }
  


  /**
     
  !!!!!!!!!!!! to be commented

  */

  virtual double Up() const { return 1.0; } 

 private: 

  // A pointer to the model function which describes the data
  const ParametricFunction *fModelFunction;

   

};

  }  // namespace Minuit2

}  // namespace ROOT

#endif  // ROOT_Minuit2_FumiliChi2FCN
