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 233 234 235 236 237 238 239 240 241
|
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
#include <config.h>
#include <iostream>
#include <memory>
#include <functional>
#include <dune/common/exceptions.hh>
#include <dune/common/parallel/mpihelper.hh>
#include <dune/functions/common/differentiablefunction.hh>
#include <dune/functions/common/differentiablefunctionfromcallables.hh>
#include <dune/functions/common/functionconcepts.hh>
#include <dune/functions/analyticfunctions/polynomial.hh>
#include <dune/functions/analyticfunctions/trigonometricfunction.hh>
//#include "derivativecheck.hh"
bool checkTrue(bool value, std::string error)
{
if (not(value))
std::cout << "TEST FAILURE:" << error << std::endl;
return value;
}
// Check if interface compiles and is implementable by a simple dummy
struct DifferentiableFunctionImplementableTest
{
template<class F>
static bool checkWithFunction(F&& f)
{
bool passed = true;
using Dune::Functions::Concept::isFunction;
using Dune::Functions::Concept::isDifferentiableFunction;
using Dune::Functions::SignatureTag;
{
std::cout << "--------------" << std::endl;
// passed = passed and DerivativeCheck<QuadraticPolynomial>::checkAllImplementedTrulyDerived(testFunction, 10);
// Test whether I can evaluate the function somewhere
std::cout << "Function value at x=5: " << f(5) << std::endl;
passed = checkTrue(isDifferentiableFunction(f, SignatureTag<double(double)>()), "Raw function f does not satisfy DifferentiableFunction concept");
std::cout << std::endl << "Check calling derivatives through function object" << std::endl;
// Test whether I can evaluate the first derivative
auto df = derivative(f);
passed = checkTrue(isDifferentiableFunction(df, SignatureTag<double(double)>()), "Raw function df does not satisfy DifferentiableFunction concept");
std::cout << "Derivative at x=5: " << df(5) << std::endl;
// Test whether I can evaluate the second derivative through FunctionHandle
auto ddf = derivative(df);
passed = checkTrue(isDifferentiableFunction(ddf, SignatureTag<double(double)>()), "Raw function ddf does not satisfy DifferentiableFunction concept");
std::cout << "Second derivative at x=5: " << ddf(5) << std::endl;
// Test whether I can evaluate the third derivative through FunctionHandle
auto dddf = derivative(ddf);
passed = checkTrue(isFunction(dddf, SignatureTag<double(double)>()), "Raw function dddf does not satisfy Function concept");
std::cout << "Third derivative at x=5: " << dddf(5) << std::endl;
std::cout << std::endl << "Check calling derivatives through DifferentiableFunction object" << std::endl;
Dune::Functions::DifferentiableFunction<double(const double&)> fi = f;
passed = checkTrue(isDifferentiableFunction(fi, SignatureTag<double(double)>()), "Wrapped function fi does not satisfy DifferentiableFunction concept");
// Try to reassign wrapper
fi = f;
// Try assigning a default constructed wrapper
Dune::Functions::DifferentiableFunction<double(const double&)> fii;
passed = checkTrue(isDifferentiableFunction(fii, SignatureTag<double(double)>()), "Wrapped function fii does not satisfy DifferentiableFunction concept");
fii = fi;
// Try to copy wrapper
auto fiii = fii;
passed = checkTrue(isDifferentiableFunction(fiii, SignatureTag<double(double)>()), "Wrapped function fiii does not satisfy DifferentiableFunction concept");
std::cout << "Function value at x=5: " << fiii(5) << std::endl;
// Test whether I can evaluate the first derivative
auto dfiii = derivative(fiii);
passed = checkTrue(isDifferentiableFunction(dfiii, SignatureTag<double(double)>()), "Wrapped function dfiii does not satisfy DifferentiableFunction concept");
std::cout << "Derivative at x=5: " << dfiii(5) << std::endl;
// Test whether I can evaluate the second derivative through FunctionHandle
auto ddfiii = derivative(dfiii);
passed = checkTrue(isDifferentiableFunction(ddfiii, SignatureTag<double(double)>()), "Wrapped function ddfiii does not satisfy DifferentiableFunction concept");
std::cout << "Second derivative at x=5: " << ddfiii(5) << std::endl;
// Test whether I can evaluate the third derivative through FunctionHandle
auto dddfiii = derivative(ddfiii);
passed = checkTrue(isFunction(dddfiii, SignatureTag<double(double)>()), "Wrapped function dddfiii does not satisfy Function concept");
std::cout << "Third derivative at x=5: " << dddfiii(5) << std::endl;
// Wrap as non-differentiable function
auto g = [=] (const double& x) {return f(x);};
passed = checkTrue(isFunction(g, SignatureTag<double(double)>()), "Lambda function g does not satisfy Function concept");
Dune::Functions::DifferentiableFunction<double(const double&)> gg = [=] (const double& x) {return f(x);};
passed = checkTrue(isFunction(gg, SignatureTag<double(double)>()), "Wrapped function gg does not satisfy DifferentiableFunction concept");
std::cout << "Function value at x=5: " << gg(5) << std::endl;
try {
auto dg = derivative(gg);
passed = false;
}
catch (Dune::NotImplemented& e)
{
std::cout << "Obtaining derivative from nondifferentiable function failed expectedly" << std::endl;
passed = checkTrue(not(isDifferentiableFunction(g, SignatureTag<double(double)>())), "But unwrapped function g does satisfy DifferentiableFunction concept");
}
}
return passed;
}
static bool check()
{
bool passed = true;
passed = passed and checkWithFunction(Dune::Functions::Polynomial<double>({1, 2, 3}));
passed = passed and checkWithFunction(Dune::Functions::TrigonometricFunction<double, 1, 0>());
auto f = [](double x){ return std::sin(x);};
auto df = [](double x){ return std::cos(x);};
auto ddf = [](double x){ return -std::sin(x);};
auto dddf = [](double x){ return -std::cos(x);};
auto F = makeDifferentiableFunctionFromCallables(Dune::Functions::SignatureTag<double(double)>(), f, df, ddf, dddf);
passed = passed and checkWithFunction(F);
return passed;
}
};
#if 0
// Check if recursive DerivativeRange definition terminates
// after at most maxRecursionLevel=k derivatives, i.e. if
// the type of the k-th and (k+1)-nd derivative is the same.
template<class D, class R, int maxRecursionLevel>
struct DerivativeRangeTerminationTest
{
template<class DR, int recursionLevel>
struct TerminationTest
{
static int level()
{
std::cout << "Type of " << recursionLevel << "-th derivative is " << Dune::className<DR>() << std::endl;
typedef typename Dune::Functions::DerivativeTraits<D, DR>::DerivativeRange DDR;
int upperBound = TerminationTest<DDR, recursionLevel+1>::level();
if (std::is_same_v<DR, DDR>)
return recursionLevel;
else
return upperBound;
}
};
template<class DR>
struct TerminationTest<DR, maxRecursionLevel>
{
static int level()
{
std::cout << "Type of " << maxRecursionLevel << "-th derivative is " << Dune::className<DR>() << std::endl;
typedef typename Dune::Functions::DerivativeTraits<D, DR>::DerivativeRange DDR;
if (std::is_same_v<DR, DDR>)
return maxRecursionLevel;
else
return maxRecursionLevel+1;
}
};
static bool check()
{
std::cout << "Checking recursion for Domain=" << Dune::className<D>() << " and Range=" << Dune::className<R>() << std::endl;
int terminationLevel = TerminationTest<R, 0>::level();
if (terminationLevel <= maxRecursionLevel)
{
std::cout << "Recursion terminated after " << terminationLevel << "-th derivative" << std::endl;
return true;
}
else
{
std::cout << "Recursion did not terminated after given maxRecursionLevel " << maxRecursionLevel;
return false;
}
}
};
#endif
int main ( int argc, char **argv )
try
{
Dune::MPIHelper::instance(argc, argv);
bool passed = true;
passed = passed and DifferentiableFunctionImplementableTest::check();
#if 0
passed = passed and DerivativeRangeTerminationTest<double, double, 5>::check();
passed = passed and DerivativeRangeTerminationTest<Dune::FieldVector<double, 3> , Dune::FieldVector<double, 1>, 5 >::check();
passed = passed and DerivativeRangeTerminationTest<Dune::FieldVector<double, 1> , Dune::FieldVector<double, 1>, 5 >::check();
#endif
if (passed)
std::cout << "All tests passed" << std::endl;
return passed ? 0: 1;
}
catch( Dune::Exception &e )
{
std::cerr << "Dune reported error: " << e << std::endl;
return 1;
}
catch(...)
{
std::cerr << "Unknown exception thrown!" << std::endl;
return 1;
}
|