/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011 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 .
*
******************************************************************************/
#ifndef TRIQS_ARRAYS_INDEXMAP_CUBOID_MAP_H
#define TRIQS_ARRAYS_INDEXMAP_CUBOID_MAP_H
#include "./domain.hpp"
#include "./mem_layout.hpp"
#include "../../impl/flags.hpp"
#include
#include
namespace triqs { namespace arrays { namespace indexmaps { namespace cuboid {
template< bool BC, class D, class K> struct _chk;
template< class D, class K> struct _chk { static void invoke (D const & d, K const & k) {d.assert_key_in_domain(k);} };
template< class D, class K> struct _chk { static void invoke (D const & d, K const & k) {} };
template< bool BC, class D, class ... K> struct _chk_v;
template< class D, class ... K> struct _chk_v { static void invoke (D const & d, K const & ... k) {d.assert_key_in_domain_v(k...);} };
template< class D, class ... K> struct _chk_v { static void invoke (D const & d, K const & ... k) {} };
template ull_t memory_layout_from_strides(mini_vector const & strides) {
int c[Rank]; for (size_t i=0; i strides[j]) c[i]++; else c[j]++;
// we computed the map : index -> memory_rank, which is the inverse map, cf mem_layout
return permutations::inverse(permutations::permutation_from_array(c, Rank));
}
/** Standard hyper_rectangular arrays, implementing the IndexMap concept.
*/
template
class map {
public :
static constexpr bool CheckBounds = flags::bound_check_trait::value;
static constexpr ull_t traversal_order_in_template = TraversalOrder;
static constexpr ull_t traversal_order = indexmaps::mem_layout::get_traversal_order::value;
typedef void has_traversal_order_tag;
static const unsigned int rank = Rank;
typedef mini_vector lengths_type;
typedef mini_vector strides_type;
typedef domain_t domain_type;
domain_type const & domain() const { return mydomain;}
// semi-regular type
map (): start_shift_(0), memory_order_(memory_layout(traversal_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_(traversal_order) {compute_stride_compact();}
map(domain_type const & C, memory_layout ml): mydomain(C), start_shift_(0), memory_order_(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 (used in grouping indices)
template map (map const & C):
mydomain(C.domain()), strides_(C.strides()), start_shift_(C.start_shift()), memory_order_ (C.memory_indices_layout()) {}
// transposition
template friend map transpose(map const& m, INT... is) {
return map{{m.domain().lengths()[is]...}, {m.strides_[is]...}, m.start_shift_, transpose(m.memory_order_, is...)};
}
/// Returns the shift in position of the element key.
template
size_t operator[] (KeyType const & key ) const {
_chk::invoke (this->domain(),key);
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 {
_chk_v::invoke (this->domain(),args...);
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 {
const size_t last_index = mem_layout::memory_rank_to_index(memory_order_.value, rank-1);
return (strides()[last_index] * this->lengths()[last_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 & memory_indices_layout() const { return memory_order_;}
memory_layout traversal_order_indices_layout() const { return memory_layout(traversal_order);}
ull_t memory_indices_layout_ull() const { return memory_order_.value;}
bool memory_layout_is_c() const { return memory_indices_layout().value == mem_layout::c_order(Rank);}
bool memory_layout_is_fortran() const { return memory_indices_layout().value == mem_layout::fortran_order(Rank);}
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
void compute_stride_compact() {
size_t str = 1;
csc_impl(memory_order_.value, str, std::integral_constant());
assert(this->domain().number_of_elements()==str);
}
template
void csc_impl(ull_t order, size_t & str, std::integral_constant) {
size_t u = mem_layout::memory_rank_to_index(order, rank-v);
this->strides_[u] = str;
str *= this->lengths() [u];
csc_impl(order, str, std::integral_constant());
}
void csc_impl(ull_t order,size_t & str, std::integral_constant) {}
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:
typedef map indexmap_type;
typedef typename domain_type::index_value_type indices_type;
typedef const std::ptrdiff_t return_type;
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) {
constexpr size_t p = mem_layout::memory_rank_to_index(traversal_order, rank-v);
#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.memory_indices_layout() == X2.memory_indices_layout())
&& X1.is_contiguous() && X2.is_contiguous()
&& (X1.domain().number_of_elements()==X2.domain().number_of_elements()));
}
}}}//namespace triqs::arrays::indexmaps
#endif