2019-06-19 14:34:30 +02:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2005 Ondra Kamenik
|
|
|
|
|
* Copyright © 2019 Dynare Team
|
|
|
|
|
*
|
|
|
|
|
* This file is part of Dynare.
|
|
|
|
|
*
|
|
|
|
|
* Dynare is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* Dynare is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-06-09 17:33:48 +02:00
|
|
|
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
2019-06-19 14:34:30 +02:00
|
|
|
|
*/
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
// Quadrature.
|
|
|
|
|
|
|
|
|
|
/* This file defines an interface for one dimensional (non-nested) quadrature
|
2019-06-19 17:33:01 +02:00
|
|
|
|
OneDQuadrature, and a parent for all multi-dimensional quadratures. This
|
|
|
|
|
parent class Quadrature presents a general concept of quadrature, this is
|
|
|
|
|
|
|
|
|
|
N
|
|
|
|
|
∫ f(x)dx ≃ ∑ wᵢxᵢ
|
|
|
|
|
ⁱ⁼¹
|
|
|
|
|
|
|
|
|
|
The class Quadrature just declares this concept. The concept is implemented
|
|
|
|
|
by class QuadratureImpl which paralelizes the summation. All implementations
|
|
|
|
|
therefore wishing to use the parallel implementation should inherit from
|
|
|
|
|
QuadratureImpl and integration is done.
|
|
|
|
|
|
|
|
|
|
The integration concept relies on a point iterator, which goes through all
|
|
|
|
|
xᵢ and wᵢ for i=1,…,N. All the iterators must be able to go through only a
|
|
|
|
|
portion of the set i=1,…,N. This enables us to implement paralelism, for two
|
|
|
|
|
threads for example, one iterator goes from the beginning to the
|
|
|
|
|
(approximately) half, and the other goes from the half to the end.
|
|
|
|
|
|
|
|
|
|
Besides this concept of the general quadrature, this file defines also one
|
|
|
|
|
dimensional quadrature, which is basically a scheme of points and weights
|
|
|
|
|
for different levels. The class OneDQuadrature is a parent of all such
|
|
|
|
|
objects, the classes GaussHermite and GaussLegendre are specific
|
|
|
|
|
implementations for Gauss-Hermite and Gauss-Legendre quadratures resp. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
#ifndef QUADRATURE_H
|
|
|
|
|
#define QUADRATURE_H
|
|
|
|
|
|
2019-01-14 16:09:49 +01:00
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
|
2019-01-04 17:27:23 +01:00
|
|
|
|
#include "vector_function.hh"
|
2019-01-08 16:09:25 +01:00
|
|
|
|
#include "int_sequence.hh"
|
|
|
|
|
#include "sthread.hh"
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This pure virtual class represents a concept of one-dimensional (non-nested)
|
|
|
|
|
quadrature. So, one dimensional quadrature must return number of levels,
|
|
|
|
|
number of points in a given level, and then a point and a weight in a given
|
|
|
|
|
level and given order. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
class OneDQuadrature
|
|
|
|
|
{
|
|
|
|
|
public:
|
2019-01-14 16:09:49 +01:00
|
|
|
|
virtual ~OneDQuadrature() = default;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
virtual int numLevels() const = 0;
|
|
|
|
|
virtual int numPoints(int level) const = 0;
|
|
|
|
|
virtual double point(int level, int i) const = 0;
|
|
|
|
|
virtual double weight(int lelel, int i) const = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This is a general concept of multidimensional quadrature. at this general
|
|
|
|
|
level, we maintain only a dimension, and declare virtual functions for
|
|
|
|
|
integration. The function take two forms; first takes a constant
|
|
|
|
|
VectorFunction as an argument, creates locally VectorFunctionSet and do
|
|
|
|
|
calculation, second one takes as an argument VectorFunctionSet.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
Part of the interface is a method returning a number of evaluations for a
|
|
|
|
|
specific level. Note two things: this assumes that the number of evaluations
|
|
|
|
|
is known apriori and thus it is not applicable for adaptive quadratures,
|
|
|
|
|
second for Monte Carlo type of quadrature, the level is a number of
|
|
|
|
|
evaluations. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
class Quadrature
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
int dim;
|
|
|
|
|
public:
|
|
|
|
|
Quadrature(int d) : dim(d)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
virtual ~Quadrature() = default;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
int
|
|
|
|
|
dimen() const
|
|
|
|
|
{
|
|
|
|
|
return dim;
|
|
|
|
|
}
|
|
|
|
|
virtual void integrate(const VectorFunction &func, int level,
|
|
|
|
|
int tn, Vector &out) const = 0;
|
|
|
|
|
virtual void integrate(VectorFunctionSet &fs, int level, Vector &out) const = 0;
|
|
|
|
|
virtual int numEvals(int level) const = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This is just an integration worker, which works over a given QuadratureImpl.
|
|
|
|
|
It also needs the function, level, a specification of the subgroup of
|
|
|
|
|
points, and output vector.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
See QuadratureImpl class declaration for details. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-12-20 14:36:20 +01:00
|
|
|
|
template<typename _Tpit>
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class QuadratureImpl;
|
|
|
|
|
|
2019-12-20 14:36:20 +01:00
|
|
|
|
template<typename _Tpit>
|
2019-01-28 18:39:42 +01:00
|
|
|
|
class IntegrationWorker : public sthread::detach_thread
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
const QuadratureImpl<_Tpit> &quad;
|
|
|
|
|
VectorFunction &func;
|
|
|
|
|
int level;
|
|
|
|
|
int ti;
|
|
|
|
|
int tn;
|
|
|
|
|
Vector &outvec;
|
|
|
|
|
public:
|
|
|
|
|
IntegrationWorker(const QuadratureImpl<_Tpit> &q, VectorFunction &f, int l,
|
|
|
|
|
int tii, int tnn, Vector &out)
|
|
|
|
|
: quad(q), func(f), level(l), ti(tii), tn(tnn), outvec(out)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This integrates the given portion of the integral. We obtain first and
|
|
|
|
|
last iterators for the portion (‘beg’ and ‘end’). Then we iterate through
|
|
|
|
|
the portion. and finally we add the intermediate result to the result
|
|
|
|
|
‘outvec’.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
This method just everything up as it is coming. This might be imply large
|
|
|
|
|
numerical errors, perhaps in future something smarter should be implemented. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
void
|
2019-01-29 15:52:56 +01:00
|
|
|
|
operator()(std::mutex &mut) override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
_Tpit beg = quad.begin(ti, tn, level);
|
|
|
|
|
_Tpit end = quad.begin(ti+1, tn, level);
|
|
|
|
|
Vector tmpall(outvec.length());
|
|
|
|
|
tmpall.zeros();
|
|
|
|
|
Vector tmp(outvec.length());
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* Note that since ‘beg’ came from begin(), it has empty signal and first
|
|
|
|
|
evaluation gets no signal */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
for (_Tpit run = beg; run != end; ++run)
|
|
|
|
|
{
|
|
|
|
|
func.eval(run.point(), run.signal(), tmp);
|
|
|
|
|
tmpall.add(run.weight(), tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2019-01-29 15:52:56 +01:00
|
|
|
|
std::unique_lock<std::mutex> lk{mut};
|
2019-01-04 17:27:23 +01:00
|
|
|
|
outvec.add(1.0, tmpall);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This is the class which implements the integration. The class is templated
|
|
|
|
|
by the iterator type. We declare a method begin() returning an iterator to
|
|
|
|
|
the beginnning of the ‘ti’-th portion out of total ‘tn’ portions for a given
|
|
|
|
|
level.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
In addition, we define a method which saves all the points to a given file.
|
|
|
|
|
Only for debugging purposes. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-12-20 14:36:20 +01:00
|
|
|
|
template<typename _Tpit>
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class QuadratureImpl : public Quadrature
|
|
|
|
|
{
|
|
|
|
|
friend class IntegrationWorker<_Tpit>;
|
|
|
|
|
public:
|
|
|
|
|
QuadratureImpl(int d) : Quadrature(d)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just fill a thread group with workes and run it. */
|
|
|
|
|
void
|
2019-01-09 16:26:42 +01:00
|
|
|
|
integrate(VectorFunctionSet &fs, int level, Vector &out) const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// TODO: out.length()==func.outdim()
|
|
|
|
|
// TODO: dim == func.indim()
|
2019-01-04 17:27:23 +01:00
|
|
|
|
out.zeros();
|
2019-01-28 18:39:42 +01:00
|
|
|
|
sthread::detach_thread_group gr;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
for (int ti = 0; ti < fs.getNum(); ti++)
|
2019-01-14 12:19:00 +01:00
|
|
|
|
gr.insert(std::make_unique<IntegrationWorker<_Tpit>>(*this, fs.getFunc(ti),
|
|
|
|
|
level, ti, fs.getNum(), out));
|
2019-01-04 17:27:23 +01:00
|
|
|
|
gr.run();
|
|
|
|
|
}
|
|
|
|
|
void
|
|
|
|
|
integrate(const VectorFunction &func,
|
2019-01-09 16:26:42 +01:00
|
|
|
|
int level, int tn, Vector &out) const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
VectorFunctionSet fs(func, tn);
|
|
|
|
|
integrate(fs, level, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Just for debugging. */
|
|
|
|
|
void
|
2019-02-06 15:50:01 +01:00
|
|
|
|
savePoints(const std::string &fname, int level) const
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::ofstream fd{fname, std::ios::out | std::ios::trunc};
|
2019-01-14 16:09:49 +01:00
|
|
|
|
if (fd.fail())
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// TODO: raise
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cerr << "Cannot open file " << fname << " for writing." << std::endl;
|
|
|
|
|
exit(EXIT_FAILURE);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
_Tpit beg = begin(0, 1, level);
|
|
|
|
|
_Tpit end = begin(1, 1, level);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
fd << std::setprecision(12);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
for (_Tpit run = beg; run != end; ++run)
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
fd << std::setw(16) << run.weight();
|
2019-01-04 17:27:23 +01:00
|
|
|
|
for (int i = 0; i < dimen(); i++)
|
2019-01-14 16:09:49 +01:00
|
|
|
|
fd << '\t' << std::setw(16) << run.point()[i];
|
|
|
|
|
fd << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
fd.close();
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_Tpit
|
|
|
|
|
start(int level) const
|
|
|
|
|
{
|
|
|
|
|
return begin(0, 1, level);
|
|
|
|
|
}
|
|
|
|
|
_Tpit
|
|
|
|
|
end(int level) const
|
|
|
|
|
{
|
|
|
|
|
return begin(1, 1, level);
|
|
|
|
|
}
|
|
|
|
|
protected:
|
|
|
|
|
virtual _Tpit begin(int ti, int tn, int level) const = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* This is only an interface to a precalculated data in file
|
|
|
|
|
precalc_quadrature.hh which is basically C coded static data. It implements
|
|
|
|
|
OneDQuadrature. The data file is supposed to define the following data:
|
|
|
|
|
number of levels, array of number of points at each level, an array of
|
|
|
|
|
weights and array of points. The both latter array store data level by
|
|
|
|
|
level. An offset for a specific level is stored in ‘offsets’ integer
|
|
|
|
|
sequence.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
The implementing subclasses just fill the necessary data from the file, the
|
|
|
|
|
rest is calculated here. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
class OneDPrecalcQuadrature : public OneDQuadrature
|
|
|
|
|
{
|
|
|
|
|
int num_levels;
|
|
|
|
|
const int *num_points;
|
|
|
|
|
const double *weights;
|
|
|
|
|
const double *points;
|
|
|
|
|
IntSequence offsets;
|
|
|
|
|
public:
|
|
|
|
|
OneDPrecalcQuadrature(int nlevels, const int *npoints,
|
|
|
|
|
const double *wts, const double *pts)
|
2019-12-20 14:36:20 +01:00
|
|
|
|
: num_levels(nlevels), num_points(npoints),
|
2019-01-04 17:27:23 +01:00
|
|
|
|
weights(wts), points(pts), offsets(num_levels)
|
|
|
|
|
{
|
|
|
|
|
calcOffsets();
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
~OneDPrecalcQuadrature() override = default;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
int
|
2019-01-09 16:26:42 +01:00
|
|
|
|
numLevels() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
return num_levels;
|
|
|
|
|
}
|
|
|
|
|
int
|
2019-01-09 16:26:42 +01:00
|
|
|
|
numPoints(int level) const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
return num_points[level-1];
|
|
|
|
|
}
|
|
|
|
|
double
|
2019-01-09 16:26:42 +01:00
|
|
|
|
point(int level, int i) const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
return points[offsets[level-1]+i];
|
|
|
|
|
}
|
|
|
|
|
double
|
2019-01-09 16:26:42 +01:00
|
|
|
|
weight(int level, int i) const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
return weights[offsets[level-1]+i];
|
|
|
|
|
}
|
|
|
|
|
protected:
|
|
|
|
|
void calcOffsets();
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* Just precalculated Gauss-Hermite quadrature. This quadrature integrates
|
|
|
|
|
exactly integrals
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
+∞
|
|
|
|
|
∫ xᵏe^{−x²}dx
|
|
|
|
|
−∞
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
for level k.
|
|
|
|
|
|
|
|
|
|
Note that if pluging this one-dimensional quadrature to product or Smolyak
|
|
|
|
|
rule in order to integrate a function f through normally distributed inputs,
|
|
|
|
|
one has to wrap f to GaussConverterFunction and apply the product or Smolyak
|
|
|
|
|
rule to the new function.
|
|
|
|
|
|
|
|
|
|
Check precalc_quadrature.hh for available levels. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
class GaussHermite : public OneDPrecalcQuadrature
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
GaussHermite();
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* Just precalculated Gauss-Legendre quadrature. This quadrature integrates
|
|
|
|
|
exactly integrals
|
|
|
|
|
|
|
|
|
|
₁
|
|
|
|
|
∫ xᵏdx
|
|
|
|
|
⁰
|
|
|
|
|
|
|
|
|
|
for level k.
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
Check precalc_quadrature.hh for available levels. */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
|
|
|
|
class GaussLegendre : public OneDPrecalcQuadrature
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
GaussLegendre();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|