// Copyright (C) 2026 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef GRIDANDREGRESSEDVALUEAUTODIFF_H
#define GRIDANDREGRESSEDVALUEAUTODIFF_H
#include <Eigen/Dense>
#include <memory>
#include <type_traits>
#include <utility>
#include "StOpt/regression/BaseRegression.h"
#include "StOpt/core/grids/FullGrid.h"
#include "StOpt/core/grids/InterpolatorSpectral.h"
#include "StOpt/core/grids/LegendreInterpolatorSpectral.h"
#include "StOpt/core/grids/LinearInterpolatorSpectral.h"
#include "StOpt/core/grids/GridIterator.h"
#include "StOpt/core/grids/cloneInterpolator.h"
#include "StOpt/regression/dispatchRegressionAutoDiff.h"
#include "StOpt/regression/GridAndRegressedValue.h"


/** \file GridAndRegressedValueAutoDiff.h
 * \brief Permits to store a function value  defined in dimension \f$n  = p+q \f$
 *    defined partly on a grid (dimension \f$ p \f$)  and partly by regression (dimension \f$ q \f$)
 *    This is a version used for autodiff.
 *    \author Xavier Warin
 */


namespace StOpt
{
/// \class GridAndRegressedValueAutoDiff GridAndRegressedValueAutoDiff.h
/// Permits to store  a function value partly defined on a grid and by regression
  template<typename T>
class GridAndRegressedValueAutoDiff
{

private :
    std::shared_ptr< FullGrid >    m_grid ; ///< grid used to define stock points
    std::shared_ptr< BaseRegression >  m_reg ; ///< regressor
    std::vector< std::shared_ptr<InterpolatorSpectral<T>> > m_interpFuncBasis; /// vector of spectral operator associated to the grid used for each regressed function basis

public :

    /// \brief Default constructor
    GridAndRegressedValueAutoDiff() {}

   /// \brief Constructor used for deserialization
    /// \param  p_grid                grid for stocks
    /// \param  p_reg                 regressor
    /// \param  p_interpFuncBasis     spectral interpolator associated to each regression function basis
    GridAndRegressedValueAutoDiff(const  std::shared_ptr< FullGrid >   &p_grid,
                          const std::shared_ptr< BaseRegression >   &p_reg,
                          const std::vector< std::shared_ptr<InterpolatorSpectral<T>> > &p_interpFuncBasis):  m_grid(p_grid), m_reg(p_reg), m_interpFuncBasis(p_interpFuncBasis) {}


 
    T getValueAutoDiff(const  Eigen::Array<T, Eigen::Dynamic, 1> & p_ptOfStock,
                        const Eigen::Array<T, Eigen::Dynamic, 1> & p_coordinates) const 
     {
       return  dispatchRegressionGetAValue(*m_reg, p_coordinates, p_ptOfStock, m_interpFuncBasis);
      }

  void cloneFromDouble(const  std::shared_ptr< FullGrid >   &p_grid,
                       const std::shared_ptr< BaseRegression >   &p_reg,
                       const GridAndRegressedValue & p_gridARVDouble)
  {
    m_grid= p_grid;
    m_reg= p_reg;
    const std::vector< std::shared_ptr<InterpolatorSpectral<double>> > &  interpol= p_gridARVDouble.getInterpolators();
    m_interpFuncBasis.resize(interpol.size());
    for (int i= 0; i< m_interpFuncBasis.size(); ++i)
      {
        m_interpFuncBasis[i]=cloneInterpolator<T,double>(*interpol[i]);
      }
  }
};
}
#endif
