/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2012-2013 by M. Ferrero, O. Parcollet
*
* TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* TRIQS. If not, see .
*
******************************************************************************/
#pragma once
#define TRIQS_GF_INCLUDED
#include
#include
#include
#include
#include
#include
#include
#include "./tools.hpp"
#include "./data_proxies.hpp"
#include "./local/tail.hpp"
namespace triqs {
namespace gfs {
using utility::factory;
using arrays::make_shape;
using arrays::array;
using arrays::array_view;
using arrays::matrix;
using arrays::matrix_view;
using triqs::make_clone;
// the gf mesh
template struct gf_mesh;
// The regular type
template class gf;
// The view type
template class gf_view;
// The const view type
template
using gf_const_view = gf_view;
// the implementation class
template class gf_impl;
// various implementation traits
namespace gfs_implementation { // never use using of this...
// evaluator regroup functions to evaluate the function.
template struct evaluator {
static constexpr int arity = 0;
};
// closest_point mechanism
template struct get_closest_point;
// singularity
template struct singularity {
using type = nothing;
};
// symmetry
template struct symmetry {
using type = nothing;
};
// indices
template struct indices {
using type = nothing;
};
template struct indices {
using type = indices_2;
};
// data_proxy contains function to manipulate the data array, but no data itself.
// this is used to specialize this part of the code to array of dim 3 (matrix gf), dim 1 (scalar gf) and vector (e.g. block gf,
// ...)
template struct data_proxy;
// Traits to read/write in hdf5 files. Can be specialized for some case (Cf block). Defined below
template struct h5_name; // value is a const char
template struct h5_rw;
// factories regroup all factories (constructors..) for all types of gf. Defaults implemented below.
template struct factories;
} // gfs_implementation
// The trait that "marks" the Green function
TRIQS_DEFINE_CONCEPT_AND_ASSOCIATED_TRAIT(ImmutableGreenFunction);
template auto get_gf_data_shape(G const &g) DECL_AND_RETURN(g.get_data_shape());
template
auto get_target_shape(gf_impl const &g) DECL_AND_RETURN(g.data().shape().front_pop());
// ---------------------- implementation --------------------------------
// overload get_shape for a vector to simplify code below in gf block case.
template long get_shape(std::vector const &x) { return x.size(); }
/// A common implementation class for gf and gf_view. They will only redefine contructor and = ...
template
class gf_impl : TRIQS_CONCEPT_TAG_NAME(ImmutableGreenFunction) {
static_assert(!(!IsView && IsConst), "Internal error");
public:
using mutable_view_type = gf_view;
using const_view_type = gf_const_view;
using view_type = typename std::conditional::type;
using regular_type = gf;
using variable_t = Variable;
using target_t = Target;
using option_t = Opt;
using mesh_t = gf_mesh;
using domain_t = typename mesh_t::domain_t;
using mesh_point_t = typename mesh_t::mesh_point_t;
using mesh_index_t = typename mesh_t::index_t;
using symmetry_t = typename gfs_implementation::symmetry::type;
using indices_t = typename gfs_implementation::indices::type;
using evaluator_t = gfs_implementation::evaluator;
using data_proxy_t = gfs_implementation::data_proxy;
using data_regular_t = typename data_proxy_t::storage_t;
using data_view_t = typename data_proxy_t::storage_view_t;
using data_const_view_t = typename data_proxy_t::storage_const_view_t;
using data_t = std14::conditional_t, data_regular_t>;
using singularity_non_view_t = typename gfs_implementation::singularity::type;
using singularity_view_t = typename view_type_if_exists_else_type::type;
using singularity_t = std14::conditional_t;
mesh_t const &mesh() const { return _mesh; }
domain_t const &domain() const { return _mesh.domain(); }
data_t &data() { return _data; }
data_t const &data() const { return _data; }
singularity_t &singularity() { return _singularity; }
singularity_t const &singularity() const { return _singularity; }
symmetry_t const &symmetry() const { return _symmetry; }
indices_t const &indices() const { return _indices; }
evaluator_t const &get_evaluator() const { return _evaluator; }
auto get_data_shape() const DECL_AND_RETURN(get_shape(this -> data()));
protected:
mesh_t _mesh;
data_t _data;
singularity_t _singularity;
symmetry_t _symmetry;
indices_t _indices;
public :
std::string name;
protected :
evaluator_t _evaluator;
data_proxy_t _data_proxy;
// --------------------------------Constructors -----------------------------------------------
// all protected but one, this is an implementation class, see gf/gf_view later for public one
gf_impl() {} // all arrays of zero size (empty)
public: // everyone can make a copy and a move (for clef lib in particular, this one needs to be public)
gf_impl(gf_impl const &x)
: _mesh(x.mesh()),
_data(factory(x.data())),
_singularity(factory(x.singularity())),
_symmetry(x.symmetry()),
_indices(x.indices()),
name(x.name),
_evaluator(x._evaluator) {}
gf_impl(gf_impl &&) = default;
protected:
template
gf_impl(G &&x, bool) // bool to disambiguate
: _mesh(x.mesh()),
_data(factory(x.data())),
_singularity(factory(x.singularity())),
_symmetry(x.symmetry()),
_indices(x.indices()),
name(x.name),
_evaluator(x.get_evaluator()) {}
template
gf_impl(M &&m, D &&dat, S &&sing, SY &&sy, indices_t ind, std::string name, EV &&ev)
: _mesh(std::forward(m))
, _data(std::forward(dat))
, _singularity(std::forward(sing))
, _symmetry(std::forward(sy))
, _indices(std::move(ind))
, name(name)
, _evaluator(std::forward(ev)) {
if (!_indices.check_size(this)) TRIQS_RUNTIME_ERROR << "Size of indices mismatch with data size";
}
void operator=(gf_impl const &rhs) = delete; // done in derived class.
void swap_impl(gf_impl &b) noexcept {
using std::swap;
swap(this->_mesh, b._mesh);
swap(this->_data, b._data);
swap(this->_singularity, b._singularity);
swap(this->_symmetry, b._symmetry);
swap(this->_indices, b._indices);
swap(this->name, b.name);
swap(this->_evaluator, b._evaluator);
}
public:
// ------------- All the call operators -----------------------------
// First, a simple () returns a view, like for an array...
const_view_type operator()() const { return *this; }
view_type operator()() { return *this; }
/// Calls are (perfectly) forwarded to the evaluator::operator(), except mesh_point_t and when
/// there is at least one lazy argument ...
template // match any argument list, picking out the first type : () is not permitted
typename boost::lazy_disable_if_c< // disable the template if one the following conditions it true
(sizeof...(Args) == 0) || clef::is_any_lazy::value ||
((sizeof...(Args) != evaluator_t::arity) && (evaluator_t::arity != -1)) // if -1 : no check
,
std::result_of // what is the result type of call
>::type // end of lazy_disable_if
operator()(Args &&... args) const {
return _evaluator(this, std::forward(args)...);
}
template typename clef::_result_of::make_expr_call::type operator()(Args &&... args) & {
return clef::make_expr_call(*this, std::forward(args)...);
}
template
typename clef::_result_of::make_expr_call::type operator()(Args &&... args) const &{
return clef::make_expr_call(*this, std::forward(args)...);
}
template typename clef::_result_of::make_expr_call::type operator()(Args &&... args) && {
return clef::make_expr_call(std::move(*this), std::forward(args)...);
}
// ------------- All the [] operators -----------------------------
// [] and access to the grid point
using r_type = typename std::result_of::type;
using cr_type = typename std::result_of::type;
r_type operator[](mesh_index_t const &arg) { return _data_proxy(_data, _mesh.index_to_linear(arg)); }
cr_type operator[](mesh_index_t const &arg) const { return _data_proxy(_data, _mesh.index_to_linear(arg)); }
r_type operator[](mesh_point_t const &x) { return _data_proxy(_data, x.linear_index()); }
cr_type operator[](mesh_point_t const &x) const { return _data_proxy(_data, x.linear_index()); }
template r_type operator[](closest_pt_wrap const &p) {
return _data_proxy(_data,
_mesh.index_to_linear(gfs_implementation::get_closest_point::invoke(this, p)));
}
template cr_type operator[](closest_pt_wrap const &p) const {
return _data_proxy(_data,
_mesh.index_to_linear(gfs_implementation::get_closest_point::invoke(this, p)));
}
template
typename clef::_result_of::make_expr_subscript::type operator[](Arg &&arg) const &{
return clef::make_expr_subscript(*this, std::forward(arg));
}
template typename clef::_result_of::make_expr_subscript::type operator[](Arg &&arg) & {
return clef::make_expr_subscript(*this, std::forward(arg));
}
template typename clef::_result_of::make_expr_subscript::type operator[](Arg &&arg) && {
return clef::make_expr_subscript(std::move(*this), std::forward(arg));
}
/// --------------------- A direct access to the grid point --------------------------
template r_type on_mesh(Args &&... args) {
return _data_proxy(_data, _mesh.index_to_linear(mesh_index_t(std::forward(args)...)));
}
template cr_type on_mesh(Args &&... args) const {
return _data_proxy(_data, _mesh.index_to_linear(mesh_index_t(std::forward(args)...)));
}
// The on_mesh little adaptor ....
private:
struct _on_mesh_wrapper_const {
gf_impl const &f;
template cr_type operator()(Args &&... args) const { return f.on_mesh(std::forward(args)...); }
};
struct _on_mesh_wrapper {
gf_impl &f;
template r_type operator()(Args &&... args) const { return f.on_mesh(std::forward(args)...); }
};
public:
_on_mesh_wrapper_const friend on_mesh(gf_impl const &f) {
return {f};
}
_on_mesh_wrapper friend on_mesh(gf_impl &f) {
return {f};
}
//----------------------------- HDF5 -----------------------------
friend std::string get_triqs_hdf5_data_scheme(gf_impl const &g) {
auto s = gfs_implementation::h5_name::invoke();
return (s == "BlockGf" ? s : "Gf" + s);
}
friend struct gfs_implementation::h5_rw;
/// Write into HDF5
friend void h5_write(h5::group fg, std::string subgroup_name, gf_impl const &g) {
auto gr = fg.create_group(subgroup_name);
gr.write_triqs_hdf5_data_scheme(g);
gfs_implementation::h5_rw::write(gr, g);
}
/// Read from HDF5
friend void h5_read(h5::group fg, std::string subgroup_name, gf_impl &g) {
auto gr = fg.open_group(subgroup_name);
// Check the attribute or throw
auto tag_file = gr.read_triqs_hdf5_data_scheme();
auto tag_expected = get_triqs_hdf5_data_scheme(g);
if (tag_file != tag_expected)
TRIQS_RUNTIME_ERROR << "h5_read : mismatch of the tag TRIQS_HDF5_data_scheme tag in the h5 group : found " << tag_file
<< " while I expected " << tag_expected;
gfs_implementation::h5_rw::read(gr, g);
}
//----------------------------- BOOST Serialization -----------------------------
friend class boost::serialization::access;
template void serialize(Archive &ar, const unsigned int version) {
ar &TRIQS_MAKE_NVP("data", _data);
ar &TRIQS_MAKE_NVP("singularity", _singularity);
ar &TRIQS_MAKE_NVP("mesh", _mesh);
ar &TRIQS_MAKE_NVP("symmetry", _symmetry);
ar &TRIQS_MAKE_NVP("indices", _indices);
ar &TRIQS_MAKE_NVP("name", name);
}
/// print
friend std::ostream &operator<<(std::ostream &out, gf_impl const &x) { return out << (IsView ? "gf_view" : "gf"); }
friend std::ostream &triqs_nvl_formal_print(std::ostream &out, gf_impl const &x) { return out << (IsView ? "gf_view" : "gf"); }
};
// -------------------------Interaction with the CLEF library : auto assignement implementation -----------------
// auto assignment of the gf (gf(om_) << expression fills the functions by evaluation of expression)
template
void triqs_clef_auto_assign(gf_impl &g, RHS const &rhs) {
triqs_clef_auto_assign_impl(g, rhs, typename std::is_base_of>::type());
assign_from_expression(g.singularity(), rhs);
// access to the data . Beware, we view it as a *matrix* NOT an array... (crucial for assignment to scalars !)
// if f is an expression, replace the placeholder with a simple tail. If f is a function callable on freq_infty,
// it uses the fact that tail_non_view_t can be casted into freq_infty
}
// enable the writing g[om_] << .... also
template
void triqs_clef_auto_assign_subscript(gf_impl &g, RHS const &rhs) {
triqs_clef_auto_assign(g, rhs);
}
template void triqs_gf_clef_auto_assign_impl_aux_assign(G &&g, RHS &&rhs) {
std::forward(g) = std::forward(rhs);
}
template
void triqs_gf_clef_auto_assign_impl_aux_assign(G &&g, clef::make_fun_impl &&rhs) {
triqs_clef_auto_assign(std::forward(g), std::forward>(rhs));
}
template
void triqs_clef_auto_assign_impl(gf_impl &g, RHS const &rhs,
std::integral_constant) {
for (auto const &w : g.mesh()) {
triqs_gf_clef_auto_assign_impl_aux_assign(g[w], rhs(w));
//(*this)[w] = rhs(w);
}
}
template
void triqs_clef_auto_assign_impl(gf_impl &g, RHS const &rhs,
std::integral_constant) {
for (auto const &w : g.mesh()) {
triqs_gf_clef_auto_assign_impl_aux_assign(g[w], triqs::tuple::apply(rhs, w.components_tuple()));
//(*this)[w] = triqs::tuple::apply(rhs, w.components_tuple());
}
}
// -------------------------The regular class of GF --------------------------------------------------------
template class gf : public gf_impl {
using B = gf_impl;
using factory = gfs_implementation::factories;
public:
gf() : B() {}
gf(gf const &g) : B(g) {}
gf(gf &&g) noexcept : B(std::move(g)) {}
gf(gf_view const &g) : B(g, bool {}) {}
gf(gf_const_view const &g) : B(g, bool {}) {}
template
gf(GfType const &x, typename std::enable_if::value>::type *dummy = 0)
: B() {
*this = x;
}
gf(typename B::mesh_t m, typename B::data_t dat, typename B::singularity_view_t const &si, typename B::symmetry_t const &s,
typename B::indices_t const &ind, std::string name = "")
: B(std::move(m), std::move(dat), si, s, ind, name, typename B::evaluator_t{}) {}
using target_shape_t = typename factory::target_shape_t;
gf(typename B::mesh_t m, target_shape_t shape = target_shape_t{}, typename B::indices_t const &ind = typename B::indices_t{}, std::string name = "")
: B(std::move(m), factory::make_data(m, shape), factory::make_singularity(m, shape), typename B::symmetry_t{}, ind, name, // clean unncessary types
typename B::evaluator_t{}) {
if (this->_indices.is_empty()) this->_indices = typename B::indices_t(shape);
}
friend void swap(gf &a, gf &b) noexcept { a.swap_impl(b); }
// CLEAN THIS : one op only gf rhs, + move
gf &operator=(gf const &rhs) {
*this = gf(rhs);
return *this;
} // use move =
gf &operator=(gf &rhs) {
*this = gf(rhs);
return *this;
} // use move =
gf &operator=(gf &&rhs) noexcept {
swap(*this, rhs);
return *this;
}
template void operator=(RHS &&rhs) {
this->_mesh = rhs.mesh();
this->_data.resize(get_gf_data_shape(rhs));
for (auto const &w : this->mesh()) {
(*this)[w] = rhs[w];
}
this->_singularity = rhs.singularity();
// to be implemented : there is none in the gf_expr in particular....
// this->_symmetry = rhs.symmetry();
// indices and name are not affected by it ???
}
};
// in most expression, the gf_impl version is enough.
// But in chained clef expression, A(i_)(om_) where A is an array of gf
// we need to call it with the gf, not gf_impl (or the template resolution find the deleted funciton in clef).
// Another fix is to make gf, gf_view in the expression tree, but this requires using CRPT in gf_impl...
template
void triqs_clef_auto_assign(gf &g, RHS const &rhs) {
triqs_clef_auto_assign( static_cast&>(g), rhs);
}
// --------------------------The const View class of GF -------------------------------------------------------
template
class gf_view : public gf_impl {
using B = gf_impl;
public:
gf_view() = delete;
gf_view(gf_view const &g) : B(g) {}
gf_view(gf_view &&g) noexcept : B(std::move(g)) {}
gf_view(gf_impl const &g) : B(g, bool {}) {} // from a const_view
gf_view(gf_impl const &g) : B(g, bool {}) {} // from a view
gf_view(gf_impl const &g) : B(g, bool {}) {} // from a const gf
gf_view(gf_impl &g) : B(g, bool {}) {} // from a gf &
gf_view(gf_impl &&g) noexcept : B(std::move(g), bool {}) {} // from a gf &&
template
gf_view(typename B::mesh_t const &m, D const &dat, typename B::singularity_view_t const &t, typename B::symmetry_t const &s,
typename B::indices_t const &ind, std::string name = "")
: B(m, factory(dat), t, s, ind, name, typename B::evaluator_t{}) {}
void rebind(gf_view const &X) noexcept {
this->_mesh = X._mesh;
this->_symmetry = X._symmetry;
this->_data_proxy.rebind(this->_data, X);
this->_singularity.rebind(X._singularity);
this->_indices = X._indices;
this->name = X.name;
}
void rebind(gf_view const &X) noexcept {
rebind(gf_view{X});
}
gf_view &operator=(gf_view const &) = delete;
}; // class gf_const_view
// ------------------------- The View class of GF -------------------------------------------------------
template
class gf_view : public gf_impl {
using B = gf_impl;
public:
gf_view() = delete;
gf_view(gf_view const &g) : B(g) {}
gf_view(gf_view &&g) noexcept : B(std::move(g)) {}
gf_view(gf_impl const &g) = delete; // from a const view : impossible
gf_view(gf_impl const &g) : B(g, bool {}) {} // from a view
gf_view(gf_impl const &g) = delete; // from a const gf : impossible
gf_view(gf_impl &g) : B(g, bool {}) {} // from a gf &
gf_view(gf_impl &&g) noexcept : B(std::move(g), bool {}) {} // from a gf &&
template
gf_view(typename B::mesh_t const &m, D &&dat, typename B::singularity_view_t const &t, typename B::symmetry_t const &s,
typename B::indices_t const &ind = typename B::indices_t{}, std::string name = "")
: B(m, factory(std::forward(dat)), t, s, ind, name, typename B::evaluator_t{}) {}
friend void swap(gf_view &a, gf_view &b) noexcept { a.swap_impl(b); }
void rebind(gf_view const &X) noexcept {
this->_mesh = X._mesh;
this->_symmetry = X._symmetry;
this->_data_proxy.rebind(this->_data, X);
this->_singularity.rebind(X._singularity);
this->_indices = X._indices;
this->name = X.name;
}
gf_view &operator=(gf_view const &rhs) {
triqs_gf_view_assign_delegation(*this, rhs);
return *this;
}
template gf_view &operator=(RHS const &rhs) {
triqs_gf_view_assign_delegation(*this, rhs);
return *this;
}
}; // class gf_view
// delegate = so that I can overload it for specific RHS...
template
DISABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation(gf_view g, RHS const &rhs) {
if (!(g.mesh() == rhs.mesh()))
TRIQS_RUNTIME_ERROR << "Gf Assignment in View : incompatible mesh" << g.mesh() << " vs " << rhs.mesh();
for (auto const &w : g.mesh()) g[w] = rhs[w];
g.singularity() = rhs.singularity();
}
template
ENABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation(gf_view g, T const &x) {
gf_view::data_proxy_t::assign_to_scalar(g.data(), x);
g.singularity() = x;
}
// tool for lazy transformation
template struct gf_keeper {
gf_const_view g;
};
// Cf gf
template
void triqs_clef_auto_assign(gf_view &g, RHS const &rhs) {
triqs_clef_auto_assign( static_cast&>(g), rhs);
}
// ---------------------------------- slicing ------------------------------------
// slice
template
gf_view slice_target(gf_view g, Args &&... args) {
static_assert(std::is_same::value, "slice_target only for matrix_valued GF's");
using arrays::range;
return {g.mesh(), g.data()(range(), std::forward(args)...),
slice_target(g.singularity(), std::forward(args)...), g.symmetry(), slice(g.indices(),std::forward(args)...), g.name };
}
template
gf_view slice_target(gf &g, Args &&... args) {
return slice_target(g(), std::forward(args)...);
}
template
gf_const_view slice_target(gf const &g, Args &&... args) {
return slice_target(g(), std::forward(args)...);
}
// slice to scalar
template
gf_view slice_target_to_scalar(gf_view g,
Args &&... args) {
static_assert(std::is_same::value, "slice_target only for matrix_valued GF's");
using arrays::range;
return {g.mesh(), g.data()(range(), std::forward(args)...),
slice_target(g.singularity(), range(args, args + 1)...), g.symmetry(), {}, g.name};
}
template
gf_view slice_target_to_scalar(gf &g, Args &&... args) {
return slice_target_to_scalar(g(), std::forward(args)...);
}
template
gf_const_view slice_target_to_scalar(gf const &g, Args &&... args) {
return slice_target_to_scalar(g(), std::forward(args)...);
}
/*// slice with string arguments, for python mainly.
template
gf_view slice_target_string_indices(gf_view g, std::string const & a1, std::string const & a2) {
int n1 = g.indices().convert_index(a1,0);
int n2 = g.indices().convert_index(a2,1);
return slice_target (g, n1, n2); // the slice will have no indices. Ok ?
}
*/
// ---------------------------------- target reinterpretation ------------------------------------
// a scalar_valued gf can be viewed as a 1x1 matrix
template
gf_view
reinterpret_scalar_valued_gf_as_matrix_valued(gf_view g) {
using a_t = typename gf_view::data_view_t;
auto a = a_t{typename a_t::indexmap_type(join(g.data().shape(), make_shape(1, 1))), g.data().storage()};
return {g.mesh(), a, g.singularity(), g.symmetry(), {} , g.name};
}
template
gf_view reinterpret_scalar_valued_gf_as_matrix_valued(gf &g) {
return reinterpret_scalar_valued_gf_as_matrix_valued(g());
}
template
gf_const_view
reinterpret_scalar_valued_gf_as_matrix_valued(gf const &g) {
return reinterpret_scalar_valued_gf_as_matrix_valued(g());
}
/*
template
gf_view slice_mesh (gf_impl const & g, Args... args) {
return gf_view(g.mesh().slice(args...), g.data()(g.mesh().slice_get_range(args...),arrays::ellipsis()),
g.singularity(), g.symmetry());
}*/
// ---------------------------------- some functions : invert, conjugate, transpose, ... ------------------------------------
// ---- inversion
// auxiliary function : invert the data : one function for all matrix valued gf (save code).
template void _gf_invert_data_in_place(A3 && a) {
for (int i = 0; i < first_dim(a); ++i) {// Rely on the ordering
auto v = a(i, arrays::range(), arrays::range());
v = inverse(v);
}
}
template
void invert_in_place(gf_view g) {
_gf_invert_data_in_place(g.data());
g.singularity() = inverse(g.singularity());
}
template gf inverse(gf const & g) {
auto res = g;
gf_view v = res;
invert_in_place(v);
return res;
}
template gf inverse(gf_view g) {
return inverse(gf(g));
}
// ---- transpose : a new gf
template
gf transpose(gf_view g) {
return {g.mesh(), transposed_view(g.data(), 0, 2, 1), transpose(g.singularity()), g.symmetry(), transpose(g.indices()), g.name};
}
// ---- conjugate : always a new function -> changelog
template gf conj(gf_view g) {
return {g.mesh(), conj(g.data()), conj(g.singularity()), g.symmetry(), g.indices(), g.name};
}
// ---- matrix mult R and L
template void _gf_data_mul_R(A3 &&a, matrix const &r) {
for (int i = 0; i < first_dim(a); ++i) { // Rely on the ordering
matrix_view v = a(i, arrays::range(), arrays::range());
v = v * r;
}
}
template void _gf_data_mul_L(matrix const &l, A3 &&a) {
for (int i = 0; i < first_dim(a); ++i) { // Rely on the ordering
matrix_view v = a(i, arrays::range(), arrays::range());
v = l * v;
}
}
template typename A3::regular_type _gf_data_mul_LR(matrix const &l, A3 &a, matrix const &r) {
auto res = typename A3::regular_type(first_dim(a), first_dim(l), second_dim(r));
for (int i = 0; i < first_dim(a); ++i) { // Rely on the ordering
auto _ = arrays::range{};
res(i, _, _) = l * make_matrix_view(a(i, _, _))* r;
}
return res;
}
template
gf operator*(gf g, matrix r) {
_gf_data_mul_R(g.data(), r);
g.singularity() = g.singularity() * r;
return g;
}
template
gf operator*(matrix l, gf g) {
_gf_data_mul_L(l, g.data());
g.singularity() = l * g.singularity();
return g;
}
template
gf L_G_R(matrix l, gf g, matrix r) {
auto res = gf{g.mesh(), {int(first_dim(l)), int(second_dim(r))}};
res.data() = _gf_data_mul_LR(l, g.data(), r);
res.singularity() = l * g.singularity() * r;
return res;
}
namespace gfs_implementation { // implement some default traits
// ------------------------- default factories ---------------------
// ----- tensor_valued
template struct factories, Opt> {
using gf_t = gf, Opt>;
using target_shape_t = arrays::mini_vector;
using mesh_t = typename gf_t::mesh_t;
static typename gf_t::data_t make_data(mesh_t const &m, target_shape_t shape) {
typename gf_t::data_t A(shape.front_append(m.size()));
A() = 0;
return A;
}
static typename gf_t::singularity_t make_singularity(mesh_t const &m, target_shape_t shape) {
return typename gf_t::singularity_t(shape);
}
};
// ----- matrix_valued
template struct factories