// @(#)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_FumiliStandardMaximumLikelihoodFCN
#define ROOT_Minuit2_FumiliStandardMaximumLikelihoodFCN

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

namespace ROOT {

namespace Minuit2 {

/**

Class implementing the Elements member function for the standard
maximum likelihood method.

@author Andras Zsenei and Lorenzo Moneta, Creation date: 4 Sep 2004

@see FumiliMaximumLikelihoodFCN

@ingroup Minuit

*/

class FumiliStandardMaximumLikelihoodFCN : public FumiliMaximumLikelihoodFCN {

public:
   /**

   Constructor which initializes the measurement points for the one dimensional model function.

   @param modelFCN the model function used for describing the data.

   @param pos vector containing the x values corresponding to the
   measurements

   */

   FumiliStandardMaximumLikelihoodFCN(const ParametricFunction &modelFCN, std::span<const double> pos)
   {
      this->SetModelFunction(modelFCN);
      unsigned int n = pos.size();
      fPositions.reserve(n);
      std::vector<double> x(1);
      for (unsigned int i = 0; i < n; ++i) {
         x[0] = pos[i];
         fPositions.push_back(x);
      }
   }

   /**

   Constructor which initializes the measurement points for the multi dimensional model function.

   @param modelFCN the model function used for describing the data.

   @param pos vector containing the x values corresponding to the
   measurements

   */

   FumiliStandardMaximumLikelihoodFCN(const ParametricFunction &modelFCN, std::span<const std::vector<double>> pos)
   {
      this->SetModelFunction(modelFCN);
      fPositions.assign(pos.begin(), pos.end());
   }

   /**

   Evaluates the model function for the different measurement points and
   the Parameter values supplied.

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

   @return A vector containing the model function evaluated
   for each measurement point.

   */

   std::vector<double> Elements(std::vector<double> const &par) const override;

   /**

   Accessor to the position of the measurement (x coordinate).

   @param Index Index of the measuerement the position of which to return.

   @return the position of the measurement.

   */

   const std::vector<double> &GetMeasurement(int Index) const override;

   /**

   Accessor to the number of measurements used for calculating
   the maximum likelihood.

   @return the number of measurements.

   */

   int GetNumberOfMeasurements() const override;

   /**

   Evaluate function Value, Gradient and Hessian using Fumili approximation, for values of parameters p
   The result is cached inside and is return from the FumiliFCNBase::Value ,  FumiliFCNBase::Gradient and
   FumiliFCNBase::Hessian methods

   @param par vector of parameters

   **/

   void EvaluateAll(std::vector<double> const &par) override;

private:
   std::vector<std::vector<double>> fPositions;
};

} // namespace Minuit2

} // namespace ROOT

#endif // ROOT_Minuit2_FumiliStandardMaximumLikelihoodFCN
