ampsci
High-precision calculations for one- and two-valence atomic systems
Vector.hpp
1#pragma once
2#include "Matrix.hpp"
3
4namespace LinAlg {
5
6//==============================================================================
7/*!
8 @brief Owning 1D array; inherits from Matrix<T> with a single column.
9 @details
10 Stores elements contiguously. Provides 1D index access via `[]`, `()`,
11 and `at()`, plus arithmetic operators and GSL interop inherited from Matrix.
12
13 Supports inner product (`a * b`), matrix-vector product (`A * v`), and
14 outer product (`outer_product(a, b)`).
15
16 **Vector vs View<T>:**
17 Use `Vector<T>` when you need to own the data (e.g. storing a result,
18 passing to a solver). Use `View<T>` (@ref LinAlg::View) for non-owning,
19 zero-copy access into an existing array e.g. a row or column of a Matrix,
20 obtained via `Matrix::row_view()` or `Matrix::column_view()`.
21
22 @tparam T Element type (default: `double`).
23*/
24template <typename T = double>
25class Vector : public Matrix<T> {
26public:
27 //! Default construct: empty vector
28 Vector() : Matrix<T>() {}
29
30 //! Construct zero-initialised vector of length `dimension`
31 Vector(std::size_t dimension) : Matrix<T>(dimension, 1) {}
32
33 //! Construct from initialiser list: `Vector<double> v = {1.0, 2.0, 3.0};`
34 Vector(std::initializer_list<T> l) : Matrix<T>(l.size(), 1, l) {}
35
36 //! Construct from std::vector by move
37 Vector(std::vector<T> &&v)
38 : Matrix<T>(v.size(), 1, std::forward<std::vector<T>>(v)) {}
39
40 //! Construct from std::vector by copy
41 Vector(const std::vector<T> &v) : Matrix<T>(v.size(), 1, v) {}
42
43 //! Construct from single-column Matrix by move
44 Vector(const Matrix<T> &&m) : Matrix<T>(std::move(m)) {
45 assert(m.cols() == 1 && "Can only convert Matrix to Vector if matrix has 1 "
46 "column. Traspose first?");
47 }
48
49 //! Construct from single-column Matrix by copy
50 Vector(const Matrix<T> &m) : Matrix<T>(m) {
51 assert(m.cols() == 1 && "Can only convert Matrix to Vector if matrix has 1 "
52 "column. Traspose first?");
53 }
54
55 //============================================================================
56
57 //! Element access by index, no range checking, mutable
58 T &operator[](std::size_t i) { return this->data()[i]; }
59 //! Element access by index, no range checking, const
60 T operator[](std::size_t i) const { return this->data()[i]; }
61 //! Element access by index, with range checking, mutable
62 T &at(std::size_t i) {
63 assert(i < this->size());
64 return this->data()[i];
65 }
66 //! Element access by index, with range checking, const
67 T at(std::size_t i) const {
68 assert(i < this->size());
69 return this->data()[i];
70 }
71 //! Element access by index, with range checking, mutable
72 T &operator()(std::size_t i) { return at(i); }
73 //! Element access by index, with range checking, const
74 T operator()(std::size_t i) const { return at(i); }
75
76 //============================================================================
77
78 //! Returns element-wise complex conjugate
79 [[nodiscard]] Vector<T> conj() const;
80 //! Returns real part of each element as a new Vector
81 [[nodiscard]] auto real() const;
82 //! Returns imaginary part of each element as a new Vector
83 [[nodiscard]] auto imag() const;
84 //! Returns a complex-valued copy of this Vector
85 [[nodiscard]] auto complex() const;
86
87 //! Transpose is not defined for Vector (deleted)
88 Vector<T> transpose() const = delete;
89
90 //============================================================================
91
92 //! Addition assignment: element-wise `*this += rhs`
93 Vector<T> &operator+=(const Vector<T> &rhs);
94 //! Subtraction assignment: element-wise `*this -= rhs`
95 Vector<T> &operator-=(const Vector<T> rhs);
96 //! Scalar multiplication assignment: `*this *= x`
97 Vector<T> &operator*=(const T x);
98 //! Scalar division assignment: `*this /= x`
99 Vector<T> &operator/=(const T x);
100
101 //! Element-wise addition: `lhs + rhs`
102 [[nodiscard]] friend Vector<T> operator+(Vector<T> lhs,
103 const Matrix<T> &rhs) {
104 return (lhs += rhs);
105 }
106 //! Element-wise subtraction: `lhs - rhs`
107 [[nodiscard]] friend Vector<T> operator-(Vector<T> lhs,
108 const Matrix<T> &rhs) {
109 return (lhs -= rhs);
110 }
111 //! Scalar multiplication: `x * v`
112 [[nodiscard]] friend Vector<T> operator*(const T x, Vector<T> rhs) {
113 return (rhs *= x);
114 }
115 //! Scalar multiplication: `v * x`
116 [[nodiscard]] friend Vector<T> operator*(Vector<T> lhs, const T x) {
117 return (lhs *= x);
118 }
119 //! Scalar division: `v / x`
120 [[nodiscard]] friend Vector<T> operator/(Vector<T> lhs, const T x) {
121 return (lhs /= x);
122 }
123
124 //============================================================================
125
126 //! Matrix-vector product: returns `A * b`, i.e. `v_i = sum_j A_ij * b_j`
127 [[nodiscard]] friend Vector<T> operator*(const Matrix<T> &a,
128 const Vector<T> &b) {
129 // https://www.gnu.org/software/gsl/doc/html/blas.html
130 assert(a.cols() == b.rows());
131 Vector<T> product(b.rows());
132 const auto a_gsl = a.as_gsl_view();
133 const auto b_gsl = b.as_gsl_view();
134 auto product_gsl = product.as_gsl_view();
135 if constexpr (std::is_same_v<T, double>) {
136 gsl_blas_dgemv(CblasNoTrans, 1.0, &a_gsl.matrix, &b_gsl.vector, 0.0,
137 &product_gsl.vector);
138 } else if constexpr (std::is_same_v<T, float>) {
139 gsl_blas_sgemv(CblasNoTrans, 1.0f, &a_gsl.matrix, &b_gsl.vector, 0.0f,
140 &product_gsl.vector);
141 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
142 gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_ONE, &a_gsl.matrix,
143 &b_gsl.vector, GSL_COMPLEX_ZERO, &product_gsl.vector);
144 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
145 const gsl_complex_float one{1.0f, 0.0f};
146 const gsl_complex_float zero{0.0f, 0.0f};
147 gsl_blas_cgemv(CblasNoTrans, one, &a_gsl.matrix, &b_gsl.vector, zero,
148 &product_gsl.vector);
149 }
150
151 return product;
152 }
153
154 //! Inner (dot) product: returns `sum_i a_i * b_i`
155 [[nodiscard]] friend T operator*(const Vector<T> &a, const Vector<T> &b) {
156 // https://www.gnu.org/software/gsl/doc/html/blas.html
157 assert(a.rows() == b.rows());
158 const auto a_gsl = a.as_gsl_view();
159 const auto b_gsl = b.as_gsl_view();
160 T product = T(0);
161 if constexpr (std::is_same_v<T, double>) {
162 gsl_blas_ddot(&a_gsl.vector, &b_gsl.vector, &product);
163 } else if constexpr (std::is_same_v<T, float>) {
164 gsl_blas_sdot(&a_gsl.vector, &b_gsl.vector, &product);
165 } else if constexpr (std::is_same_v<T, std::complex<double>>) {
166 gsl_blas_zdotu(&a_gsl.vector, &b_gsl.vector,
167 reinterpret_cast<gsl_complex *>(&product));
168 } else if constexpr (std::is_same_v<T, std::complex<float>>) {
169 gsl_blas_cdotu(&a_gsl.vector, &b_gsl.vector,
170 reinterpret_cast<gsl_complex_float *>(&product));
171 }
172
173 return product;
174 }
175
176 //! Outer product: returns matrix M with `M_ij = a_i * b_j`
177 [[nodiscard]] friend Matrix<T> outer_product(const Vector<T> &a,
178 const Vector<T> &b) {
179 Matrix<T> op(a.rows(), b.rows());
180 for (std::size_t i = 0; i < op.rows(); ++i) {
181 for (std::size_t j = 0; j < op.cols(); ++j) {
182 op[i][j] = a[i] * b[j];
183 }
184 }
185 return op;
186 }
187
188 //============================================================================
189
190 //! Returns a GSL vector view of the underlying data (no copy).
191 //! The Vector must remain in scope for the lifetime of the view.
192 [[nodiscard]] auto as_gsl_view();
193
194 //! Returns a const GSL vector view of the underlying data (no copy).
195 //! The Vector must remain in scope for the lifetime of the view.
196 [[nodiscard]] auto as_gsl_view() const;
197};
198
199} // namespace LinAlg
200
201#include "Vector.ipp"
Row-major dense matrix with arithmetic and linear algebra support.
Definition Matrix.hpp:209
std::size_t size() const
Return rows*columns [total array size].
Definition Matrix.hpp:286
T * data()
Pointer to first element; for std::complex<T> this is complex<T>*, not T*.
Definition Matrix.hpp:292
std::size_t rows() const
Return rows [major index size].
Definition Matrix.hpp:282
auto as_gsl_view()
Returns a GSL matrix view for use with GSL functions (no copy).
Definition Matrix.ipp:390
Matrix< T > & zero()
Sets all elements to zero, in place.
Definition Matrix.ipp:108
std::size_t cols() const
Return columns [minor index size].
Definition Matrix.hpp:284
Owning 1D array; inherits from Matrix<T> with a single column.
Definition Vector.hpp:25
Vector< T > & operator/=(const T x)
Scalar division assignment: *this /= x
Definition Vector.ipp:71
friend Vector< T > operator-(Vector< T > lhs, const Matrix< T > &rhs)
Element-wise subtraction: lhs - rhs
Definition Vector.hpp:107
Vector< T > conj() const
Returns element-wise complex conjugate.
Definition Vector.ipp:7
Vector(std::size_t dimension)
Construct zero-initialised vector of length dimension
Definition Vector.hpp:31
T & at(std::size_t i)
Element access by index, with range checking, mutable.
Definition Vector.hpp:62
Vector()
Default construct: empty vector.
Definition Vector.hpp:28
friend Vector< T > operator*(const T x, Vector< T > rhs)
Scalar multiplication: x * v
Definition Vector.hpp:112
Vector< T > & operator*=(const T x)
Scalar multiplication assignment: *this *= x
Definition Vector.ipp:65
Vector< T > transpose() const =delete
Transpose is not defined for Vector (deleted)
friend Vector< T > operator/(Vector< T > lhs, const T x)
Scalar division: v / x
Definition Vector.hpp:120
auto as_gsl_view()
Returns a GSL vector view of the underlying data (no copy). The Vector must remain in scope for the l...
Definition Vector.ipp:79
Vector< T > & operator+=(const Vector< T > &rhs)
Addition assignment: element-wise *this += rhs
Definition Vector.ipp:51
Vector(const Matrix< T > &&m)
Construct from single-column Matrix by move.
Definition Vector.hpp:44
Vector(std::vector< T > &&v)
Construct from std::vector by move.
Definition Vector.hpp:37
auto real() const
Returns real part of each element as a new Vector.
Definition Vector.ipp:18
friend Matrix< T > outer_product(const Vector< T > &a, const Vector< T > &b)
Outer product: returns matrix M with M_ij = a_i * b_j
Definition Vector.hpp:177
friend T operator*(const Vector< T > &a, const Vector< T > &b)
Inner (dot) product: returns sum_i a_i * b_i
Definition Vector.hpp:155
Vector(std::initializer_list< T > l)
Construct from initialiser list: Vector<double> v = {1.0, 2.0, 3.0};
Definition Vector.hpp:34
friend Vector< T > operator+(Vector< T > lhs, const Matrix< T > &rhs)
Element-wise addition: lhs + rhs
Definition Vector.hpp:102
Vector< T > & operator-=(const Vector< T > rhs)
Subtraction assignment: element-wise *this -= rhs
Definition Vector.ipp:58
Vector(const std::vector< T > &v)
Construct from std::vector by copy.
Definition Vector.hpp:41
T operator()(std::size_t i) const
Element access by index, with range checking, const.
Definition Vector.hpp:74
auto complex() const
Returns a complex-valued copy of this Vector.
Definition Vector.ipp:38
T at(std::size_t i) const
Element access by index, with range checking, const.
Definition Vector.hpp:67
Vector(const Matrix< T > &m)
Construct from single-column Matrix by copy.
Definition Vector.hpp:50
friend Vector< T > operator*(Vector< T > lhs, const T x)
Scalar multiplication: v * x
Definition Vector.hpp:116
auto imag() const
Returns imaginary part of each element as a new Vector.
Definition Vector.ipp:28
friend Vector< T > operator*(const Matrix< T > &a, const Vector< T > &b)
Matrix-vector product: returns A * b, i.e. v_i = sum_j A_ij * b_j
Definition Vector.hpp:127
T operator[](std::size_t i) const
Element access by index, no range checking, const.
Definition Vector.hpp:60
T & operator()(std::size_t i)
Element access by index, with range checking, mutable.
Definition Vector.hpp:72
T & operator[](std::size_t i)
Element access by index, no range checking, mutable.
Definition Vector.hpp:58
Linear algebra: matrices, vectors, views, and solvers.
Definition Matrix.hpp:54