LBANN  0.103.0
LivermoreBigArtificialNeuralNetworkToolkit
tensor_dims_utils.hpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2023, Lawrence Livermore National Security, LLC.
3 // Produced at the Lawrence Livermore National Laboratory.
4 // Written by the LBANN Research Team (B. Van Essen, et al.) listed in
5 // the CONTRIBUTORS file. <lbann-dev@llnl.gov>
6 //
7 // LLNL-CODE-697807.
8 // All rights reserved.
9 //
10 // This file is part of LBANN: Livermore Big Artificial Neural Network
11 // Toolkit. For details, see http://software.llnl.gov/LBANN or
12 // https://github.com/LLNL/LBANN.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "Licensee"); you
15 // may not use this file except in compliance with the License. You may
16 // obtain a copy of the License at:
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
23 // implied. See the License for the specific language governing
24 // permissions and limitations under the license.
26 #ifndef SRC_LAYERS_TRANSFORM_TENSOR_DIMS_UTILS_HPP_INCLUDED
27 #define SRC_LAYERS_TRANSFORM_TENSOR_DIMS_UTILS_HPP_INCLUDED
28 
30 
31 #include <algorithm>
32 #include <utility>
33 #include <vector>
34 
35 // This stuff shouldn't be publicly accessible.
36 namespace lbann {
37 
38 template <typename T, typename Tag>
40 {
41  std::vector<T> m_data;
42 
43 public:
44  using vector_type = std::vector<T>;
45  using value_type = typename vector_type::value_type;
46 
47 public:
48  NamedVector() = default;
49  explicit NamedVector(std::vector<T> const& v) : m_data{v} {}
50  explicit NamedVector(std::vector<T>&& v) : m_data{std::move(v)} {}
51 
52  NamedVector(NamedVector const& other) = default;
53  NamedVector(NamedVector&& other) = default;
54  NamedVector& operator=(NamedVector const& other) = default;
55  NamedVector& operator=(NamedVector&& other) = default;
56 
57  template <typename U, typename UTag>
59  {
60  convert(other, *this);
61  }
62 
63  template <typename U, typename UTag>
65  {
66  convert(other, *this);
67  return *this;
68  }
69 
70  std::vector<T>& get() noexcept { return m_data; }
71  std::vector<T> const& get() const noexcept { return m_data; }
72 
73  // Convenience
74  auto size() const noexcept { return m_data.size(); }
75  void swap(NamedVector& other) { swap(m_data, other.m_data); }
76 };
77 
78 template <typename IndexT>
80 
81 template <typename IndexT>
83 
84 template <typename IndexT>
86 
87 template <typename IndexT>
89 
91 
93 
94 // Conversion functions RowMajor <-> ColMajor
95 
96 // For dimensions, this is a simple reversal.
97 template <typename IndexT>
99 {
100  tgt.get().assign(crbegin(src.get()), crend(src.get()));
101 }
102 
103 template <typename IndexT>
105 {
106  tgt.get().assign(crbegin(src.get()), crend(src.get()));
107 }
108 
109 // For dimensions, this is a simple reversal.
110 template <typename IndexT>
112 {
113  tgt.get().assign(crbegin(src.get()), crend(src.get()));
114 }
115 
116 template <typename IndexT>
118 {
119  tgt.get().assign(crbegin(src.get()), crend(src.get()));
120 }
121 
122 // For permutation arrays, it's a reversal with a complement with
123 // respect to the total number of dimensions.
124 inline void switch_perm_majorness(std::vector<int> const& in,
125  std::vector<int>& out)
126 {
127  int const ndims = static_cast<int>(in.size());
128  out.resize(ndims);
129  std::transform(crbegin(in), crend(in), begin(out), [ndims](int const& a) {
130  return ndims - a - 1;
131  });
132 }
133 
134 inline void convert(RowMajorPerm const& src, ColMajorPerm& tgt)
135 {
136  switch_perm_majorness(src.get(), tgt.get());
137 }
138 
139 inline void convert(ColMajorPerm const& src, RowMajorPerm& tgt)
140 {
141  switch_perm_majorness(src.get(), tgt.get());
142 }
143 
148 template <typename OutT, typename InT>
149 auto vec_convert(std::vector<InT> const& in)
150 {
151  return std::vector<OutT>{cbegin(in), cend(in)};
152 }
153 
155 
157 template <typename IndexT>
158 auto RowMajor(std::vector<IndexT>&& ds)
159 {
160  return RowMajorDims<IndexT>{std::move(ds)};
161 }
162 
163 template <typename IndexT>
164 auto RowMajor(std::vector<IndexT> const& ds)
165 {
166  return RowMajorDims<IndexT>{ds};
167 }
168 
169 template <typename IndexT>
171 {
172  return RowMajorDims<IndexT>(dims);
173 }
174 
175 template <typename IndexT>
177 {
178  return RowMajorDims<IndexT>(dims);
179 }
180 
181 template <typename IndexT>
183 {
184  return RowMajorDims<IndexT>(std::move(dims));
185 }
186 
187 template <typename IndexT>
188 auto ColMajor(std::vector<IndexT>&& ds)
189 {
190  return ColMajorDims<IndexT>{std::move(ds)};
191 }
192 
193 template <typename IndexT>
194 auto ColMajor(std::vector<IndexT> const& ds)
195 {
196  return ColMajorDims<IndexT>{ds};
197 }
198 
199 template <typename IndexT>
201 {
202  return ColMajorDims<IndexT>(dims);
203 }
204 
205 template <typename IndexT>
207 {
208  return ColMajorDims<IndexT>(dims);
209 }
210 
211 template <typename IndexT>
213 {
214  return ColMajorDims<IndexT>(std::move(dims));
215 }
216 
218 
219 
227 template <typename StrideT, typename DimT>
229 {
230  std::vector<DimT> const& dim_vec = dims.get();
231  size_t const ndims = dim_vec.size();
232 
233  std::vector<StrideT> strides;
234  strides.reserve(ndims);
235  strides.push_back(StrideT{1});
236  for (size_t ii = 0UL; ii < ndims - 1; ++ii)
237  strides.push_back(strides[ii] * static_cast<StrideT>(dim_vec[ii]));
238  return ColMajorStrides<StrideT>(strides);
239 }
240 
247 template <typename DimT>
249 {
250  return get_strides_as<DimT>(dims);
251 }
252 
253 // TODO: RowMajorDims impl for get_strides -- not needed for now.
254 
256 
257 
263 template <typename T>
264 bool check_perm_impl(std::vector<T> perm)
265 {
266  size_t const ndims = perm.size();
267  std::sort(begin(perm), end(perm));
268  for (size_t ii = 0; ii < ndims; ++ii)
269  if (static_cast<size_t>(perm[ii]) != ii)
270  return false;
271  return true;
272 }
273 
275 template <typename T>
276 auto invert_perm_impl(std::vector<T> const& perm)
277 {
278  size_t const size = perm.size();
279  std::vector<T> out(size);
280  for (size_t ii = 0; ii < size; ++ii)
281  out[perm[ii]] = ii;
282  return out;
283 }
284 
285 // This does the raw vector permute. The assumption is that "in" and
286 // "perm" are with respect to the same ordering (either row-major or
287 // column-major). output[i] = input[perm[i]]. This is enforced via the
288 // public interfaces below. If perm.size() < in.size(), the remaining
289 // elements in "in" are copied without permutation (e.g.,
290 // permute_impl({1,2,3,4}, {1,0}) -> {2,1,3,4}). This is useful for
291 // the "modes", which might include the non-permutable sample
292 // dimension.
293 template <typename IndexT, typename PermT>
294 auto permute_impl(std::vector<IndexT> const& in, std::vector<PermT> const& perm)
295 {
296  if (perm.size() == 0UL)
297  return in;
298 
299  size_t const ndims = in.size();
300  size_t const nperm = perm.size();
301 
302  LBANN_ASSERT_DEBUG(nperm <= ndims);
303  std::vector<IndexT> out;
304  out.reserve(ndims);
305  for (size_t ii = 0UL; ii < nperm; ++ii)
306  out.push_back(in[perm[ii]]);
307  for (size_t ii = nperm; ii < ndims; ++ii)
308  out.push_back(in[ii]);
309  return out;
310 }
311 
313 
314 
316 inline bool is_valid(RowMajorPerm const& perm)
317 {
318  return perm.size() == 0UL || check_perm_impl(perm.get());
319 }
320 
321 inline bool is_valid(ColMajorPerm const& perm)
322 {
323  return perm.size() == 0UL || check_perm_impl(perm.get());
324 }
325 
327 {
328  return RowMajorPerm{invert_perm_impl(in.get())};
329 }
330 
332 {
333  return ColMajorPerm{invert_perm_impl(in.get())};
334 }
335 
337 
338 
340 template <typename IndexT>
341 auto permute_dims(RowMajorDims<IndexT> const& in, RowMajorPerm const& perm)
342 {
343  return RowMajor(permute_impl(in.get(), perm.get()));
344 }
345 
346 template <typename IndexT>
347 auto permute_dims(ColMajorDims<IndexT> const& in, ColMajorPerm const& perm)
348 {
349  return ColMajor(permute_impl(in.get(), perm.get()));
350 }
351 
353 
354 } // namespace lbann
355 #endif // SRC_LAYERS_TRANSFORM_TENSOR_DIMS_UTILS_HPP_INCLUDED
NamedVector(std::vector< T > const &v)
auto get_strides(ColMajorDims< DimT > const &dims)
Compute packed strides of the given dimensions.
auto permute_impl(std::vector< IndexT > const &in, std::vector< PermT > const &perm)
std::vector< T > m_data
NamedVector(NamedVector< U, UTag > const &other)
#define LBANN_ASSERT_DEBUG(cond)
Definition: exception.hpp:104
NamedVector(std::vector< T > &&v)
std::vector< int > vector_type
typename vector_type::value_type value_type
NamedVector & operator=(NamedVector const &other)=default
auto RowMajor(std::vector< IndexT > &&ds)
std::vector< T > & get() noexcept
NamedVector()=default
auto size() const noexcept
auto invert_perm_impl(std::vector< T > const &perm)
Returns the inverse of the given permutation.
auto vec_convert(std::vector< InT > const &in)
Copy the input vector to a new type.
void switch_perm_majorness(std::vector< int > const &in, std::vector< int > &out)
auto get_strides_as(ColMajorDims< DimT > const &dims)
Compute packed strides of the given dimensions.
RowMajorPerm invert(RowMajorPerm const &in)
bool is_valid(RowMajorPerm const &perm)
void convert(RowMajorDims< IndexT > const &src, ColMajorDims< IndexT > &tgt)
auto ColMajor(std::vector< IndexT > &&ds)
void swap(NamedVector &other)
auto permute_dims(RowMajorDims< IndexT > const &in, RowMajorPerm const &perm)
NamedVector & operator=(NamedVector< U, UTag > const &other)
bool check_perm_impl(std::vector< T > perm)
Checks that the permutation is valid.