Initial import

This commit is contained in:
Guilhem Lavaux 2023-05-29 10:41:03 +02:00
commit 56a50eead3
820 changed files with 192077 additions and 0 deletions

View file

@ -0,0 +1,139 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/optimization/array_helper.hpp
Copyright (C) 2018-2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_TOOLS_OPTIMIZATION_ARRAY_HELPER_HPP
#define __LIBLSS_TOOLS_OPTIMIZATION_ARRAY_HELPER_HPP
#include <complex>
#include <boost/tti/has_type.hpp>
#include <boost/multi_array.hpp>
#include "libLSS/tools/array_tools.hpp"
#include "libLSS/tools/fusewrapper.hpp"
#include "libLSS/tools/uninitialized_type.hpp"
namespace LibLSS {
namespace Optimization {
BOOST_TTI_HAS_TYPE(array_t);
BOOST_TTI_HAS_TYPE(holder_array_t);
template<typename T> struct is_complex: public std::false_type {};
template<typename U> struct is_complex<std::complex<U>> : public std::true_type {};
template <typename Array1, typename Array2, typename U = typename Array1::array_t::element>
inline typename std::enable_if<!is_complex<U>::value, double>::type dotprod(Array1 const &a1, Array2 const &a2) {
return (a1*a2).sum();
}
template <typename Array1, typename Array2, typename U = typename Array1::array_t::element>
inline typename std::enable_if<is_complex<U>::value, double>::type dotprod(Array1 const &a1, Array2 const &a2) {
auto r = [](auto&& a) { return std::real(a); };
auto i = [](auto&& a) { return std::imag(a); };
auto r1 = r(a1);
auto r2 = r(a2);
auto i1 = i(a1);
auto i2 = i(a2);
return (r1*r2 + i1*i2).sum();
}
template <typename Array1, typename Array2>
inline double dotprod(MPI_Communication* comm, Array1 const &a1, Array2 const &a2) {
double r = dotprod(a1, a2);
comm->all_reduce_t(MPI_IN_PLACE, &r, 1, MPI_SUM);
return r;
}
template <typename Array>
struct array_holder {
public:
typedef Array array_t;
typedef UninitializedArray<array_t> u_array_t;
typedef std::shared_ptr<u_array_t> holder_array_t;
holder_array_t holder;
array_holder() : holder() {}
array_holder(array_holder<Array> &other) : holder(other.holder) {}
array_holder(array_holder<Array> &&other)
: holder(std::move(other.holder)) {}
array_holder(holder_array_t &&h) : holder(std::move(h)) {}
array_holder(holder_array_t& h) : holder(h) {}
array_holder<Array> const &operator=(array_holder<Array> &other) {
holder = other.holder;
return *this;
}
array_holder<Array> const &operator=(array_holder<Array> &&other) {
holder = std::move(other.holder);
return *this;
}
inline array_t &get() { return holder.get()->get_array(); }
inline array_t const &get() const { return holder.get()->get_array(); }
inline operator bool() const {
return holder.operator bool();
}
inline auto operator*() -> decltype(fwrap(get())) {
return fwrap(get());
}
inline auto operator*() const -> decltype(fwrap(get())) {
return fwrap(get());
}
};
template <typename T, typename = void>
struct is_holder : std::false_type {};
template <typename T>
struct is_holder<
T, typename std::enable_if<
has_type_array_t<T>::value &&
has_type_holder_array_t<T>::value>::type> : std::true_type {};
template <typename T, size_t N>
struct BoostArrayAllocator {
public:
typedef boost::multi_array_ref<T, N> array_t;
typedef array_holder<array_t> holder_t;
typedef typename holder_t::u_array_t new_array_t;
typedef decltype(fwrap(*(array_t *)0)) wrap_t;
inline auto wrapper(array_t const &a) const -> decltype(fwrap(a)) {
return fwrap(a);
}
inline auto wrapper(array_t &a) const -> decltype(fwrap(a)) {
return fwrap(a);
}
inline holder_t new_like(holder_t const &a) { return new_like(a.get()); }
template<typename ArrayLike>
inline holder_t new_like(ArrayLike const &a) {
return holder_t(std::unique_ptr<new_array_t>(
new new_array_t(LibLSS::array::make_extent_from(a)))
);
}
};
} // namespace Optimization
} // namespace LibLSS
// ARES TAG: num_authors = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2018-2019
#endif

View file

@ -0,0 +1,265 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/optimization/cg.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_TOOLS_OPTIMIZATION_CG_HPP
#define __LIBLSS_TOOLS_OPTIMIZATION_CG_HPP
#include <algorithm>
#include <functional>
#include <boost/multi_array.hpp>
#include <boost/bind.hpp>
#include "libLSS/tools/console.hpp"
#include "libLSS/tools/array_tools.hpp"
#include "libLSS/tools/fused_array.hpp"
#include "libLSS/tools/fused_assign.hpp"
#include "libLSS/tools/optimization/array_helper.hpp"
namespace LibLSS {
namespace Optimization {
namespace details {
template <typename T>
T lazy_conj(T const &c) {
return c;
}
template <typename T>
std::complex<T> lazy_conj(std::complex<T> const &c) {
return std::conj(c);
}
} // namespace details
template <typename ArrayAllocator>
struct CG {
public:
unsigned int cg_refresh;
double epsilon;
unsigned int T;
typedef typename ArrayAllocator::array_t array_t;
typedef std::function<void(array_t& out, array_t const& in)> Matrix_function_t;
typedef std::function<void(array_t& out, array_t const& in, int s)> Precon_Matrix_function_t;
public:
CG(ArrayAllocator alloc_ = ArrayAllocator()):allocator(alloc_) {
cg_refresh = 1000; // sets refreshing rate for conjugating directions
epsilon = 1e-9; // sets convergence criterion
T = 40000000; // sets maximum number of cg steps
}
~CG() {}
void
run(Matrix_function_t A, array_t const &b,
array_t &x) {
ConsoleContext<LOG_VERBOSE> ctx("CG::run");
Console &cons = Console::instance();
auto r = allocator.new_like(x);
auto d = allocator.new_like(x);
auto q = allocator.new_like(x);
auto wx = allocator.wrapper(x);
auto wb = allocator.wrapper(b);
double dnew = 0.0;
double dinit = 0.0;
double dold = 0.0;
//apply matrix to x vector
A(q.get(), x);
//initialize values
*r = b - *q;
*d = *r;
dinit = dotprod(wb,wb);
dnew = dotprod(*r, *r);
dold = dnew;
int t = 0;
Progress<LOG_INFO_SINGLE> &progress =
cons.start_progress<LOG_INFO_SINGLE>(
"applying conjugate gradient", T, 10);
while ((t < T)) {
//apply matrix to d vector
A(q.get(), d.get());
double dq = dotprod(*d, *q);
cons.print<LOG_DEBUG>(boost::format("residue is dq=%g ") % dq);
//now determine alpha
double alpha = dnew / (dq+1e-40);
cons.print<LOG_DEBUG>(boost::format("alpha =%g ") % alpha);
//now update x vector
wx = wx + alpha * (*d);
bool exit= false;
if (t % cg_refresh == 0) {
A(q.get(), x);
*r = b -(*q);
exit=true;
cons.print<LOG_DEBUG>("Refresh! ");
} else {
*r = r.get() - alpha*(*q);
}
dold = dnew;
dnew = dotprod(*r, *r);
double const ratio = dnew/dinit;
cons.print<LOG_DEBUG>(boost::format("t=%g residue is dnew=%g / dinit=%g => ratio=%g") % t % dnew % dinit % ratio);
double beta = dnew / dold;
cons.print<LOG_DEBUG>(boost::format("beta - 1 =%g ") % (beta-1.));
*d = *r + beta*(*d);
t++;
progress.update(t);
double const dcheck = dotprod(*r, *r);
cons.print<LOG_DEBUG>(boost::format("residue is dnew=%g / dcheck=%g / dinit=%g") % dnew % dcheck % dinit);
if( (dcheck/dinit)<epsilon) { // or ( fabs(beta-1.) < epsilon ))
A(q.get(), x);
double const dcheck2 = dotprod(*q - b, *q - b);
cons.print<LOG_DEBUG>(boost::format("breaking at %g") % (dcheck/dinit));
cons.print<LOG_DEBUG>(boost::format("breaking at %g??") % (dcheck2/dinit));
if ((dcheck2/dinit)<epsilon)
break;
cons.print<LOG_DEBUG>("no");
}
}
cons.print<LOG_DEBUG>("Done with CG");
progress.destroy();
}
void
run(Matrix_function_t A, Precon_Matrix_function_t M_inv, typename ArrayAllocator::array_t const&b,
typename ArrayAllocator::array_t &x) {
ConsoleContext<LOG_VERBOSE> ctx("CG::run");
Console &cons = Console::instance();
auto r = allocator.new_like(x);
auto d = allocator.new_like(x);
auto q = allocator.new_like(x);
auto s = allocator.new_like(x);
double dnew = 0.0;
double dinit = 0.0;
double dold = 0.0;
//apply matrix to x vector
A(q.get(), x);
//initialize values
*r = b - *q;
//use preconditioner
M_inv(d.get(), r.get(),1);
dinit = dnew = dotprod(*r, *d);
dold = dnew;
int t = 0;
Progress<LOG_INFO_SINGLE> &progress =
cons.start_progress<LOG_INFO_SINGLE>(
"applying conjugate gradient", T, 10);
while ((t < T)) {// and (dinit > epsilon * epsilon)) {
//apply matrix to d vector
A(q.get(), d.get());
double dq = dotprod(*d, *q);
//now determine alpha
double alpha = dnew / (dq+1e-40);
//now update x vector
fwrap(x) = fwrap(x) + alpha*(*d);
bool exit=false;
if (t % cg_refresh == 0) {
A(q.get(), x);
*r = b -(*q);
exit=true;
} else {
*r = r.get() - alpha*(*q);
}
M_inv(s.get(), r.get(),1);
dold = dnew;
dnew = dotprod(*r, *s);
double beta = dnew / dold;
*d = *s + beta*(*d);
t++;
progress.update(t);
double const dcheck = dotprod(*r, *r);
cons.print<LOG_DEBUG>(boost::format("residue is dnew=%g / dcheck=%g / dinit=%g") % dnew % dcheck % dinit);
if( (dcheck/dinit)<epsilon) { // or ( fabs(beta-1.) < epsilon ))
cons.print<LOG_DEBUG>(boost::format("breaking at %g") % (dcheck/dinit));
break;
}
}
progress.destroy();
}
private:
ArrayAllocator allocator;
};
} // namespace Optimization
using Optimization::CG;
}; // namespace LibLSS
#endif