TiledArray  0.7.0
elemental.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2016 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Drew Lewis
19  * Department of Chemistry, Virginia Tech
20  *
21  * diagonal_array.h
22  * Dec 1, 2016
23  *
24  */
25 
26 #ifndef TILEDARRAY_CONVERSIONS_TO_ELEMENTAL_H__INCLUDED
27 #define TILEDARRAY_CONVERSIONS_TO_ELEMENTAL_H__INCLUDED
28 
29 #if TILEDARRAY_HAS_ELEMENTAL
30 #if HAVE_EL_H
31 
32 #include <TiledArray/dist_array.h>
33 #include <TiledArray/error.h>
34 #include <TiledArray/tiled_range.h>
35 #include <TiledArray/tensor.h>
36 
37 #include <El.hpp>
38 
39 #include <utility>
40 
41 namespace TiledArray {
42 namespace detail {
43 inline bool uniformly_blocked(TiledRange const &trange){
44  for(auto i = 0ul; i < trange.rank(); ++i){
45  auto const &tr1 = trange.data()[i];
46 
47  auto it = tr1.begin();
48  auto end = --tr1.end(); // 2nd to last since last can be a different size
49 
50  if(it == end){ // only 1 block in this dim
51  break;
52  }
53 
54  // Take first block to define the blocksize
55  auto blocksize = it->second - it->first;
56 
57  // Loop over other blocks (except last one) to compare size.
58  ++it;
59  for(; it != end; ++it){
60  auto size = it->second - it->first;
61  if(size != blocksize){
62  return false;
63  }
64  }
65  }
66 
67  return true;
68 }
69 
70 template <typename Array>
71 El::DistMatrix<typename Array::element_type> matrix_to_el(
72  Array const& A, El::Grid const &g){
73 
74  // Check for matrix and uniform blocking
75  TiledRange const &trange = A.trange();
76  TA_ASSERT(trange.rank() == 2);
77 
78  // Determine matrix total size
79  auto elem_extent = trange.elements_range().extent_data();
80  const auto nrows = elem_extent[0];
81  const auto ncols = elem_extent[1];
82 
83  // Construct elem array, zero it to avoid having to write zero tiles
84  auto el_A = El::DistMatrix<typename Array::element_type>(nrows, ncols, g);
85  El::Zero(el_A);
86 
87  // Loop over all tiles
88  const auto vol = trange.tiles_range().volume();
89  for(auto i = 0ul; i < vol; ++i){
90 
91  // Write local tiles into a queue and allow elemental to do all
92  // communication of elements to the remote nodes.
93  if(!A.is_zero(i) && A.is_local(i)){
94  auto tile = A.find(i).get();
95 
96  auto lo = tile.range().lobound_data();
97  auto up = tile.range().upbound_data();
98 
99  for(auto m = lo[0]; m < up[0]; ++m){
100  for(auto n = lo[1]; n < up[1]; ++n){
101  el_A.QueueUpdate(m,n,tile(m,n));
102  }
103  }
104  }
105  }
106 
107  // Initialize the communication process
108  el_A.ProcessQueues();
109 
110  return el_A;
111 }
112 
113 
114 template<typename T>
115 DistArray<Tensor<T>, DensePolicy> el_to_matrix(
116  El::AbstractDistMatrix<T> const &M, World& world,
117  TiledRange const &trange){
118  TA_ASSERT(trange.rank() == 2);
119  TA_USER_ASSERT(uniformly_blocked(trange), "The output TiledRange must be uniformly blocked.");
120 #if !defined(EL_RELEASE)
121  TA_USER_ASSERT(madness::ThreadPool::size() == 0, "TA::el_to_matrix(): Elemental compiled in Debug mode is not re-entrant," \
122  " can only with MAD_NUM_THREADS=1 (and without TBB). Recompile Elemental in Release mode to use MAD_NUM_THREADS>1 or to use TBB.");
123 #endif
124 
125  // Determine block size
126  auto const& tr1_row = trange.data()[0];
127  auto const& tr1_col = trange.data()[1];
128  auto row_bs = tr1_row.begin()->second - tr1_row.begin()->first;
129  auto col_bs = tr1_col.begin()->second - tr1_col.begin()->first;
130 
131  // Copy the unknown matrix distribution into a block based distribution
132  El::DistMatrix<T, El::MC, El::MR, El::BLOCK> Mb(M.Height(), M.Width(), M.Grid(), row_bs, col_bs);
133  Mb = M;
134 
135  DistArray<Tensor<T>, DensePolicy> A(world, trange);
136 
137  // Loop over the tiles in the trange
138  const auto vol = trange.tiles_range().volume();
139  for(auto i = 0ul; i < vol; ++i){
140  // Make the tiled range for tile i
141  auto range = trange.make_tile_range(i);
142  auto lo = range.lobound_data();
143 
144  auto task = [&](Range rng){
145  auto lo = rng.lobound_data();
146  auto up = rng.upbound_data();
147  auto tile = Tensor<T>(rng, 0.0);
148 
149  // Copy by element
150  for(auto m = lo[0]; m != up[0]; ++m){
151  for(auto n = lo[1]; n != up[1]; ++n){
152  tile(m,n) = Mb.GetLocal(Mb.LocalRow(m),Mb.LocalCol(n));
153  }
154  }
155 
156  return tile;
157  };
158 
159  // Send local writes to task
160  if(Mb.IsLocal(lo[0], lo[1])){
161  auto tile_future = A.world().taskq.add(task, range);
162  A.set(i, tile_future);
163  }
164  }
165  A.world().gop.fence();
166 
167  return A;
168 }
169 
170 } // namespace detail
171 
174 
177 
178 class TensorFlattening {
179  private:
180  std::pair<std::vector<int>, std::vector<int>> flattening_;
181 
182  public:
184  TensorFlattening() :
185  flattening_(std::make_pair(std::vector<int>{0}, std::vector<int>{1}))
186  {}
187 
188  TensorFlattening(
189  std::pair<std::vector<int>, std::vector<int>> const& flattening) :
190  flattening_(flattening)
191  {}
192 
193  TensorFlattening(std::vector<int> const& left,
194  std::vector<int> const &right) :
195  flattening_(std::make_pair(left, right))
196  {}
197 
198  std::vector<int> const &left_dims() const {return flattening_.first; }
199  std::vector<int> const &right_dims() const {return flattening_.second; }
200 };
201 
203 
207 template <typename Array>
208 El::DistMatrix<typename Array::element_type> array_to_el(
209  Array const& A, El::Grid const &g = El::Grid::Default(),
210  TensorFlattening const &tf = TensorFlattening()){
211 
212  if(A.trange().rank() == 2){
213  // Flattening is not needed for the matrix case.
214  return detail::matrix_to_el(A, g);
215  } else {
216  TA_USER_ASSERT(false, "array_to_el currently only supports converting matrices, higher order tensor conversions will be supported at a latter date.");
217  }
218 }
219 
221 
226 template<typename T>
227 DistArray<Tensor<T>, DensePolicy> el_to_array(
228  El::AbstractDistMatrix<T> const &M, World& world,
229  TiledRange const &trange,
230  TensorFlattening const &tf = TensorFlattening()){
231 
232  if(trange.rank() == 2){
233  // Flattening is not needed for the matrix case.
234  return detail::el_to_matrix(M, world, trange);
235  } else {
236  TA_USER_ASSERT(false, "el_to_array currently only supports converting matrices, higher order tensor conversions will be supported at a latter date.");
237  }
238 }
239 
240 } // namespace TiledArray
241 
242 #endif // HAVE_EL_H
243 #endif // TILEDARRAY_HAS_ELEMENTAL
244 
245 #endif // TILEDARRAY_CONVERSIONS_TO_ELEMENTAL_H__INCLUDED
STL namespace.
size_t size(const DistArray< Tile, Policy > &a)
Definition: utils.h:49
constexpr std::size_t size(T(&)[N])
Array size accessor.
Definition: utility.h:47
#define TA_ASSERT(a)
Definition: error.h:107
#define TA_USER_ASSERT(a, m)
Definition: error.h:123
DistArray< Tile, Policy > Array