ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
Vector.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#ifndef SRC_UTILS_INCLUDE_UTILS_VECTOR_HPP
20#define SRC_UTILS_INCLUDE_UTILS_VECTOR_HPP
21
22/**
23 * @file
24 *
25 * @brief Vector implementation and trait types
26 * for boost qvm interoperability.
27 */
28
29#include <boost/qvm/deduce_vec.hpp>
30#include <boost/qvm/vec_traits.hpp>
31
32#include "utils/Array.hpp"
33
34#include <algorithm>
35#include <cassert>
36#include <cmath>
37#include <cstddef>
38#include <functional>
39#include <initializer_list>
40#include <iterator>
41#include <numeric>
42#include <span>
43#include <type_traits>
44#include <vector>
45
46namespace Utils {
47
48template <typename T, std::size_t N> class Vector : public Array<T, N> {
49 using Base = Array<T, N>;
50
51public:
52 using Base::Base;
53 using Array<T, N>::at;
54 using Array<T, N>::operator[];
55 using Array<T, N>::front;
56 using Array<T, N>::back;
57 using Array<T, N>::data;
58 using Array<T, N>::begin;
59 using Array<T, N>::cbegin;
60 using Array<T, N>::end;
61 using Array<T, N>::cend;
62 using Array<T, N>::empty;
63 using Array<T, N>::size;
64 using Array<T, N>::max_size;
65 using Array<T, N>::fill;
66 using Array<T, N>::broadcast;
67 Vector() = default;
68 Vector(Vector const &) = default;
69 Vector &operator=(Vector const &) = default;
70
71 void swap(Vector &rhs) { std::swap_ranges(begin(), end(), rhs.begin()); }
72
73private:
74 constexpr void copy_init(T const *first, T const *last) {
75 auto it = begin();
76 while (first != last) {
77 *it++ = *first++;
78 }
79 }
80
81public:
82 template <class Range>
83 explicit constexpr Vector(Range const &rng)
84 : Vector(std::begin(rng), std::end(rng)) {}
85 explicit constexpr Vector(T const (&v)[N]) : Base() {
86 copy_init(std::begin(v), std::end(v));
87 }
88
89 constexpr Vector(std::initializer_list<T> v) : Base() {
90 if (N != v.size()) {
91 throw std::length_error(
92 "Construction of Vector from Container of wrong length.");
93 }
94
95 copy_init(v.begin(), v.end());
96 }
97
98 template <typename InputIterator>
99 Vector(InputIterator first, InputIterator last) : Base() {
100 if (std::distance(first, last) == N) {
101 std::copy_n(first, N, begin());
102 } else {
103 throw std::length_error(
104 "Construction of Vector from Container of wrong length.");
105 }
106 }
107
108 /** @brief Create a vector that has all entries set to the same value. */
109 DEVICE_QUALIFIER static constexpr Vector<T, N>
110 broadcast(typename Base::value_type const &value) {
111 Vector<T, N> ret{};
112 for (std::size_t i = 0u; i != N; ++i) {
113 ret[i] = value;
114 }
115 return ret;
116 }
117
118 std::vector<T> as_vector() const { return std::vector<T>(begin(), end()); }
119
120 operator std::vector<T>() const { return as_vector(); }
121
122 constexpr std::span<T, N> as_span() const {
123 return std::span<T, N>(const_cast<T *>(begin()), size());
124 }
125
126 constexpr operator std::span<T, N>() const { return as_span(); }
127
128 template <class U> explicit operator Vector<U, N>() const {
129 Vector<U, N> ret;
130
131 std::transform(begin(), end(), ret.begin(),
132 [](auto const &e) { return static_cast<U>(e); });
133
134 return ret;
135 }
136
137 T norm2() const { return (*this) * (*this); }
138 T norm() const { return std::sqrt(norm2()); }
139
140 /*
141 * @brief Normalize the vector.
142 *
143 * Normalize the vector by its length,
144 * if not zero, otherwise the vector is unchanged.
145 */
146
148 auto const l = norm();
149 if (l > T(0)) {
150 for (std::size_t i = 0u; i < N; ++i)
151 this->operator[](i) /= l;
152 }
153
154 return *this;
155 }
156
157 Vector normalized() const { return (*this) / (*this).norm(); }
158};
159
160template <class T> using Vector3 = Vector<T, 3>;
161
162template <std::size_t N> using VectorXd = Vector<double, N>;
168
169template <std::size_t N> using VectorXf = Vector<float, N>;
171
172template <std::size_t N> using VectorXi = Vector<int, N>;
174
175namespace detail {
176template <std::size_t N, typename T, typename U, typename Op>
177auto binary_op(Vector<T, N> const &a, Vector<U, N> const &b, Op op) {
178 using std::declval;
179
180 using R = decltype(op(declval<T>(), declval<U>()));
181 Vector<R, N> ret;
182
183 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(ret),
184 op);
185
186 return ret;
187}
188
189template <std::size_t N, typename T, typename Op>
190Vector<T, N> &binary_op_assign(Vector<T, N> &a, Vector<T, N> const &b, Op op) {
191 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(a), op);
192 return a;
193}
194
195template <std::size_t N, typename T, typename Op>
196constexpr bool all_of(Vector<T, N> const &a, Vector<T, N> const &b, Op op) {
197 for (unsigned int i = 0; i < N; i++) {
198 /* Short circuit */
199 if (!static_cast<bool>(op(a[i], b[i]))) {
200 return false;
201 }
202 }
203
204 return true;
205}
206} // namespace detail
207
208template <std::size_t N, typename T>
209constexpr bool operator<(Vector<T, N> const &a, Vector<T, N> const &b) {
210 return detail::all_of(a, b, std::less<T>());
211}
212
213template <std::size_t N, typename T>
214constexpr bool operator>(Vector<T, N> const &a, Vector<T, N> const &b) {
215 return detail::all_of(a, b, std::greater<T>());
216}
217
218template <std::size_t N, typename T>
219constexpr bool operator<=(Vector<T, N> const &a, Vector<T, N> const &b) {
220 return detail::all_of(a, b, std::less_equal<T>());
221}
222
223template <std::size_t N, typename T>
224constexpr bool operator>=(Vector<T, N> const &a, Vector<T, N> const &b) {
225 return detail::all_of(a, b, std::greater_equal<T>());
226}
227
228template <std::size_t N, typename T>
229constexpr bool operator==(Vector<T, N> const &a, Vector<T, N> const &b) {
230 return detail::all_of(a, b, std::equal_to<T>());
231}
232
233template <std::size_t N, typename T>
234constexpr bool operator!=(Vector<T, N> const &a, Vector<T, N> const &b) {
235 return not(a == b);
236}
237
238template <std::size_t N, typename T, typename U>
239auto operator+(Vector<T, N> const &a, Vector<U, N> const &b) {
240 return detail::binary_op(a, b, std::plus<>());
241}
242
243template <std::size_t N, typename T>
245 return detail::binary_op_assign(a, b, std::plus<T>());
246}
247
248template <std::size_t N, typename T, typename U>
249auto operator-(Vector<T, N> const &a, Vector<U, N> const &b) {
250 return detail::binary_op(a, b, std::minus<>());
251}
252
253template <std::size_t N, typename T>
255 Vector<T, N> ret;
256
257 std::transform(std::begin(a), std::end(a), std::begin(ret), std::negate<T>());
258
259 return ret;
260}
261
262template <std::size_t N, typename T>
264 return detail::binary_op_assign(a, b, std::minus<T>());
265}
266
267/* Scalar multiplication */
268template <std::size_t N, typename T, class U,
269 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
270auto operator*(U const &a, Vector<T, N> const &b) {
271 using R = decltype(a * std::declval<T>());
272 Vector<R, N> ret;
273
274 std::transform(std::begin(b), std::end(b), std::begin(ret),
275 [a](T const &val) { return a * val; });
276
277 return ret;
278}
279
280template <std::size_t N, typename T, class U,
281 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
282auto operator*(Vector<T, N> const &b, U const &a) {
283 using R = decltype(std::declval<T>() * a);
284 Vector<R, N> ret;
285
286 std::transform(std::begin(b), std::end(b), std::begin(ret),
287 [a](T const &val) { return a * val; });
288
289 return ret;
290}
291
292template <std::size_t N, typename T>
294 std::transform(std::begin(b), std::end(b), std::begin(b),
295 [a](T const &val) { return a * val; });
296 return b;
297}
298
299/* Scalar division */
300template <std::size_t N, typename T>
301Vector<T, N> operator/(Vector<T, N> const &a, T const &b) {
302 Vector<T, N> ret;
303
304 std::transform(std::begin(a), std::end(a), ret.begin(),
305 [b](T const &val) { return val / b; });
306 return ret;
307}
308
309template <std::size_t N, typename T>
310Vector<T, N> operator/(T const &a, Vector<T, N> const &b) {
311 Vector<T, N> ret;
312
313 std::transform(std::begin(b), std::end(b), ret.begin(),
314 [a](T const &val) { return a / val; });
315 return ret;
316}
317
318template <std::size_t N, typename T>
320 std::transform(std::begin(a), std::end(a), std::begin(a),
321 [b](T const &val) { return val / b; });
322 return a;
323}
324
325namespace detail {
326template <class T> struct is_vector : std::false_type {};
327template <class T, std::size_t N>
328struct is_vector<Vector<T, N>> : std::true_type {};
329} // namespace detail
330
331/* Scalar product */
332template <std::size_t N, typename T, class U,
333 class = std::enable_if_t<not(detail::is_vector<T>::value or
334 detail::is_vector<U>::value)>>
335auto operator*(Vector<T, N> const &a, Vector<U, N> const &b) {
336 using std::declval;
337 using R = decltype(declval<T>() * declval<U>());
338
339 return std::inner_product(std::begin(a), std::end(a), std::begin(b), R{});
340}
341
342template <
343 std::size_t N, typename T, class U,
344 class = std::enable_if_t<std::is_integral_v<T> and std::is_integral_v<U>>>
345auto operator%(Vector<T, N> const &a, Vector<U, N> const &b) {
346 using std::declval;
347 using R = decltype(declval<T>() % declval<U>());
348 Vector<R, N> ret;
349
350 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(ret),
351 [](T const &ai, U const &bi) { return ai % bi; });
352
353 return ret;
354}
355
356/* Componentwise square root */
357template <std::size_t N, typename T> Vector<T, N> sqrt(Vector<T, N> const &a) {
358 using std::sqrt;
359 Vector<T, N> ret;
360
361 std::transform(std::begin(a), std::end(a), ret.begin(),
362 [](T const &v) { return sqrt(v); });
363
364 return ret;
365}
366
367template <class T>
369 return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
370 a[0] * b[1] - a[1] * b[0]};
371}
372
373// Product of array elements.
374template <class T, std::size_t N> T product(Vector<T, N> const &v) {
375 return std::accumulate(v.cbegin(), v.cend(), T{1}, std::multiplies<T>());
376}
377
378template <class T, class U, std::size_t N>
380 using std::declval;
381 using R = decltype(declval<T>() * declval<U>());
382
383 Vector<R, N> ret;
384 std::transform(a.cbegin(), a.cend(), b.cbegin(), ret.begin(),
385 [](auto const &ai, auto const &bi) { return ai * bi; });
386
387 return ret;
388}
389
390// specializations for when one or both operands is a scalar depending on
391// compile time features (e.g. when PARTICLE_ANISOTROPY is not enabled)
392template <class T, class U, std::size_t N,
393 class = std::enable_if_t<not(detail::is_vector<T>::value)>>
394auto hadamard_product(T const &a, Vector<U, N> const &b) {
395 using std::declval;
396 using R = decltype(declval<T>() * declval<U>());
397
398 Vector<R, N> ret = a * b;
399
400 return ret;
401}
402
403template <class T, class U, std::size_t N,
404 class = std::enable_if_t<not(detail::is_vector<U>::value)>>
405auto hadamard_product(Vector<T, N> const &a, U const &b) {
406 using std::declval;
407 using R = decltype(declval<T>() * declval<U>());
408
409 Vector<R, N> ret = a * b;
410
411 return ret;
412}
413
414template <typename T, typename U,
415 class = std::enable_if_t<not(detail::is_vector<T>::value or
416 detail::is_vector<U>::value)>>
417auto hadamard_product(T const &a, U const &b) {
418 return a * b;
419}
420
421template <class T, class U, std::size_t N>
423 using std::declval;
424 using R = decltype(declval<T>() * declval<U>());
425
426 Vector<R, N> ret;
427 std::transform(a.cbegin(), a.cend(), b.cbegin(), ret.begin(),
428 [](auto const &ai, auto const &bi) { return ai / bi; });
429
430 return ret;
431}
432
433// specializations for when one or both operands is a scalar depending on
434// compile time features (e.g. when PARTICLE_ANISOTROPY is not enabled)
435template <class T, class U, std::size_t N,
436 class = std::enable_if_t<not(detail::is_vector<U>::value)>>
437auto hadamard_division(Vector<T, N> const &a, U const &b) {
438 using std::declval;
439 using R = decltype(declval<T>() * declval<U>());
440
441 Vector<R, N> ret = a / b;
442
443 return ret;
444}
445
446template <class T, class U, std::size_t N,
447 class = std::enable_if_t<not(detail::is_vector<T>::value)>>
448auto hadamard_division(T const &a, Vector<U, N> const &b) {
449 using std::declval;
450 using R = decltype(declval<T>() * declval<U>());
451
452 Vector<R, N> ret;
453 std::transform(std::begin(b), std::end(b), ret.begin(),
454 [a](T const &bi) { return a / bi; });
455 return ret;
456}
457
458template <typename T, typename U,
459 class = std::enable_if_t<not(detail::is_vector<T>::value or
460 detail::is_vector<U>::value)>>
461auto hadamard_division(T const &a, U const &b) {
462 return a / b;
463}
464
465template <typename T> Vector<T, 3> unit_vector(unsigned int i) {
466 if (i == 0u)
467 return {T{1}, T{0}, T{0}};
468 if (i == 1u)
469 return {T{0}, T{1}, T{0}};
470 if (i == 2u)
471 return {T{0}, T{0}, T{1}};
472 throw std::domain_error("coordinate out of range");
473}
474
475/**
476 * @brief Meta function to turns a Vector<1, T> into T.
477 */
478template <typename T> struct decay_to_scalar {};
479template <typename T, std::size_t N> struct decay_to_scalar<Vector<T, N>> {
481};
482
483template <typename T> struct decay_to_scalar<Vector<T, 1>> {
484 using type = T;
485};
486
487template <std::size_t I, class T, std::size_t N>
488struct tuple_element<I, Vector<T, N>> {
489 using type = T;
490};
491
492template <class T, std::size_t N>
493struct tuple_size<Vector<T, N>> : std::integral_constant<std::size_t, N> {};
494
495template <std::size_t I, class T, std::size_t N>
496auto get(Vector<T, N> const &a) -> std::enable_if_t<(I < N), const T &> {
497 return a[I];
498}
499} // namespace Utils
500namespace boost {
501namespace qvm {
502
503template <class T, std::size_t N> struct vec_traits<::Utils::Vector<T, N>> {
504
505 static constexpr std::size_t dim = N;
506 using scalar_type = T;
507
508 template <std::size_t I>
509 static constexpr inline scalar_type &write_element(::Utils::Vector<T, N> &v) {
510 return v[I];
511 }
512
513 template <std::size_t I>
514 static constexpr inline scalar_type
516 return v[I];
517 }
518
519 static inline scalar_type read_element_idx(std::size_t i,
520 ::Utils::Vector<T, N> const &v) {
521 return v[i];
522 }
523 static inline scalar_type &write_element_idx(std::size_t i,
525 return v[i];
526 }
527};
528
529template <typename T> struct deduce_vec<Utils::Vector<T, 3>, 3> {
530 using type = typename Utils::Vector<T, 3>;
531};
532
533} // namespace qvm
534} // namespace boost
535
538UTILS_ARRAY_BOOST_CLASS(Utils::Vector, N, object_serializable)
540
541#endif
Array implementation with CUDA support.
#define UTILS_ARRAY_BOOST_MPI_T(Container, N)
Mark array types as MPI data types.
Definition array.hpp:50
#define UTILS_ARRAY_BOOST_BIT_S(Container, N)
Mark array types as MPI bitwise serializable.
Definition array.hpp:63
#define UTILS_ARRAY_BOOST_CLASS(Container, N, ImplementationLevel)
Redefinition of BOOST_CLASS_IMPLEMENTATION for array types.
Definition array.hpp:78
#define UTILS_ARRAY_BOOST_TRACK(Container, N, TrackingLevel)
Redefinition of BOOST_CLASS_TRACKING for array types.
Definition array.hpp:97
T norm2() const
Definition Vector.hpp:137
Vector & operator=(Vector const &)=default
Vector & normalize()
Definition Vector.hpp:147
T norm() const
Definition Vector.hpp:138
constexpr Vector(Range const &rng)
Definition Vector.hpp:83
void swap(Vector &rhs)
Definition Vector.hpp:71
Vector normalized() const
Definition Vector.hpp:157
std::vector< T > as_vector() const
Definition Vector.hpp:118
Vector(InputIterator first, InputIterator last)
Definition Vector.hpp:99
constexpr Vector(std::initializer_list< T > v)
Definition Vector.hpp:89
constexpr Vector(T const (&v)[N])
Definition Vector.hpp:85
constexpr std::span< T, N > as_span() const
Definition Vector.hpp:122
Vector()=default
Vector(Vector const &)=default
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value)
Create a vector that has all entries set to the same value.
Definition Vector.hpp:110
#define DEVICE_QUALIFIER
auto operator+(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:239
Vector< T, 3 > unit_vector(unsigned int i)
Definition Vector.hpp:465
T product(Vector< T, N > const &v)
Definition Vector.hpp:374
Vector< T, N > & operator-=(Vector< T, N > &a, Vector< T, N > const &b)
Definition Vector.hpp:263
Vector< T, N > & operator/=(Vector< T, N > &a, T const &b)
Definition Vector.hpp:319
Vector< T, N > & operator+=(Vector< T, N > &a, Vector< T, N > const &b)
Definition Vector.hpp:244
constexpr bool operator<(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:209
constexpr bool operator>=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:224
constexpr bool operator>(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:214
Vector< T, 3 > vector_product(Vector< T, 3 > const &a, Vector< T, 3 > const &b)
Definition Vector.hpp:368
auto get(Array< T, N > const &a) -> std::enable_if_t<(I< N), const T & >
Definition Array.hpp:214
Vector< T, N > operator/(Vector< T, N > const &a, T const &b)
Definition Vector.hpp:301
Quaternion< T > operator*(const U &b, const Quaternion< T > &a)
Product quaternion and arithmetic type.
constexpr bool operator==(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:229
constexpr bool operator!=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:234
Vector< T, N > sqrt(Vector< T, N > const &a)
Definition Vector.hpp:357
constexpr bool operator<=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:219
auto operator%(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:345
auto hadamard_division(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:422
auto hadamard_product(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:379
Vector< T, N > & operator*=(Vector< T, N > &b, T const &a)
Definition Vector.hpp:293
auto operator-(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:249
DEVICE_QUALIFIER constexpr reference at(size_type i)
Definition Array.hpp:86
DEVICE_QUALIFIER constexpr bool empty() const noexcept
Definition Array.hpp:152
DEVICE_QUALIFIER constexpr reference back()
Definition Array.hpp:114
DEVICE_QUALIFIER constexpr pointer data() noexcept
Definition Array.hpp:120
DEVICE_QUALIFIER constexpr size_type max_size() const noexcept
Definition Array.hpp:156
DEVICE_QUALIFIER constexpr iterator begin() noexcept
Definition Array.hpp:128
DEVICE_QUALIFIER constexpr const_iterator cbegin() const noexcept
Definition Array.hpp:136
DEVICE_QUALIFIER constexpr const_iterator cend() const noexcept
Definition Array.hpp:148
DEVICE_QUALIFIER constexpr size_type size() const noexcept
Definition Array.hpp:154
DEVICE_QUALIFIER constexpr reference front()
Definition Array.hpp:110
DEVICE_QUALIFIER constexpr iterator end() noexcept
Definition Array.hpp:140
DEVICE_QUALIFIER void fill(const value_type &value)
Definition Array.hpp:158
Meta function to turns a Vector<1, T> into T.
Definition Vector.hpp:478
static constexpr scalar_type read_element(::Utils::Vector< T, N > const &v)
Definition Vector.hpp:515
static scalar_type & write_element_idx(std::size_t i, ::Utils::Vector< T, N > &v)
Definition Vector.hpp:523
static constexpr scalar_type & write_element(::Utils::Vector< T, N > &v)
Definition Vector.hpp:509
static scalar_type read_element_idx(std::size_t i, ::Utils::Vector< T, N > const &v)
Definition Vector.hpp:519