File: SparseRegression.h

package info (click to toggle)
stopt 5.12%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 8,860 kB
  • sloc: cpp: 70,456; python: 5,950; makefile: 72; sh: 57
file content (232 lines) | stat: -rw-r--r-- 12,991 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// Copyright (C) 2016 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef SPARSEREGRESSION_H
#define SPARSEREGRESSION_H
#include <Eigen/Dense>
#include <functional>
#ifdef _OPENMP
#include <omp.h>
#endif
#include "StOpt/core/grids/SparseSpaceGridNoBound.h"
#include "StOpt/regression/BaseRegression.h"

/** \file SparseRegression.h
 * \brief Compute conditional expectation with sparse grids
 *        As  in article "Monte-Carlo valorisation of American options: facts and new algorithms to improve existing methods"
 *          by Bouchard, Warin in "Numerical methods in finance", Springer,2012
 *        particle are sorted in each dimension such that the basis support have particles
 *       First draft is without adaptation.
 *       \author Xavier Warin
 */

namespace StOpt
{
/**
 * \defgroup Regression with sparse grids with linear, quadratic and cubic polynomials
 *@{
 */

class SparseRegression : public BaseRegression
{

private:

    std::shared_ptr< SparseSpaceGridNoBound > m_spGrid ; ///< to store the grid
    Eigen::ArrayXXd  m_partRescaled;  ///< Particles used to regress but rescaled according to transformToUnitSquare : dimension of the problem , second dimension : the  number of particles
    std::vector< std::vector< double> > m_mesh ; ///< For each direction, give the coordinate of the mesh
    std::vector< std::vector< std::function< double(const double &) > > > m_functionScal ;   ///< for each position, for  the level used, defines the  basis function
    Eigen::LLT<Eigen::MatrixXd>  m_llt; ///< llt factorization by eigen
    Eigen::MatrixXd m_yReg ; ///< utilitarian to calculate pseudo inverse if the matrix is singular
    bool  m_bSingular ; ///< true if the regression matrix is singular
    bool m_bNoRescale ; //< Don't rescale if true

    /// \brief create and factorize the regression matrix
    /// \param p_levelMax    maximum level of the sparse grid
    /// \param p_weight      weight for the anisotropy : the level \f$ (l_i)_i\f$  satisfy  \f$\sum_i weight[i] l_i \le NDIM + levelMax -1 \f$
    /// \param p_degree      Degree of the interpolation sparse grid
    void createAndFactorize(const int &p_levelMax, const Eigen::ArrayXd &p_weight, const int &p_degree);

    /// \brief rescale the particle values
    /// \param  p_aParticle  The particle to rescale according the mesh
    /// \param  p_aPartRescaled  The same particle rescaled
    void rescaleAParticle(const Eigen::Ref< const Eigen::ArrayXd>  p_aParticle, Eigen::Ref< Eigen::ArrayXd>  p_aPartRescaled) const;

    /// \brief Transform each direction to unit square : in each direction , the same number number of particles in each mesh.
    /// \param p_levelMax    maximum level of the sparse grid
    /// \param p_weight      weight for the anisotropy : the level \f$ (l_i)_i\f$  satisfy  \f$\sum_i weight[i] l_i \le NDIM + levelMax -1 \f$
    void transformToUnitSquare(const int &p_levelMax,  const Eigen::ArrayXd &p_weight);

    /// \brief Rescale simply
    /// \param p_weight      weight for the anisotropy : the level \f$ (l_i)_i\f$  satisfy \f$ \sum_i weight[i] l_i \le NDIM + levelMax -1 \f$
    void rescale(const Eigen::ArrayXd &p_weight);

    /// \brief Recursive calculation function basis at a point  using "son"" knowledge
    /// \param p_levelCurrent                      Current index of levels of the point
    /// \param p_positionCurrent                   Current position of the point, at the given level
    /// \param p_ipoint                            Point number
    /// \param p_xMiddle                           Position in [0,1] of current node in each dimension
    /// \param p_dx                                Semi mesh size
    /// \param p_x                                 Evaluation point
    /// \param p_idimMin                           Minimal dimension search (to avoid to go twice at same node)
    /// \param p_funcVal                           Function basis values at current node for all dimensions
    /// \param p_son                               Son array (first dimension is the node number, second is the dimension , 0 in array corresponds to left, 1 to right)
    /// \param p_nonNullFunctionValues            To fill in : values of the different non null function basis
    /// \param  p_associatedFunctionNumber        Cell number associated to each previous non num value
    void recursiveFillFunctionBasisWithSon(Eigen::ArrayXc &p_levelCurrent,
                                           Eigen::ArrayXui   &p_positionCurrent,
                                           const int &p_ipoint,
                                           Eigen::ArrayXd &p_xMiddle,
                                           Eigen::ArrayXd &p_dx,
                                           const Eigen::ArrayXd &p_x,
                                           const unsigned short int &p_idimMin,
                                           Eigen::ArrayXd &p_funcVal,
                                           const Eigen::Array< std::array<int, 2 >, Eigen::Dynamic, Eigen::Dynamic >    &p_son,
                                           std::vector<double> &p_nonNullFunctionValues,
                                           std::vector<int>    &p_associatedFunctionNumber) const;

    /// \brief  For a particle asses the value of all basis functions
    /// \param  p_particle                         particle rescaled coordinates
    ///  \param p_nonNullFunctionValues            To fill in : values of the different non null function basis
    ///  \param  p_associatedFunctionNumber        Cell number associated to each previous non num value
    void assessFuncBasis(const Eigen::ArrayXd &p_particle, std::vector<double> &p_nonNullFunctionValues, std::vector<int>    &p_associatedFunctionNumber) const ;


    /// \brief fill in matrix regression using the minimum of memory possible
    ///    Each thread fills part of the matrix for the simulations it uses, then the matrix is reconstructed
    /// \param  p_matReg  matrix to fill in
    void fillInRegressionMatrix(Eigen::MatrixXd &p_matReg);


    /// \brief Fill in second member  with minimal cost of storage
    /// \param  p_fToRegress  functions to regress associated to each simulation used in optimization (number of functions to regress times the simulations)
    /// \return   second members to  construct (number of functions to regress times the number of basis functions)
    Eigen::MatrixXd  fillInSecondMember(const Eigen::MatrixXd &p_fToRegress) const ;


    /// \brief Reconstruct the solution using the basis coordinates
    /// \param p_basisCoeff  basis function coefficients (number)
    /// \param  p_fRegressed  the result of the regression
    void reconstruct(const Eigen::ArrayXXd &p_basisCoeff, Eigen::ArrayXXd &p_fRegressed) const ;

    /// \brief Reconstruct the solution using the basis coordinates
    /// \param p_basisCoeff  basis function coefficients
    /// \param  p_aParticle  coordinates of the point where to reconstruct the value function
    /// \return regressed value
    double  reconstructOneParticle(const Eigen::ArrayXd &p_basisCoeff, const Eigen::ArrayXd &p_aParticle) const ;

public :

    /// \brief default constructor
    SparseRegression() {}

    /// \brief Constructor (for constructor achieved once)
    /// \param p_levelMax   Level max associated to the sparse grid
    /// \param p_weight     Weight for anisotropic sparse grids
    /// \param p_degree     Degree of the interpolator
    /// \param p_bNoRescale Don't use a complex rescaling
    SparseRegression(const int &p_levelMax, const Eigen::ArrayXd &p_weight, const int &p_degree, bool p_bNoRescale = false);

    /// \brief Constructor for object constructed at each time step
    /// \param  p_bZeroDate    first date is 0?
    /// \param  p_particles    particles used for the meshes.
    ///                        First dimension  : dimension of the problem,
    ///                        second dimension : the  number of particles
    /// \param p_levelMax      Level max associated to the sparse grid
    /// \param p_weight        Weight for anisotropic sparse grids
    /// \param p_degree     Degree of the interpolator
    SparseRegression(const bool &p_bZeroDate,
                     const Eigen::ArrayXXd  &p_particles,
                     const int &p_levelMax, const Eigen::ArrayXd &p_weight,
                     const int &p_degree);

    /// \brief constructor to recreate the dumped object (for simulation)
    /// \param p_bZeroDate first date is 0?
    /// \param p_spGrid    sparse grid
    /// \param p_mesh      mesh used for rescaling
    /// \param  p_meanX            scaled factor in each direction (average of particles values in each direction)
    /// \param  p_etypX            scaled factor in each direction (standard deviation of particles in each direction)
    /// \param  p_svdMatrix        svd matrix transposed  used to transform particles
    SparseRegression(const bool &p_bZeroDate, std::shared_ptr< SparseSpaceGridNoBound>  p_spGrid,  const std::vector< std::vector< double> > &p_mesh, const   Eigen::ArrayXd &p_meanX,
                     const   Eigen::ArrayXd   &p_etypX, const   Eigen::MatrixXd   &p_svdMatrix);


    /// \brief update the particles used in regression  and construct the matrices
    /// \param  p_bZeroDate    first date is 0?
    /// \param  p_particles    particles used for the meshes.
    ///                        First dimension  : dimension of the problem,
    ///                        second dimension : the  number of particles
    void updateSimulations(const bool &p_bZeroDate, const Eigen::ArrayXXd  &p_particles);

    /// \brief conditional expectation basis function coefficient calculation
    /// \param  p_fToRegress  function to regress associated to each simulation used in optimization
    /// \return regression coordinates on the basis  (size : number of meshes multiplied by the dimension plus one)
    /// @{
    Eigen::ArrayXd getCoordBasisFunction(const Eigen::ArrayXd &p_fToRegress) const;
    Eigen::ArrayXXd getCoordBasisFunctionMultiple(const Eigen::ArrayXXd &p_fToRegress) const;
    ///@}

    /// \brief conditional expectation calculation
    /// \param  p_fToRegress  simulations  to regress used in optimization
    /// \return regressed value function
    /// @{
    Eigen::ArrayXd getAllSimulations(const Eigen::ArrayXd &p_fToRegress) const ;
    Eigen::ArrayXXd getAllSimulationsMultiple(const Eigen::ArrayXXd &p_fToRegress) const;
    ///@}

    /// \brief Use basis functions to reconstruct the solution
    /// \param p_basisCoefficients basis coefficients
    ///@{
    Eigen::ArrayXd reconstruction(const Eigen::ArrayXd   &p_basisCoefficients) const ;
    Eigen::ArrayXXd reconstructionMultiple(const Eigen::ArrayXXd   &p_basisCoefficients) const ;
    /// @}

    /// \brief use basis function to reconstruct a given simulation
    /// \param p_isim               simulation number
    /// \param p_basisCoefficients  basis coefficients to reconstruct a given conditional expectation
    double reconstructionASim(const int &p_isim, const Eigen::ArrayXd   &p_basisCoefficients) const ;

    /// \brief conditional expectation reconstruction
    /// \param  p_coordinates        coordinates to interpolate (uncertainty sample)
    /// \param  p_coordBasisFunction regression coordinates on the basis  (size: number of meshes multiplied by the dimension plus one)
    /// \return regressed value function reconstructed for each simulation
    double getValue(const Eigen::ArrayXd   &p_coordinates,
                    const Eigen::ArrayXd   &p_coordBasisFunction) const ;

    /// \brief permits to reconstruct a function with basis functions coefficients values given on a grid
    /// \param  p_coordinates            coordinates  (uncertainty sample)
    /// \param  p_ptOfStock              grid point
    /// \param   p_interpFuncBasis       spectral interpolator to interpolate the basis functions  coefficients used in regression on the grid (given for each basis function)
    double getAValue(const Eigen::ArrayXd &p_coordinates,  const Eigen::ArrayXd &p_ptOfStock,
                     const std::vector< std::shared_ptr<InterpolatorSpectral> > &p_interpFuncBasis) const;


    /// \brief Accessor
    ///@{
    std::shared_ptr<SparseSpaceGridNoBound> getSpGrid() const
    {
        return m_spGrid ;   ///< grid
    }
    const std::vector< std::vector< double> > &getMesh() const
    {
        return m_mesh;    ///< mesh to rescale particles;
    }
    ///@}

    /// \brief get the number of basis functions
    inline int getNumberOfFunction() const
    {
        return m_spGrid->getNbPoints();
    }
    /// \brief Clone the regressor
    std::shared_ptr<BaseRegression> clone() const
    {
        return std::static_pointer_cast<BaseRegression>(std::make_shared<SparseRegression>(*this));
    }

};
/**@}*/
}
#endif /* SPARSEREGRESSION */