TiledArray  0.7.0
diagonal_array.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  * Nov 30, 2016
23  *
24  */
25 
26 #ifndef TILEDARRAY_SPECIALARRAYS_DIAGONAL_ARRAY_H__INCLUDED
27 #define TILEDARRAY_SPECIALARRAYS_DIAGONAL_ARRAY_H__INCLUDED
28 
29 #include <TiledArray/dist_array.h>
30 #include <TiledArray/range.h>
31 #include <TiledArray/tensor.h>
32 #include <TiledArray/tiled_range.h>
33 
34 #include <vector>
35 
36 namespace TiledArray {
37 namespace detail {
38 
39 // Function that returns a range containing the diagonal elements in the tile
40 inline Range diagonal_range(Range const &rng) {
41  auto lo = rng.lobound();
42  auto up = rng.upbound();
43 
44  // Determine the largest lower index and the smallest upper index
45  auto max_low = *std::max_element(std::begin(lo), std::end(lo));
46  auto min_up = *std::min_element(std::begin(up), std::end(up));
47 
48  // If the max small elem is less than the min large elem then a diagonal
49  // elem is in this tile;
50  if (max_low < min_up) {
51  return Range({max_low}, {min_up});
52  } else {
53  return Range();
54  }
55 }
56 
57 template <typename T>
58 Tensor<float> diagonal_shape(TiledRange const &trange, T val) {
59  Tensor<float> shape(trange.tiles_range(), 0.0);
60 
61  auto ext = trange.elements_range().extent();
62  auto min_dim_len = *std::min_element(std::begin(ext), std::end(ext));
63 
64  auto ndim = trange.rank();
65  auto diag_elem = 0ul;
66  // the diagonal elements will never be larger than the length of the
67  // shortest dimension
68  while(diag_elem < min_dim_len){
69  // Get the tile index corresponding to the current diagonal_elem
70  auto tile_idx = trange.element_to_tile(std::vector<int>(ndim, diag_elem));
71  auto tile_range = trange.make_tile_range(tile_idx);
72 
73  // Compute the range of diagonal elements in the tile
74  auto d_range = diagonal_range(tile_range);
75 
76  // Since each diag elem has the same value the norm of the tile is
77  // \sqrt{\sum_{diag} val^2} = \sqrt{ndiags * val^2}
78  float t_norm = std::sqrt(val * val * d_range.volume());
79  shape(tile_idx) = t_norm;
80 
81  // Update diag_elem to the next elem not in this tile
82  diag_elem = d_range.upbound_data()[0];
83  }
84 
85  return shape;
86 }
87 
88 // Actually do all the work of writing the diagonal tiles
89 template<typename Array, typename T>
90 void write_tiles_to_array(Array &A, T val){
91  auto const &trange = A.trange();
92  const auto ndims = trange.rank();
93 
94  // Task to create each tile
95  auto tile_task = [val, &trange, ndims](unsigned long ord){
96  auto rng = trange.make_tile_range(ord);
97 
98  // Compute range of diagonal elements in the tile
99  auto diags = detail::diagonal_range(rng);
100 
101  Tensor<T> tile(rng, 0.0);
102 
103  if (diags.volume() > 0) { // If the tile has diagonal elems
104 
105  // Loop over the elements and write val into them
106  auto diag_lo = diags.lobound_data()[0];
107  auto diag_hi = diags.upbound_data()[0];
108  for (auto elem = diag_lo; elem < diag_hi; ++elem) {
109  tile(std::vector<int>(ndims, elem)) = val;
110  }
111  }
112 
113  return tile;
114  };
115 
116  // SparsePolicy arrays incur a small overhead by looping over all ordinals,
117  // Until proven to be a problem we will just keep it.
118  const auto vol = trange.tiles_range().volume();
119  for (auto ord = 0ul; ord < vol; ++ord) {
120  if (A.is_local(ord) && !A.is_zero(ord)) {
121  auto tile_future = A.world().taskq.add(tile_task, ord);
122  A.set(ord, tile_future);
123  }
124  }
125 }
126 
127 } // namespace detail
128 
129 
132 
136 
137 template <typename T>
139  TiledRange const &trange,
140  T val = 1) {
141  // Init the array
142  DistArray<Tensor<T>, DensePolicy> A(world, trange);
143 
145 
146  world.gop.fence();
147  return A;
148 }
149 
152 
156 
157 template <typename T>
159  TiledRange const &trange,
160  T val = 1) {
161 
162  // Compute shape and init the Array
163  auto shape_norm = detail::diagonal_shape(trange, val);
164  SparseShape<float> shape(shape_norm, trange);
165  DistArray<Tensor<T>, SparsePolicy> A(world, trange, shape);
166 
168 
169  world.gop.fence();
170  return A;
171 }
172 
173 template <typename T, typename Policy>
174 DistArray<Tensor<T>,
175  std::enable_if_t<std::is_same<Policy, DensePolicy>::value, Policy>
176 >
177 diagonal_array(World &world, TiledRange const &trange, T val = 1) {
178  return dense_diagonal_array<T>(world, trange, val);
179 }
180 
181 template <typename T, typename Policy>
182 DistArray<Tensor<T>,
183  std::enable_if_t<std::is_same<Policy, SparsePolicy>::value, Policy>
184 >
185 diagonal_array(World &world, TiledRange const &trange, T val = 1) {
186  return sparse_diagonal_array<T>(world, trange, val);
187 }
188 
189 } // namespace TiledArray
190 
191 #endif // TILEDARRAY_SPECIALARRAYS_DIAGONAL_ARRAY_H__INCLUDED
A (hyperrectangular) interval on , space of integer n-indices.
Definition: range.h:39
DistArray< Tensor< T >, SparsePolicy > sparse_diagonal_array(World &world, TiledRange const &trange, T val=1)
size_array lobound() const
Range lower bound accessor.
Definition: range.h:555
std::size_t rank() const
The rank accessor.
Definition: tiled_range.h:253
std::enable_if< detail::is_input_iterator< InIter >::value >::type set(const Index &i, InIter first)
Set a tile and fill it using a sequence.
Definition: dist_array.h:348
An N-dimensional tensor object.
Definition: foreach.h:40
Tensor< float > diagonal_shape(TiledRange const &trange, T val)
const trange_type & trange() const
Tiled range accessor.
Definition: dist_array.h:547
Range diagonal_range(Range const &rng)
Arbitrary sparse shape.
Definition: sparse_shape.h:55
bool is_zero(const Index &i) const
Check for zero tiles.
Definition: dist_array.h:723
DistArray< Tensor< T >, DensePolicy > dense_diagonal_array(World &world, TiledRange const &trange, T val=1)
range_type make_tile_range(const size_type &i) const
Construct a range for the tile indexed by the given ordinal index.
Definition: tiled_range.h:165
const range_type & tiles_range() const
Access the tile range.
Definition: tiled_range.h:122
Forward declarations.
Definition: clone.h:32
World & world() const
World accessor.
Definition: dist_array.h:633
DistArray< Tensor< T >, std::enable_if_t< std::is_same< Policy, DensePolicy >::value, Policy >> diagonal_array(World &world, TiledRange const &trange, T val=1)
bool is_local(const Index &i) const
Check if the tile at index i is stored locally.
Definition: dist_array.h:702
Range data of a tiled array.
Definition: tiled_range.h:31
size_array upbound() const
Range upper bound accessor.
Definition: range.h:577
extent_type extent() const
Range extent accessor.
Definition: range.h:601
std::enable_if<! std::is_integral< Index >::value, typename range_type::index >::type element_to_tile(const Index &index) const
Convert an element index to a tile index.
Definition: tiled_range.h:240
const range_type & elements_range() const
Access the element range.
Definition: tiled_range.h:137
void write_tiles_to_array(Array &A, T val)