TiledArray  0.7.0
foreach.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2015 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  * Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * foreach.h
22  * Apr 15, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_CONVERSIONS_FOREACH_H__INCLUDED
27 #define TILEDARRAY_CONVERSIONS_FOREACH_H__INCLUDED
28 
29 #include <TiledArray/type_traits.h>
30 
32 namespace Eigen {
33  template <typename> class aligned_allocator;
34 } // namespace Eigen
35 
36 namespace TiledArray {
37 
39  template <typename, typename> class DistArray;
40  template <typename, typename> class Tensor;
41  class DensePolicy;
42  class SparsePolicy;
43 
45 
46  namespace detail {
47 
48  namespace {
49 
50  template <bool inplace, typename Result = void>
51  struct void_op_helper;
52 
53  template <typename Result>
54  struct void_op_helper<false, Result> {
55  template <typename Op, typename Arg, typename... Args>
56  Result operator()(Op&&op, Arg&& arg, Args&&... args) {
57  Result result;
58  op(result, std::forward<Arg>(arg), std::forward<Args>(args)...);
59  return result;
60  }
61  };
62  template <typename Result>
63  struct void_op_helper<true, Result> {
64  template <typename Op, typename Arg, typename... Args>
65  decltype(auto) operator()(Op&&op, Arg&& arg, Args&&... args) {
66  op(std::forward<Arg>(arg), std::forward<Args>(args)...);
67  return arg;
68  }
69  };
70 
71  template <bool inplace, typename Result = void>
72  struct nonvoid_op_helper;
73 
74  template <typename Result>
75  struct nonvoid_op_helper<false, Result> {
76  template <typename Op, typename OpResult,
77  typename Arg, typename... Args>
78  Result operator()(Op&&op, OpResult& op_result,
79  Arg&& arg, Args&&... args) {
80  Result result;
81  op_result = op(result, std::forward<Arg>(arg), std::forward<Args>(args)...);
82  return result;
83  }
84  };
85  template <typename Result>
86  struct nonvoid_op_helper<true, Result> {
87  template <typename Op, typename OpResult,
88  typename Arg, typename... Args>
89  std::decay_t<Arg> operator()(Op&&op, OpResult& op_result,
90  Arg&& arg, Args&&... args) {
91  op_result = op(std::forward<Arg>(arg), std::forward<Args>(args)...);
92  return arg;
93  }
94  };
95 
96  template <typename Tile, typename Policy>
97  inline bool compare_trange(const DistArray<Tile, Policy>& array1) {
98  return true;
99  }
100 
101  template <typename Tile1, typename Tile2, typename Policy, typename... Arrays>
102  inline bool compare_trange(const DistArray<Tile1, Policy>& array1,
103  const DistArray<Tile2, Policy>& array2, const Arrays&... arrays) {
104  return(array1.trange() == array2.trange()
105  && compare_trange(array1, arrays...));
106  }
107 
108  inline bool is_zero_intersection(const std::initializer_list<bool>& is_zero_list ) {
109  return std::any_of(is_zero_list.begin(), is_zero_list.end(),
110  [](const bool val) -> bool {return val;});
111  }
112  inline bool is_zero_union(const std::initializer_list<bool>& is_zero_list ) {
113  return std::all_of(is_zero_list.begin(), is_zero_list.end(),
114  [](const bool val) -> bool {return val;});
115  }
116 
117  template <typename I, typename A>
118  Future<typename A::value_type> get_sparse_tile(const I& index, const A& array) {
119  return (!array.is_zero(index)? array.find(index)
120  : Future<typename A::value_type>(typename A::value_type()));
121  }
122  template <typename I, typename A>
123  Future<typename A::value_type> get_sparse_tile(const I& index, A& array) {
124  return (!array.is_zero(index)? array.find(index)
125  : Future<typename A::value_type>(typename A::value_type()));
126  }
127 
128  }
129 
131 
133  template <bool inplace = false, typename Op,
134  typename ResultTile, typename ArgTile, typename... ArgTiles>
135  inline DistArray<ResultTile, DensePolicy> foreach ( Op && op,
136  const_if_t<not inplace, DistArray<ArgTile, DensePolicy>>& arg,
137  const DistArray<ArgTiles, DensePolicy>&... args) {
138 
139  TA_USER_ASSERT(compare_trange(arg, args...), "Tiled ranges of args must match");
140 
141  typedef DistArray<ArgTile, DensePolicy> arg_array_type;
142  typedef DistArray<ResultTile, DensePolicy> result_array_type;
143 
144  World& world = arg.world();
145 
146  // Make an empty result array
147  result_array_type result(world, arg.trange(), arg.pmap());
148 
149  // Construct the task function for making result tiles.
151  const ArgTiles&... arg_tiles) {
152  void_op_helper<inplace, typename result_array_type::value_type> op_caller;
153  return op_caller(std::forward<Op>(op), arg_tile, arg_tiles...);
154  };
155 
156  // Iterate over local tiles of arg
157  for (auto index: *(arg.pmap())) {
158  // Spawn a task to evaluate the tile
159  Future<typename result_array_type::value_type> tile =
160  world.taskq.add(task, arg.find(index), args.find(index)...);
161 
162  // Store result tile
163  result.set(index, tile);
164  }
165 
166  return result;
167  }
168 
170 
172  template <bool inplace = false, typename Op,
173  typename ResultTile, typename ArgTile, typename... ArgTiles>
174  inline DistArray<ResultTile, SparsePolicy> foreach (Op&& op, const ShapeReductionMethod shape_reduction,
175  const_if_t<not inplace, DistArray<ArgTile, SparsePolicy>>& arg,
176  const DistArray<ArgTiles, SparsePolicy>&... args) {
177 
178  TA_USER_ASSERT(detail::compare_trange(arg, args...), "Tiled ranges of args must match");
179 
180  typedef DistArray<ArgTile, SparsePolicy> arg_array_type;
181  typedef DistArray<ResultTile, SparsePolicy> result_array_type;
182 
183  typedef typename arg_array_type::value_type arg_value_type;
184  typedef typename result_array_type::value_type result_value_type;
185  typedef typename arg_array_type::size_type size_type;
186  typedef typename arg_array_type::shape_type shape_type;
187  typedef std::pair<size_type, Future<result_value_type>> datum_type;
188 
189  // Create a vector to hold local tiles
190  std::vector<datum_type> tiles;
191  tiles.reserve(arg.pmap()->size());
192 
193  // Construct a tensor to hold updated tile norms for the result shape.
194  TiledArray::Tensor<typename shape_type::value_type,
196  tile_norms(arg.trange().tiles_range(), 0);
197 
198  // Construct the task function used to construct the result tiles.
199  madness::AtomicInt counter; counter = 0;
200  int task_count = 0;
201  auto task = [&op,&counter,&tile_norms](const size_type index,
203  const ArgTiles&... arg_tiles) -> result_value_type {
204  nonvoid_op_helper<inplace, result_value_type> op_caller;
205  auto result_tile = op_caller(std::forward<Op>(op), tile_norms[index],
206  arg_tile, arg_tiles...);
207  ++counter;
208  return std::move(result_tile);
209  };
210 
211  World& world = arg.world();
212 
213  switch (shape_reduction) {
215  // Get local tile index iterator
216  for(auto index: *(arg.pmap())) {
217  if(is_zero_intersection({arg.is_zero(index), args.is_zero(index)...}))
218  continue;
219  auto result_tile = world.taskq.add(task, index, arg.find(index),
220  args.find(index)...);
221  ++task_count;
222  tiles.emplace_back(index, std::move(result_tile));
223  }
224  break;
226  // Get local tile index iterator
227  for(auto index: *(arg.pmap())) {
228  if(is_zero_union({arg.is_zero(index), args.is_zero(index)...}))
229  continue;
230  auto result_tile = world.taskq.add(task, index, detail::get_sparse_tile(index, arg),
231  detail::get_sparse_tile(index, args)...);
232  ++task_count;
233  tiles.emplace_back(index, std::move(result_tile));
234  }
235  break;
236  default:
237  TA_ASSERT(false);
238  break;
239  }
240 
241  // Wait for tile norm data to be collected.
242  if(task_count > 0)
243  world.await([&counter,task_count] () -> bool { return counter == task_count; });
244 
245  // Construct the new array
246  result_array_type result(world, arg.trange(),
247  shape_type(world, tile_norms, arg.trange()), arg.pmap());
248  for(typename std::vector<datum_type>::const_iterator it = tiles.begin(); it != tiles.end(); ++it) {
249  const size_type index = it->first;
250  if(! result.is_zero(index))
251  result.set(it->first, it->second);
252  }
253 
254  return result;
255  }
256 
257  } // namespace TiledArray::detail
258 
260 
285  template <typename ResultTile, typename ArgTile, typename Op,
286  typename = typename std::enable_if<!std::is_same<ResultTile,ArgTile>::value>::type>
287  inline DistArray<ResultTile, DensePolicy>
288  foreach(const DistArray<ArgTile, DensePolicy>& arg, Op&& op) {
289  return detail::foreach<false, Op, ResultTile, ArgTile>(std::forward<Op>(op), arg);
290  }
291 
293 
296  template <typename Tile, typename Op>
297  inline DistArray<Tile, DensePolicy>
298  foreach(const DistArray<Tile, DensePolicy>& arg, Op&& op) {
299  return detail::foreach<false, Op, Tile, Tile>(std::forward<Op>(op), arg);
300  }
301 
303 
332  template <typename Tile, typename Op,
333  typename = typename std::enable_if<! TiledArray::detail::is_array<typename std::decay<Op>::type>::value>::type>
334  inline void
335  foreach_inplace(DistArray<Tile, DensePolicy>& arg, Op&& op, bool fence = true) {
336  // The tile data is being modified in place, which means we may need to
337  // fence to ensure no other threads are using the data.
338  if(fence)
339  arg.world().gop.fence();
340 
341  arg = detail::foreach<true, Op, Tile, Tile>(std::forward<Op>(op), arg);
342  }
343 
345 
379  template <typename ResultTile, typename ArgTile, typename Op,
380  typename = typename std::enable_if<!std::is_same<ResultTile,ArgTile>::value>::type>
381  inline DistArray<ResultTile, SparsePolicy>
382  foreach(const DistArray<ArgTile, SparsePolicy> arg, Op&& op) {
383  return detail::foreach<false, Op, ResultTile, ArgTile>(std::forward<Op>(op), ShapeReductionMethod::Intersect, arg);
384  }
385 
387 
390  template <typename Tile, typename Op>
391  inline DistArray<Tile, SparsePolicy>
392  foreach(const DistArray<Tile, SparsePolicy>& arg, Op&& op) {
393  return detail::foreach<false, Op, Tile, Tile>(std::forward<Op>(op), ShapeReductionMethod::Intersect, arg);
394  }
395 
396 
398 
436  template <typename Tile, typename Op,
437  typename = typename std::enable_if<! TiledArray::detail::is_array<typename std::decay<Op>::type>::value>::type>
438  inline void
439  foreach_inplace(DistArray<Tile, SparsePolicy>& arg, Op&& op, bool fence = true) {
440 
441  // The tile data is being modified in place, which means we may need to
442  // fence to ensure no other threads are using the data.
443  if(fence)
444  arg.world().gop.fence();
445 
446  // Set the arg with the new array
447  arg = detail::foreach<true, Op, Tile, Tile>(std::forward<Op>(op), ShapeReductionMethod::Intersect, arg);
448  }
449 
452  template <typename ResultTile, typename LeftTile, typename RightTile, typename Op,
453  typename = typename std::enable_if<!std::is_same<ResultTile, LeftTile>::value>::type>
454  inline DistArray<ResultTile, DensePolicy>
455  foreach(const DistArray<LeftTile, DensePolicy>& left,
456  const DistArray<RightTile, DensePolicy>& right, Op&& op) {
457  return detail::foreach<false, Op, ResultTile, LeftTile, RightTile>(std::forward<Op>(op),
458  left, right);
459  }
460 
463  template <typename LeftTile, typename RightTile, typename Op>
464  inline DistArray<LeftTile, DensePolicy>
465  foreach(const DistArray<LeftTile, DensePolicy>& left,
466  const DistArray<RightTile, DensePolicy>& right, Op&& op) {
467  return detail::foreach<false, Op, LeftTile, LeftTile, RightTile>(std::forward<Op>(op),
468  left, right);
469  }
470 
472  template <typename LeftTile, typename RightTile, typename Op>
473  inline void
475  const DistArray<RightTile, DensePolicy>& right, Op&& op, bool fence = true) {
476  // The tile data is being modified in place, which means we may need to
477  // fence to ensure no other threads are using the data.
478  if(fence)
479  left.world().gop.fence();
480 
481  left = detail::foreach<true, Op, LeftTile, LeftTile, RightTile>(std::forward<Op>(op),
482  left, right);
483  }
484 
487  template <typename ResultTile, typename LeftTile, typename RightTile, typename Op,
488  typename = typename std::enable_if<!std::is_same<ResultTile, LeftTile>::value>::type>
489  inline DistArray<ResultTile, SparsePolicy>
491  const DistArray<RightTile, SparsePolicy>& right, Op&& op,
492  const ShapeReductionMethod shape_reduction = ShapeReductionMethod::Intersect) {
493  return detail::foreach<false, Op, ResultTile, LeftTile, RightTile>(std::forward<Op>(op),
494  shape_reduction, left, right);
495  }
496 
499  template <typename LeftTile, typename RightTile, typename Op>
500  inline DistArray<LeftTile, SparsePolicy>
502  const DistArray<RightTile, SparsePolicy>& right, Op&& op,
503  const ShapeReductionMethod shape_reduction = ShapeReductionMethod::Intersect) {
504  return detail::foreach<false, Op, LeftTile, LeftTile, RightTile>(std::forward<Op>(op),
505  shape_reduction, left, right);
506  }
507 
509  template <typename LeftTile, typename RightTile, typename Op>
510  inline void
512  const DistArray<RightTile, SparsePolicy>& right, Op&& op,
514  bool fence = true) {
515 
516  // The tile data is being modified in place, which means we may need to
517  // fence to ensure no other threads are using the data.
518  if(fence)
519  left.world().gop.fence();
520 
521  // Set the arg with the new array
522  left = detail::foreach<true, Op, LeftTile, LeftTile, RightTile>(std::forward<Op>(op),
523  shape_reduction, left, right);
524  }
525 
526 } // namespace TiledArray
527 
528 #endif // TILEDARRAY_CONVERSIONS_TRUNCATE_H__INCLUDED
Future< value_type > find(const Index &i) const
Find local or remote tile.
Definition: dist_array.h:324
void foreach_inplace(DistArray< Tile, DensePolicy > &arg, Op &&op, bool fence=true)
Modify each tile of a dense Array.
Definition: foreach.h:335
An N-dimensional tensor object.
Definition: foreach.h:40
typename std::conditional< B, const T, T >::type const_if_t
prepends const to T if B is true
Definition: type_traits.h:653
Forward declarations.
Definition: foreach.h:32
bool is_zero(const Index &i) const
Check for zero tiles.
Definition: dist_array.h:723
Forward declarations.
Definition: clone.h:32
#define TA_ASSERT(a)
Definition: error.h:107
World & world() const
World accessor.
Definition: dist_array.h:633
ShapeReductionMethod
Definition: foreach.h:44
#define TA_USER_ASSERT(a, m)
Definition: error.h:123