#include <iostream>
#include <complex>
#include <functional>
class Kernel {
public:
/*
Covariance function : return the covariance between two R.V. for the entire kernel's domain definition.
*/
virtual double covarianceFunction(
double X,
double Y
)const = 0 ;
~Kernel() = default;
};
template <typename Func>
class FooKernel : public Kernel {
public:
FooKernel(Func&& fun) : fun_(std::forward<Func>(fun)) {}
double covarianceFunction(
double X,
double Y
) const {
return fun_(X, Y);
}
template<class T>
auto operator+(const T b) const {
return make_foo_kernel([b, this](double X, double Y) -> double {
return this->covarianceFunction(X, Y) + b.covarianceFunction(X, Y);
});
}
FooKernel operator=(const FooKernel other) const {
return other;
}
private:
Func fun_;
};
template <typename Func>
auto make_foo_kernel(Func&& fun)
{
return FooKernel<Func>(std::forward<Func>(fun));
}
class GaussianKernel : public Kernel {
public:
GaussianKernel(double sigma, double scale) : m_sigma(sigma), m_scale(scale) {}
GaussianKernel(double sigma) : m_sigma(sigma), m_scale(1) {}
/*
A well known covariance function that enforces smooth deformations
Ref : Shape modeling using Gaussian process Morphable Models, Luethi et al.
*/
double covarianceFunction(
double X,
double Y
) const
{
//use diagonal matrix
double result;
result = m_scale * exp(-std::norm(X - Y) / (m_sigma*m_sigma));
return result;
}
template<class T>
auto operator+(const T b) const {
return make_foo_kernel([b, this](double X, double Y) -> double {
auto debugBval = b.covarianceFunction(X, Y);
auto debugAval = this->covarianceFunction(X, Y);
auto test = debugBval + debugAval;
return test;
});
}
private:
double m_sigma;
double m_scale;
};
int main()
{
auto C = GaussianKernel(50,60) + GaussianKernel(100,200);
auto result = C.covarianceFunction(30.0,40.0);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y29tcGxleD4KI2luY2x1ZGUgPGZ1bmN0aW9uYWw+CgoKY2xhc3MgS2VybmVsIHsKcHVibGljOiAKICAgIC8qCiAgICBDb3ZhcmlhbmNlIGZ1bmN0aW9uIDogcmV0dXJuIHRoZSBjb3ZhcmlhbmNlIGJldHdlZW4gdHdvIFIuVi4gZm9yIHRoZSBlbnRpcmUga2VybmVsJ3MgZG9tYWluIGRlZmluaXRpb24uIAogICAgKi8KICAgIHZpcnR1YWwgZG91YmxlIGNvdmFyaWFuY2VGdW5jdGlvbigKICAgICAgICBkb3VibGUgICBYLAogICAgICAgIGRvdWJsZSAgIFkKICAgICljb25zdCA9IDAgOwogICAgfktlcm5lbCgpID0gZGVmYXVsdDsKfTsKCgp0ZW1wbGF0ZSA8dHlwZW5hbWUgRnVuYz4KY2xhc3MgRm9vS2VybmVsIDogcHVibGljIEtlcm5lbCB7CnB1YmxpYzoKCiAgICBGb29LZXJuZWwoRnVuYyYmIGZ1bikgOiBmdW5fKHN0ZDo6Zm9yd2FyZDxGdW5jPihmdW4pKSB7fQogICAgZG91YmxlIGNvdmFyaWFuY2VGdW5jdGlvbigKICAgICAgICBkb3VibGUgICBYLAogICAgICAgIGRvdWJsZSAgIFkKICAgICkgY29uc3QgewogICAgICAgIHJldHVybiBmdW5fKFgsIFkpOwogICAgfQogICAgdGVtcGxhdGU8Y2xhc3MgVD4KICAgIGF1dG8gb3BlcmF0b3IrKGNvbnN0IFQgYikgY29uc3QgewogICAgICAgIHJldHVybiBtYWtlX2Zvb19rZXJuZWwoW2IsIHRoaXNdKGRvdWJsZSBYLCBkb3VibGUgWSkgLT4gZG91YmxlIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMtPmNvdmFyaWFuY2VGdW5jdGlvbihYLCBZKSArIGIuY292YXJpYW5jZUZ1bmN0aW9uKFgsIFkpOwogICAgICAgIH0pOwogICAgfQogICAgRm9vS2VybmVsIG9wZXJhdG9yPShjb25zdCBGb29LZXJuZWwgb3RoZXIpIGNvbnN0IHsKICAgICAgICByZXR1cm4gb3RoZXI7CiAgICB9CnByaXZhdGU6CiAgIEZ1bmMgZnVuXzsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBGdW5jPgphdXRvIG1ha2VfZm9vX2tlcm5lbChGdW5jJiYgZnVuKQp7CiAgICByZXR1cm4gRm9vS2VybmVsPEZ1bmM+KHN0ZDo6Zm9yd2FyZDxGdW5jPihmdW4pKTsKfQoKCmNsYXNzIEdhdXNzaWFuS2VybmVsIDogcHVibGljIEtlcm5lbCB7CnB1YmxpYzoKICAgIEdhdXNzaWFuS2VybmVsKGRvdWJsZSBzaWdtYSwgZG91YmxlIHNjYWxlKSA6IG1fc2lnbWEoc2lnbWEpLCBtX3NjYWxlKHNjYWxlKSB7fQogICAgR2F1c3NpYW5LZXJuZWwoZG91YmxlIHNpZ21hKSA6IG1fc2lnbWEoc2lnbWEpLCBtX3NjYWxlKDEpIHt9CiAgICAvKgogICAgQSB3ZWxsIGtub3duIGNvdmFyaWFuY2UgZnVuY3Rpb24gdGhhdCBlbmZvcmNlcyBzbW9vdGggZGVmb3JtYXRpb25zCiAgICBSZWYgOiBTaGFwZSBtb2RlbGluZyB1c2luZyBHYXVzc2lhbiBwcm9jZXNzIE1vcnBoYWJsZSBNb2RlbHMsIEx1ZXRoaSBldCBhbC4KICAgICovCiAgICBkb3VibGUgY292YXJpYW5jZUZ1bmN0aW9uKAogICAgICAgIGRvdWJsZSAgIFgsCiAgICAgICAgZG91YmxlICAgWQogICAgKSBjb25zdCAKICAgIHsKICAgICAgICAvL3VzZSBkaWFnb25hbCBtYXRyaXgKICAgIGRvdWJsZSByZXN1bHQ7CiAgICByZXN1bHQgPSBtX3NjYWxlICAqICBleHAoLXN0ZDo6bm9ybShYIC0gWSkgLyAobV9zaWdtYSptX3NpZ21hKSk7CiAgICByZXR1cm4gcmVzdWx0OyAgICAgIAogICAgfQogICAgdGVtcGxhdGU8Y2xhc3MgVD4KICAgIGF1dG8gb3BlcmF0b3IrKGNvbnN0IFQgYikgY29uc3QgewogICAgICAgIHJldHVybiBtYWtlX2Zvb19rZXJuZWwoW2IsIHRoaXNdKGRvdWJsZSBYLCBkb3VibGUgWSkgLT4gZG91YmxlIHsKICAgICAgICAgICAgYXV0byBkZWJ1Z0J2YWwgPSBiLmNvdmFyaWFuY2VGdW5jdGlvbihYLCBZKTsKICAgICAgICAgICAgYXV0byBkZWJ1Z0F2YWwgPSB0aGlzLT5jb3ZhcmlhbmNlRnVuY3Rpb24oWCwgWSk7CiAgICAgICAgICAgIGF1dG8gdGVzdCA9IGRlYnVnQnZhbCArIGRlYnVnQXZhbDsKICAgICAgICAgICAgcmV0dXJuIHRlc3Q7CiAgICAgICAgfSk7CiAgICB9CnByaXZhdGU6CiAgICBkb3VibGUgbV9zaWdtYTsKICAgIGRvdWJsZSBtX3NjYWxlOwp9OwoKaW50IG1haW4oKQp7CiAgICBhdXRvIEMgPSBHYXVzc2lhbktlcm5lbCg1MCw2MCkgKyBHYXVzc2lhbktlcm5lbCgxMDAsMjAwKTsKICAgIGF1dG8gcmVzdWx0ID0gQy5jb3ZhcmlhbmNlRnVuY3Rpb24oMzAuMCw0MC4wKTsKCiAgICByZXR1cm4gMDsKfQ==