// Copyright (C) 2019 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef CONTINUATIONCUTS_H
#define CONTINUATIONCUTS_H
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include "StOpt/regression/BaseRegression.h"
#include "StOpt/core/grids/SpaceGrid.h"

/** \file ContinuationCuts.h
 *  \brief In DP, when transition problem are solved using LP some final cuts are given to the LP solver as ending conditions
 *        This permits to store cuts regressing the cuts coefficients.
 *        For each point of the grid, the cuts are stored.
 *        From one point given, one gets a list of cuts of the grids points corresponding to the hypercube surrounding the point
 * \author  Xavier Warin
 */

namespace StOpt
{

/// \class ContinuationCuts ContinuationCuts.h
/// Permits to store  some cuts at each point of a space grid
class ContinuationCuts
{

private :
    std::shared_ptr< SpaceGrid >    m_grid ; ///< grid used to define stock points
    std::shared_ptr< BaseRegression >  m_condExp ; ///< conditional expectation
    Eigen::Array< Eigen::ArrayXXd, Eigen::Dynamic, 1  > m_regressedCutCoeff ; ///< for each cut  \f$ \bar a_0 + \sum_i^d a_i x_i  \f$ store the  coefficients coefficient for each basis function and each stock points (nb basis , nb points). Notice that  \f$ \bar a_0 =  a_0 - \sum_i^d a_i \bar x_i \f$

public :
    /// \brief Default constructor
    ContinuationCuts() {}

    /// \brief Constructor
    /// \param p_grid   grid for stocks
    /// \param p_condExp regressor for conditional expectation
    /// \param p_values   functions to store  ((number of simulations by number of cuts) by (nb of stocks)). The pValues are given as
    ///                   \f$ a_0 + \sum_i^d a_i (x_i -\bar x_i) \f$ at a point \f$ \bar x \f$.
    ///                   These cuts are
    ContinuationCuts(const  std::shared_ptr< SpaceGrid >   &p_grid,
                     const  std::shared_ptr< BaseRegression >   &p_condExp,
                     const  Eigen::ArrayXXd &p_values);

    /// \brief Constructor
    ContinuationCuts(const std::shared_ptr<BaseRegression>   &p_condExp) :
        m_condExp(p_condExp)
    {}

    /// \brief Load another Continuation value object
    ///  Only a partial load of the objects is achieved
    /// \param p_grid   Grid to load
    /// \param p_condExp Condition expectation
    /// \param p_values coefficient polynomials for regression
    virtual void loadForSimulation(const  std::shared_ptr< SpaceGrid > &p_grid,
                                   const std::shared_ptr< BaseRegression >   &p_condExp,
                                   const Eigen::Array< Eigen::ArrayXXd, Eigen::Dynamic, 1  >  &p_values)
    {
        m_grid = p_grid;
        m_condExp = p_condExp;
        m_regressedCutCoeff = p_values ;
    }

    /// \brief Get a list of all cuts for all simulations  \f$ (\bar a_0, a_1, ...a_d) \f$
    ///        for  stock points in a set
    /// \param  p_hypStock list of points  defining an hypercube :
    ///          - (i,0)  coordinate corresponds to min value in dimension i
    ///          - (i,1)  coordinate corresponds to max value in dimension i
    ///          .
    /// Return an array of cuts for all points in the hypercube  and simulation used
    /// shape  :  first dimenson :   (nb simulations by number of cuts)
    ///           second dimension : nb of points  in the  hypercube
    Eigen::ArrayXXd  getCutsAllSimulations(const Eigen::ArrayXXd &p_hypStock) const;


    /// \brief get list of cuts associated to an hypercube
    /// \param  p_hypStock      list of points  defining an hypercube
    /// \param  p_coordinates   simulation coordinates
    /// \return  list of cuts (nb cut coeff, nb stock points)
    Eigen::ArrayXXd getCutsASim(const Eigen::ArrayXXd &p_hypStock, const Eigen::ArrayXd &p_coordinates) const;


    /// \brief get Regressed values stored
    const Eigen::Array< Eigen::ArrayXXd, Eigen::Dynamic, 1 >   &getValues() const
    {
        return m_regressedCutCoeff;
    }

    /// \brief Get back particles associated to regression
    inline Eigen::ArrayXXd  getParticles() const
    {
        return m_condExp->getParticles();
    }

    //// \brief Get back
    ///@{
    std::shared_ptr< SpaceGrid > getGrid() const
    {
        return m_grid;
    }
    std::shared_ptr<BaseRegression > getCondExp()  const
    {
        return m_condExp ;
    }

    inline int getNbSimul() const
    {
        return m_condExp->getNbSimul() ;
    }
    ///@}

};
}
#endif
