/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011-2014 by 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
#include "./domain.hpp"
#include "./mem_layout.hpp"
#include
#include
namespace triqs { namespace arrays {
struct _traversal_c {};
struct _traversal_fortran {};
struct _traversal_dynamical {};
template struct _traversal_custom {};
template struct _get_traversal_order_t {
using type = T;
};
template <> struct _get_traversal_order_t {
using type = _traversal_c;
};
constexpr ull_t _get_traversal_order_permutation(int R, _traversal_c) { return permutations::identity(R); }
constexpr ull_t _get_traversal_order_permutation(int R, _traversal_fortran) { return permutations::ridentity(R); }
template constexpr ull_t _get_traversal_order_permutation(int R,_traversal_custom) {
static_assert(sizeof...(Is) == R, " Rank mismatch");
return permutations::permutation(Is...);
}
namespace indexmaps { namespace cuboid {
/** Standard hyper_rectangular arrays, implementing the IndexMap concept.
*/
template class map {
public :
static const int rank = Rank;
using lengths_type=mini_vector ;
using strides_type=mini_vector ;
using domain_type = domain_t;
using traversal_order_in_template = TraversalOrder;
using has_traversal_order_tag = void;
domain_type const& domain() const { return mydomain; }
// semi-regular type
map (): start_shift_(0), memory_order_() {}
map (map const & C) = default;
map (map && C) = default;
map & operator = (map const & m) = default;
map & operator = (map && m) = default;
// basic construction
map(memory_layout const & ml):mydomain(), start_shift_(0), memory_order_(ml) {}
map(domain_type const & C): mydomain(C), start_shift_(0), memory_order_() {compute_stride_compact();}
map(domain_type const & C, memory_layout ml): mydomain(C), start_shift_(0), memory_order_(std::move(ml)) {compute_stride_compact();}
/// Construction from the length, the stride, start_shift
map(lengths_type Lengths, strides_type strides, std::ptrdiff_t start_shift ):
mydomain(std::move(Lengths)), strides_(std::move(strides)), start_shift_(start_shift),
memory_order_ (memory_layout_from_strides(strides_)) {}
/// Construction from the length, the stride, start_shift, ml
map(lengths_type Lengths, strides_type strides, std::ptrdiff_t start_shift, memory_layout const & ml ):
mydomain(std::move(Lengths)), strides_(std::move(strides)), start_shift_(start_shift), memory_order_ (ml) {}
/// Construction from another map with the same order
template
map(map const& C)
: mydomain(C.domain()), strides_(C.strides()), start_shift_(C.start_shift()), memory_order_(C.get_memory_layout()) {}
template map& operator=(map const& m) {
*this = map{m};
}
// transposition
friend map transpose(map const& m, mini_vector const & perm) {
lengths_type l;
strides_type s;
for (int u = 0; u < Rank; ++u) {
l[perm[u]] = m.domain().lengths()[u];
s[perm[u]] = m.strides_[u];
}
return map{l, s, m.start_shift_, transpose(m.memory_order_, perm)};
}
/// Returns the shift in position of the element key.
template size_t operator[](KeyType const& key) const {
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
this->domain().assert_key_in_domain(key);
#endif
return start_shift_ + dot_product(key, this->strides());
}
friend std::ostream & operator << (std::ostream & out, const map & P) {
return out <<" ordering = {"< size_t operator()(Args const & ... args) const {
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
this->domain().assert_key_in_domain_v(args...);
#endif
return start_shift_ + _call_impl<0>(args...);
}
private :
template
size_t _call_impl( Arg0 const & arg0, Args const & ... args) const { return arg0* strides_[N] + _call_impl(args...); }
template size_t _call_impl() const { return 0;}
public:
///
bool is_contiguous() const {
int slowest_index = memory_order_[0];
return (strides()[slowest_index] * this->lengths()[slowest_index] == mydomain.number_of_elements());
}
size_t start_shift() const { return start_shift_;}
lengths_type const & lengths() const { return mydomain.lengths();}
strides_type const & strides() const { return this->strides_;}
memory_layout const & get_memory_layout() const { return memory_order_;}
bool memory_layout_is_c() const { return get_memory_layout().is_c();}
bool memory_layout_is_fortran() const { return get_memory_layout().is_fortran();}
private :
domain_type mydomain;
strides_type strides_;
std::ptrdiff_t start_shift_;
memory_layout memory_order_;
// BOOST Serialization
friend class boost::serialization::access;
template void serialize(Archive & ar, const unsigned int version) {
ar & TRIQS_MAKE_NVP("domain",mydomain);
ar & TRIQS_MAKE_NVP("strides",strides_);
ar & TRIQS_MAKE_NVP("start_shift",start_shift_);
}
// for construction
// TODO : use tupletools
void compute_stride_compact() {
size_t str = 1;
csc_impl(memory_order_, str, std::integral_constant());
assert(this->domain().number_of_elements()==str);
}
// call for indices fastest (rank -1) to slowest (0)
template void csc_impl(memory_layout const& ml, size_t& str, std::integral_constant) {
// size_t u = mem_layout::memory_rank_to_index(order, rank-v);
int u = ml[v - 1];
this->strides_[u] = str;
str *= this->lengths()[u];
csc_impl(ml, str, std::integral_constant());
}
void csc_impl(memory_layout const&, size_t&, std::integral_constant) {}
// iterator helper impl.
static constexpr int __iter_get_p(int p, map const * im, _traversal_c) { return p;}
static constexpr int __iter_get_p(int p, map const* im, _traversal_fortran) { return Rank - p - 1; }
static int __iter_get_p(int p, map const* im, _traversal_dynamical) { return im->get_memory_layout()[p]; }
template static constexpr int __iter_get_p(int p, map const* im, _traversal_custom) {
return permutations::apply(_get_traversal_order_permutation(Rank, _traversal_custom{}),
p);
}
public:
/**
* Iterator on a cuboid_map, modeling the IndexMapIterator concept.
* Iteration order is the order in which to iterate on the indices.
* It is given by a permutation, with the same convention as IndexOrder.
*/
class iterator : public boost::iterator_facade< iterator, const std::ptrdiff_t, boost::forward_traversal_tag > {
public:
using indexmap_type=map ;
using indices_type=typename domain_type::index_value_type ;
using return_type=const std::ptrdiff_t ;
iterator (): im(NULL), pos(0),atend(true) {}
iterator (const map & P, bool atEnd=false, ull_t iteration_order=0):
im(&P), pos(im->start_shift()),atend(atEnd) {}
indices_type const & indices() const { return indices_tuple; }
operator bool() const { return !atend;}
private:
friend class boost::iterator_core_access;
void increment(){ inc_ind_impl (std::integral_constant()); }
template inline void inc_ind_impl(std::integral_constant) {
int p = __iter_get_p(v - 1, im, typename _get_traversal_order_t::type{});
#ifdef TRIQS_ARRAYS_ENFORCE_BOUNDCHECK
if (atend) TRIQS_RUNTIME_ERROR << "Iterator in cuboid cannot be pushed after end !";
#endif
if (indices_tuple[p] < im->lengths()[p]-1) { ++(indices_tuple[p]); pos += im->strides()[p]; return; }
indices_tuple[p] = 0;
pos -= (im->lengths()[p]-1) * im->strides()[p];
inc_ind_impl (std::integral_constant());
}
inline void inc_ind_impl(std::integral_constant) { atend = true;}
bool equal(iterator const & other) const {return ((other.im==im)&&(other.atend==atend)&&(other.pos==pos));}
return_type & dereference() const { assert (!atend); return pos; }
map const * im;
indices_type indices_tuple;
std::ptrdiff_t pos;
bool atend;
};
}; //------------- end class ---------------------
}//namespace cuboid
template
bool compatible_for_assignment(const cuboid::map& X1, const cuboid::map& X2) {
return X1.lengths() == X2.lengths();
}
template
bool raw_copy_possible(const cuboid::map& X1, const cuboid::map& X2) {
return ( (X1.get_memory_layout() == X2.get_memory_layout())
&& X1.is_contiguous() && X2.is_contiguous()
&& (X1.domain().number_of_elements()==X2.domain().number_of_elements()));
}
}}}//namespace triqs::arrays::indexmaps