Initial import
This commit is contained in:
commit
56a50eead3
820 changed files with 192077 additions and 0 deletions
139
libLSS/tools/optimization/array_helper.hpp
Normal file
139
libLSS/tools/optimization/array_helper.hpp
Normal 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
|
265
libLSS/tools/optimization/cg.hpp
Normal file
265
libLSS/tools/optimization/cg.hpp
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue