/******************************************************************************* * * 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 namespace triqs { namespace arrays { struct __mem_layout_fortran_order {}; struct __mem_layout_c_order {}; #define C_LAYOUT (triqs::arrays::__mem_layout_c_order()) #define FORTRAN_LAYOUT (triqs::arrays::__mem_layout_fortran_order()) enum class memory_order_type { C, Fortran, Custom }; /* The storage order is given by a permutation P * P[0] : the slowest index, * P[Rank-1] : the fastest index * Example : * 210 : Fortran, the first index is the fastest * 012 : C the last index is the fastest * 120 : storage (i,j,k) is : index j is slowest, then k, then i */ template class memory_layout { memory_order_type order = memory_order_type::C; mini_vector p = utility::no_init_tag{}; public: static const int rank = Rank; explicit memory_layout() { for (int u = 0; u < Rank; ++u) p[u] = u; } memory_layout(__mem_layout_fortran_order) { order = memory_order_type::Fortran; for (int u = 0; u < Rank; ++u) p[u] = Rank - u - 1; } memory_layout(__mem_layout_c_order) : memory_layout() {} // internal use only : no check , we KNOW the order is not C or Fortran template explicit memory_layout(mini_vector v, bool) : p(std::move(v)) { order = memory_order_type::Custom; } // For the user : we find out whether it is C or Fortran template explicit memory_layout(mini_vector v) : p(std::move(v)) { bool c = true, f = true; for (int u = 0; u < Rank; ++u) { c = c && (v[u] == u); f = f && (v[u] == Rank - u - 1); } if (c) return; order = (f ? memory_order_type::Fortran : memory_order_type::Custom); } template explicit memory_layout(int i0, INT... in) : memory_layout(mini_vector{i0, in...}) {} bool operator==(memory_layout const &ml) const { return p == ml.p; } bool operator!=(memory_layout const &ml) const { return !operator==(ml); } int operator[](int u) const { return p[u]; } bool is_c() const { return order == memory_order_type::C; } bool is_fortran() const { return order == memory_order_type::Fortran; } mini_vector get_memory_positions() const { auto r = mini_vector(utility::no_init_tag{}); for (int u = 0; u < Rank; ++u) r[p[u]] = u; return r; } mini_vector get_indices_in_order() const { return p; } friend std::ostream &operator<<(std::ostream &out, memory_layout const &s) { return out << s.p; } }; // ------------------------- functions ------------------------------------- /// Make a memory_layout from the indices template memory_layout make_memory_layout(T... x) { return memory_layout(x...); } /// Make a memory_layout from the strides template memory_layout memory_layout_from_strides(mini_vector const &strides) { mini_vector c; // rely on init to 0 by default of mini_vector for (int i = 0; i < Rank; ++i) for (int j = i + 1; j < Rank; ++j) if (strides[i] > strides[j]) c[i]++; else c[j]++; // we computed the map : index -> memory_rank, which is the inverse map, cf mem_layout return memory_layout{c}; } /// Apply a permutation to the indices template memory_layout transpose(memory_layout const &ml, mini_vector const &perm) { mini_vector res; for (int u = 0; u < R; ++u) res[u] = perm[ml[u]]; return memory_layout{res}; } } } // namespace triqs::arrays