Tensorium
Loading...
Searching...
No Matches
Vector.hpp
Go to the documentation of this file.
1#pragma once
2
5#include "../SIMD/CPU_id.hpp"
6#include "../SIMD/SIMD.hpp"
7#include <cassert>
8#include <cmath>
9#include <iostream>
10#include <vector>
11
12namespace tensorium {
26template <typename K> class Vector {
27 public:
32
37 Vector(const std::vector<K> &vec) : data(vec.begin(), vec.end()) {}
39
42
43 K &operator[](size_t i) { return data[i]; }
44 const K &operator[](size_t i) const { return data[i]; }
45 const K &operator()(size_t i) const { return data[i]; }
46 K &operator()(size_t i) { return data[i]; }
51 Vector(size_t n) : data(n, K()) {}
56 Vector(std::initializer_list<K> init) : data(init) {}
62 Vector(size_t n, K value) : data(n, value) {}
64
67 auto begin() { return data.begin(); }
68 auto end() { return data.end(); }
69 auto begin() const { return data.begin(); }
70 auto end() const { return data.end(); }
72
75
76 size_t size() const { return data.size(); }
77 void resize(size_t n) { data.resize(n); }
79
82
87 void print() const {
88 std::cout << "Vector size: " << size() << "\n";
89 for (float f : data)
90 std::cout << "[" << f << "]\n";
91 }
94
95 static Vector<K> canonical(int index, K dx, K dy, K dz) {
96 Vector<K> out(3, K(0));
97 if (index == 0)
98 out(0) = dx;
99 else if (index == 1)
100 out(1) = dy;
101 else if (index == 2)
102 out(2) = dz;
103 else
104 throw std::invalid_argument("Index must be 0, 1, or 2");
105 return out;
106 }
113 Vector<K> result(data.size());
114 size_t m = std::min(data.size(), other.data.size());
115 for (size_t i = 0; i < m; ++i)
116 result[i] = data[i] - other[i];
117 for (size_t i = m; i < data.size(); ++i)
118 result[i] = data[i];
119 return result;
120 }
121
126 __attribute__((always_inline, hot, flatten)) inline void add(const Vector &v) {
127 if (v.size() != size())
128 throw std::invalid_argument("Vector sizes do not match");
130 using reg = typename Simd::reg;
131 const size_t simd_width = Simd::width;
132 size_t n = size();
133 size_t i = 0;
134
135 _mm_prefetch((const char *)&v.data[0], _MM_HINT_T0);
136
137 for (; i + 15 < n; i += 16) {
138 reg a0 = Simd::load(&data[i]);
139 reg b0 = Simd::load(&v.data[i]);
140 a0 = Simd::add(a0, b0);
141 Simd::store(&data[i], a0);
142
143 reg a1 = Simd::load(&data[i + simd_width]);
144 reg b1 = Simd::load(&v.data[i + simd_width]);
145 a1 = Simd::add(a1, b1);
146 Simd::store(&data[i + simd_width], a1);
147 }
148
149 for (; i < n; ++i)
150 data[i] += v.data[i];
151 }
156 __attribute__((always_inline, hot, flatten)) inline void sub(const Vector &v) {
157 if (v.size() != size())
158 throw std::invalid_argument("Vector sizes do not match");
160 using reg = typename Simd::reg;
161 const size_t simd_width = Simd::width;
162 size_t n = size();
163 size_t i = 0;
164
165 _mm_prefetch((const char *)&v.data[0], _MM_HINT_T0);
166 for (; i + 15 < n; i += 16) {
167 reg a0 = Simd::load(&data[i]);
168 reg b0 = Simd::load(&v.data[i]);
169 a0 = Simd::sub(a0, b0);
170 Simd::store(&data[i], a0);
171
172 reg a1 = Simd::load(&data[i + simd_width]);
173 reg b1 = Simd::load(&v.data[i + simd_width]);
174 a1 = Simd::sub(a1, b1);
175 Simd::store(&data[i + simd_width], a1);
176 }
177
178 for (; i < n; ++i)
179 data[i] -= v.data[i];
180 }
185 __attribute__((always_inline, hot, flatten)) inline void scl(float a) {
186 size_t n = size();
187 size_t i = 0;
189 using reg = typename Simd::reg;
190 const size_t simd_width = Simd::width;
191 _mm_prefetch((const char *)&data[0], _MM_HINT_T0);
192 reg scalar = Simd::set1(a);
193 float *__restrict out = &data[0];
194
195 for (; i + 15 < n; i += 16) {
196 reg v0 = Simd::load(out + i);
197 v0 = Simd::mul(v0, scalar);
198 Simd::store(out + i, v0);
199
200 reg v1 = Simd::load(out + i + simd_width);
201 v1 = Simd::mul(v1, scalar);
202 Simd::store(out + i + simd_width, v1);
203 }
204
205 for (; i < n; ++i)
206 out[i] *= a;
207 }
208
217 linear_combination(const std::vector<Vector<float>> &u, const std::vector<float> &coefs) {
219 using reg = typename Simd::reg;
220 const size_t simd_width = Simd::width;
221
222 if (u.size() != coefs.size())
223 throw std::invalid_argument("Mismatched number of vectors and coefficients");
224 if (u.empty())
225 return Vector<float>(0);
226
227 const size_t n = u[0].size();
228 for (const auto &v : u)
229 if (v.size() != n)
230 throw std::invalid_argument("Vector sizes do not match");
231
233
234 size_t i = 0;
235 constexpr size_t W = simd_width;
236 for (; i + W - 1 < n; i += W) {
237 reg acc = Simd::zero();
238 for (size_t j = 0; j < u.size(); ++j) {
239 reg v = Simd::load(&u[j].data[i]);
240 reg c = Simd::set1(coefs[j]);
241 acc = Simd::fmadd(v, c, acc);
242 }
243 Simd::store(&result.data[i], acc);
244 }
245
246 for (; i < n; ++i) {
247 float acc = 0.f;
248 for (size_t j = 0; j < u.size(); ++j)
249 acc += coefs[j] * u[j].data[i];
250 result.data[i] = acc;
251 }
252
253 return result;
254 }
264 lerp(const Vector<float> &a, const Vector<float> &b, float t) {
265 if (a.size() != b.size())
266 throw std::invalid_argument("Vector sizes do not match");
268 using reg = typename Simd::reg;
269 const size_t simd_width = Simd::width;
270
271 const size_t n = a.size();
273
274 const reg vt = Simd::set1(t);
275 const reg vt1 = Simd::sub(Simd::set1(1.0f), vt);
276
277 size_t i = 0;
278 _mm_prefetch((const char *)&a.data[0], _MM_HINT_T0);
279 for (; i + 7 < n; i += simd_width) {
280 reg va = Simd::load(&a.data[i]);
281 reg vb = Simd::load(&b.data[i]);
282
283 reg r = Simd::fmadd(vb, vt, Simd::mul(va, vt1));
284
285 Simd::store_stream(&result.data[i], r);
286 }
287
288 for (; i < n; ++i)
289 result.data[i] = (1.0f - t) * a.data[i] + t * b.data[i];
290
291 return result;
292 }
294
297
303 __attribute__((always_inline, hot, flatten)) inline float dot(const Vector<float> &v) const {
305 using reg = typename Simd::reg;
306 const size_t simd_width = Simd::width;
307 if (v.size() != size())
308 throw std::invalid_argument("Vector sizes do not match");
309 const size_t n = size();
310 size_t i = 0;
311 reg acc = Simd::zero();
312
313 const float *__restrict a_ptr = &data[0];
314 const float *__restrict b_ptr = &v.data[0];
315 _mm_prefetch((const char *)&v.data[0], _MM_HINT_T0);
316 for (; i + 7 < n; i += simd_width) {
317 reg a = Simd::load(a_ptr + i);
318 reg b = Simd::load(b_ptr + i);
319 acc = Simd::fmadd(a, b, acc);
320 }
321
322 float result = detail::reduce_sum(acc);
323
324 for (; i < n; ++i)
325 result += a_ptr[i] * b_ptr[i];
326
327 return result;
328 }
329
334 __attribute__((always_inline, hot, flatten)) inline float norm_1() const {
335 size_t n = size();
336 size_t i = 0;
338 using reg = typename Simd::reg;
339 const size_t simd_width = Simd::width;
340 reg acc = Simd::zero();
341 reg sign_mask = Simd::set1(-0.0f);
342 const float *__restrict v_ptr = &data[0];
343 _mm_prefetch((const char *)&data[0], _MM_HINT_T0);
344 for (; i + 7 < n; i += simd_width) {
345 reg v = Simd::load(v_ptr + i);
346 reg abs_v = Simd::andnot(sign_mask, v);
347 acc = Simd::add(acc, abs_v);
348 }
349
350 float result = detail::reduce_sum(acc);
351
352 for (; i < n; ++i)
354
355 return result;
356 }
361 __attribute__((always_inline, hot, flatten)) inline float norm_2() const {
362 size_t n = size();
363 size_t i = 0;
365 using reg = typename Simd::reg;
366 const size_t simd_width = Simd::width;
367 reg acc = Simd::zero();
368 const float *__restrict v_ptr = &data[0];
369 _mm_prefetch((const char *)&data[0], _MM_HINT_T0);
370 for (; i + 7 < n; i += simd_width) {
371 reg v = Simd::load(v_ptr + i);
372 acc = Simd::fmadd(v, v, acc);
373 }
374
375 float result = detail::reduce_sum(acc);
376
377 for (; i < n; ++i)
378 result += v_ptr[i] * v_ptr[i];
379
380 return std::pow(result, 0.5f);
381 }
386 __attribute__((always_inline, hot, flatten)) inline float norm_inf() const {
387 size_t n = size();
388 size_t i = 0;
390 using reg = typename Simd::reg;
391 const size_t simd_width = Simd::width;
392 reg max_v = Simd::zero();
393 reg sign_mask = Simd::set1(-0.0f);
394 const float *__restrict v_ptr = &data[0];
395 _mm_prefetch((const char *)&data[0], _MM_HINT_T0);
396 for (; i + 7 < n; i += simd_width) {
397 reg v = Simd::load(v_ptr + i);
398 reg abs_v = Simd::andnot(sign_mask, v);
399 max_v = Simd::max(max_v, abs_v);
400 }
401
402 float result = detail::reduce_sum(max_v);
403
404 for (; i < n; ++i)
406
407 return result;
408 }
416 __attribute__((always_inline, hot, flatten)) static inline float
418 if (u.size() != v.size())
419 throw std::invalid_argument("Vector sizes do not match");
420
421 const float dot = u.dot(v);
422 const float norm_u = u.norm_2();
423 const float norm_v = v.norm_2();
424
425 return dot / (norm_u * norm_v);
426 }
427
436 if (u.size() != 3 || v.size() != 3)
437 throw std::invalid_argument("Cross product is only defined for 3D vectors.");
438
440
441 __m128 uxy = _mm_set_ps(0.0f, u.data[0], u.data[2], u.data[1]);
442 __m128 vxy = _mm_set_ps(0.0f, v.data[0], v.data[2], v.data[1]);
443
444 r.data[0] = std::fma(u.data[1], v.data[2], -u.data[2] * v.data[1]);
445 r.data[1] = std::fma(u.data[2], v.data[0], -u.data[0] * v.data[2]);
446 r.data[2] = std::fma(u.data[0], v.data[1], -u.data[1] * v.data[0]);
447
448 return r;
449 }
450};
451
452template <typename K> inline Vector<K> operator+(const Vector<K> &a, const Vector<K> &b) {
453 size_t n = a.size();
454 Vector<K> result(n);
455 size_t m = std::min(n, b.size());
456 for (size_t i = 0; i < m; ++i)
457 result[i] = a[i] + b[i];
458 for (size_t i = m; i < n; ++i)
459 result[i] = a[i];
460 return result;
461}
462
463template <typename K> inline Vector<K> operator-(const Vector<K> &a, const Vector<K> &b) {
464 assert(a.size() == b.size());
465 Vector<K> result(a.size());
466 for (size_t i = 0; i < a.size(); ++i)
467 result[i] = a[i] - b[i];
468 return result;
469}
470
471} // namespace tensorium
static double _max(double a, double b)
Definition MathsUtils.hpp:21
static float _fabs(float a)
Definition MathsUtils.hpp:13
Multi-dimensional tensor class with fixed rank and SIMD support.
Definition Tensor.hpp:25
void resize(const std::array< size_t, Rank > &dims)
Resize 2D tensor.
Definition Tensor.hpp:70
aligned_vector< K > data
Definition Tensor.hpp:31
Aligned, SIMD-optimized mathematical vector class for scientific computing.
Definition Vector.hpp:26
__attribute__((always_inline, hot, flatten)) inline float dot(const Vector< float > &v) const
Compute the dot product with another vector.
Definition Vector.hpp:303
Vector(size_t n, K value)
Construct a constant vector.
Definition Vector.hpp:62
size_t i
Definition Vector.hpp:277
Vector< float > r(3)
__attribute__((always_inline, hot, flatten)) static inline Vector< float > cross_product(const Vector< float > &u
Compute the cross product between two 3D vectors.
const K & operator()(size_t i) const
Definition Vector.hpp:45
__m128 uxy
Definition Vector.hpp:441
__attribute__((always_inline, hot, flatten)) Vector< K > operator-(const Vector< K > &other) const
Subtract two vectors.
Definition Vector.hpp:112
const size_t simd_width
Definition Vector.hpp:269
Vector< float > result(n)
const float norm_v
Definition Vector.hpp:423
_mm_prefetch((const char *)&a.data[0], _MM_HINT_T0)
const K & operator[](size_t i) const
Definition Vector.hpp:44
Vector(std::initializer_list< K > init)
Construct from an initializer list.
Definition Vector.hpp:56
auto end()
Definition Vector.hpp:68
const reg vt
Definition Vector.hpp:274
__attribute__((always_inline, hot, flatten)) inline void scl(float a)
Scale this vector by a scalar (in-place).
Definition Vector.hpp:185
auto end() const
Definition Vector.hpp:70
__attribute__((always_inline, hot, flatten)) static inline Vector< float > lerp(const Vector< float > &a
Linearly interpolate between two vectors.
__attribute__((always_inline, hot, flatten)) inline void sub(const Vector &v)
Subtract another vector from this one (in-place).
Definition Vector.hpp:156
void resize(size_t n)
Definition Vector.hpp:77
return r
Definition Vector.hpp:448
typename Simd::reg reg
Definition Vector.hpp:268
Vector(const std::vector< K > &vec)
Construct from a standard vector.
Definition Vector.hpp:37
const size_t n
Definition Vector.hpp:271
const float dot
Definition Vector.hpp:421
void print() const
Print the vector to stdout.
Definition Vector.hpp:87
Vector(size_t n)
Construct an empty vector of size n.
Definition Vector.hpp:51
auto begin() const
Definition Vector.hpp:69
__attribute__((always_inline, hot, flatten)) inline float norm_2() const
Compute the 2-norm (Euclidean norm).
Definition Vector.hpp:361
const Vector< float > & b
Definition Vector.hpp:264
const Vector< float > & v
Definition Vector.hpp:417
aligned_vector< K > data
Underlying aligned data storage (SIMD-friendly).
Definition Vector.hpp:29
size_t size() const
Definition Vector.hpp:76
__attribute__((always_inline, hot, flatten)) static inline float angle_cos(const Vector< float > &u
Compute the cosine of the angle between two vectors.
return result
Definition Vector.hpp:291
__attribute__((always_inline, hot, flatten)) inline float norm_inf() const
Compute the infinity norm (maximum absolute value).
Definition Vector.hpp:386
auto begin()
Definition Vector.hpp:67
K & operator()(size_t i)
Definition Vector.hpp:46
const reg vt1
Definition Vector.hpp:275
K & operator[](size_t i)
Definition Vector.hpp:43
__m128 vxy
Definition Vector.hpp:442
const float norm_u
Definition Vector.hpp:422
static Vector< K > canonical(int index, K dx, K dy, K dz)
Definition Vector.hpp:95
__attribute__((always_inline, hot, flatten)) static inline Vector< float > linear_combination(const std
Compute the linear combination of vectors with coefficients.
Definition Vector.hpp:216
__attribute__((always_inline, hot, flatten)) inline void add(const Vector &v)
Add another vector to this one (in-place).
Definition Vector.hpp:126
const Vector< float > float t
Definition Vector.hpp:264
__attribute__((always_inline, hot, flatten)) inline float norm_1() const
Compute the 1-norm (sum of absolute values).
Definition Vector.hpp:334
Definition Derivate.hpp:24
Vector< K > operator-(const Vector< K > &a, const Vector< K > &b)
Definition Vector.hpp:463
Vector< K > operator+(const Vector< K > &a, const Vector< K > &b)
Definition Vector.hpp:452
Definition SIMD.hpp:177