Firefly 3.1.0
Standalone library for vector calculations
Loading...
Searching...
No Matches
vector.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cassert>
6#include <cmath>
7#include <complex>
8#include <cstddef>
9#include <initializer_list>
10#include <iomanip>
11#include <numeric>
12#include <sstream>
13#include <stdexcept>
14#include <type_traits>
15
16namespace firefly {
17
29template <typename T1, typename T2>
30struct common_type : std::common_type<T1, T2> {};
31
41template <typename T1, typename T2>
42struct common_type<T1, std::complex<T2>> {
44 using type = std::complex<typename std::common_type_t<T1, T2>>;
45};
46
56template <typename T1, typename T2>
57struct common_type<std::complex<T1>, T2> {
59 using type = std::complex<typename std::common_type_t<T1, T2>>;
60};
61
70template <typename T1, typename T2>
71struct common_type<std::complex<T1>, std::complex<T2>> {
73 using type = std::complex<typename std::common_type_t<T1, T2>>;
74};
75
84template <typename T1, typename T2>
86
96template <typename T>
97concept complex_type = std::is_same_v<std::decay_t<T>, std::complex<typename T::value_type>> &&
98 std::is_arithmetic_v<typename T::value_type>;
99
109template <typename T>
110concept vector_type = std::is_arithmetic_v<T> || complex_type<T>;
111
120template <typename T>
121struct is_complex : std::false_type {};
122
130template <typename T>
131struct is_complex<std::complex<T>> : std::true_type {};
132
140template <typename T>
141inline constexpr bool is_complex_v = is_complex<T>::value;
142
147template <vector_type T, std::size_t Length> //
148class vector : private std::array<T, Length> {
149
150public:
151 using value_type = T;
152 using std::array<T, Length>::begin;
153 using std::array<T, Length>::end;
154 using std::array<T, Length>::cbegin;
155 using std::array<T, Length>::cend;
156 using std::array<T, Length>::rbegin;
157 using std::array<T, Length>::rend;
158 using std::array<T, Length>::crbegin;
159 using std::array<T, Length>::crend;
160 using std::array<T, Length>::empty;
161 using std::array<T, Length>::size;
162 using std::array<T, Length>::operator[];
163
169 [[nodiscard]] constexpr vector() : std::array<T, Length>() {
170 std::fill(begin(), end(), T{});
171 }
172
179 [[nodiscard]] constexpr vector(std::initializer_list<T> const &list) : std::array<T, Length>() {
180 if (list.size() > Length) {
181 throw std::out_of_range("Initializer list size must match vector Length");
182 }
183 std::copy(list.begin(), list.end(), begin());
184 }
185
194 [[nodiscard]] constexpr vector(T const value) : std::array<T, Length>() {
195 std::fill(begin(), end(), value);
196 }
197
209 template <vector_type U>
210 [[nodiscard]] constexpr auto add(vector<U, Length> const &other) const {
211 vector<common_type_t<T, U>, Length> result;
212 std::transform(cbegin(), cend(), other.cbegin(), result.begin(),
213 [](auto const &a, auto const &b) { return common_type_t<T, U>(a) + common_type_t<T, U>(b); });
214
215 return result;
216 }
217
229 template <typename U>
230 [[nodiscard]] constexpr auto add(U const scalar) const {
231 vector<common_type_t<T, U>, Length> result;
232 std::transform(cbegin(), cend(), result.begin(),
233 [scalar](auto const &a) { return common_type_t<T, U>(a) + common_type_t<T, U>(scalar); });
234 return result;
235 }
236
247 template <vector_type U>
248 [[nodiscard]] constexpr auto operator+(vector<U, Length> const &other) const {
249 return add(other);
250 }
251
262 template <vector_type U>
263 [[nodiscard]] constexpr auto operator+(U const scalar) const {
264 return add(scalar);
265 }
266
279 template <vector_type U>
280 friend constexpr auto operator+(U const scalar, vector<T, Length> const &vec) {
281 return vec + scalar;
282 }
283
294 template <vector_type U>
295 constexpr auto &operator+=(vector<U, Length> const &other) {
296 std::transform(cbegin(), cend(), other.cbegin(), begin(),
297 [](auto const &a, auto const &b) { return common_type_t<T, U>(a) + common_type_t<T, U>(b); });
298 return *this;
299 }
300
311 template <vector_type U>
312 constexpr auto &operator+=(U const scalar) {
313 std::transform(cbegin(), cend(), begin(),
314 [scalar](T const &el) { return common_type_t<T, U>(el) + common_type_t<T, U>(scalar); });
315 return *this;
316 }
317
328 template <vector_type U>
329 [[nodiscard]] constexpr auto subtract(vector<U, Length> const &other) const {
330 return add(-other);
331 }
332
343 template <vector_type U>
344 [[nodiscard]] constexpr auto subtract(U const scalar) const {
345 return add(-scalar);
346 }
347
358 template <vector_type U>
359 [[nodiscard]] constexpr auto operator-(vector<U, Length> const &other) const {
360 return subtract(other);
361 }
362
373 template <vector_type U>
374 [[nodiscard]] constexpr auto operator-(U const scalar) const {
375 return subtract(scalar);
376 }
377
390 template <vector_type U>
391 friend constexpr auto operator-(U const scalar, vector<T, Length> const &vec) {
392 return vec - scalar;
393 }
394
405 template <vector_type U>
406 constexpr auto &operator-=(vector<U, Length> const &other) {
407 std::transform(cbegin(), cend(), other.cbegin(), begin(),
408 [](auto const &a, auto const &b) { return common_type_t<T, U>(a) - common_type_t<T, U>(b); });
409 return *this;
410 }
411
422 template <vector_type U>
423 constexpr auto &operator-=(U const scalar) {
424 std::transform(cbegin(), cend(), begin(),
425 [scalar](auto const &el) { return common_type_t<T, U>(el) - common_type_t<T, U>(scalar); });
426 return *this;
427 }
428
446 template <typename U>
447 [[nodiscard]] constexpr auto dot(vector<U, Length> const &other) const {
448 return std::transform_reduce(
449 cbegin(), cend(), other.cbegin(), common_type_t<T, U>(0), std::plus<>(),
450 [](auto const &a, auto const &b) { return common_type_t<T, U>(a) * common_type_t<T, U>(b); });
451 }
452
464 template <vector_type U>
465 [[nodiscard]] constexpr auto cross(vector<U, Length> const &other) const {
466 static_assert(Length == 3, "Cross product is only allowed for 3D vectors.");
468
469 cross[0] = (*this)[1] * other[2] - (*this)[2] * other[1];
470 cross[1] = (*this)[2] * other[0] - (*this)[0] * other[2];
471 cross[2] = (*this)[0] * other[1] - (*this)[1] * other[0];
472
473 return cross;
474 }
475
486 template <vector_type U>
487 [[nodiscard]] constexpr auto scale(U const scalar) const {
488 vector<common_type_t<T, U>, Length> result;
489 std::transform(cbegin(), cend(), result.begin(),
490 [scalar](auto const &el) { return common_type_t<T, U>(el) * common_type_t<T, U>(scalar); });
491 return result;
492 }
493
504 template <vector_type U>
505 [[nodiscard]] constexpr auto operator*(vector<U, Length> const &other) const {
506 return dot(other);
507 }
508
518 template <vector_type U>
519 [[nodiscard]] constexpr auto operator*(U const scalar) const {
520 return scale(scalar);
521 }
522
535 template <vector_type U>
536 friend constexpr auto operator*(U const scalar, vector<T, Length> const &vec) {
537 return vec * scalar;
538 }
539
549 template <vector_type U>
550 constexpr auto &operator*=(U const scalar) {
551 std::transform(cbegin(), cend(), begin(),
552 [scalar](auto const &el) { return common_type_t<T, U>(el) * common_type_t<T, U>(scalar); });
553 return *this;
554 }
555
565 template <vector_type U>
566 [[nodiscard]] constexpr auto operator/(U const scalar) const {
567 return scale(1 / scalar);
568 }
569
582 template <vector_type U>
583 friend constexpr auto operator/(U const scalar, vector<T, Length> const &vec) {
584 return vec / scalar;
585 }
586
596 template <vector_type U>
597 constexpr auto &operator/=(U const scalar) {
598 std::transform(cbegin(), cend(), begin(),
599 [scalar](T const &el) { return common_type_t<T, U>(el) * (1 / common_type_t<T, U>(scalar)); });
600 return *this;
601 }
602
610 [[nodiscard]] constexpr auto operator-() const {
611 return scale(-1);
612 }
613
630 [[nodiscard]] constexpr auto norm() const {
631 if constexpr (is_complex_v<T>) {
632 return std::sqrt(std::transform_reduce(cbegin(), cend(), 0.0, std::plus<>(), [](const auto &val) {
633 return std::norm(val); // |val|^2 = val * conj(val)
634 }));
635 } else {
636 return std::sqrt(dot(*this));
637 }
638 }
639
649 [[nodiscard]] constexpr auto to_normalized() const {
650 auto _norm = norm();
651 if (_norm == 0) {
652 throw std::logic_error("zero norm results in divide by zero");
653 }
654 return scale(1 / norm());
655 }
656
665 [[nodiscard]] constexpr auto is_equal(vector<T, Length> const &other) const {
666 return std::equal(cbegin(), cend(), other.cbegin());
667 }
668
677 [[nodiscard]] constexpr auto operator==(vector<T, Length> const &other) const {
678 return is_equal(other);
679 }
680
690 template <vector_type AsType>
691 [[nodiscard]] vector<AsType, Length> constexpr const as_type() const {
693
694 std::transform(cbegin(), cend(), result.begin(), [](T el) {
695 if constexpr (std::is_same_v<T, std::complex<typename T::value_type>>) {
696 return static_cast<AsType>(el.real() * el.real() + el.imag() * el.imag());
697 } else {
698 return static_cast<AsType>(el);
699 }
700 });
701
702 return result;
703 }
704
712 [[nodiscard]] constexpr std::string view(int precision = 20) const {
713 bool f_is_first = false;
714 std::stringstream ss;
715
716 ss << std::setprecision(precision) << "[";
717 if (!empty()) {
718 for (auto const &el : *this) {
719 if (!f_is_first) {
720 ss << el;
721 f_is_first = true;
722 } else {
723 ss << ", " << el;
724 }
725 }
726 }
727 ss << "]";
728
729 return ss.str();
730 }
731
742 friend std::ostream &operator<<(std::ostream &os, vector const &other) {
743 os << other.view();
744 return os;
745 }
746};
747
748} // namespace firefly
Represents a mathematical vector in n-dimensional space.
Definition vector.hpp:148
constexpr auto operator-(U const scalar) const
Subtracts a scalar from each element of the vector using the - operator.
Definition vector.hpp:374
constexpr auto norm() const
Computes the Euclidean magnitude (Length) of the vector.
Definition vector.hpp:630
constexpr auto & operator-=(vector< U, Length > const &other)
Performs element-wise subtraction of another vector using the -= operator.
Definition vector.hpp:406
constexpr std::string view(int precision=20) const
Converts the vector to a string representation.
Definition vector.hpp:712
constexpr auto operator+(U const scalar) const
Adds a scalar to each element of the vector using the + operator.
Definition vector.hpp:263
constexpr auto dot(vector< U, Length > const &other) const
Calculates the dot product of two vectors.
Definition vector.hpp:447
constexpr auto & operator+=(vector< U, Length > const &other)
Performs element-wise addition of two vectors using the += operator.
Definition vector.hpp:295
constexpr auto & operator-=(U const scalar)
Subtracts a scalar from each element of the vector using the -= operator.
Definition vector.hpp:423
constexpr auto is_equal(vector< T, Length > const &other) const
Compares two vectors for equality.
Definition vector.hpp:665
constexpr auto operator+(vector< U, Length > const &other) const
Adds two vectors element-wise using the + operator.
Definition vector.hpp:248
T value_type
Definition vector.hpp:151
constexpr vector()
Default constructor that initialises all elements of the vector to zero.
Definition vector.hpp:169
constexpr auto to_normalized() const
Normalizes the vector.
Definition vector.hpp:649
constexpr auto add(U const scalar) const
Adds a scalar to each element of the vector and returns the result.
Definition vector.hpp:230
vector< AsType, Length > constexpr const as_type() const
Converts the vector elements to a different type, handling complex numbers.
Definition vector.hpp:691
friend std::ostream & operator<<(std::ostream &os, vector const &other)
Stream insertion operator for vectors.
Definition vector.hpp:742
friend constexpr auto operator*(U const scalar, vector< T, Length > const &vec)
Scales a vector by a scalar.
Definition vector.hpp:536
constexpr auto operator/(U const scalar) const
Scales the vector by the inverse of a scalar using the / operator.
Definition vector.hpp:566
constexpr auto operator==(vector< T, Length > const &other) const
Equality operator for vectors.
Definition vector.hpp:677
constexpr auto subtract(U const scalar) const
Subtracts a scalar from each element of the vector.
Definition vector.hpp:344
constexpr auto cross(vector< U, Length > const &other) const
Calculates the cross product of two 3D vectors.
Definition vector.hpp:465
constexpr auto operator-() const
Negates the vector.
Definition vector.hpp:610
constexpr auto & operator+=(U const scalar)
Adds a scalar to each element of the vector using the += operator.
Definition vector.hpp:312
constexpr auto operator-(vector< U, Length > const &other) const
Subtracts another vector from this vector using the - operator.
Definition vector.hpp:359
friend constexpr auto operator-(U const scalar, vector< T, Length > const &vec)
Subtracts a scalar to a vector.
Definition vector.hpp:391
friend constexpr auto operator+(U const scalar, vector< T, Length > const &vec)
Adds a scalar to a vector.
Definition vector.hpp:280
friend constexpr auto operator/(U const scalar, vector< T, Length > const &vec)
Performs inverse scaling of a vector by a scalar.
Definition vector.hpp:583
constexpr auto & operator/=(U const scalar)
Scales the vector in place using the /= operator.
Definition vector.hpp:597
constexpr vector(std::initializer_list< T > const &list)
Constructor that initializes the vector using an initializer list.
Definition vector.hpp:179
constexpr auto operator*(vector< U, Length > const &other) const
Calculates the dot product using the * operator.
Definition vector.hpp:505
constexpr auto operator*(U const scalar) const
Scales the vector using the * operator.
Definition vector.hpp:519
constexpr vector(T const value)
Constructor that initialises all elements of the vector to a given value.
Definition vector.hpp:194
constexpr auto subtract(vector< U, Length > const &other) const
Subtracts another vector from this vector.
Definition vector.hpp:329
constexpr auto add(vector< U, Length > const &other) const
Adds two vectors element-wise and returns the result.
Definition vector.hpp:210
constexpr auto & operator*=(U const scalar)
Scales the vector in place using the *= operator.
Definition vector.hpp:550
constexpr auto scale(U const scalar) const
Scales the vector by a given scalar.
Definition vector.hpp:487
Concept that ensures the type is a complex number type.
Definition vector.hpp:97
Concept that ensures the type is either arithmetic or a complex type.
Definition vector.hpp:110
Definition utilities.hpp:3
typename common_type< T1, T2 >::type common_type_t
Helper alias template for the common_type structure, similar to std::common_type_t.
Definition vector.hpp:85
constexpr bool is_complex_v
Helper variable template for is_complex.
Definition vector.hpp:141
std::complex< typename std::common_type_t< T1, T2 > > type
The resulting type is std::complex with the common type of T1 and T2.
Definition vector.hpp:44
std::complex< typename std::common_type_t< T1, T2 > > type
The resulting type is std::complex with the common type of T1 and T2.
Definition vector.hpp:59
std::complex< typename std::common_type_t< T1, T2 > > type
The resulting type is std::complex with the common type of T1 and T2.
Definition vector.hpp:73
Customised common_type implementation that handles cases where one or both types may be arithmetic or...
Definition vector.hpp:30
Trait to determine if a type is a std::complex type.
Definition vector.hpp:121