/******************************************************************************* * * 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;} // basic construction map (memory_layout const & ml = memory_layout(traversal_order)):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 const & Lengths, strides_type const & strides, std::ptrdiff_t start_shift ): mydomain(Lengths), strides_(strides), start_shift_(start_shift), memory_order_ (memory_layout_from_strides(strides_)) {} /// 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 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()) {} // regular type map (map const & C) = default; map (map && C) = default; map & operator = (map const & m) = default; map & operator = (map && m) = default; /// 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 can not 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