Graph Framework
Loading...
Searching...
No Matches
backend.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
6//------------------------------------------------------------------------------
7
8#ifndef backend_h
9#define backend_h
10
11#include <algorithm>
12#include <vector>
13#include <cmath>
14
15#include "special_functions.hpp"
16#include "register.hpp"
17
19namespace backend {
20//******************************************************************************
21// Data buffer.
22//******************************************************************************
23//------------------------------------------------------------------------------
27//------------------------------------------------------------------------------
28 template<jit::float_scalar T>
29 class buffer : public std::vector<T> {
30 public:
31 using std::vector<T>::size;
32 using std::vector<T>::data;
33 using std::vector<T>::assign;
34
35//------------------------------------------------------------------------------
37//------------------------------------------------------------------------------
39 std::vector<T> () {}
40
41//------------------------------------------------------------------------------
45//------------------------------------------------------------------------------
46 buffer(const size_t s) :
47 std::vector<T> (s) {}
48
49//------------------------------------------------------------------------------
54//------------------------------------------------------------------------------
55 buffer(const size_t s, const T d) :
56 std::vector<T> (s, d) {}
57
58//------------------------------------------------------------------------------
62//------------------------------------------------------------------------------
63 buffer(const std::vector<T> &d) :
64 std::vector<T> (d) {}
65
66//------------------------------------------------------------------------------
70//------------------------------------------------------------------------------
71 buffer(const buffer &d) :
72 std::vector<T> (d) {}
73
74//------------------------------------------------------------------------------
80//------------------------------------------------------------------------------
81 buffer(const T min, const T dx, const size_t num) : std::vector<T> (num) {
82 for (size_t i = 0; i < num; i++) {
83 (*this)[i] = dx*i + min;
84 }
85 }
86
87//------------------------------------------------------------------------------
91//------------------------------------------------------------------------------
92 void set(const T d) {
93 assign(size(), d);
94 }
95
96//------------------------------------------------------------------------------
100//------------------------------------------------------------------------------
101 void set(const std::vector<T> &d) {
102 assign(d.cbegin(), d.cend());
103 }
104
105//------------------------------------------------------------------------------
109//------------------------------------------------------------------------------
110 bool is_same() const {
111 const T same = (*this)[0];
112 for (size_t i = 1, ie = size(); i < ie; i++) {
113 if ((*this)[i] != same) {
114 return false;
115 }
116 }
117
118 return true;
119 }
120
121//------------------------------------------------------------------------------
125//------------------------------------------------------------------------------
126 bool is_zero() const {
127 for (const T &d : *this) {
128 if (d != static_cast<T> (0.0)) {
129 return false;
130 }
131 }
132
133 return true;
134 }
135
136//------------------------------------------------------------------------------
140//------------------------------------------------------------------------------
141 bool has_zero() const {
142 for (const T &d : *this) {
143 if (d == static_cast<T> (0.0)) {
144 return true;
145 }
146 }
147
148 return false;
149 }
150
151//------------------------------------------------------------------------------
155//------------------------------------------------------------------------------
156 bool is_negative() const {
157 for (const T &d : *this) {
158 if (std::real(d) > std::real(static_cast<T> (0.0))) {
159 return false;
160 }
161 }
162
163 return true;
164 }
165
166//------------------------------------------------------------------------------
170//------------------------------------------------------------------------------
171 bool is_even() const {
172 for (const T &d : *this) {
173 if (std::fmod(std::real(d), std::real(static_cast<T> (2.0)))) {
174 return false;
175 }
176 }
177
178 return true;
179 }
180
181//------------------------------------------------------------------------------
185//------------------------------------------------------------------------------
186 bool is_none() const {
187 for (const T &d : *this) {
188 if (d != static_cast<T> (-1.0)) {
189 return false;
190 }
191 }
192
193 return true;
194 }
195
196//------------------------------------------------------------------------------
200//------------------------------------------------------------------------------
201#define apply_op(op) \
202for (T &d : *this) { \
203 d = op(d); \
204}
205
206//------------------------------------------------------------------------------
208//------------------------------------------------------------------------------
209 void sqrt() {
210 apply_op(std::sqrt)
211 }
212
213//------------------------------------------------------------------------------
215//------------------------------------------------------------------------------
216 void exp() {
217 apply_op(std::exp)
218 }
219
220//------------------------------------------------------------------------------
222//------------------------------------------------------------------------------
223 void log() {
224 apply_op(std::log)
225 }
226
227//------------------------------------------------------------------------------
229//------------------------------------------------------------------------------
230 void sin() {
231 apply_op(std::sin)
232 }
233
234//------------------------------------------------------------------------------
236//------------------------------------------------------------------------------
237 void cos() {
238 apply_op(std::cos)
239 }
240
241//------------------------------------------------------------------------------
243//------------------------------------------------------------------------------
244 void real() {
245 apply_op(std::real)
246 }
247
248//------------------------------------------------------------------------------
250//------------------------------------------------------------------------------
251 void erf() requires(std::floating_point<T>) {
252 apply_op(std::erf)
253 }
254
255//------------------------------------------------------------------------------
257//------------------------------------------------------------------------------
258 void erfi() requires(jit::complex_scalar<T>) {
260 }
261
262//------------------------------------------------------------------------------
266//------------------------------------------------------------------------------
267 bool is_normal() const {
268 for (const T &x : *this) {
269 if constexpr (jit::complex_scalar<T>) {
270 if (std::isnan(std::real(x)) || std::isinf(std::real(x)) ||
271 std::isnan(std::imag(x)) || std::isinf(std::imag(x))) {
272 return false;
273 }
274 } else {
275 if (std::isnan(x) || std::isinf(x)) {
276 return false;
277 }
278 }
279 }
280 return true;
281 }
282
283//------------------------------------------------------------------------------
289//------------------------------------------------------------------------------
290 buffer<T> index_row(const size_t index, const size_t num_columns) {
291 buffer<T> b(num_columns);
292 const size_t num_rows = size()/num_columns;
293 for (size_t j = 0; j < num_columns; j++) {
294 b[j] = (*this)[index*num_rows + j];
295 }
296 return b;
297 }
298
299//------------------------------------------------------------------------------
305//------------------------------------------------------------------------------
306 buffer<T> index_column(const size_t index, const size_t num_columns) {
307 const size_t num_rows = size()/num_columns;
308 buffer<T> b(num_rows);
309 for (size_t i = 0; i < num_rows; i++) {
310 b[i] = (*this)[i*num_rows + index];
311 }
312 return b;
313 }
314
315//------------------------------------------------------------------------------
320//------------------------------------------------------------------------------
321#define row_op(opp, oppeq) \
322if (size() > x.size()) { \
323 assert(size()%x.size() == 0 && \
324 "Vector operand size is not a multiple of matrix operand size"); \
325 \
326 const size_t num_columns = size()/x.size(); \
327 const size_t num_rows = x.size(); \
328 for (size_t i = 0; i < num_rows; i++) { \
329 for (size_t j = 0; j < num_columns; j++) { \
330 (*this)[i*num_columns + j] oppeq x[i]; \
331 } \
332 } \
333} else { \
334 assert(x.size()%size() == 0 && \
335 "Vector operand size is not a multiple of matrix operand size"); \
336 \
337 std::vector<T> m(x.size()); \
338 const size_t num_columns = x.size()/size(); \
339 const size_t num_rows = size(); \
340 for (size_t i = 0; i < num_rows; i++) { \
341 for (size_t j = 0; j < num_columns; j++) { \
342 m[i*num_columns + j] = (*this)[i] opp x[i*num_columns + j]; \
343 } \
344 } \
345 *this = m; \
346}
347
348//------------------------------------------------------------------------------
355//------------------------------------------------------------------------------
356 void add_row(const buffer<T> &x) {
357 row_op(+, +=)
358 }
359
360//------------------------------------------------------------------------------
365//------------------------------------------------------------------------------
366#define col_op(opp, oppeq) \
367if (size() > x.size()) { \
368 assert(size()%x.size() == 0 && \
369 "Vector operand size is not a multiple of matrix operand size"); \
370 \
371 const size_t num_columns = size()/x.size(); \
372 const size_t num_rows = x.size(); \
373 for (size_t i = 0; i < num_rows; i++) { \
374 for (size_t j = 0; j < num_columns; j++) { \
375 (*this)[i*num_columns + j] oppeq x[j]; \
376 } \
377 } \
378} else { \
379 assert(x.size()%size() == 0 && \
380 "Vector operand size is not a multiple of matrix operand size"); \
381 \
382 std::vector<T> m(x.size()); \
383 const size_t num_columns = x.size()/size(); \
384 const size_t num_rows = size(); \
385 for (size_t i = 0; i < num_rows; i++) { \
386 for (size_t j = 0; j < num_columns; j++) { \
387 m[i*num_columns + j] = (*this)[j] opp x[i*num_columns + j]; \
388 } \
389 } \
390 *this = m; \
391}
392
393//------------------------------------------------------------------------------
400//------------------------------------------------------------------------------
401 void add_col(const buffer<T> &x) {
402 col_op(+, +=)
403 }
404
405//------------------------------------------------------------------------------
412//------------------------------------------------------------------------------
413 void subtract_row(const buffer<T> &x) {
414 row_op(-, -=)
415 }
416
417//------------------------------------------------------------------------------
424//------------------------------------------------------------------------------
425 void subtract_col(const buffer<T> &x) {
426 col_op(-, -=)
427 }
428
429//------------------------------------------------------------------------------
436//------------------------------------------------------------------------------
437 void multiply_row(const buffer<T> &x) {
438 row_op(*, *=)
439 }
440
441//------------------------------------------------------------------------------
448//------------------------------------------------------------------------------
449 void multiply_col(const buffer<T> &x) {
450 col_op(*, *=)
451 }
452
453//------------------------------------------------------------------------------
460//------------------------------------------------------------------------------
461 void divide_row(const buffer<T> &x) {
462 row_op(/, /=)
463 }
464
465//------------------------------------------------------------------------------
472//------------------------------------------------------------------------------
473 void divide_col(const buffer<T> &x) {
474 col_op(/, /=)
475 }
476
477//------------------------------------------------------------------------------
481//------------------------------------------------------------------------------
482 #define row_fn(fn) \
483 if (size() > x.size()) { \
484 assert(size()%x.size() == 0 && \
485 "Vector operand size is not a multiple of matrix operand size"); \
486 \
487 const size_t num_columns = size()/x.size(); \
488 const size_t num_rows = x.size(); \
489 for (size_t i = 0; i < num_rows; i++) { \
490 for (size_t j = 0; j < num_columns; j++) { \
491 (*this)[i*num_columns + j] = fn((*this)[i*num_columns + j], x[i]); \
492 } \
493 } \
494 } else { \
495 assert(x.size()%size() == 0 && \
496 "Vector operand size is not a multiple of matrix operand size"); \
497 \
498 std::vector<T> m(x.size()); \
499 const size_t num_columns = x.size()/size(); \
500 const size_t num_rows = size(); \
501 for (size_t i = 0; i < num_rows; i++) { \
502 for (size_t j = 0; j < num_columns; j++) { \
503 m[i*num_columns + j] = fn((*this)[i], x[i*num_columns + j]); \
504 } \
505 } \
506 *this = m; \
507 }
508
509//------------------------------------------------------------------------------
516//------------------------------------------------------------------------------
517 void min_row(const buffer<T> &x) {
518 row_fn(std::min)
519 }
520
521//------------------------------------------------------------------------------
525//------------------------------------------------------------------------------
526 #define col_fn(fn) \
527 if (size() > x.size()) { \
528 assert(size()%x.size() == 0 && \
529 "Vector operand size is not a multiple of matrix operand size"); \
530 \
531 const size_t num_columns = size()/x.size(); \
532 const size_t num_rows = x.size(); \
533 for (size_t i = 0; i < num_rows; i++) { \
534 for (size_t j = 0; j < num_columns; j++) { \
535 (*this)[i*num_columns + j] = fn((*this)[i*num_columns + j], x[j]); \
536 } \
537 } \
538 } else { \
539 assert(x.size()%size() == 0 && \
540 "Vector operand size is not a multiple of matrix operand size"); \
541 \
542 std::vector<T> m(x.size()); \
543 const size_t num_columns = x.size()/size(); \
544 const size_t num_rows = size(); \
545 for (size_t i = 0; i < num_rows; i++) { \
546 for (size_t j = 0; j < num_columns; j++) { \
547 m[i*num_columns + j] = fn((*this)[j], x[i*num_columns + j]); \
548 } \
549 } \
550 *this = m; \
551 }
552
553//------------------------------------------------------------------------------
560//------------------------------------------------------------------------------
561 void min_col(const buffer<T> &x) {
562 col_fn(std::min)
563 }
564
565//------------------------------------------------------------------------------
572//------------------------------------------------------------------------------
573 void atan_row(const buffer<T> &x) {
574 if (size() > x.size()) {
575 assert(size()%x.size() == 0 &&
576 "Vector operand size is not a multiple of matrix operand size");
577
578 const size_t num_columns = size()/x.size();
579 const size_t num_rows = x.size();
580 for (size_t i = 0; i < num_rows; i++) {
581 for (size_t j = 0; j < num_columns; j++) {
582 if constexpr (jit::complex_scalar<T>) {
583 (*this)[i*num_columns + j] = std::atan(x[i]/(*this)[i*num_columns + j]);
584 } else {
585 (*this)[i*num_columns + j] = std::atan2(x[i], (*this)[i*num_columns + j]);
586 }
587 }
588 }
589 } else {
590 assert(x.size()%size() == 0 &&
591 "Vector operand size is not a multiple of matrix operand size");
592
593 std::vector<T> m(x.size());
594 const size_t num_columns = x.size()/size();
595 const size_t num_rows = size();
596 for (size_t i = 0; i < num_rows; i++) {
597 for (size_t j = 0; j < num_columns; j++) {
598 if constexpr (jit::complex_scalar<T>) {
599 m[i*num_columns + j] = std::atan(x[i*num_columns + j]/(*this)[i]);
600 } else {
601 m[i*num_columns + j] = std::atan2(x[i*num_columns + j], (*this)[i]);
602 }
603 }
604 }
605 *this = m;
606 }
607 }
608
609//------------------------------------------------------------------------------
616//------------------------------------------------------------------------------
617 void atan_col(const buffer<T> &x) {
618 if (size() > x.size()) {
619 assert(size()%x.size() == 0 &&
620 "Vector operand size is not a multiple of matrix operand size");
621
622 const size_t num_columns = size()/x.size();
623 const size_t num_rows = x.size();
624 for (size_t i = 0; i < num_columns; i++) {
625 for (size_t j = 0; j < num_rows; j++) {
626 if constexpr (jit::complex_scalar<T>) {
627 (*this)[i*num_columns + j] = std::atan(x[j]/(*this)[i*num_columns + j]);
628 } else {
629 (*this)[i*num_columns + j] = std::atan2(x[j], (*this)[i*num_columns + j]);
630 }
631 }
632 }
633 } else {
634 assert(x.size()%size() == 0 &&
635 "Vector operand size is not a multiple of matrix operand size");
636
637 std::vector<T> m(x.size());
638 const size_t num_columns = x.size()/size();
639 const size_t num_rows = size();
640 for (size_t i = 0; i < num_rows; i++) {
641 for (size_t j = 0; j < num_columns; j++) {
642 if constexpr (jit::complex_scalar<T>) {
643 m[i*num_columns + j] = std::atan(x[i*num_columns + j]/(*this)[j]);
644 } else {
645 m[i*num_columns + j] = std::atan2(x[i*num_columns + j], (*this)[j]);
646 }
647 }
648 }
649 *this = m;
650 }
651 }
652
653//------------------------------------------------------------------------------
660//------------------------------------------------------------------------------
661 void pow_row(const buffer<T> &x) {
662 if (size() > x.size()) {
663 assert(size()%x.size() == 0 &&
664 "Vector operand size is not a multiple of matrix operand size");
665
666 const size_t num_columns = size()/x.size();
667 const size_t num_rows = x.size();
668 for (size_t i = 0; i < num_rows; i++) {
669 for (size_t j = 0; j < num_columns; j++) {
670 (*this)[i*num_columns + j] = std::pow((*this)[i*num_columns + j], x[i]);
671 }
672 }
673 } else {
674 assert(x.size()%size() == 0 &&
675 "Vector operand size is not a multiple of matrix operand size");
676
677 std::vector<T> m(x.size());
678 const size_t num_columns = x.size()/size();
679 const size_t num_rows = size();
680 for (size_t i = 0; i < num_columns; i++) {
681 for (size_t j = 0; j < num_rows; j++) {
682 m[i*num_columns + j] = std::pow((*this)[i], x[i*num_columns + j]);
683 }
684 }
685 *this = m;
686 }
687 }
688
689//------------------------------------------------------------------------------
696//------------------------------------------------------------------------------
697 void pow_col(const buffer<T> &x) {
698 if (size() > x.size()) {
699 assert(size()%x.size() == 0 &&
700 "Vector operand size is not a multiple of matrix operand size");
701
702 const size_t num_columns = size()/x.size();
703 const size_t num_rows = x.size();
704 for (size_t i = 0; i < num_rows; i++) {
705 for (size_t j = 0; j < num_columns; j++) {
706 (*this)[i*num_columns + j] = std::pow((*this)[i*num_columns + j], x[j]);
707 }
708 }
709 } else {
710 assert(x.size()%size() == 0 &&
711 "Vector operand size is not a multiple of matrix operand size");
712
713 std::vector<T> m(x.size());
714 const size_t num_columns = x.size()/size();
715 const size_t num_rows = size();
716 for (size_t i = 0; i < num_rows; i++) {
717 for (size_t j = 0; j < num_columns; j++) {
718 m[i*num_columns + j] = std::pow((*this)[j], x[i*num_columns + j]);
719 }
720 }
721 *this = m;
722 }
723 }
724
725//------------------------------------------------------------------------------
732//------------------------------------------------------------------------------
733 void hypot_row(const buffer<T> &x) requires(std::floating_point<T>) {
734 if (size() > x.size()) {
735 assert(size()%x.size() == 0 &&
736 "Vector operand size is not a multiple of matrix operand size");
737
738 const size_t num_columns = size()/x.size();
739 const size_t num_rows = x.size();
740 for (size_t i = 0; i < num_rows; i++) {
741 for (size_t j = 0; j < num_columns; j++) {
742 (*this)[i*num_columns + j] = std::hypot((*this)[i*num_columns + j], x[i]);
743 }
744 }
745 } else {
746 assert(x.size()%size() == 0 &&
747 "Vector operand size is not a multiple of matrix operand size");
748
749 std::vector<T> m(x.size());
750 const size_t num_columns = x.size()/size();
751 const size_t num_rows = size();
752 for (size_t i = 0; i < num_columns; i++) {
753 for (size_t j = 0; j < num_rows; j++) {
754 m[i*num_columns + j] = std::hypot((*this)[i], x[i*num_columns + j]);
755 }
756 }
757 *this = m;
758 }
759 }
760
761//------------------------------------------------------------------------------
768//------------------------------------------------------------------------------
769 void hypot_col(const buffer<T> &x) requires(std::floating_point<T>) {
770 if (size() > x.size()) {
771 assert(size()%x.size() == 0 &&
772 "Vector operand size is not a multiple of matrix operand size");
773
774 const size_t num_columns = size()/x.size();
775 const size_t num_rows = x.size();
776 for (size_t i = 0; i < num_rows; i++) {
777 for (size_t j = 0; j < num_columns; j++) {
778 (*this)[i*num_columns + j] = std::hypot((*this)[i*num_columns + j], x[j]);
779 }
780 }
781 } else {
782 assert(x.size()%size() == 0 &&
783 "Vector operand size is not a multiple of matrix operand size");
784
785 std::vector<T> m(x.size());
786 const size_t num_columns = x.size()/size();
787 const size_t num_rows = size();
788 for (size_t i = 0; i < num_rows; i++) {
789 for (size_t j = 0; j < num_columns; j++) {
790 m[i*num_columns + j] = std::hypot((*this)[j], x[i*num_columns + j]);
791 }
792 }
793 *this = m;
794 }
795 }
796
797//------------------------------------------------------------------------------
804//------------------------------------------------------------------------------
805 void copysign_row(const buffer<T> &x) requires(std::floating_point<T>) {
806 if (size() > x.size()) {
807 assert(size()%x.size() == 0 &&
808 "Vector operand size is not a multiple of matrix operand size");
809
810 const size_t num_columns = size()/x.size();
811 const size_t num_rows = x.size();
812 for (size_t i = 0; i < num_rows; i++) {
813 for (size_t j = 0; j < num_columns; j++) {
814 (*this)[i*num_columns + j] = std::copysign((*this)[i*num_columns + j], x[i]);
815 }
816 }
817 } else {
818 assert(x.size()%size() == 0 &&
819 "Vector operand size is not a multiple of matrix operand size");
820
821 std::vector<T> m(x.size());
822 const size_t num_columns = x.size()/size();
823 const size_t num_rows = size();
824 for (size_t i = 0; i < num_rows; i++) {
825 for (size_t j = 0; j < num_columns; j++) {
826 m[i*num_columns + j] = std::copysign((*this)[i], x[i*num_columns + j]);
827 }
828 }
829 *this = m;
830 }
831 }
832
833//------------------------------------------------------------------------------
840//------------------------------------------------------------------------------
841 void copysign_col(const buffer<T> &x) {
842 if (size() > x.size()) {
843 assert(size()%x.size() == 0 &&
844 "Vector operand size is not a multiple of matrix operand size");
845
846 const size_t num_columns = size()/x.size();
847 const size_t num_rows = x.size();
848 for (size_t i = 0; i < num_columns; i++) {
849 for (size_t j = 0; j < num_rows; j++) {
850 (*this)[i*num_columns + j] = std::copysign((*this)[i*num_columns + j], x[j]);
851 }
852 }
853 } else {
854 assert(x.size()%size() == 0 &&
855 "Vector operand size is not a multiple of matrix operand size");
856
857 std::vector<T> m(x.size());
858 const size_t num_columns = x.size()/size();
859 const size_t num_rows = size();
860 for (size_t i = 0; i < num_rows; i++) {
861 for (size_t j = 0; j < num_columns; j++) {
862 m[i*num_columns + j] = std::copysign((*this)[j], x[i*num_columns + j]);
863 }
864 }
865 *this = m;
866 }
867 }
868
869//------------------------------------------------------------------------------
873//------------------------------------------------------------------------------
875 for (T &d : *this) {
876 if constexpr (jit::complex_scalar<T>) {
877 assert(d.imag() == 0.0 && "Imaginary part not zero.");
878 d = static_cast<T> (!d.real());
879 } else {
880 d = !d;
881 }
882 }
883 return *this;
884 }
885
886//------------------------------------------------------------------------------
891//------------------------------------------------------------------------------
892 buffer<T> if_(const buffer<T> &t, const buffer<T> &f) {
893 if (size() == 1) {
894 if constexpr (std::floating_point<T>) {
895 return (*this)[0] ? t : f;
896 } else {
897 return (*this)[0] != static_cast<T> (0) ? t : f;
898 }
899 } else {
900 if (t.size() == 1) {
901 if (f.size() == 1) {
902 for (T &d : *this) {
903 if constexpr (std::floating_point<T>) {
904 d = d ? t[0] : f[0];
905 } else {
906 d = d != static_cast<T> (0) ? t[0] : f[0];
907 }
908 }
909 return *this;
910 } else {
911 assert(size() == f.size() && "Incompatable buffersize.");
912 for (size_t i = 0, ie = size(); i < ie; i++) {
913 if constexpr (std::floating_point<T>) {
914 (*this)[i] = (*this)[i] ? t[0] : f[i];
915 } else {
916 (*this)[i] = (*this)[i] != static_cast<T> (0) ? t[0] : f[i];
917 }
918 }
919 return *this;
920 }
921 } else {
922 assert(size() == t.size() && "Incompatable buffersize.");
923 if (f.size() == 1) {
924 for (size_t i = 0, ie = size(); i < ie; i++) {
925 if constexpr (std::floating_point<T>) {
926 (*this)[i] = (*this)[i] ? t[i] : f[0];
927 } else {
928 (*this)[i] = (*this)[i] != static_cast<T> (0) ? t[i] : f[0];
929 }
930 }
931 return *this;
932 } else {
933 assert(size() == f.size() && "Incompatable buffersize.");
934 for (size_t i = 0, ie = size(); i < ie; i++) {
935 if constexpr (std::floating_point<T>) {
936 (*this)[i] = (*this)[i] ? t[i] : f[i];
937 } else {
938 (*this)[i] = (*this)[i] != static_cast<T> (0) ? t[i] : f[i];
939 }
940 }
941 return *this;
942 }
943 }
944 }
945 }
946
947//------------------------------------------------------------------------------
951//------------------------------------------------------------------------------
952#define logic_is(op) \
953for (T &d : *this) { \
954 d = std::op(d); \
955}
956
957//------------------------------------------------------------------------------
959//------------------------------------------------------------------------------
960 void isinf() {
962 }
963
964//------------------------------------------------------------------------------
966//------------------------------------------------------------------------------
967 void isnan() {
969 }
970
972 typedef T base;
973 };
974
975//------------------------------------------------------------------------------
983//------------------------------------------------------------------------------
984 template<jit::float_scalar T>
985 inline bool operator==(const buffer<T> &a, const buffer<T> &b) {
986 if (a.size() != b.size()) {
987 return false;
988 }
989
990 for (size_t i = 0, ie = a.size(); i < ie; i++) {
991 if (a[i] != b[i]) {
992 return false;
993 }
994 }
995 return true;
996 }
997
998//------------------------------------------------------------------------------
1002//------------------------------------------------------------------------------
1003#define build_assoc_func(func) \
1004if (b.size() == 1) { \
1005 const T right = b[0]; \
1006 for (T &l : a) { \
1007 l = func(std::real(l), \
1008 std::real(right)); \
1009 } \
1010 return a; \
1011} else if (a.size() == 1) { \
1012 const T left = a[0]; \
1013 for (T &r : b) { \
1014 r = func(std::real(r), \
1015 std::real(left)); \
1016 } \
1017 return b; \
1018} \
1019 \
1020assert(a.size() == b.size() && \
1021 "Left and right sizes are incompatible."); \
1022for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1023 a[i] = func(std::real(a[i]), \
1024 std::real(b[i])); \
1025} \
1026return a;
1027
1028//------------------------------------------------------------------------------
1036//------------------------------------------------------------------------------
1037 template<jit::float_scalar T>
1039 build_assoc_func(std::max);
1040 }
1041
1042//------------------------------------------------------------------------------
1050//------------------------------------------------------------------------------
1051 template<jit::float_scalar T>
1053 build_assoc_func(std::min);
1054 }
1055
1056//------------------------------------------------------------------------------
1060//------------------------------------------------------------------------------
1061#define build_assoc_op(op) \
1062if (b.size() == 1) { \
1063 const T right = b[0]; \
1064 for (T &l : a) { \
1065 l op right; \
1066 } \
1067 return a; \
1068} else if (a.size() == 1) { \
1069 const T left = a[0]; \
1070 for (T &r : b) { \
1071 r op left; \
1072 } \
1073 return b; \
1074} \
1075 \
1076assert(a.size() == b.size() && \
1077 "Left and right sizes are incompatible."); \
1078for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1079 a[i] op b[i]; \
1080} \
1081return a;
1082
1083//------------------------------------------------------------------------------
1091//------------------------------------------------------------------------------
1092 template<jit::float_scalar T>
1094 build_assoc_op(+=)
1095 }
1096
1097//------------------------------------------------------------------------------
1102//------------------------------------------------------------------------------
1103#define build_non_assoc_op(op, opeq) \
1104if (b.size() == 1) { \
1105 const T right = b[0]; \
1106 for (T &l : a) { \
1107 l opeq right; \
1108 } \
1109 return a; \
1110} else if (a.size() == 1) { \
1111 const T left = a[0]; \
1112 for (T &r : b) { \
1113 r = left op r; \
1114 } \
1115 return b; \
1116} \
1117 \
1118assert(a.size() == b.size() && \
1119 "Left and right sizes are incompatible."); \
1120for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1121 a[i] opeq b[i]; \
1122} \
1123return a;
1124
1125//------------------------------------------------------------------------------
1133//------------------------------------------------------------------------------
1134 template<jit::float_scalar T>
1136 build_non_assoc_op(-, -=)
1137 }
1138
1139//------------------------------------------------------------------------------
1147//------------------------------------------------------------------------------
1148 template<jit::float_scalar T>
1150 build_assoc_op(*=)
1151 }
1152
1153//------------------------------------------------------------------------------
1161//------------------------------------------------------------------------------
1162 template<jit::float_scalar T>
1164 build_non_assoc_op(/, /=)
1165 }
1166
1167//------------------------------------------------------------------------------
1171//------------------------------------------------------------------------------
1172#define build_assoc_func(func) \
1173if (b.size() == 1) { \
1174 const T right = b[0]; \
1175 for (T &l : a) { \
1176 l = func(l, right); \
1177 } \
1178 return a; \
1179} else if (a.size() == 1) { \
1180 const T left = a[0]; \
1181 for (T &r : b) { \
1182 r = func(r, left); \
1183 } \
1184 return b; \
1185} \
1186 \
1187assert(a.size() == b.size() && \
1188 "Left and right sizes are incompatible."); \
1189for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1190 a[i] = func(a[i], b[i]); \
1191} \
1192return a;
1193
1194//------------------------------------------------------------------------------
1202//------------------------------------------------------------------------------
1203 template<std::floating_point T>
1205 build_assoc_func(std::hypot)
1206 }
1207
1208//------------------------------------------------------------------------------
1217//------------------------------------------------------------------------------
1218 template<jit::float_scalar T>
1220 constexpr bool use_fma = !jit::complex_scalar<T> &&
1221#ifdef FP_FAST_FMA
1222 true;
1223#else
1224 false;
1225#endif
1226
1227 if (a.size() == 1) {
1228 const T left = a[0];
1229
1230 if (b.size() == 1) {
1231 const T middle = b[0];
1232 for (size_t i = 0, ie = c.size(); i < ie; i++) {
1233 if constexpr (use_fma) {
1234 c[i] = std::fma(left, middle, c[i]);
1235 } else {
1236 c[i] = left*middle + c[i];
1237 }
1238 }
1239 return c;
1240 } else if (c.size() == 1) {
1241 const T right = c[0];
1242 for (size_t i = 0, ie = b.size(); i < ie; i++) {
1243 if constexpr (use_fma) {
1244 b[i] = std::fma(left, b[i], right);
1245 } else {
1246 b[i] = left*b[i] + right;
1247 }
1248 }
1249 return b;
1250 }
1251
1252 assert(b.size() == c.size() &&
1253 "Size mismatch between middle and right.");
1254 for (size_t i = 0, ie = b.size(); i < ie; i++) {
1255 if constexpr (use_fma) {
1256 b[i] = std::fma(left, b[i], c[i]);
1257 } else {
1258 b[i] = left*b[i] + c[i];
1259 }
1260 }
1261 return b;
1262 } else if (b.size() == 1) {
1263 const T middle = b[0];
1264 if (c.size() == 1) {
1265 const T right = c[0];
1266 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1267 if constexpr (use_fma) {
1268 a[i] = std::fma(a[i], middle, right);
1269 } else {
1270 a[i] = a[i]*middle + right;
1271 }
1272 }
1273 return a;
1274 }
1275
1276 assert(a.size() == c.size() &&
1277 "Size mismatch between left and right.");
1278 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1279 if constexpr (use_fma) {
1280 a[i] = std::fma(a[i], middle, c[i]);
1281 } else {
1282 a[i] = a[i]*middle + c[i];
1283 }
1284 }
1285 return a;
1286 } else if (c.size() == 1) {
1287 assert(a.size() == b.size() &&
1288 "Size mismatch between left and middle.");
1289 const T right = c[0];
1290 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1291 if constexpr (use_fma) {
1292 a[i] = std::fma(a[i], b[i], right);
1293 } else {
1294 a[i] = a[i]*b[i] + right;
1295 }
1296 }
1297 return a;
1298 }
1299
1300 assert(a.size() == b.size() &&
1301 b.size() == c.size() &&
1302 a.size() == c.size() &&
1303 "Left, middle and right sizes are incompatible.");
1304 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1305 if constexpr (use_fma) {
1306 a[i] = std::fma(a[i], b[i], c[i]);
1307 } else {
1308 a[i] = a[i]*b[i] + c[i];
1309 }
1310 }
1311 return a;
1312 }
1313
1314//------------------------------------------------------------------------------
1322//------------------------------------------------------------------------------
1323 template<std::floating_point T>
1325 if (b.size() == 1) {
1326 const T right = b[0];
1327 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1328 a[i] = std::fmod(a[i], right);
1329 }
1330 return a;
1331 } else if (a.size() == 1) {
1332 const T left = a[0];
1333 for (size_t i = 0, ie = b.size(); i < ie; i++) {
1334 b[i] = std::fmod(left, b[i]);
1335 }
1336 return b;
1337 }
1338
1339 assert(a.size() == b.size() &&
1340 "Left and right sizes are incompatible.");
1341 for (size_t i = 0, ie = a.size(); i < ie; i++) {
1342 a[i] = std::fmod(a[i], b[i]);
1343 }
1344 return a;
1345 }
1346
1347//------------------------------------------------------------------------------
1351//------------------------------------------------------------------------------
1352#define logic_op(op) \
1353if (b.size() == 1) { \
1354 const T right = b[0]; \
1355 for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1356 a[i] = static_cast<T> (a[i] op right); \
1357 } \
1358 return a; \
1359} else if (a.size() == 1) { \
1360 const T left = a[0]; \
1361 for (size_t i = 0, ie = b.size(); i < ie; i++) { \
1362 b[i] = static_cast<T> (left op b[i]); \
1363 } \
1364 return b; \
1365} \
1366 \
1367assert(a.size() == b.size() && \
1368 "Left and right sizes are incompatible."); \
1369for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1370 a[i] = static_cast<T> (a[i] op b[i]); \
1371} \
1372return a;
1373
1374//------------------------------------------------------------------------------
1382//------------------------------------------------------------------------------
1383 template<jit::float_scalar T>
1385 logic_op(==)
1386 }
1387
1388//------------------------------------------------------------------------------
1396//------------------------------------------------------------------------------
1397 template<jit::float_scalar T>
1399 logic_op(!=)
1400 }
1401
1402//------------------------------------------------------------------------------
1410//------------------------------------------------------------------------------
1411 template<std::floating_point T>
1413 logic_op(>)
1414 }
1415
1416//------------------------------------------------------------------------------
1424//------------------------------------------------------------------------------
1425 template<std::floating_point T>
1426 inline buffer<T> operator<(buffer<T> &a, buffer<T> &b) {
1427 logic_op(<)
1428 }
1429
1430//------------------------------------------------------------------------------
1438//------------------------------------------------------------------------------
1439 template<std::floating_point T>
1441 logic_op(>=)
1442 }
1443
1444//------------------------------------------------------------------------------
1452//------------------------------------------------------------------------------
1453 template<std::floating_point T>
1454 inline buffer<T> operator<=(buffer<T> &a, buffer<T> &b) {
1455 logic_op(<=)
1456 }
1457
1458//------------------------------------------------------------------------------
1466//------------------------------------------------------------------------------
1467 template<std::floating_point T>
1469 logic_op(&&)
1470 }
1471
1472//------------------------------------------------------------------------------
1480//------------------------------------------------------------------------------
1481 template<std::floating_point T>
1483 logic_op(||)
1484 }
1485
1486//------------------------------------------------------------------------------
1490//------------------------------------------------------------------------------
1491#define branch_fn(fn) \
1492if (b.size() == 1) { \
1493 const T right = b[0]; \
1494 for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1495 a[i] = fn(a[i], right); \
1496 } \
1497 return a; \
1498} else if (a.size() == 1) { \
1499 const T left = a[0]; \
1500 for (size_t i = 0, ie = b.size(); i < ie; i++) { \
1501 b[i] = fn(left, b[i]); \
1502 } \
1503 return b; \
1504} \
1505 \
1506assert(a.size() == b.size() && \
1507 "Left and right sizes are incompatible."); \
1508for (size_t i = 0, ie = a.size(); i < ie; i++) { \
1509 a[i] = fn(a[i], b[i]); \
1510} \
1511return a;
1512
1513//------------------------------------------------------------------------------
1521//------------------------------------------------------------------------------
1522 template<std::floating_point T>
1523 inline buffer<T> min(buffer<T> &a, buffer<T> &b) {
1524 branch_fn(std::min)
1525 }
1526
1527//------------------------------------------------------------------------------
1535//------------------------------------------------------------------------------
1536 template<jit::float_scalar T>
1537 inline buffer<T> pow(buffer<T> &base, buffer<T> &exponent) {
1538 if (exponent.size() == 1) {
1539 const T right = exponent[0];
1540 if (std::imag(right) == 0) {
1541 const int64_t right_int = static_cast<int64_t> (std::real(right));
1542 if (std::real(right) - right_int) {
1543 if (right == static_cast<T> (0.5)) {
1544 base.sqrt();
1545 return base;
1546 }
1547
1548 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1549 base[i] = std::pow(base[i], right);
1550 }
1551 return base;
1552 }
1553
1554 if (right_int > 0) {
1555 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1556 const T left = base[i];
1557 for (size_t j = 0, je = right_int - 1; j < je; j++) {
1558 base[i] *= left;
1559 }
1560 }
1561 return base;
1562 } else if (right_int == 0) {
1563 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1564 base[i] = 1.0;
1565 }
1566 return base;
1567 } else {
1568 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1569 const T left = static_cast<T> (1.0)/base[i];
1570 base[i] = left;
1571 for (size_t j = 0, je = std::abs(right_int) - 1; j < je; j++) {
1572 base[i] *= left;
1573 }
1574 }
1575 return base;
1576 }
1577 } else {
1578 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1579 base[i] = std::pow(base[i], right);
1580 }
1581 return base;
1582 }
1583 } else if (base.size() == 1) {
1584 const T left = base[0];
1585 for (size_t i = 0, ie = exponent.size(); i < ie; i++) {
1586 exponent[i] = std::pow(left, exponent[i]);
1587 }
1588 return exponent;
1589 }
1590
1591 assert(base.size() == exponent.size() &&
1592 "Left and right sizes are incompatible.");
1593 for (size_t i = 0, ie = base.size(); i < ie; i++) {
1594 base[i] = std::pow(base[i], exponent[i]);
1595 }
1596 return base;
1597 }
1598
1599//------------------------------------------------------------------------------
1607//------------------------------------------------------------------------------
1608 template<jit::float_scalar T>
1610 if (y.size() == 1) {
1611 const T right = y[0];
1612 for (size_t i = 0, ie = x.size(); i < ie; i++) {
1613 if constexpr (jit::complex_scalar<T>) {
1614 x[i] = std::atan(right/x[i]);
1615 } else {
1616 x[i] = std::atan2(right, x[i]);
1617 }
1618 }
1619 return x;
1620 } else if (x.size() == 1) {
1621 const T left = x[0];
1622 for (size_t i = 0, ie = y.size(); i < ie; i++) {
1623 if constexpr (jit::complex_scalar<T>) {
1624 y[i] = std::atan(y[i]/left);
1625 } else {
1626 y[i] = std::atan2(y[i], left);
1627 }
1628 }
1629 return y;
1630 }
1631
1632 assert(x.size() == y.size() &&
1633 "Left and right sizes are incompatible.");
1634 for (size_t i = 0, ie = x.size(); i < ie; i++) {
1635 if constexpr (jit::complex_scalar<T>) {
1636 x[i] = std::atan(y[i]/x[i]);
1637 } else {
1638 x[i] = std::atan2(y[i], x[i]);
1639 }
1640 }
1641 return x;
1642 }
1643
1644//------------------------------------------------------------------------------
1652//------------------------------------------------------------------------------
1653 template<std::floating_point T>
1655 buffer<T> &y) {
1656 if (y.size() == 1) {
1657 const T right = y[0];
1658 for (size_t i = 0, ie = x.size(); i < ie; i++) {
1659 x[i] = std::copysign(x[i], right);
1660 }
1661 return x;
1662 } else if (x.size() == 1) {
1663 const T left = x[0];
1664 for (size_t i = 0, ie = y.size(); i < ie; i++) {
1665 y[i] = std::copysign(left, y[i]);
1666 }
1667 return y;
1668 }
1669
1670 assert(x.size() == y.size() &&
1671 "Left and right sizes are incompatible.");
1672 for (size_t i = 0, ie = x.size(); i < ie; i++) {
1673 x[i] = std::copysign(x[i], y[i]);
1674 }
1675 return x;
1676 }
1677}
1678
1679#endif /* backend_h */
#define col_op(opp, oppeq)
Applies an operator along a column.
Definition backend.hpp:366
#define col_fn(fn)
Applies a function along a column.
Definition backend.hpp:526
#define branch_fn(fn)
Applies a function with two operands.
Definition backend.hpp:1491
#define row_op(opp, oppeq)
Applies an operator along a row.
Definition backend.hpp:321
#define logic_op(op)
Applies a logical operator.
Definition backend.hpp:1352
#define build_assoc_func(func)
Applies an associative function.
Definition backend.hpp:1003
#define build_assoc_op(op)
Applies an associative operator.
Definition backend.hpp:1061
#define logic_is(op)
Applies a logical is operator.
Definition backend.hpp:952
#define build_non_assoc_op(op, opeq)
Applies a non-associative operator.
Definition backend.hpp:1103
#define apply_op(op)
Applies an operation over all elements in the buffer.
Definition backend.hpp:201
#define row_fn(fn)
Applies a function along a row.
Definition backend.hpp:482
Class representing a generic buffer.
Definition backend.hpp:29
void set(const std::vector< T > &d)
Assign a vector value.
Definition backend.hpp:101
void subtract_row(const buffer< T > &x)
Subtract row operation.
Definition backend.hpp:413
void multiply_row(const buffer< T > &x)
Multiply row operation.
Definition backend.hpp:437
void add_col(const buffer< T > &x)
Add col operation.
Definition backend.hpp:401
void erfi()
Take erfi.
Definition backend.hpp:258
void copysign_col(const buffer< T > &x)
copysign col operation.
Definition backend.hpp:841
void log()
Take log.
Definition backend.hpp:223
buffer(const buffer &d)
Construct a buffer backend from a buffer backend.
Definition backend.hpp:71
void sqrt()
Take sqrt.
Definition backend.hpp:209
buffer(const size_t s)
Construct a buffer backend with a size.
Definition backend.hpp:46
void hypot_row(const buffer< T > &x)
Hypot row operation.
Definition backend.hpp:733
bool is_normal() const
Check for normal values.
Definition backend.hpp:267
buffer()
Construct an empty buffer backend.
Definition backend.hpp:38
void isinf()
isinf query.
Definition backend.hpp:960
buffer< T > index_row(const size_t index, const size_t num_columns)
Index row.
Definition backend.hpp:290
bool is_negative() const
Is every element negative.
Definition backend.hpp:156
void pow_col(const buffer< T > &x)
Pow col operation.
Definition backend.hpp:697
buffer(const std::vector< T > &d)
Construct a buffer backend from a vector.
Definition backend.hpp:63
bool is_same() const
Is every element the same.
Definition backend.hpp:110
buffer(const size_t s, const T d)
Construct a buffer backend with a size.
Definition backend.hpp:55
buffer< T > operator!()
Not operation.
Definition backend.hpp:874
void divide_col(const buffer< T > &x)
Divide col operation.
Definition backend.hpp:473
void erf()
Take erf.
Definition backend.hpp:251
bool is_none() const
Is every element negative one.
Definition backend.hpp:186
void min_row(const buffer< T > &x)
Min row operation.
Definition backend.hpp:517
void pow_row(const buffer< T > &x)
Pow row operation.
Definition backend.hpp:661
void sin()
Take sin.
Definition backend.hpp:230
void add_row(const buffer< T > &x)
Add row operation.
Definition backend.hpp:356
buffer(const T min, const T dx, const size_t num)
Construct a buffer backend linearly.
Definition backend.hpp:81
void subtract_col(const buffer< T > &x)
Subtract col operation.
Definition backend.hpp:425
buffer< T > if_(const buffer< T > &t, const buffer< T > &f)
Apply condition.
Definition backend.hpp:892
void multiply_col(const buffer< T > &x)
Multiply col operation.
Definition backend.hpp:449
void min_col(const buffer< T > &x)
Min col operation.
Definition backend.hpp:561
bool is_even() const
Is every element even.
Definition backend.hpp:171
T base
Type def to retrieve the backend T type.
Definition backend.hpp:972
void divide_row(const buffer< T > &x)
Divide row operation.
Definition backend.hpp:461
void real()
Take cos.
Definition backend.hpp:244
void isnan()
isnan query.
Definition backend.hpp:967
void copysign_row(const buffer< T > &x)
copysign row operation.
Definition backend.hpp:805
void hypot_col(const buffer< T > &x)
Hypot col operation.
Definition backend.hpp:769
void atan_col(const buffer< T > &x)
Atan col operation.
Definition backend.hpp:617
void atan_row(const buffer< T > &x)
Atan row operation.
Definition backend.hpp:573
buffer< T > index_column(const size_t index, const size_t num_columns)
Index column.
Definition backend.hpp:306
void exp()
Take exp.
Definition backend.hpp:216
bool has_zero() const
Is any element zero.
Definition backend.hpp:141
bool is_zero() const
Is every element zero.
Definition backend.hpp:126
void set(const T d)
Assign a constant value.
Definition backend.hpp:92
void cos()
Take cos.
Definition backend.hpp:237
Complex scalar concept.
Definition register.hpp:25
subroutine assert(test, message)
Assert check.
Definition f_binding_test.f90:38
Name space for backend buffers.
Definition backend.hpp:19
buffer< T > fma(buffer< T > &a, buffer< T > &b, buffer< T > &c)
Fused multiply add operation.
Definition backend.hpp:1219
buffer< T > operator*(buffer< T > &a, buffer< T > &b)
Multiply operation.
Definition backend.hpp:1149
buffer< T > operator>=(buffer< T > &a, buffer< T > &b)
Greater than equal operation.
Definition backend.hpp:1440
buffer< T > operator&&(buffer< T > &a, buffer< T > &b)
And operation.
Definition backend.hpp:1468
buffer< T > min(buffer< T > &a, buffer< T > &b)
Min operation.
Definition backend.hpp:1052
buffer< T > max(buffer< T > &a, buffer< T > &b)
Max operation.
Definition backend.hpp:1038
bool operator==(const buffer< T > &a, const buffer< T > &b)
Equal operation.
Definition backend.hpp:985
buffer< T > atan(buffer< T > &x, buffer< T > &y)
Take the inverse tangent.
Definition backend.hpp:1609
buffer< T > operator>(buffer< T > &a, buffer< T > &b)
Greater than operation.
Definition backend.hpp:1412
buffer< T > operator<=(buffer< T > &a, buffer< T > &b)
Less than equal operation.
Definition backend.hpp:1454
buffer< T > operator!=(buffer< T > &a, buffer< T > &b)
Not equal operation.
Definition backend.hpp:1398
buffer< T > operator/(buffer< T > &a, buffer< T > &b)
Divide operation.
Definition backend.hpp:1163
buffer< T > operator-(buffer< T > &a, buffer< T > &b)
Subtract operation.
Definition backend.hpp:1135
buffer< T > operator+(buffer< T > &a, buffer< T > &b)
Add operation.
Definition backend.hpp:1093
buffer< T > operator%(buffer< T > &a, buffer< T > &b)
Modulo operation.
Definition backend.hpp:1324
buffer< T > operator||(buffer< T > &a, buffer< T > &b)
Or operation.
Definition backend.hpp:1482
buffer< T > operator<(buffer< T > &a, buffer< T > &b)
Less than operation.
Definition backend.hpp:1426
buffer< T > pow(buffer< T > &base, buffer< T > &exponent)
Take the power.
Definition backend.hpp:1537
buffer< T > copysign(buffer< T > &x, buffer< T > &y)
Copy the sign of x and apply it to y.
Definition backend.hpp:1654
buffer< T > hypot(buffer< T > &a, buffer< T > &b)
hypot operation.
Definition backend.hpp:1204
complex_type< T > erfi(const complex_type< T > z)
erfi(z) = -i erf(iz)
Definition special_functions.hpp:1583
Utilities for writing jit source code.
Implementations for special functions.