HILA
Loading...
Searching...
No Matches
array.h
Go to the documentation of this file.
1/**
2 * @file array.h
3 * @brief Definition of Array class
4 * @details This file contains the definitions of Array class and utility functions related to it.
5 */
6
7#ifndef ARRAY_H_
8#define ARRAY_H_
9
10#include "datatypes/matrix.h"
11
12/**
13 * @brief \f$ n\times m \f$ Array type
14 * @details Acts as array class which stores data in a simple C style array.
15 *
16 * Main functionality which the Array class offers is to supplement the fall backs of storing
17 * information in a Matrix data structure.
18 *
19 * For example assigning a value to each element with the Matrix class is not directly possible
20 * using the assignment operator=. This is because assignment with matrices is defined as
21 * \f$ M = a = a*I \f$ where M is a general matrix, a is a scalar and I an identity matrix. The
22 * result would only assign a to the diagonal elements.
23 *
24 * Unlike the Matrix object, the Array object assigns element wise. This allows filling the Array
25 * with the assignment operator. Additionally element wise operations are useable as long as they
26 * are defined for the Array type. For example the operation:
27 *
28 * \code
29 * Array<n,m,double> m.random();
30 * sin(m);
31 * \endcode
32 *
33 * is defined, since the \f$sin\f$ function is defined for doubles.
34 *
35 * The above operation would not work for matrices, but with casting operations. Matrix::asArray and
36 * Array::asMatrix one can take full advantage of element wise operations.
37 *
38 * @tparam n Number of rows
39 * @tparam m Number of columns
40 * @tparam T Array element type
41 */
42template <const int n, const int m, typename T>
43class Array {
44 public:
46 "Array requires Complex or arithmetic type");
47
48 // Store Array contents in one dimensional C style array
49 T c[n * m];
50
51 // std incantation for field types
52 using base_type = hila::arithmetic_type<T>;
53 using argument_type = T;
54
55 static constexpr bool is_array() {
56 return true;
57 }
58
59 /**
60 * @brief Construct a new Matrix object
61 * @details The following ways of constructing a matrix are:
62 *
63 * __NOTE__: n,m are integers and MyType is a HILA [standard type](@ref standard) or Complex.
64 *
65 * __Default constructor__:
66 *
67 * Allocates undefined \f$ n\times m\f$ Array.
68 *
69 * \code{.cpp}
70 * Array<n,m,MyType> A;
71 * \endcode
72 *
73 *
74 * __Scalar constructor__:
75 *
76 * Construct with given scalar which is assigned to all elements in array
77 *
78 * \code{.cpp}
79 * MyType x = hila::random();
80 * Array<n,m,MyType> A = x;
81 * \endcode
82 *
83 * __Copy constructor__:
84 *
85 * Construction from previously defined Array.
86 *
87 * \code{.cpp}
88 * Array<n,m,MyOtherType> A_0;
89 * //
90 * // A_0 is filled with content
91 * //
92 * Array<n,m,MyType> A = A_0;
93 * \endcode
94 *
95 * __Initializer list__:
96 *
97 * Construction from c++ initializer list.
98 *
99 * \code{.cpp}
100 * Array<2,2,int> A = {1, 0
101 * 0, 1};
102 * \endcode
103 */
104 Array() = default;
105 ~Array() = default;
106 Array(const Array<n, m, T> &v) = default;
107
108 // constructor from scalar - make this also explicit, consistency
109 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
110 explicit inline Array(const S rhs) {
111 for (int i = 0; i < n * m; i++) {
112 this->c[i] = rhs;
113 }
114 }
115
116 // and make non-explicit constructor from 0
117 inline Array(const std::nullptr_t &z) {
118 for (int i = 0; i < n * m; i++)
119 c[i] = 0;
120 }
121
122 // Construct array automatically from right-size initializer list
123 // This does not seem to be dangerous, so keep non-explicit
124
125 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
126 inline Array(std::initializer_list<S> rhs) {
127 assert(rhs.size() == n * m && "Array initializer list size must match variable size");
128 int i = 0;
129 for (auto it = rhs.begin(); it != rhs.end(); it++, i++) {
130 c[i] = *it;
131 }
132 }
133
134 /**
135 * @brief Returns number of rows
136 *
137 * @return constexpr int
138 */
139 constexpr int rows() const {
140 return n;
141 }
142 /**
143 * @brief Returns number of columns
144 *
145 * @return constexpr int
146 */
147 constexpr int columns() const {
148 return m;
149 }
150
151 /**
152 * @brief Returns size of #Vector Array or square Array
153 *
154 * @tparam q Number of rows n
155 * @tparam p Number of columns m
156 * @return constexpr int
157 */
158 template <int q = n, int p = m, std::enable_if_t<q == 1, int> = 0>
159 constexpr int size() const {
160 return p;
161 }
162
163 template <int q = n, int p = m, std::enable_if_t<p == 1, int> = 0>
164 constexpr int size() const {
165 return q;
166 }
167
168 template <int q = n, int p = m, std::enable_if_t<q == p, int> = 0>
169 constexpr int size() const {
170 return q;
171 }
172
173 /**
174 * @brief Standard array indexing operation for 2D and 1D Arrays
175 *
176 * @details Accessing singular elements is insufficient, but matrix elements are often quite
177 * small.
178 *
179 * Exammple for 2D Array:
180 * \code
181 * Array<n,m,MyType> A;
182 * MyType a = A.e(i,j); \\ i <= n, j <= m
183 * \endcode
184 *
185 * Example for Vector Array:
186 * \code {.cpp}
187 * Array1d<n,MyType> A;
188 * MyType a = A.e(i) \\ i <= n
189 * \endcode
190 *
191 * @param i row index
192 * @param j column index
193 * @return T matrix element type
194 */
195#pragma hila loop_function
196 inline T e(const int i, const int j) const {
197 return c[i * m + j];
198 }
199 // standard access ops m.e(i,j) - assume T is small, as it should
200 inline T &e(const int i, const int j) const_function {
201 return c[i * m + j];
202 }
203
204 // declare single e here too in case we have a vector
205 // (one size == 1)
206#pragma hila loop_function
207 template <int q = n, int p = m, std::enable_if_t<(q == 1 || p == 1), int> = 0>
208 inline T e(const int i) const {
209 return c[i];
210 }
211
212 template <int q = n, int p = m, std::enable_if_t<(q == 1 || p == 1), int> = 0>
213 inline T &e(const int i) const_function {
214 return c[i];
215 }
216
217 /**
218 * @brief Cast Array to Matrix
219 *
220 * @return Matrix<n, m, T>&
221 */
222 Matrix<n, m, T> &asMatrix() const_function {
223 return *reinterpret_cast<Matrix<n, m, T> *>(this);
224 }
225
226#pragma hila loop_function
227 const Matrix<n, m, T> &asMatrix() const {
228 return *reinterpret_cast<const Matrix<n, m, T> *>(this);
229 }
230
231 /**
232 * @brief Cast Array1D to Vector
233 * @details asMatrix will perform the same operation.
234 *
235 * @return Vector<n, T>&
236 */
237 Vector<n, T> &asVector() const_function {
238 static_assert(1 == m, "asVector() only for column arrays");
239 return *reinterpret_cast<Vector<n, T> *>(this);
240 }
241
242#pragma hila loop_function
243 const Vector<n, T> &asVector() const {
244 static_assert(1 == m, "asVector() only for column arrays");
245 return *reinterpret_cast<const Vector<n, T> *>(this);
246 }
247
248 DiagonalMatrix<n, T> &asDiagonalMatrix() const_function {
249 static_assert(1 == m, "asDiagonalMatrix() only for column arrays");
250 return *reinterpret_cast<DiagonalMatrix<n, T> *>(this);
251 }
252
253#pragma hila loop_function
254 const DiagonalMatrix<n, T> &asDiagonalMatrix() const {
255 static_assert(1 == m, "asDiagonalMatrix() only for column arrays");
256 return *reinterpret_cast<const DiagonalMatrix<n, T> *>(this);
257 }
258
259
260 // casting from one Array (number) type to another
261 // TODO: CHECK AVX CONVERSIONS
262 template <typename S, std::enable_if_t<hila::is_assignable<S &, T>::value, int> = 0>
263 operator Array<n, m, S>() {
264 Array<n, m, S> res;
265 for (int i = 0; i < n * m; i++) {
266 res.c[i] = c[i];
267 }
268 return res;
269 }
270
271 /**
272 * @brief Unary - operator
273 * @details Returns Array with the signs of all the elements in the Arrat flipped.
274 *
275 * @return Array<n,m,T>
276 */
277 inline Array<n, m, T> operator-() const {
278 Array<n, m, T> res;
279 for (int i = 0; i < n * m; i++) {
280 res.c[i] = -c[i];
281 }
282 return res;
283 }
284
285 /**
286 * @brief Unary + operator
287 * @details Equivalent to identity operator meaning that Arrat stays as is.
288 *
289 * @return const Array<n, m, T>
290 */
291 inline Array<n, m, T> operator+() const {
292 return *this;
293 }
294
295 /**
296 * @brief Assignment operator = to assign values to Array
297 * @details The following ways to assign an Array are:
298 *
299 *
300 * __Assignment from Array__:
301 *
302 * \code {.cpp}
303 * Array<n,m,MyType> A_0;
304 * .
305 * . A_0 has values assigned to it
306 * .
307 * Array<n,m,MyType> A; \\ undefined matrix
308 * A = A_0; \\ Assignment from A_0
309 * \endcode
310 *
311 * __Assignment from scalar__:
312 *
313 * Assignment from scalar assigns the scalar to the diagonal elements as \f$ A = I\cdot a\f$
314 *
315 * \code {.cpp}
316 * MyType a = hila::random;
317 * Array<n,m,MyType> A;
318 * A = a; A = I*a
319 * \endcode
320 *
321 *__Initializer list__:
322 *
323 * Assignment from c++ initializer list.
324 *
325 * \code{.cpp}
326 * Array<2,2,int> A ;
327 * A = {1, 0
328 * 0, 1};
329 * \endcode
330 */
331
332 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
333 inline Array<n, m, T> &operator=(const S rhs) out_only & {
334 for (int i = 0; i < n * m; i++) {
335 c[i] = rhs;
336 }
337 return *this;
338 }
339
340 template <typename S, std::enable_if_t<hila::is_assignable<T &, S>::value, int> = 0>
341 inline Array<n, m, T> &operator=(const Array<n, m, S> &rhs) out_only & {
342 for (int i = 0; i < n; i++)
343 for (int j = 0; j < m; j++) {
344 e(i, j) = rhs.e(i, j);
345 }
346 return *this;
347 }
348
349
350 /**
351 * @brief Compare equality of Arrays
352 *
353 * Two Arrays are equal iff Arrays are of same dimension and all elements compare to equal
354 * Note: Complex == scalar if arithmetic value is equal
355 *
356 * @tparam S
357 * @param rhs
358 * @return true if equal
359 */
360
361 template <typename S, int n1, int m1>
362 bool operator==(const Array<n1, m1, S> &rhs) const {
363 if constexpr (n != n1 || m != m1)
364 return false;
365
366 for (int i = 0; i < n; i++)
367 for (int j = 0; j < m; j++) {
368 if (e(i, j) != rhs.e(i, j))
369 return false;
370 }
371 return true;
372 }
373
374 /**
375 * @brief Compare non-equality of two Arrays
376 *
377 * Negation of operator==()
378 *
379 * @tparam S
380 * @tparam n1
381 * @tparam m1
382 * @param rhs
383 * @return true
384 * @return false
385 */
386
387 template <typename S, int n1, int m1>
388 bool operator!=(const Array<n1, m1, S> &rhs) const {
389 return !(*this == rhs);
390 }
391
392 /**
393 * @brief Add assign operator with Array or scalar
394 * @details Add assign operator can be used in the following ways
395 *
396 * __Add assign Array__:
397 *
398 * Requires that Arrays have same dimensions
399 *
400 * \code {.cpp}
401 * Array<n,m,MyType> A,B;
402 * A = 1;
403 * B = 1;
404 * A += B; \\ A is uniformly 2
405 * \endcode
406 *
407 * __Add assign scalar__:
408 *
409 * Adds scalar \f$ a \f$ to Array uniformly
410 *
411 * \code {.cpp}
412 * Array<n,m,MyType> A = 1;
413 * A += 1 ; \\ A is uniformly 2
414 * \endcode
415 *
416 * @tparam S Element type of rhs
417 * @param rhs Array to add
418 * @return Array<n, m, T>
419 */
420
421 template <typename S, std::enable_if_t<std::is_convertible<S, T>::value, int> = 0>
423 for (int i = 0; i < n; i++)
424 for (int j = 0; j < m; j++) {
425 e(i, j) += rhs.e(i, j);
426 }
427 return *this;
428 }
429
430 /**
431 * @brief Subtract assign operator with Array or scalar
432 * @details Subtract assign operator can be used in the following ways
433 *
434 * __Subtract assign Array__:
435 *
436 * \code {.cpp}
437 * Array<n,m,MyType> A,B;
438 * A = 3;
439 * B = 1;
440 * A -= B; \\ A is uniformly 2
441 * \endcode
442 *
443 * __Subtract assign scalar__:
444 *
445 * Subtract scalar uniformly from square matrix
446 *
447 * \code {.cpp}
448 * A<n,m,MyType> A = 3;
449 * A -= 1 ; \\ A is uniformly 2
450 * \endcode
451 * @tparam S
452 * @param rhs
453 * @return Array<n, m, T>&
454 */
455 template <typename S, std::enable_if_t<std::is_convertible<S, T>::value, int> = 0>
457 for (int i = 0; i < n; i++)
458 for (int j = 0; j < m; j++) {
459 e(i, j) -= rhs.e(i, j);
460 }
461 return *this;
462 }
463
464 // add assign type T and convertible
465 template <typename S,
466 std::enable_if_t<std::is_convertible<hila::type_plus<T, S>, T>::value, int> = 0>
467 Array<n, m, T> &operator+=(const S rhs) & {
468 for (int i = 0; i < n * m; i++) {
469 c[i] += rhs;
470 }
471 return *this;
472 }
473
474 // subtract assign type T and convertible
475 template <typename S,
476 std::enable_if_t<std::is_convertible<hila::type_minus<T, S>, T>::value, int> = 0>
477 Array<n, m, T> &operator-=(const S rhs) & {
478 for (int i = 0; i < n * m; i++) {
479 c[i] -= rhs;
480 }
481 return *this;
482 }
483
484 /**
485 * @brief Multiply assign scalar or array
486 * @details Multiplication works element wise
487 *
488 * Multiply assign operator can be used in the following ways
489 *
490 * __Multiply assign Array__:
491 *
492 * \code {.cpp}
493 * Array<n,m,MyType> A,B;
494 * A = 2;
495 * B = 2;
496 * A *= B; \\ A is uniformly 4
497 * \endcode
498 *
499 * __Multiply assign scalar__:
500 *
501 * \code {.cpp}
502 * Array<n,m,MyType> A = 1;
503
504 * A *= 2 ; \\ A is uniformly 2
505 * \endcode
506 * @tparam S
507 * @param rhs
508 * @return Array<n, m, T>&
509 */
510 template <typename S,
511 std::enable_if_t<std::is_convertible<hila::type_mul<T, S>, T>::value, int> = 0>
513 for (int i = 0; i < n; i++)
514 for (int j = 0; j < m; j++) {
515 e(i, j) *= rhs.e(i, j);
516 }
517 return *this;
518 }
519
520 /// multiply assign with scalar
521 template <typename S,
522 std::enable_if_t<std::is_convertible<hila::type_mul<T, S>, T>::value, int> = 0>
523 Array<n, m, T> &operator*=(const S rhs) & {
524 for (int i = 0; i < n * m; i++) {
525 c[i] *= rhs;
526 }
527 return *this;
528 }
529
530 /**
531 * @brief Division assign with array or scalar
532 * @details Division works element wise
533 *
534 * Division assign operator can be used in the following ways
535 *
536 * __Division assign Array__:
537 *
538 * \code {.cpp}
539 * Array<n,m,MyType> A,B;
540 * A = 2;
541 * B = 2;
542 * A /= B; \\ A is uniformly 1
543 * \endcode
544 *
545 * __Division assign scalar__:
546 *
547 * \code {.cpp}
548 * Array<n,m,MyType> A = 2;
549
550 * A /= 2 ; \\ A is uniformly 1
551 * \endcode
552 * @tparam S
553 * @param rhs
554 * @return Array<n, m, T>&
555 */
556 template <typename S,
557 std::enable_if_t<std::is_convertible<hila::type_div<T, S>, T>::value, int> = 0>
559 for (int i = 0; i < n; i++)
560 for (int j = 0; j < m; j++) {
561 e(i, j) /= rhs.e(i, j);
562 }
563 return *this;
564 }
565
566 // divide assign with scalar
567 template <typename S,
568 std::enable_if_t<std::is_convertible<hila::type_div<T, S>, T>::value, int> = 0>
569 Array<n, m, T> &operator/=(const S rhs) & {
570 for (int i = 0; i < n * m; i++) {
571 c[i] /= rhs;
572 }
573 return *this;
574 }
575
576 /**
577 * @brief Returns element wise Complex conjugate of Array
578 *
579 * @return Array<n, m, T>
580 */
581 inline Array<n, m, T> conj() const {
582 Array<n, m, T> res;
583 for (int i = 0; i < n * m; i++) {
584 res.c[i] = ::conj(c[i]);
585 }
586 return res;
587 }
588 /**
589 * @brief Returns real part of Array
590 *
591 * @return Array<n, m, T>
592 */
595 for (int i = 0; i < m * n; i++) {
596 res.c[i] = ::real(c[i]);
597 }
598 return res;
599 }
600
601 /// return imaginary part
604 for (int i = 0; i < m * n; i++) {
605 res.c[i] = ::imag(c[i]);
606 }
607 return res;
608 }
609
610 /// calculate square norm - sum of squared elements
611 hila::arithmetic_type<T> squarenorm() const {
612 hila::arithmetic_type<T> result = 0;
613 for (int i = 0; i < n * m; i++) {
614 result += ::squarenorm(c[i]);
615 }
616 return result;
617 }
618
619 /**
620 * @brief Fill Array with random elements
621 *
622 * @return Array<n, m, T>&
623 */
624 Array<n, m, T> &random() out_only {
625 for (int i = 0; i < n * m; i++) {
626 hila::random(c[i]);
627 }
628 return *this;
629 }
630
631 /**
632 * @brief Fill Array with Gaussian random elements
633 *
634 * @param width
635 * @return Array<n, m, T>&
636 */
637 Array<n, m, T> &gaussian_random(double width = 1.0) out_only {
638 for (int i = 0; i < n * m; i++) {
639 hila::gaussian_random(c[i], width);
640 }
641 return *this;
642 }
643
644 /// Convert to string for printing
645 std::string str(int prec = 8, char separator = ' ') const {
646 return this->asMatrix().str(prec, separator);
647 }
648
649 /// implement sort as casting to array
650#pragma hila novector
651 template <int N>
653 hila::sort order = hila::sort::ascending) const {
654 return this->asMatrix().sort(permutation, order).asArray();
655 }
656
657#pragma hila novector
658 Array<n, m, T> sort(hila::sort order = hila::sort::ascending) const {
659 return this->asMatrix().sort(order).asArray();
660 }
661};
662
663/**
664 * @brief Return conjugate Array
665 * @details Wrapper around Array::conj
666 *
667 * @tparam n Number of rows
668 * @tparam m Number of columns
669 * @tparam T Array element type
670 * @param arg Array to be conjugated
671 * @return Array<n, m, T>
672 */
673template <const int n, const int m, typename T>
675 return arg.conj();
676}
677/**
678 * @brief Return real part of Array
679 * @details Wrapper around Array::real
680 *
681 * @tparam n Number of rows
682 * @tparam m Number of columns
683 * @tparam T Array element type
684 * @param arg Array to return real part of
685 * @return Array<n, m, T>
686 */
687template <const int n, const int m, typename T>
689 return arg.real();
690}
691/**
692 * @brief Return imaginary part of Array
693 * @details Wrapper around Array::imag
694 *
695 * @tparam n Number of rows
696 * @tparam m Number of columns
697 * @tparam T Array element type
698 * @param arg Array to return real part of
699 * @return Array<n, m, T>
700 */
701template <const int n, const int m, typename T>
703 return arg.imag();
704}
705
706/**
707 * @brief Addition operator
708 * @details Defined for the following operations
709 *
710 * __Array + Array:__
711 *
712 * __NOTE__: Arrays must share same dimensionality
713 *
714 * \code {.cpp}
715 * Array<n,m,MyType> A, B, C;
716 * A = 1;
717 * B = 1;
718 * C = A + B; // C is uniformly 2
719 * \endcode
720 *
721 *
722 * __Scalar + Array / Array + Scalar:__
723 *
724 * __NOTE__: Exact definition exist in overloaded functions that can be viewed in source code.
725 * *
726 * \code {.cpp}
727 * Array<n,m,MyType> A,B;
728 * A = 1;
729 * B = A + 1; // B is uniformly 2
730 * \endcode
731 *
732 * @tparam n Number of rows
733 * @tparam m Number of columns
734 * @tparam T Array element type
735 * @param a
736 * @param b
737 * @return Array<n, m, T>
738 */
739template <int n, int m, typename A, typename B>
740inline auto operator+(const Array<n, m, A> &a, const Array<n, m, B> &b) {
742 for (int i = 0; i < n * m; i++)
743 res.c[i] = a.c[i] * b.c[i];
744 return res;
745}
746
747/**
748 * @brief Subtraction operator
749 * @details Defined for the following operations
750 *
751 * __Array - Array:__
752 *
753 * __NOTE__: Arrays must share same dimensionality
754 *
755 * \code {.cpp}
756 * Array<n,m,MyType> A, B, C;
757 * A = 2;
758 * B = 1;
759 * C = A - B; // C is uniformly 2
760 * \endcode
761 *
762 *
763 * __Scalar - Array / Array - Scalar:__
764 *
765 * __NOTE__: Exact definition exist in overloaded functions that can be viewed in source code.
766 * *
767 * \code {.cpp}
768 * Array<n,m,MyType> A,B;
769 * A = 2;
770 * B = A - 1; // B is uniformly 2
771 * \endcode
772 *
773 * @tparam n Number of rows
774 * @tparam m Number of columns
775 * @tparam T Array element type
776 * @param a
777 * @param b
778 * @return Array<n, m, T>
779 */
780template <int n, int m, typename A, typename B>
781inline auto operator-(const Array<n, m, A> &a, const Array<n, m, B> &b) {
783 for (int i = 0; i < n * m; i++)
784 res.c[i] = a.c[i] - b.c[i];
785 return res;
786}
787
788// Array + scalar
789template <int n, int m, typename T, typename S,
790 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
791inline auto operator+(const Array<n, m, T> &a, const S b) {
793 for (int i = 0; i < n * m; i++)
794 res.c[i] = a.c[i] + b;
795 return res;
796}
797
798// scalar + Array
799template <int n, int m, typename T, typename S,
800 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
801inline auto operator+(const S b, const Array<n, m, T> &a) {
802 return a + b;
803}
804
805// Array - scalar
806template <int n, int m, typename T, typename S,
807 std::enable_if_t<std::is_convertible<hila::type_minus<T, S>, T>::value, int> = 0>
808inline auto operator-(const Array<n, m, T> &a, const S b) {
810 for (int i = 0; i < n * m; i++)
811 res.c[i] = a.c[i] - b;
812 return res;
813}
814
815// scalar - Array
816template <int n, int m, typename T, typename S,
817 std::enable_if_t<std::is_convertible<hila::type_minus<T, S>, T>::value, int> = 0>
818inline auto operator-(const S b, const Array<n, m, T> &a) {
820 for (int i = 0; i < n * m; i++)
821 res.c[i] = b - a.c[i];
822 return res;
823}
824
825
826/**
827 * @brief Multiplication operator
828 * @details Defined for the following operations
829 *
830 * __Array*Array:__
831 *
832 * __NOTE__: Arrays must share same dimensionality
833 *
834 * \code {.cpp}
835 * Array<n,m,MyType> A, B, C;
836 * A = 2;
837 * B = 3;
838 * C = A*B; // C is uniformly 6
839 * \endcode
840 *
841 *
842 * __Scalar * Array / Array * Scalar:__
843 *
844 * __NOTE__: Exact definition exist in overloaded functions that can be viewed in source code.
845 * *
846 * \code {.cpp}
847 * Array<n,m,MyType> A,B;
848 * A = 2;
849 * B = A*3; // B is uniformly 6
850 * \endcode
851 *
852 * @tparam n Number of rows
853 * @tparam m Number of columns
854 * @tparam T Array element type
855 * @param a
856 * @param b
857 * @return Array<n, m, T>
858 */
859
860template <int n, int m, typename T>
862 a *= b;
863 return a;
864}
865
866// mult with different type arrays
867
868template <int n, int m, typename A, typename B,
869 std::enable_if_t<!std::is_same<A, B>::value, int> = 0>
870inline auto operator*(const Array<n, m, A> &a, const Array<n, m, B> &b) {
871
872 using R = hila::type_mul<A, B>;
873
874 Array<n, m, R> res;
875 for (int i = 0; i < n; i++)
876 for (int j = 0; j < m; j++)
877 res.e(i, j) = a.e(i, j) * b.e(i, j);
878
879 return res;
880}
881
882/**
883 * @brief Division operator
884 * @details Defined for the following operations
885 *
886 * __Array/Array:__
887 *
888 * __NOTE__: Arrays must share same dimensionality
889 *
890 * \code {.cpp}
891 * Array<n,m,MyType> A, B, C;
892 * A = 4;
893 * B = 2;
894 * C = A/B; // C is uniformly 2
895 * \endcode
896 *
897 *
898 * __Scalar / Array / Array / Scalar:__
899 *
900 * __NOTE__: Exact definition exist in overloaded functions that can be viewed in source code.
901 * *
902 * \code {.cpp}
903 * Array<n,m,MyType> A,B;
904 * A = 4;
905 * B = A/2; // B is uniformly 2
906 * \endcode
907 *
908 * @tparam n Number of rows
909 * @tparam m Number of columns
910 * @tparam T Array element type
911 * @param a
912 * @param b
913 * @return Array<n, m, T>
914 */
915template <int n, int m, typename A, typename B>
916inline auto operator/(const Array<n, m, A> &a, const Array<n, m, B> &b) {
918 for (int i = 0; i < n; i++)
919 for (int j = 0; j < m; j++)
920 res.e(i, j) = a.e(i, j) / b.e(i, j);
921 return res;
922}
923
924
925// Array * scalar
926template <int n, int m, typename T, typename S,
927 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
928inline auto operator*(const Array<n, m, T> &a, const S b) {
930 for (int i = 0; i < n * m; i++)
931 res.c[i] = a.c[i] * b;
932 return res;
933}
934
935// scalar * Array
936template <int n, int m, typename T, typename S,
937 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
938inline auto operator*(const S b, const Array<n, m, T> &a) {
939 return a * b;
940}
941
942
943// Array / scalar
944template <int n, int m, typename T, typename S,
945 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
946inline auto operator/(const Array<n, m, T> &a, const S b) {
948 for (int i = 0; i < n * m; i++)
949 res.c[i] = a.c[i] / b;
950 return res;
951}
952
953// scalar / Array
954template <int n, int m, typename T, typename S,
955 std::enable_if_t<hila::is_complex_or_arithmetic<S>::value, int> = 0>
956inline auto operator/(const S b, const Array<n, m, T> &a) {
958 for (int i = 0; i < n * m; i++)
959 res.c[i] = b / a.c[i];
960 return res;
961}
962
963
964/**
965 * @brief Stream operator
966 * @details Naive Stream operator for formatting Matrix for printing. Simply puts elements one after
967 * the other in row major order
968 *
969 * @tparam n Number of rows
970 * @tparam m Number of columns
971 * @tparam T Array element type
972 * @param strm OS stream
973 * @param A Array to write
974 * @return std::ostream&
975 */
976template <int n, int m, typename T>
977std::ostream &operator<<(std::ostream &strm, const Array<n, m, T> &A) {
978 return operator<<(strm, A.asMatrix());
979}
980
981namespace hila {
982
983/**
984 * @brief Converts Array object to string
985 *
986 * @tparam n Number of rows
987 * @tparam m Number of columns
988 * @tparam T Array element type
989 * @param A Array to convert to string
990 * @param prec Precision of T
991 * @param separator Separator between elements
992 * @return std::string
993 */
994template <int n, int m, typename T>
995std::string to_string(const Array<n, m, T> &A, int prec = 8, char separator = ' ') {
996 return to_string(A.asMatrix(), prec, separator);
997}
998
999template <int n, int m, typename T>
1000std::string prettyprint(const Array<n, m, T> &A, int prec = 8) {
1001 return prettyprint(A.asMatrix(), prec);
1002}
1003
1004} // namespace hila
1005
1006
1007/**
1008 * @brief Return square norm of Array
1009 * @details Wrapper around Array::squarenrom
1010 *
1011 * @tparam n Number of rows
1012 * @tparam m Number of columns
1013 * @tparam T Array element type
1014 * @param rhs Array to compute squarenorm of
1015 * @return hila::arithmetic_type<T>
1016 */
1017template <int n, int m, typename T>
1018inline hila::arithmetic_type<T> squarenorm(const Array<n, m, T> &rhs) {
1019 return rhs.squarenorm();
1020}
1021
1022/** @name Arithmetic operations
1023 * @details all operations are applied linearly to the Array A
1024 *
1025 * Most functions are self explanitory, but if necessary function will have a detailed section with
1026 * additional information.
1027 * @tparam n Number of rows
1028 * @tparam m Number of columns
1029 * @tparam T Array element type
1030 * @param a Input array
1031 * @return Array<n, m, T>
1032 * @{
1033 */
1034
1035/**
1036 * @brief Square root
1037 */
1038template <int n, int m, typename T>
1040 for (int i = 0; i < n * m; i++)
1041 a.c[i] = sqrt(a.c[i]);
1042 return a;
1043}
1044
1045/**
1046 * @brief Cuberoot
1047 */
1048template <int n, int m, typename T>
1050 for (int i = 0; i < n * m; i++)
1051 a.c[i] = cbrt(a.c[i]);
1052 return a;
1053}
1054
1055/**
1056 * @brief Exponential
1057 */
1058template <int n, int m, typename T>
1060 for (int i = 0; i < n * m; i++)
1061 a.c[i] = exp(a.c[i]);
1062 return a;
1063}
1064
1065/**
1066 * @brief Logarithm
1067 */
1068template <int n, int m, typename T>
1070 for (int i = 0; i < n * m; i++)
1071 a.c[i] = log(a.c[i]);
1072 return a;
1073}
1074
1075/**
1076 * @brief Sine
1077 */
1078template <int n, int m, typename T>
1080 for (int i = 0; i < n * m; i++)
1081 a.c[i] = sin(a.c[i]);
1082 return a;
1083}
1084
1085/**
1086 * @brief Cosine
1087 */
1088template <int n, int m, typename T>
1090 for (int i = 0; i < n * m; i++)
1091 a.c[i] = cos(a.c[i]);
1092 return a;
1093}
1094
1095/**
1096 * @brief Tangent
1097 */
1098template <int n, int m, typename T>
1100 for (int i = 0; i < n * m; i++)
1101 a.c[i] = tan(a.c[i]);
1102 return a;
1103}
1104
1105/**
1106 * @brief Inverse Sine
1107 */
1108template <int n, int m, typename T>
1110 for (int i = 0; i < n * m; i++)
1111 a.c[i] = asin(a.c[i]);
1112 return a;
1113}
1114
1115/**
1116 * @brief Inverse Cosine
1117 */
1118template <int n, int m, typename T>
1120 for (int i = 0; i < n * m; i++)
1121 a.c[i] = acos(a.c[i]);
1122 return a;
1123}
1124
1125/**
1126 * @brief Inverse Tangent
1127 */
1128template <int n, int m, typename T>
1130 for (int i = 0; i < n * m; i++)
1131 a.c[i] = atan(a.c[i]);
1132 return a;
1133}
1134
1135/**
1136 * @brief Hyperbolic Sine
1137 */
1138template <int n, int m, typename T>
1140 for (int i = 0; i < n * m; i++)
1141 a.c[i] = sinh(a.c[i]);
1142 return a;
1143}
1144
1145/**
1146 * @brief Hyperbolic Cosine
1147 */
1148template <int n, int m, typename T>
1150 for (int i = 0; i < n * m; i++)
1151 a.c[i] = cosh(a.c[i]);
1152 return a;
1153}
1154
1155/**
1156 * @brief Hyperbolic tangent
1157 */
1158template <int n, int m, typename T>
1160 for (int i = 0; i < n * m; i++)
1161 a.c[i] = tanh(a.c[i]);
1162 return a;
1163}
1164
1165/**
1166 * @brief Inverse Hyperbolic Sine
1167 */
1168template <int n, int m, typename T>
1170 for (int i = 0; i < n * m; i++)
1171 a.c[i] = asinh(a.c[i]);
1172 return a;
1173}
1174
1175/**
1176 * @brief Inverse Hyperbolic Cosine
1177 */
1178template <int n, int m, typename T>
1180 for (int i = 0; i < n * m; i++)
1181 a.c[i] = acosh(a.c[i]);
1182 return a;
1183}
1184
1185/**
1186 * @brief Inverse Hyperbolic Tangent
1187 */
1188template <int n, int m, typename T>
1190 for (int i = 0; i < n * m; i++)
1191 a.c[i] = atanh(a.c[i]);
1192 return a;
1193}
1194
1195/**
1196 * @brief Power
1197 *
1198 * @details Array can be raised homogeneously to the power of a integer or scalar b or Array can be
1199 * raised to the power of another Array b element wise.
1200 *
1201 * @param b Array, Integer or Real scalar to raise to the power of
1202 */
1203template <int n, int m, typename T>
1205 for (int i = 0; i < n * m; i++)
1206 a.c[i] = pow(a.c[i], b);
1207 return a;
1208}
1209
1210template <int n, int m, typename T>
1211inline Array<n, m, T> pow(Array<n, m, T> a, T b) {
1212 for (int i = 0; i < n * m; i++)
1213 a.c[i] = pow(a.c[i], b);
1214 return a;
1215}
1216
1217template <int n, int m, typename T>
1218inline Array<n, m, T> pow(Array<n, m, T> a, const Array<n, m, T> &b) {
1219 for (int i = 0; i < n * m; i++)
1220 a.c[i] = pow(a.c[i], b.c[i]);
1221 return a;
1222}
1223
1224/**
1225 * @brief Rounding
1226 * @details Rounding function if T is arithmetic type
1227 * @tparam T Array element type, must be arithmetic type
1228 */
1229template <int n, int m, typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1231 for (int i = 0; i < n * m; i++)
1232 a.c[i] = round(a.c[i]);
1233 return a;
1234}
1235
1236/**
1237 * @brief Floor
1238 * @details Flooring function if T is arithmetic type
1239 * @tparam T Array element type, must be arithmetic type
1240 */
1241template <int n, int m, typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1243 for (int i = 0; i < n * m; i++)
1244 a.c[i] = floor(a.c[i]);
1245 return a;
1246}
1247
1248/**
1249 * @brief Ceiling
1250 * @details Ceiling function if T is arithmetic type
1251 * @tparam T Array element type, must be arithmetic type
1252 */
1253template <int n, int m, typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1255 for (int i = 0; i < n * m; i++)
1256 a.c[i] = ceil(a.c[i]);
1257 return a;
1258}
1259
1260/**
1261 * @brief Truncation
1262 * @details Truncation function if T is arithmetic type
1263 * @tparam T Array element type, must be arithmetic type
1264 */
1265template <int n, int m, typename T, std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1267 for (int i = 0; i < n * m; i++)
1268 a.c[i] = trunc(a.c[i]);
1269 return a;
1270}
1271/** @} */
1272
1273/**
1274 * @brief Array casting operation
1275 * @details Cast array to different number type or Complex type
1276 *
1277 * Allowed casting: number->number, number->Complex, Complex->Complex
1278 *
1279 * Not allowed casting: Complex->number
1280 * @tparam Ntype Type to cast to
1281 * @tparam T Input Array type
1282 * @tparam n Number of rows
1283 * @tparam m Number of columns
1284 * @param mat Array to cast
1285 * @return Array<n, m, Ntype>
1286 */
1287template <typename Ntype, typename T, int n, int m,
1288 std::enable_if_t<hila::is_arithmetic<T>::value, int> = 0>
1291 for (int i = 0; i < n * m; i++)
1292 res.c[i] = mat.c[i];
1293 return res;
1294}
1295
1296template <typename Ntype, typename T, int n, int m,
1297 std::enable_if_t<hila::is_complex<T>::value, int> = 0>
1300 for (int i = 0; i < n * m; i++)
1301 res.c[i] = cast_to<Ntype>(mat.c[i]);
1302 return res;
1303}
1304
1305
1306/// Array1d and Array2d are just aliased to Array
1307template <int n, typename T = double>
1309
1310/// Array1d and Array2d are just aliased to Array
1311template <int n, int m, typename T = double>
1313
1314#endif
Array< n, m, T > conj(const Array< n, m, T > &arg)
Return conjugate Array.
Definition array.h:674
auto operator/(const Array< n, m, A > &a, const Array< n, m, B > &b)
Division operator.
Definition array.h:916
std::ostream & operator<<(std::ostream &strm, const Array< n, m, T > &A)
Stream operator.
Definition array.h:977
Array< n, m, T > floor(Array< n, m, T > a)
Floor.
Definition array.h:1242
Array< n, m, T > round(Array< n, m, T > a)
Rounding.
Definition array.h:1230
Array< n, m, T > asin(Array< n, m, T > a)
Inverse Sine.
Definition array.h:1109
auto operator-(const Array< n, m, A > &a, const Array< n, m, B > &b)
Subtraction operator.
Definition array.h:781
Array< n, m, T > exp(Array< n, m, T > a)
Exponential.
Definition array.h:1059
Array< n, m, T > tanh(Array< n, m, T > a)
Hyperbolic tangent.
Definition array.h:1159
Array< n, m, T > trunc(Array< n, m, T > a)
Truncation.
Definition array.h:1266
Array< n, m, hila::arithmetic_type< T > > imag(const Array< n, m, T > &arg)
Return imaginary part of Array.
Definition array.h:702
hila::arithmetic_type< T > squarenorm(const Array< n, m, T > &rhs)
Return square norm of Array.
Definition array.h:1018
Array< n, m, T > cosh(Array< n, m, T > a)
Hyperbolic Cosine.
Definition array.h:1149
Array< n, m, T > tan(Array< n, m, T > a)
Tangent.
Definition array.h:1099
auto operator+(const Array< n, m, A > &a, const Array< n, m, B > &b)
Addition operator.
Definition array.h:740
Array< n, m, T > cos(Array< n, m, T > a)
Cosine.
Definition array.h:1089
Array< n, m, T > cbrt(Array< n, m, T > a)
Cuberoot.
Definition array.h:1049
Array< n, m, T > acos(Array< n, m, T > a)
Inverse Cosine.
Definition array.h:1119
Array< n, m, T > acosh(Array< n, m, T > a)
Inverse Hyperbolic Cosine.
Definition array.h:1179
Array< n, m, T > sqrt(Array< n, m, T > a)
Square root.
Definition array.h:1039
Array< n, m, T > asinh(Array< n, m, T > a)
Inverse Hyperbolic Sine.
Definition array.h:1169
Array< n, m, T > ceil(Array< n, m, T > a)
Ceiling.
Definition array.h:1254
Array< n, m, T > atan(Array< n, m, T > a)
Inverse Tangent.
Definition array.h:1129
Array< n, m, T > pow(Array< n, m, T > a, int b)
Power.
Definition array.h:1204
Array< n, m, T > operator*(Array< n, m, T > a, const Array< n, m, T > &b)
Multiplication operator.
Definition array.h:861
Array< n, m, Ntype > cast_to(const Array< n, m, T > &mat)
Array casting operation.
Definition array.h:1289
Array< n, m, T > sin(Array< n, m, T > a)
Sine.
Definition array.h:1079
Array< n, m, T > sinh(Array< n, m, T > a)
Hyperbolic Sine.
Definition array.h:1139
Array< n, m, hila::arithmetic_type< T > > real(const Array< n, m, T > &arg)
Return real part of Array.
Definition array.h:688
Array< n, m, T > atanh(Array< n, m, T > a)
Inverse Hyperbolic Tangent.
Definition array.h:1189
Array< n, m, T > log(Array< n, m, T > a)
Logarithm.
Definition array.h:1069
Array type
Definition array.h:43
Array< n, m, T > & operator+=(const Array< n, m, S > &rhs) &
Add assign operator with Array or scalar.
Definition array.h:422
constexpr int rows() const
Returns number of rows.
Definition array.h:139
constexpr int size() const
Returns size of Vector Array or square Array.
Definition array.h:159
Array< n, m, T > & operator=(const S rhs) &
Assignment operator = to assign values to Array.
Definition array.h:333
std::string str(int prec=8, char separator=' ') const
Convert to string for printing.
Definition array.h:645
Array< n, m, T > operator+() const
Unary + operator.
Definition array.h:291
bool operator==(const Array< n1, m1, S > &rhs) const
Compare equality of Arrays.
Definition array.h:362
Array< n, m, T > & operator/=(const Array< n, m, S > &rhs) &
Division assign with array or scalar.
Definition array.h:558
Array< n, m, T > sort(Vector< N, int > &permutation, hila::sort order=hila::sort::ascending) const
implement sort as casting to array
Definition array.h:652
Array< n, m, hila::arithmetic_type< T > > real() const
Returns real part of Array.
Definition array.h:593
Array()=default
Construct a new Matrix object.
Array< n, m, T > & operator*=(const S rhs) &
multiply assign with scalar
Definition array.h:523
Array< n, m, hila::arithmetic_type< T > > imag() const
return imaginary part
Definition array.h:602
Array< n, m, T > operator-() const
Unary - operator.
Definition array.h:277
Array< n, m, T > & operator-=(const Array< n, m, S > &rhs) &
Subtract assign operator with Array or scalar.
Definition array.h:456
constexpr int columns() const
Returns number of columns.
Definition array.h:147
T e(const int i, const int j) const
Standard array indexing operation for 2D and 1D Arrays.
Definition array.h:196
bool operator!=(const Array< n1, m1, S > &rhs) const
Compare non-equality of two Arrays.
Definition array.h:388
hila::arithmetic_type< T > squarenorm() const
calculate square norm - sum of squared elements
Definition array.h:611
Vector< n, T > & asVector()
Cast Array1D to Vector.
Definition array.h:237
Array< n, m, T > conj() const
Returns element wise Complex conjugate of Array.
Definition array.h:581
Matrix< n, m, T > & asMatrix()
Cast Array to Matrix.
Definition array.h:222
Array< n, m, T > & random()
Fill Array with random elements.
Definition array.h:624
Array< n, m, T > & operator*=(const Array< n, m, S > &rhs) &
Multiply assign scalar or array.
Definition array.h:512
Array< n, m, T > & gaussian_random(double width=1.0)
Fill Array with Gaussian random elements.
Definition array.h:637
Define type DiagonalMatrix<n,T>
Matrix class which defines matrix operations.
Definition matrix.h:1620
T arg(const Complex< T > &a)
Return argument of Complex number.
Definition cmplx.h:1199
Definition of Matrix types.
Implement hila::swap for gauge fields.
Definition array.h:981
T gaussian_random()
Template function T hila::gaussian_random<T>(),generates gaussian random value of type T,...
Definition random.h:183
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:121
std::string to_string(const Array< n, m, T > &A, int prec=8, char separator=' ')
Converts Array object to string.
Definition array.h:995
hila::is_complex_or_arithmetic<T>::value
Definition cmplx.h:665