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 <type_traits>
43#include <vector>
44
45namespace Utils {
46
47template <typename T, std::size_t N> class Vector : public Array<T, N> {
48 using Base = Array<T, N>;
49
50public:
51 using Base::Base;
52 using Array<T, N>::at;
53 using Array<T, N>::operator[];
54 using Array<T, N>::front;
55 using Array<T, N>::back;
56 using Array<T, N>::data;
57 using Array<T, N>::begin;
58 using Array<T, N>::cbegin;
59 using Array<T, N>::end;
60 using Array<T, N>::cend;
61 using Array<T, N>::empty;
62 using Array<T, N>::size;
63 using Array<T, N>::max_size;
64 using Array<T, N>::fill;
65 using Array<T, N>::broadcast;
66 Vector() = default;
67 Vector(Vector const &) = default;
68 Vector &operator=(Vector const &) = default;
69
70 void swap(Vector &rhs) { std::swap_ranges(begin(), end(), rhs.begin()); }
71
72private:
73 constexpr void copy_init(T const *first, T const *last) {
74 auto it = begin();
75 while (first != last) {
76 *it++ = *first++;
77 }
78 }
79
80public:
81 template <class Range>
82 explicit Vector(Range const &rng) : Vector(std::begin(rng), std::end(rng)) {}
83 explicit constexpr Vector(T const (&v)[N]) : Base() {
84 copy_init(std::begin(v), std::end(v));
85 }
86
87 constexpr Vector(std::initializer_list<T> v) : Base() {
88 if (N != v.size()) {
89 throw std::length_error(
90 "Construction of Vector from Container of wrong length.");
91 }
92
93 copy_init(v.begin(), v.end());
94 }
95
96 template <typename InputIterator>
97 Vector(InputIterator first, InputIterator last) : Base() {
98 if (std::distance(first, last) == N) {
99 std::copy_n(first, N, begin());
100 } else {
101 throw std::length_error(
102 "Construction of Vector from Container of wrong length.");
103 }
104 }
105
106 /**
107 * @brief Create a vector that has all entries set to
108 * one value.
109 */
110 static Vector<T, N> broadcast(T const &s) {
111 Vector<T, N> ret;
112 std::fill(ret.begin(), ret.end(), s);
113
114 return ret;
115 }
116
117 std::vector<T> as_vector() const { return std::vector<T>(begin(), end()); }
118
119 operator std::vector<T>() const { return as_vector(); }
120
121 template <class U> explicit operator Vector<U, N>() const {
122 Vector<U, N> ret;
123
124 std::transform(begin(), end(), ret.begin(),
125 [](auto e) { return static_cast<U>(e); });
126
127 return ret;
128 }
129
130 T norm2() const { return (*this) * (*this); }
131 T norm() const { return std::sqrt(norm2()); }
132
133 /*
134 * @brief Normalize the vector.
135 *
136 * Normalize the vector by its length,
137 * if not zero, otherwise the vector is unchanged.
138 */
139
141 auto const l = norm();
142 if (l > T(0)) {
143 for (std::size_t i = 0; i < N; i++)
144 this->operator[](i) /= l;
145 }
146
147 return *this;
148 }
149
150 Vector normalized() const { return (*this) / (*this).norm(); }
151};
152
153template <class T> using Vector3 = Vector<T, 3>;
154
155template <std::size_t N> using VectorXd = Vector<double, N>;
161
162template <std::size_t N> using VectorXf = Vector<float, N>;
164
165template <std::size_t N> using VectorXi = Vector<int, N>;
167
168namespace detail {
169template <std::size_t N, typename T, typename U, typename Op>
170auto binary_op(Vector<T, N> const &a, Vector<U, N> const &b, Op op) {
171 using std::declval;
172
173 using R = decltype(op(declval<T>(), declval<U>()));
174 Vector<R, N> ret;
175
176 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(ret),
177 op);
178
179 return ret;
180}
181
182template <std::size_t N, typename T, typename Op>
183Vector<T, N> &binary_op_assign(Vector<T, N> &a, Vector<T, N> const &b, Op op) {
184 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(a), op);
185 return a;
186}
187
188template <std::size_t N, typename T, typename Op>
189constexpr bool all_of(Vector<T, N> const &a, Vector<T, N> const &b, Op op) {
190 for (unsigned int i = 0; i < N; i++) {
191 /* Short circuit */
192 if (!static_cast<bool>(op(a[i], b[i]))) {
193 return false;
194 }
195 }
196
197 return true;
198}
199} // namespace detail
200
201template <std::size_t N, typename T>
202constexpr bool operator<(Vector<T, N> const &a, Vector<T, N> const &b) {
203 return detail::all_of(a, b, std::less<T>());
204}
205
206template <std::size_t N, typename T>
207constexpr bool operator>(Vector<T, N> const &a, Vector<T, N> const &b) {
208 return detail::all_of(a, b, std::greater<T>());
209}
210
211template <std::size_t N, typename T>
212constexpr bool operator<=(Vector<T, N> const &a, Vector<T, N> const &b) {
213 return detail::all_of(a, b, std::less_equal<T>());
214}
215
216template <std::size_t N, typename T>
217constexpr bool operator>=(Vector<T, N> const &a, Vector<T, N> const &b) {
218 return detail::all_of(a, b, std::greater_equal<T>());
219}
220
221template <std::size_t N, typename T>
222constexpr bool operator==(Vector<T, N> const &a, Vector<T, N> const &b) {
223 return detail::all_of(a, b, std::equal_to<T>());
224}
225
226template <std::size_t N, typename T>
227constexpr bool operator!=(Vector<T, N> const &a, Vector<T, N> const &b) {
228 return not(a == b);
229}
230
231template <std::size_t N, typename T, typename U>
232auto operator+(Vector<T, N> const &a, Vector<U, N> const &b) {
233 return detail::binary_op(a, b, std::plus<>());
234}
235
236template <std::size_t N, typename T>
238 return detail::binary_op_assign(a, b, std::plus<T>());
239}
240
241template <std::size_t N, typename T, typename U>
242auto operator-(Vector<T, N> const &a, Vector<U, N> const &b) {
243 return detail::binary_op(a, b, std::minus<>());
244}
245
246template <std::size_t N, typename T>
248 Vector<T, N> ret;
249
250 std::transform(std::begin(a), std::end(a), std::begin(ret),
251 [](T const &v) { return -v; });
252
253 return ret;
254}
255
256template <std::size_t N, typename T>
258 return detail::binary_op_assign(a, b, std::minus<T>());
259}
260
261/* Scalar multiplication */
262template <std::size_t N, typename T, class U,
263 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
264auto operator*(U const &a, Vector<T, N> const &b) {
265 using R = decltype(a * std::declval<T>());
266 Vector<R, N> ret;
267
268 std::transform(std::begin(b), std::end(b), std::begin(ret),
269 [a](T const &val) { return a * val; });
270
271 return ret;
272}
273
274template <std::size_t N, typename T, class U,
275 std::enable_if_t<std::is_arithmetic_v<U>, bool> = true>
276auto operator*(Vector<T, N> const &b, U const &a) {
277 using R = decltype(std::declval<T>() * a);
278 Vector<R, N> ret;
279
280 std::transform(std::begin(b), std::end(b), std::begin(ret),
281 [a](T const &val) { return a * val; });
282
283 return ret;
284}
285
286template <std::size_t N, typename T>
288 std::transform(std::begin(b), std::end(b), std::begin(b),
289 [a](T const &val) { return a * val; });
290 return b;
291}
292
293/* Scalar division */
294template <std::size_t N, typename T>
295Vector<T, N> operator/(Vector<T, N> const &a, T const &b) {
296 Vector<T, N> ret;
297
298 std::transform(std::begin(a), std::end(a), ret.begin(),
299 [b](T const &val) { return val / b; });
300 return ret;
301}
302
303template <std::size_t N, typename T>
305 std::transform(std::begin(a), std::end(a), std::begin(a),
306 [b](T const &val) { return val / b; });
307 return a;
308}
309
310namespace detail {
311template <class T> struct is_vector : std::false_type {};
312template <class T, std::size_t N>
313struct is_vector<Vector<T, N>> : std::true_type {};
314} // namespace detail
315
316/* Scalar product */
317template <std::size_t N, typename T, class U,
318 class = std::enable_if_t<not(detail::is_vector<T>::value or
319 detail::is_vector<U>::value)>>
320auto operator*(Vector<T, N> const &a, Vector<U, N> const &b) {
321 using std::declval;
322 using R = decltype(declval<T>() * declval<U>());
323
324 return std::inner_product(std::begin(a), std::end(a), std::begin(b), R{});
325}
326
327template <
328 std::size_t N, typename T, class U,
329 class = std::enable_if_t<std::is_integral_v<T> and std::is_integral_v<U>>>
330auto operator%(Vector<T, N> const &a, Vector<U, N> const &b) {
331 using std::declval;
332 using R = decltype(declval<T>() % declval<U>());
333 Vector<R, N> ret;
334
335 std::transform(std::begin(a), std::end(a), std::begin(b), std::begin(ret),
336 [](T const &ai, U const &bi) { return ai % bi; });
337
338 return ret;
339}
340
341/* Componentwise square root */
342template <std::size_t N, typename T> Vector<T, N> sqrt(Vector<T, N> const &a) {
343 using std::sqrt;
344 Vector<T, N> ret;
345
346 std::transform(std::begin(a), std::end(a), ret.begin(),
347 [](T const &v) { return sqrt(v); });
348
349 return ret;
350}
351
352template <class T>
354 return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
355 a[0] * b[1] - a[1] * b[0]};
356}
357
358// Product of array elements.
359template <class T, std::size_t N> T product(Vector<T, N> const &v) {
360 return std::accumulate(v.cbegin(), v.cend(), T{1}, std::multiplies<T>());
361}
362
363template <class T, class U, std::size_t N>
365 using std::declval;
366 using R = decltype(declval<T>() * declval<U>());
367
368 Vector<R, N> ret;
369 std::transform(a.cbegin(), a.cend(), b.cbegin(), ret.begin(),
370 [](auto ai, auto bi) { return ai * bi; });
371
372 return ret;
373}
374
375// specializations for when one or both operands is a scalar depending on
376// compile time features (e.g. when PARTICLE_ANISOTROPY is not enabled)
377template <class T, class U, std::size_t N,
378 class = std::enable_if_t<not(detail::is_vector<T>::value)>>
379auto hadamard_product(T const &a, Vector<U, N> const &b) {
380 using std::declval;
381 using R = decltype(declval<T>() * declval<U>());
382
383 Vector<R, N> ret = a * b;
384
385 return ret;
386}
387
388template <class T, class U, std::size_t N,
389 class = std::enable_if_t<not(detail::is_vector<U>::value)>>
390auto hadamard_product(Vector<T, N> const &a, U const &b) {
391 using std::declval;
392 using R = decltype(declval<T>() * declval<U>());
393
394 Vector<R, N> ret = a * b;
395
396 return ret;
397}
398
399template <typename T, typename U,
400 class = std::enable_if_t<not(detail::is_vector<T>::value or
401 detail::is_vector<U>::value)>>
402auto hadamard_product(T const &a, U const &b) {
403 return a * b;
404}
405
406template <class T, class U, std::size_t N>
408 using std::declval;
409 using R = decltype(declval<T>() * declval<U>());
410
411 Vector<R, N> ret;
412 std::transform(a.cbegin(), a.cend(), b.cbegin(), ret.begin(),
413 [](auto ai, auto bi) { return ai / bi; });
414
415 return ret;
416}
417
418// specializations for when one or both operands is a scalar depending on
419// compile time features (e.g. when PARTICLE_ANISOTROPY is not enabled)
420template <class T, class U, std::size_t N,
421 class = std::enable_if_t<not(detail::is_vector<U>::value)>>
422auto hadamard_division(Vector<T, N> const &a, U const &b) {
423 using std::declval;
424 using R = decltype(declval<T>() * declval<U>());
425
426 Vector<R, N> ret = a / b;
427
428 return ret;
429}
430
431template <class T, class U, std::size_t N,
432 class = std::enable_if_t<not(detail::is_vector<T>::value)>>
433auto hadamard_division(T const &a, Vector<U, N> const &b) {
434 using std::declval;
435 using R = decltype(declval<T>() * declval<U>());
436
437 Vector<R, N> ret;
438 std::transform(std::begin(b), std::end(b), ret.begin(),
439 [a](T const &bi) { return a / bi; });
440 return ret;
441}
442
443template <typename T, typename U,
444 class = std::enable_if_t<not(detail::is_vector<T>::value or
445 detail::is_vector<U>::value)>>
446auto hadamard_division(T const &a, U const &b) {
447 return a / b;
448}
449
450template <typename T> Vector<T, 3> unit_vector(unsigned int i) {
451 if (i == 0)
452 return {T{1}, T{0}, T{0}};
453 if (i == 1)
454 return {T{0}, T{1}, T{0}};
455 if (i == 2)
456 return {T{0}, T{0}, T{1}};
457 throw std::domain_error("coordinate out of range");
458}
459
460/**
461 * @brief Meta function to turns a Vector<1, T> into T.
462 */
463template <typename T> struct decay_to_scalar {};
464template <typename T, std::size_t N> struct decay_to_scalar<Vector<T, N>> {
466};
467
468template <typename T> struct decay_to_scalar<Vector<T, 1>> {
469 using type = T;
470};
471
472template <std::size_t I, class T, std::size_t N>
473struct tuple_element<I, Vector<T, N>> {
474 using type = T;
475};
476
477template <class T, std::size_t N>
478struct tuple_size<Vector<T, N>> : std::integral_constant<std::size_t, N> {};
479
480template <std::size_t I, class T, std::size_t N>
481auto get(Vector<T, N> const &a) -> std::enable_if_t<(I < N), const T &> {
482 return a[I];
483}
484} // namespace Utils
485namespace boost {
486namespace qvm {
487
488template <class T, std::size_t N> struct vec_traits<::Utils::Vector<T, N>> {
489
490 static constexpr std::size_t dim = N;
491 using scalar_type = T;
492
493 template <std::size_t I>
494 static constexpr inline scalar_type &write_element(::Utils::Vector<T, N> &v) {
495 return v[I];
496 }
497
498 template <std::size_t I>
499 static constexpr inline scalar_type
501 return v[I];
502 }
503
504 static inline scalar_type read_element_idx(std::size_t i,
505 ::Utils::Vector<T, N> const &v) {
506 return v[i];
507 }
508 static inline scalar_type &write_element_idx(std::size_t i,
510 return v[i];
511 }
512};
513
514template <typename T> struct deduce_vec<Utils::Vector<T, 3>, 3> {
515 using type = typename Utils::Vector<T, 3>;
516};
517
518} // namespace qvm
519} // namespace boost
520
523UTILS_ARRAY_BOOST_CLASS(Utils::Vector, N, object_serializable)
525
526#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
float N[3]
T norm2() const
Definition Vector.hpp:130
Vector & operator=(Vector const &)=default
Vector & normalize()
Definition Vector.hpp:140
static Vector< T, N > broadcast(T const &s)
Create a vector that has all entries set to one value.
Definition Vector.hpp:110
T norm() const
Definition Vector.hpp:131
void swap(Vector &rhs)
Definition Vector.hpp:70
Vector normalized() const
Definition Vector.hpp:150
std::vector< T > as_vector() const
Definition Vector.hpp:117
Vector(InputIterator first, InputIterator last)
Definition Vector.hpp:97
constexpr Vector(std::initializer_list< T > v)
Definition Vector.hpp:87
constexpr Vector(T const (&v)[N])
Definition Vector.hpp:83
Vector(Range const &rng)
Definition Vector.hpp:82
Vector()=default
Vector(Vector const &)=default
auto operator+(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:232
Vector< T, 3 > unit_vector(unsigned int i)
Definition Vector.hpp:450
T product(Vector< T, N > const &v)
Definition Vector.hpp:359
Vector< T, N > & operator-=(Vector< T, N > &a, Vector< T, N > const &b)
Definition Vector.hpp:257
Vector< T, N > & operator/=(Vector< T, N > &a, T const &b)
Definition Vector.hpp:304
Vector< T, N > & operator+=(Vector< T, N > &a, Vector< T, N > const &b)
Definition Vector.hpp:237
constexpr bool operator<(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:202
constexpr bool operator>=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:217
constexpr bool operator>(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:207
Vector< T, 3 > vector_product(Vector< T, 3 > const &a, Vector< T, 3 > const &b)
Definition Vector.hpp:353
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:295
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:222
constexpr bool operator!=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:227
Vector< T, N > sqrt(Vector< T, N > const &a)
Definition Vector.hpp:342
constexpr bool operator<=(Vector< T, N > const &a, Vector< T, N > const &b)
Definition Vector.hpp:212
auto operator%(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:330
auto hadamard_division(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:407
auto hadamard_product(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:364
Vector< T, N > & operator*=(Vector< T, N > &b, T const &a)
Definition Vector.hpp:287
auto operator-(Vector< T, N > const &a, Vector< U, N > const &b)
Definition Vector.hpp:242
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:463
static constexpr scalar_type read_element(::Utils::Vector< T, N > const &v)
Definition Vector.hpp:500
static scalar_type & write_element_idx(std::size_t i, ::Utils::Vector< T, N > &v)
Definition Vector.hpp:508
static constexpr scalar_type & write_element(::Utils::Vector< T, N > &v)
Definition Vector.hpp:494
static scalar_type read_element_idx(std::size_t i, ::Utils::Vector< T, N > const &v)
Definition Vector.hpp:504