diff --git a/src/madness/chem/test_ccpairfunction.cc b/src/madness/chem/test_ccpairfunction.cc index a43cf338f2a..629e6fa131a 100644 --- a/src/madness/chem/test_ccpairfunction.cc +++ b/src/madness/chem/test_ccpairfunction.cc @@ -15,6 +15,24 @@ using namespace madness; +template +struct randomgaussian { + Vector random_origin; + double exponent; + double radius=2; + randomgaussian(double exponent, double radius) : exponent(exponent), radius(radius) { + Vector ran; // [0,1] + RandomVector(NDIM,ran.data()); + random_origin=2.0*radius*ran-Vector(radius); +// print("origin at ",random_origin, ", exponent",exponent); + } + double operator()(const Vector& r) const { +// return exp(-exponent*inner(r-random_origin,r-random_origin)); + return exp(-exponent*(r-random_origin).normf()); + } + +}; + bool longtest=false; struct data { @@ -99,6 +117,347 @@ struct data { data data1; +template +class LowRank { +public: + + struct LRFunctor { + LRFunctor() = default; + + Function f; + std::shared_ptr> f12; + Function a,b; + }; + + World& world; + std::vector> g,h; + LRFunctor lrfunctor; + + /// construct from the hi-dim function f + LowRank(const Function& f) : world(f.world()) { + lrfunctor.f=f; + } + + /// construct from the hi-dim function f12*a(1)(b(2) + LowRank(const std::shared_ptr> f12, const Function& a, + const Function& b) : world(a.world) { + lrfunctor.a=a; + lrfunctor.b=b; + lrfunctor.f12=f12; + } + + LowRank(std::vector> g, std::vector> h) + : world(g.front().world()), g(g), h(h) {} + + LowRank(const LowRank& a) : world(a.world), g(copy(world,a.g)), h(copy(world,a.h)) {} // Copy constructor necessary + + LowRank& operator=(const LowRank& f) { // Assignment required for storage in vector + LowRank ff(f); + std::swap(ff.g,g); + std::swap(ff.h,h); + return *this; + } + + LowRank operator-(const LowRank& b) const { // Operator- necessary + return LowRank(g-b.g,h-b.h); + } + + LowRank& operator+=(const LowRank& b) { // Operator+= necessary + g+=b.g; + h+=b.h; + return *this; + } + + LowRank operator*(double a) const { // Scale by a constant necessary + return LowRank(g*a,h); + } + + LowRank multiply(const std::vector>& vec, const long particle) { + auto result=*this; // deep copy + if (particle==0) result.g=g*vec; + if (particle==1) result.h=h*vec; + return *this; + } + + /// following Halko + + /// ||A - Q Q^T A||< epsilon + /// Y = A Omega && Q = QR(Y) + /// || f(1,2) - \sum_i g_i(1) h_i(2) || < epsilon + /// Y_i(1) = \int f(1,2) Omega_i(2) d2 && g_i(1) = QR(Y_i(1)) && h_i(2) = \int g_i^*(1) f(1,2) d1 + void project(const long rank, const double radius=3.0) { + timer t1(world); + std::vector> omega2(rank); + for (long i=0; i(world).functor(randomgaussian(RandomValue()+3,radius)); + } + t1.tag("projection 1D functions"); + + std::vector> Y(rank); + + if constexpr (NDIM==1) for (int i=0; i reconstruct() const { + auto fapprox=hartree_product(g[0],h[0]); + for (int i=1; i orthonormalize(const bool s_in_h) { + timer t(world); + /** + * |g >< h| = |g_ortho> < h | h_ortho > gg hh U s VT > g_ortho=orthonormalize_canonical(g,1.e-8); + std::vector> h_ortho=orthonormalize_canonical(h,1.e-8); + auto gg=matrix_inner(world,g_ortho,g); + auto hh=matrix_inner(world,h,h_ortho); + auto ovlp=inner(gg,hh); + Tensor U,VT; + Tensor s; + svd(ovlp,U,s,VT); + auto V=transpose(VT); + + // truncate +// for (int i=1; i> htmp(g.size()), gtmp(g.size()); + for (int j=0; j1) s=orthonormalize(true); + + if (iopt%2==1) { + double err=error(); + print("optimization iteration",iopt,", error in f_approx_opt",err); + } + } + t.tag("optimize"); + } + + double explicit_error() const { + auto fapprox=reconstruct(); + return (lrfunctor.f-fapprox).norm2(); + } + + double randomized_error() const { + return 1.e9; + } + + double error() const { + if (NDIM<3) return explicit_error(); + else return randomized_error(); + } + +// double get() const {return x;} +}; + +// This interface is necessary to compute inner products +template +double inner(const LowRank& a, const LowRank& b) { + World& world=a.world; + return (matrix_inner(world,a.g,b.g).emul(matrix_inner(world,a.h,b.h))).sum(); +} + + + +/// Computes the electrostatic potential due to a Gaussian charge distribution + +/// stolen from testsuite.cc +class GaussianPotential : public FunctionFunctorInterface { +public: + typedef Vector coordT; + const coordT center; + const double exponent; + const double coefficient; + + GaussianPotential(const coordT& center, double expnt, double coefficient) + : center(center) + , exponent(sqrt(expnt)) + , coefficient(coefficient*pow(constants::pi/exponent,1.5)*pow(expnt,-0.75)) {} + + double operator()(const coordT& x) const { + double sum = 00; + for (int i=0; i<3; ++i) { + double xx = center[i]-x[i]; + sum += xx*xx; + }; + double r = sqrt(sum); + if (r<1.e-4) { // correct thru order r^3 + const double sqrtpi=sqrt(constants::pi); + const double a=exponent; + return coefficient*(2.0*a/sqrtpi - 2.0*a*a*a*r*r/(3.0*sqrtpi)); + } else { + return coefficient*erf(exponent*r)/r; + } + } +}; + +int test_lowrank_function(World& world) { + test_output t1("CCPairFunction::low rank function"); + t1.set_cout_to_terminal(); + madness::default_random_generator.setstate(int(cpu_time())%4149); + + constexpr std::size_t LDIM=1; + constexpr std::size_t NDIM=2*LDIM; + + Function f12=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i phi0=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i phi1=FunctionFactory(world).functor([&LDIM](const Vector& r) + { + Vector r1,r2; + for (int i=0; i f = phi0*phi1; +// f= f *f12; + + double norm=f12.norm2(); + print("norm",norm); + phi0.reconstruct(); + f12.reconstruct(); + Function reference=inner(phi0,f12,{0},{0}); + return 0; + + if (0) { + Function f; + double fnorm = f.norm2(); + print("norm(2D-f)", fnorm); + t1.checkpoint(true, "hi-dim projection"); + + long rank = 50; + double radius = 5.0; + + LowRank lr(copy(f)); + lr.project(rank, radius); + double err = lr.error(); + print("error in f_approx", err); + lr.orthonormalize(true); + t1.checkpoint(true, "start stuff"); + + err = lr.error(); + print("error in f_approx", err); + t1.checkpoint(true, "compute error"); + if (LDIM < 3) { + auto fapprox = lr.reconstruct(); + plot({f, fapprox, f - fapprox}, "f_and_approx", std::vector({"adsf", "asdf", "diff"})); + t1.checkpoint(true, "plotting"); + } + + /* + * optimize + */ + + lr.optimize(2); + t1.checkpoint(true, "optimization"); + + + err = lr.error(); + print("error in f_approx_opt", err); + + if (LDIM < 3) { + auto fapprox = lr.reconstruct(); + plot({f, fapprox, f - fapprox}, "f_and_approx_opt", + std::vector({"adsf", "asdf", "diff"})); + t1.checkpoint(true, "plotting"); + } + + /// int f(1,2) f12(2,3) d2 + f12.print_tree(); + auto reference=inner(f,f12,{1},{0}); + auto hbar=copy(world,lr.h); + for (auto& hh : hbar) hh=inner(f12,hh,{0},{0}); + auto result=lr; + result.h=hbar; + auto reference_approx=result.reconstruct(); + result.lrfunctor.f=reference; + double error=result.error(); + print("error ",error); + plot({reference, reference_approx, reference-reference_approx}, "contraction", std::vector({"adsf", "asdf", "diff"})); + } + +// auto result= + + + + + return t1.end(); +} + int test_constructor(World& world, std::shared_ptr ncf, const Molecule& molecule, const CCParameters& parameter) { test_output t1("CCPairFunction::constructor"); @@ -963,6 +1322,7 @@ int main(int argc, char **argv) { FunctionDefaults<1>::set_cubic_cell(-10.,10.); FunctionDefaults<2>::set_thresh(1.e-4); FunctionDefaults<2>::set_cubic_cell(-10.,10.); + FunctionDefaults<2>::set_tensor_type(TT_FULL); FunctionDefaults<3>::set_thresh(1.e-4); FunctionDefaults<3>::set_cubic_cell(-10.,10.); FunctionDefaults<4>::set_thresh(1.e-4); diff --git a/src/madness/chem/test_low_rank_function.cc b/src/madness/chem/test_low_rank_function.cc index cccd665e37a..e5ad6cb6e5b 100644 --- a/src/madness/chem/test_low_rank_function.cc +++ b/src/madness/chem/test_low_rank_function.cc @@ -284,11 +284,6 @@ class LowRank { LowRank(const cartesian_grid& cg) : cg(cg) {} -// LowRank(World& world, long n) : world(world) { -// g= zero_functions_compressed(world,n); -// h= zero_functions_compressed(world,n); -// } - LowRank() =default; // Default constructor necessary for storage in vector LowRank(const LowRank& a) : s(copy(a.s)), g(copy(a.g.front().world(),a.g)), @@ -662,7 +657,7 @@ int test_lowrank_function(World& world) { madness::default_random_generator.setstate(int(cpu_time())%4149); print(""); - constexpr std::size_t LDIM=3; + constexpr std::size_t LDIM=1; long n_per_dim=10; double radius=2.0; long ntrial=120;