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
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
|
#include "GeneralMatrix.hh"
|
2019-01-04 17:27:23 +01:00
|
|
|
|
#include <dynlapack.h>
|
2019-01-08 17:12:05 +01:00
|
|
|
|
#include "SylvException.hh"
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
|
#include "rfs_tensor.hh"
|
|
|
|
|
#include "normal_moments.hh"
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
|
#include "vector_function.hh"
|
|
|
|
|
#include "quadrature.hh"
|
|
|
|
|
#include "smolyak.hh"
|
|
|
|
|
#include "product.hh"
|
|
|
|
|
#include "quasi_mcarlo.hh"
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-01-14 16:09:49 +01:00
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <chrono>
|
2019-01-04 17:27:23 +01:00
|
|
|
|
#include <cmath>
|
2019-01-14 16:09:49 +01:00
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <cstdlib>
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* Evaluates unfolded (Dx)ᵏ power, where x is a vector, D is a Cholesky factor
|
|
|
|
|
(lower triangular) */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class MomentFunction : public VectorFunction
|
|
|
|
|
{
|
|
|
|
|
GeneralMatrix D;
|
|
|
|
|
int k;
|
|
|
|
|
public:
|
|
|
|
|
MomentFunction(const GeneralMatrix &inD, int kk)
|
2019-04-16 12:40:50 +02:00
|
|
|
|
: VectorFunction(inD.nrows(), UFSTensor::calcMaxOffset(inD.nrows(), kk)),
|
2019-01-04 17:27:23 +01:00
|
|
|
|
D(inD), k(kk)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
MomentFunction(const MomentFunction &func) = default;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<VectorFunction>
|
2019-01-09 16:26:42 +01:00
|
|
|
|
clone() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
return std::make_unique<MomentFunction>(*this);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-01-09 16:26:42 +01:00
|
|
|
|
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MomentFunction::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
|
|
|
|
|
{
|
|
|
|
|
if (point.length() != indim() || out.length() != outdim())
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cerr << "Wrong length of vectors in MomentFunction::eval" << std::endl;
|
|
|
|
|
std::exit(EXIT_FAILURE);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
Vector y(point);
|
|
|
|
|
y.zeros();
|
|
|
|
|
D.multaVec(y, point);
|
|
|
|
|
URSingleTensor ypow(y, k);
|
|
|
|
|
out.zeros();
|
|
|
|
|
out.add(1.0, ypow.getData());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TensorPower : public VectorFunction
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
public:
|
|
|
|
|
TensorPower(int nvar, int kk)
|
|
|
|
|
: VectorFunction(nvar, UFSTensor::calcMaxOffset(nvar, kk)), k(kk)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
TensorPower(const TensorPower &func) = default;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<VectorFunction>
|
2019-01-09 16:26:42 +01:00
|
|
|
|
clone() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
return std::make_unique<TensorPower>(*this);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-01-09 16:26:42 +01:00
|
|
|
|
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TensorPower::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
|
|
|
|
|
{
|
|
|
|
|
if (point.length() != indim() || out.length() != outdim())
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cerr << "Wrong length of vectors in TensorPower::eval" << std::endl;
|
|
|
|
|
std::exit(EXIT_FAILURE);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
URSingleTensor ypow(point, k);
|
|
|
|
|
out.zeros();
|
|
|
|
|
out.add(1.0, ypow.getData());
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* Evaluates (1+1/d)ᵈ(x₁·…·x_d)^(1/d), its integral over [0,1]ᵈ
|
|
|
|
|
is 1.0, and its variation grows exponentially */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class Function1 : public VectorFunction
|
|
|
|
|
{
|
|
|
|
|
int dim;
|
|
|
|
|
public:
|
|
|
|
|
Function1(int d)
|
|
|
|
|
: VectorFunction(d, 1), dim(d)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
Function1(const Function1 &f)
|
|
|
|
|
: VectorFunction(f.indim(), f.outdim()), dim(f.dim)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::unique_ptr<VectorFunction>
|
2019-01-09 16:26:42 +01:00
|
|
|
|
clone() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
return std::make_unique<Function1>(*this);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-01-09 16:26:42 +01:00
|
|
|
|
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Function1::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
|
|
|
|
|
{
|
|
|
|
|
if (point.length() != dim || out.length() != 1)
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cerr << "Wrong length of vectors in Function1::eval" << std::endl;
|
|
|
|
|
std::exit(EXIT_FAILURE);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
double r = 1;
|
|
|
|
|
for (int i = 0; i < dim; i++)
|
|
|
|
|
r *= point[i];
|
|
|
|
|
r = pow(r, 1.0/dim);
|
2019-03-08 15:32:13 +01:00
|
|
|
|
r *= pow(1.0 + 1.0/dim, static_cast<double>(dim));
|
2019-01-04 17:27:23 +01:00
|
|
|
|
out[0] = r;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Evaluates Function1 but with transformation xᵢ=0.5(yᵢ+1)
|
|
|
|
|
// This makes the new function integrate over [−1,1]ᵈ to 1.0
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class Function1Trans : public Function1
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Function1Trans(int d)
|
|
|
|
|
: Function1(d)
|
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
Function1Trans(const Function1Trans &func) = default;
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<VectorFunction>
|
2019-01-09 16:26:42 +01:00
|
|
|
|
clone() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
return std::make_unique<Function1Trans>(*this);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-01-09 16:26:42 +01:00
|
|
|
|
void eval(const Vector &point, const ParameterSignal &sig, Vector &out) override;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Function1Trans::eval(const Vector &point, const ParameterSignal &sig, Vector &out)
|
|
|
|
|
{
|
|
|
|
|
Vector p(point.length());
|
|
|
|
|
for (int i = 0; i < p.length(); i++)
|
|
|
|
|
p[i] = 0.5*(point[i]+1);
|
|
|
|
|
Function1::eval(p, sig, out);
|
|
|
|
|
out.mult(pow(0.5, indim()));
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
/* WallTimer class. Constructor saves the wall time, destructor cancels the
|
2019-12-20 14:36:20 +01:00
|
|
|
|
current time from the saved, and prints the message with time information */
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class WallTimer
|
|
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::string mes;
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::chrono::time_point<std::chrono::high_resolution_clock> start;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
bool new_line;
|
|
|
|
|
public:
|
2019-02-06 15:50:01 +01:00
|
|
|
|
WallTimer(std::string m, bool nl = true)
|
2019-01-14 16:09:49 +01:00
|
|
|
|
: mes{m}, start{std::chrono::high_resolution_clock::now()}, new_line{nl}
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
~WallTimer()
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
auto end = std::chrono::high_resolution_clock::now();
|
|
|
|
|
std::chrono::duration<double> duration = end - start;
|
|
|
|
|
std::cout << mes << std::setw(8) << std::setprecision(4) << duration.count();
|
2019-01-04 17:27:23 +01:00
|
|
|
|
if (new_line)
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/****************************************************/
|
|
|
|
|
/* declaration of TestRunnable class */
|
|
|
|
|
/****************************************************/
|
|
|
|
|
class TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
2019-02-06 15:50:01 +01:00
|
|
|
|
const std::string name;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
int dim; // dimension of the solved problem
|
2019-06-19 17:33:01 +02:00
|
|
|
|
int nvar; // number of variables of the solved problem
|
2019-02-06 15:50:01 +01:00
|
|
|
|
TestRunnable(std::string name_arg, int d, int nv)
|
2019-01-14 16:09:49 +01:00
|
|
|
|
: name{move(name_arg)}, dim(d), nvar(nv)
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
2019-01-14 16:09:49 +01:00
|
|
|
|
virtual ~TestRunnable() = default;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
bool test() const;
|
|
|
|
|
virtual bool run() const = 0;
|
|
|
|
|
protected:
|
|
|
|
|
static bool smolyak_normal_moments(const GeneralMatrix &m, int imom, int level);
|
|
|
|
|
static bool product_normal_moments(const GeneralMatrix &m, int imom, int level);
|
|
|
|
|
static bool qmc_normal_moments(const GeneralMatrix &m, int imom, int level);
|
|
|
|
|
static bool smolyak_product_cube(const VectorFunction &func, const Vector &res,
|
|
|
|
|
double tol, int level);
|
|
|
|
|
static bool qmc_cube(const VectorFunction &func, double res, double tol, int level);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TestRunnable::test() const
|
|
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::cout << "Running test <" << name << ">" << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
bool passed;
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("Wall clock time ", false);
|
|
|
|
|
passed = run();
|
|
|
|
|
}
|
|
|
|
|
if (passed)
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "............................ passed" << std::endl << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return passed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "............................ FAILED" << std::endl << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return passed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************/
|
|
|
|
|
/* definition of TestRunnable static methods */
|
|
|
|
|
/****************************************************/
|
|
|
|
|
bool
|
|
|
|
|
TestRunnable::smolyak_normal_moments(const GeneralMatrix &m, int imom, int level)
|
|
|
|
|
{
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// First make m·mᵀ and then Cholesky factor
|
2019-02-26 16:54:34 +01:00
|
|
|
|
GeneralMatrix msq(m * transpose(m));
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Make vector function
|
2019-04-16 12:40:50 +02:00
|
|
|
|
int dim = m.nrows();
|
2019-01-04 17:27:23 +01:00
|
|
|
|
TensorPower tp(dim, imom);
|
|
|
|
|
GaussConverterFunction func(tp, msq);
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Smolyak quadrature
|
2019-01-04 17:27:23 +01:00
|
|
|
|
Vector smol_out(UFSTensor::calcMaxOffset(dim, imom));
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tSmolyak quadrature time: ");
|
|
|
|
|
GaussHermite gs;
|
|
|
|
|
SmolyakQuadrature quad(dim, level, gs);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, smol_out);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tNumber of Smolyak evaluations: " << quad.numEvals(level) << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Check against theoretical moments
|
2019-01-04 17:27:23 +01:00
|
|
|
|
UNormalMoments moments(imom, msq);
|
2019-02-20 17:51:05 +01:00
|
|
|
|
smol_out.add(-1.0, moments.get(Symmetry{imom}).getData());
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << smol_out.getMax() << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return smol_out.getMax() < 1.e-7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TestRunnable::product_normal_moments(const GeneralMatrix &m, int imom, int level)
|
|
|
|
|
{
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// First make m·mᵀ and then Cholesky factor
|
2019-02-26 16:54:34 +01:00
|
|
|
|
GeneralMatrix msq(m * transpose(m));
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Make vector function
|
2019-04-16 12:40:50 +02:00
|
|
|
|
int dim = m.nrows();
|
2019-01-04 17:27:23 +01:00
|
|
|
|
TensorPower tp(dim, imom);
|
|
|
|
|
GaussConverterFunction func(tp, msq);
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Product quadrature
|
2019-01-04 17:27:23 +01:00
|
|
|
|
Vector prod_out(UFSTensor::calcMaxOffset(dim, imom));
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tProduct quadrature time: ");
|
|
|
|
|
GaussHermite gs;
|
|
|
|
|
ProductQuadrature quad(dim, gs);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, prod_out);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tNumber of product evaluations: " << quad.numEvals(level) << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Check against theoretical moments
|
2019-01-04 17:27:23 +01:00
|
|
|
|
UNormalMoments moments(imom, msq);
|
2019-02-20 17:51:05 +01:00
|
|
|
|
prod_out.add(-1.0, moments.get(Symmetry{imom}).getData());
|
2019-02-06 15:50:01 +01:00
|
|
|
|
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << prod_out.getMax() << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return prod_out.getMax() < 1.e-7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TestRunnable::smolyak_product_cube(const VectorFunction &func, const Vector &res,
|
|
|
|
|
double tol, int level)
|
|
|
|
|
{
|
|
|
|
|
if (res.length() != func.outdim())
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cerr << "Incompatible dimensions of check value and function." << std::endl;
|
|
|
|
|
std::exit(EXIT_FAILURE);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GaussLegendre glq;
|
|
|
|
|
Vector out(func.outdim());
|
|
|
|
|
double smol_error;
|
|
|
|
|
double prod_error;
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tSmolyak quadrature time: ");
|
|
|
|
|
SmolyakQuadrature quad(func.indim(), level, glq);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, out);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
out.add(-1.0, res);
|
|
|
|
|
smol_error = out.getMax();
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tNumber of Smolyak evaluations: " << quad.numEvals(level) << std::endl;
|
|
|
|
|
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << smol_error << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tProduct quadrature time: ");
|
|
|
|
|
ProductQuadrature quad(func.indim(), glq);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
quad.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, out);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
out.add(-1.0, res);
|
|
|
|
|
prod_error = out.getMax();
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tNumber of product evaluations: " << quad.numEvals(level) << std::endl;
|
|
|
|
|
std::cout << "\tError: " << std::setw(16) << std::setprecision(12) << prod_error << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return smol_error < tol && prod_error < tol;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TestRunnable::qmc_cube(const VectorFunction &func, double res, double tol, int level)
|
|
|
|
|
{
|
|
|
|
|
Vector r(1);
|
|
|
|
|
double error1;
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tQuasi-Monte Carlo (Warnock scrambling) time: ");
|
|
|
|
|
WarnockPerScheme wps;
|
|
|
|
|
QMCarloCubeQuadrature qmc(func.indim(), level, wps);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
error1 = std::max(res - r[0], r[0] - res);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tQuasi-Monte Carlo (Warnock scrambling) error: " << std::setw(16) << std::setprecision(12) << error1 << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
double error2;
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tQuasi-Monte Carlo (reverse scrambling) time: ");
|
|
|
|
|
ReversePerScheme rps;
|
|
|
|
|
QMCarloCubeQuadrature qmc(func.indim(), level, rps);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
error2 = std::max(res - r[0], r[0] - res);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tQuasi-Monte Carlo (reverse scrambling) error: " << std::setw(16) << std::setprecision(12) << error2 << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
double error3;
|
|
|
|
|
{
|
|
|
|
|
WallTimer tim("\tQuasi-Monte Carlo (no scrambling) time: ");
|
|
|
|
|
IdentityPerScheme ips;
|
|
|
|
|
QMCarloCubeQuadrature qmc(func.indim(), level, ips);
|
2019-01-29 16:34:25 +01:00
|
|
|
|
qmc.integrate(func, level, sthread::detach_thread_group::max_parallel_threads, r);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
error3 = std::max(res - r[0], r[0] - res);
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "\tQuasi-Monte Carlo (no scrambling) error: " << std::setw(16) << std::setprecision(12) << error3 << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error1 < tol && error2 < tol && error3 < tol;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************/
|
|
|
|
|
/* definition of TestRunnable subclasses */
|
|
|
|
|
/****************************************************/
|
|
|
|
|
class SmolyakNormalMom1 : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SmolyakNormalMom1()
|
|
|
|
|
: TestRunnable("Smolyak normal moments (dim=2, level=4, order=4)", 4, 2)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
GeneralMatrix m(2, 2);
|
2019-03-08 15:32:13 +01:00
|
|
|
|
m.zeros();
|
|
|
|
|
m.get(0, 0) = 1;
|
|
|
|
|
m.get(1, 1) = 1;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return smolyak_normal_moments(m, 4, 4);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class SmolyakNormalMom2 : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SmolyakNormalMom2()
|
|
|
|
|
: TestRunnable("Smolyak normal moments (dim=3, level=8, order=8)", 8, 3)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
GeneralMatrix m(3, 3);
|
|
|
|
|
m.zeros();
|
2019-03-08 15:32:13 +01:00
|
|
|
|
m.get(0, 0) = 1;
|
|
|
|
|
m.get(0, 2) = 0.5;
|
|
|
|
|
m.get(1, 1) = 1;
|
|
|
|
|
m.get(1, 0) = 0.5;
|
|
|
|
|
m.get(2, 2) = 2;
|
|
|
|
|
m.get(2, 1) = 4;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return smolyak_normal_moments(m, 8, 8);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ProductNormalMom1 : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ProductNormalMom1()
|
|
|
|
|
: TestRunnable("Product normal moments (dim=2, level=4, order=4)", 4, 2)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
GeneralMatrix m(2, 2);
|
2019-03-08 15:32:13 +01:00
|
|
|
|
m.zeros();
|
|
|
|
|
m.get(0, 0) = 1;
|
|
|
|
|
m.get(1, 1) = 1;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return product_normal_moments(m, 4, 4);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ProductNormalMom2 : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ProductNormalMom2()
|
|
|
|
|
: TestRunnable("Product normal moments (dim=3, level=8, order=8)", 8, 3)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
GeneralMatrix m(3, 3);
|
|
|
|
|
m.zeros();
|
2019-03-08 15:32:13 +01:00
|
|
|
|
m.get(0, 0) = 1;
|
|
|
|
|
m.get(0, 2) = 0.5;
|
|
|
|
|
m.get(1, 1) = 1;
|
|
|
|
|
m.get(1, 0) = 0.5;
|
|
|
|
|
m.get(2, 2) = 2;
|
|
|
|
|
m.get(2, 1) = 4;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return product_normal_moments(m, 8, 8);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Note that here we pass 1,1 to tls since smolyak has its own PascalTriangle
|
2019-01-04 17:27:23 +01:00
|
|
|
|
class F1GaussLegendre : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
F1GaussLegendre()
|
|
|
|
|
: TestRunnable("Function1 Gauss-Legendre (dim=6, level=13", 1, 1)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
Function1Trans f1(6);
|
2019-03-08 15:32:13 +01:00
|
|
|
|
Vector res(1);
|
|
|
|
|
res[0] = 1.0;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
return smolyak_product_cube(f1, res, 1e-2, 13);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class F1QuasiMCarlo : public TestRunnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
F1QuasiMCarlo()
|
|
|
|
|
: TestRunnable("Function1 Quasi-Monte Carlo (dim=6, level=1000000)", 1, 1)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2019-01-09 16:26:42 +01:00
|
|
|
|
run() const override
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
Function1 f1(6);
|
|
|
|
|
return qmc_cube(f1, 1.0, 1.e-4, 1000000);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main()
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::vector<std::unique_ptr<TestRunnable>> all_tests;
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Fill in vector of all tests
|
2019-01-14 16:09:49 +01:00
|
|
|
|
all_tests.push_back(std::make_unique<SmolyakNormalMom1>());
|
|
|
|
|
all_tests.push_back(std::make_unique<SmolyakNormalMom2>());
|
|
|
|
|
all_tests.push_back(std::make_unique<ProductNormalMom1>());
|
|
|
|
|
all_tests.push_back(std::make_unique<ProductNormalMom2>());
|
2019-01-15 15:43:51 +01:00
|
|
|
|
all_tests.push_back(std::make_unique<F1GaussLegendre>());
|
|
|
|
|
all_tests.push_back(std::make_unique<F1QuasiMCarlo>());
|
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Find maximum dimension and maximum nvar
|
2019-01-04 17:27:23 +01:00
|
|
|
|
int dmax = 0;
|
|
|
|
|
int nvmax = 0;
|
2019-01-14 16:09:49 +01:00
|
|
|
|
for (const auto &test : all_tests)
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
2019-03-08 15:32:13 +01:00
|
|
|
|
dmax = std::max(dmax, test->dim);
|
|
|
|
|
nvmax = std::max(nvmax, test->nvar);
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|
2019-02-21 18:46:53 +01:00
|
|
|
|
TLStatic::init(dmax, nvmax); // initialize library
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-06-19 17:33:01 +02:00
|
|
|
|
// Launch the tests
|
2019-01-04 17:27:23 +01:00
|
|
|
|
int success = 0;
|
2019-01-14 16:09:49 +01:00
|
|
|
|
for (const auto &test : all_tests)
|
2019-01-04 17:27:23 +01:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
if (test->test())
|
2019-01-04 17:27:23 +01:00
|
|
|
|
success++;
|
|
|
|
|
}
|
|
|
|
|
catch (const TLException &e)
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "Caught TL exception in <" << test->name << ">:" << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
e.print();
|
|
|
|
|
}
|
|
|
|
|
catch (SylvException &e)
|
|
|
|
|
{
|
2019-01-14 16:09:49 +01:00
|
|
|
|
std::cout << "Caught Sylv exception in <" << test->name << ">:" << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
e.printMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-15 15:43:51 +01:00
|
|
|
|
int nfailed = all_tests.size() - success;
|
|
|
|
|
std::cout << "There were " << nfailed << " tests that failed out of "
|
2019-01-14 16:09:49 +01:00
|
|
|
|
<< all_tests.size() << " tests run." << std::endl;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
|
2019-01-15 15:43:51 +01:00
|
|
|
|
if (nfailed)
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
else
|
|
|
|
|
return EXIT_SUCCESS;
|
2019-01-04 17:27:23 +01:00
|
|
|
|
}
|