Molecular Dynamics Simulation  1.0
ArrayUtils.h
Go to the documentation of this file.
1 
7 #pragma once
8 
9 #include <omp.h>
10 
11 #include <algorithm>
12 #include <array>
13 #include <cmath>
14 #include <list>
15 #include <map>
16 #include <numeric>
17 #include <set>
18 #include <sstream>
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <vector>
22 
29 namespace ArrayUtils {
30 
31 // specialize a type for all of the STL containers.
38 namespace is_container_impl {
43 template <typename T>
44 struct is_container : std::false_type {};
50 template <typename T, std::size_t N>
51 struct is_container<std::array<T, N>> : std::true_type {};
56 template <typename... Args>
57 struct is_container<std::vector<Args...>> : std::true_type {};
62 template <typename... Args>
63 struct is_container<std::list<Args...>> : std::true_type {};
68 template <typename... Args>
69 struct is_container<std::set<Args...>> : std::true_type {};
74 template <typename... Args>
75 struct is_container<std::unordered_set<Args...>> : std::true_type {};
76 } // namespace is_container_impl
77 
82 template <typename T>
83 struct is_container {
85 };
86 
96 template <class Container>
97 [[nodiscard]] std::string to_string(const Container& container, const std::string& delimiter = ", ",
98  const std::array<std::string, 2>& surround = {"[", "]"}) {
99  auto iter = std::cbegin(container);
100  const auto end = std::cend(container);
101  if (iter == end) {
102  return surround[0] + surround[1];
103  }
104  std::ostringstream strStream;
105  strStream << surround[0] << *iter;
106  for (++iter; iter != end; ++iter) {
107  strStream << delimiter << *iter;
108  }
109  strStream << surround[1];
110  return strStream.str();
111 }
112 
126 template <class Container, class F>
127 inline Container elementWisePairOp(const Container& lhs, const Container& rhs, F binaryFunction) {
128  Container ret = lhs;
129  auto retIter = std::begin(ret);
130  auto lhsIter = std::cbegin(lhs);
131  const auto lhsEnd = std::cend(lhs);
132  auto rhsIter = std::cbegin(rhs);
133  const auto rhsEnd = std::cend(rhs);
134 
135  for (; lhsIter != lhsEnd and rhsIter != rhsEnd; ++lhsIter, ++rhsIter, ++retIter) {
136  *retIter = binaryFunction(*lhsIter, *rhsIter);
137  }
138 
139  return ret;
140 }
141 
153 template <class Scalar, class Container, class F>
154 inline Container elementWiseScalarOp(const Scalar& lhs, const Container& rhs, F binaryFunction) {
155  Container ret = rhs;
156  auto retIter = std::begin(ret);
157  auto rhsIter = std::cbegin(rhs);
158  const auto rhsEnd = std::cend(rhs);
159 
160  for (; rhsIter != rhsEnd; ++rhsIter, ++retIter) {
161  *retIter = binaryFunction(lhs, *rhsIter);
162  }
163 
164  return ret;
165 }
166 
173 template <class Container>
174 auto L2Norm(const Container& c) {
175  return std::sqrt(std::accumulate(std::cbegin(c), std::cend(c), 0.0, [](auto a, auto b) { return a + b * b; }));
176 }
177 
182 template <>
183 inline auto L2Norm<std::array<double, 3>>(const std::array<double, 3>& c) {
184  return std::sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
185 }
186 
193 template <class Container>
194 auto L2NormSquared(const Container& c) {
195  return std::accumulate(std::cbegin(c), std::cend(c), 0.0, [](auto a, auto b) { return a + b * b; });
196 }
197 
202 template <>
203 inline auto L2NormSquared<std::array<double, 3>>(const std::array<double, 3>& c) {
204  return c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
205 }
206 
207 } // namespace ArrayUtils
208 
219 template <class Container>
220 std::enable_if_t<ArrayUtils::is_container<Container>::value, std::ostream&> operator<<(std::ostream& os, const Container& container) {
221  os << ArrayUtils::to_string(container);
222  return os;
223 }
224 
232 template <class Container>
233 std::enable_if_t<ArrayUtils::is_container<Container>::value, Container> operator+(const Container& lhs, const Container& rhs) {
234  return ArrayUtils::elementWisePairOp(lhs, rhs, std::plus<>());
235 }
236 
244 template <class Container>
245 std::enable_if_t<ArrayUtils::is_container<Container>::value, Container> operator-(const Container& lhs, const Container& rhs) {
246  return ArrayUtils::elementWisePairOp(lhs, rhs, std::minus<>());
247 }
248 
256 template <class Container>
257 std::enable_if_t<ArrayUtils::is_container<Container>::value, Container> operator*(const Container& lhs, const Container& rhs) {
258  return ArrayUtils::elementWisePairOp(lhs, rhs, std::multiplies<>());
259 }
260 
268 template <class Scalar, class Container>
269 std::enable_if_t<ArrayUtils::is_container<Container>::value, Container> operator*(const Scalar& lhs, const Container& rhs) {
270  return ArrayUtils::elementWiseScalarOp(lhs, rhs, std::multiplies<>());
271 }
272 
281 template <class Container>
282 std::enable_if_t<ArrayUtils::is_container<Container>::value, bool> operator==(const Container& lhs, const Container& rhs) {
283  if (lhs.size() != rhs.size()) {
284  return false;
285  }
286 
287  auto lhsIter = std::cbegin(lhs);
288  const auto lhsEnd = std::cend(lhs);
289  auto rhsIter = std::cbegin(rhs);
290 
291  for (; lhsIter != lhsEnd; ++lhsIter, ++rhsIter) {
292  if (*lhsIter != *rhs) {
293  return false;
294  }
295  }
296  return true;
297 }
std::enable_if_t< ArrayUtils::is_container< Container >::value, Container > operator-(const Container &lhs, const Container &rhs)
Definition: ArrayUtils.h:245
std::enable_if_t< ArrayUtils::is_container< Container >::value, std::ostream & > operator<<(std::ostream &os, const Container &container)
Definition: ArrayUtils.h:220
std::enable_if_t< ArrayUtils::is_container< Container >::value, bool > operator==(const Container &lhs, const Container &rhs)
Definition: ArrayUtils.h:282
std::enable_if_t< ArrayUtils::is_container< Container >::value, Container > operator*(const Container &lhs, const Container &rhs)
Definition: ArrayUtils.h:257
std::enable_if_t< ArrayUtils::is_container< Container >::value, Container > operator+(const Container &lhs, const Container &rhs)
Definition: ArrayUtils.h:233
Collection of utility functions and operators for iterable data containers.
Definition: ArrayUtils.h:29
auto L2NormSquared(const Container &c)
Definition: ArrayUtils.h:194
std::string to_string(const Container &container, const std::string &delimiter=", ", const std::array< std::string, 2 > &surround={"[", "]"})
Definition: ArrayUtils.h:97
auto L2Norm(const Container &c)
Definition: ArrayUtils.h:174
Container elementWiseScalarOp(const Scalar &lhs, const Container &rhs, F binaryFunction)
Definition: ArrayUtils.h:154
Container elementWisePairOp(const Container &lhs, const Container &rhs, F binaryFunction)
Definition: ArrayUtils.h:127
static constexpr bool const value
Definition: ArrayUtils.h:84