Graph Framework
Loading...
Searching...
No Matches
piecewise.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
6//------------------------------------------------------------------------------
7
8#ifndef piecewise_h
9#define piecewise_h
10
11#include "node.hpp"
12
13namespace graph {
14//------------------------------------------------------------------------------
24//------------------------------------------------------------------------------
25 template<jit::float_scalar T>
26 void compile_index(std::ostringstream &stream,
27 const std::string &register_name,
28 const size_t length,
29 const T scale,
30 const T offset) {
31 const std::string type = jit::type_to_string<T> ();
32 stream << "(" << jit::smallest_uint_type<T> (length) << ")min";
33 if constexpr (!jit::use_metal<T> () &&
34 !jit::use_cuda()) {
35 stream << "<" << type << ">";
36 }
37 stream << "(max";
38 if constexpr (!jit::use_metal<T> () &&
39 !jit::use_cuda ()) {
40 stream << "<" << type << ">";
41 }
42 stream << "(";
43 if constexpr (jit::complex_scalar<T>) {
44 stream << "real(";
45 }
46 stream << "(" << register_name << " - ";
47 if constexpr (jit::complex_scalar<T>) {
49 }
50 stream << offset << ")/";
51 if constexpr (jit::complex_scalar<T>) {
53 }
54 stream << scale;
55 if constexpr (jit::complex_scalar<T>) {
56 stream << ")";
57 }
58 stream << ",";
59 if constexpr (jit::use_metal<T> () ||
60 jit::use_cuda()) {
61 stream << "(" << type << ")";
62 }
63 stream << "0),";
64 if constexpr (jit::use_metal<T> () ||
65 jit::use_cuda()) {
66 stream << "(" << type << ")";
67 }
68 stream << length - 1 << ")";
69 }
70
71//------------------------------------------------------------------------------
82//------------------------------------------------------------------------------
83 template<jit::float_scalar T>
84 void compile_2D_index(std::ostringstream &stream,
85 const std::string &x_register_name,
86 const std::string &y_register_name,
87 const size_t num_columns) {
88 stream << x_register_name << "*" << num_columns << " + "
90 }
91
92//******************************************************************************
93// Argument node.
94//******************************************************************************
95//------------------------------------------------------------------------------
100//------------------------------------------------------------------------------
101 template<jit::float_scalar T, bool SAFE_MATH=false>
102 class argument_node final : public no_derivative<T, SAFE_MATH, straight_node<T, SAFE_MATH>> {
103 private:
105 const T scale;
107 const T offset;
109 const size_t length;
110
111//------------------------------------------------------------------------------
119//------------------------------------------------------------------------------
120 static std::string to_string(shared_leaf<T, SAFE_MATH> x,
121 const T scale,
122 const T offset,
123 const size_t length) {
124 return jit::format_to_string(x->get_hash()) +
125 jit::format_to_string(scale) +
126 jit::format_to_string(offset) +
127 jit::format_to_string(length);
128 }
129
130 public:
131//------------------------------------------------------------------------------
138//------------------------------------------------------------------------------
140 const T scale,
141 const T offset,
142 const size_t length) :
144 straight_node<T, SAFE_MATH>> (x, argument_node::to_string(x, scale,
145 offset,
146 length)),
147 scale(scale), offset(offset), length(length) {}
148
149//------------------------------------------------------------------------------
157//------------------------------------------------------------------------------
159 backend::buffer<T> result = this->arg->evaluate();
160 backend::buffer<T> o(1, offset);
161 backend::buffer<T> s(1, scale);
162 result = result - o;
163 result = result/s;
164 result.real();
165 backend::buffer<T> upper(1, static_cast<T> (length - 1));
166 backend::buffer<T> lower(1, static_cast<T> (0));
167 result = backend::min(result, upper);
168 result = backend::max(result, lower);
169 return result;
170 }
171
172//------------------------------------------------------------------------------
179//------------------------------------------------------------------------------
181 if (constant_cast(this->arg).get()) {
182 return constant<T, SAFE_MATH> (this->evaluate());
183 }
184
185 return this->shared_from_this();
186 }
187
188//------------------------------------------------------------------------------
198//------------------------------------------------------------------------------
200 compile(std::ostringstream &stream,
201 jit::register_map &registers,
203 const jit::register_usage &usage) {
204 if (registers.find(this) == registers.end()) {
205 auto a = this->arg->compile(stream, registers,
207
208#ifdef USE_INDEX_CACHE
209 registers[this] = jit::to_string('i', this);
210 stream << " const "
211 << jit::smallest_uint_type<T> (length) << " "
212 << registers[this] << " = ";
213 compile_index<T> (stream, registers[a.get()], length,
214 scale, offset);
215 this->endline(stream, usage);
216#else
217 std::ostringstream source_buffer;
218 compile_index<T> (source_buffer, registers[a.get()],
219 length, scale, offset);
220 registers[this] = source_buffer.str();
221#endif
222 }
223
224 return this->shared_from_this();
225 }
226
227//------------------------------------------------------------------------------
235//------------------------------------------------------------------------------
237 auto temp = argument_cast(x);
238 return temp.get() &&
239 this->arg->is_match(temp->get_arg()) &&
240 (temp->get_size() == this->length) &&
241 (temp->get_scale() == this->scale) &&
242 (temp->get_offset() == this->offset);
243 }
244
245//------------------------------------------------------------------------------
249//------------------------------------------------------------------------------
250 T get_scale() const {
251 return scale;
252 }
253
254//------------------------------------------------------------------------------
258//------------------------------------------------------------------------------
259 T get_offset() const {
260 return offset;
261 }
262
263//------------------------------------------------------------------------------
267//------------------------------------------------------------------------------
268 size_t get_size() const {
269 return length;
270 }
271
272//------------------------------------------------------------------------------
278//------------------------------------------------------------------------------
279 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
280 jit::register_map &registers) {
281 if (registers.find(this) == registers.end()) {
282 const std::string name = jit::to_string('r', this);
283 registers[this] = name;
284 stream << " " << name
285 << " [label = \"arg\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
286
287 auto a = this->arg->to_vizgraph(stream, registers);
288 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
289 }
290
291 return this->shared_from_this();
292 }
293 };
294
295//------------------------------------------------------------------------------
306//------------------------------------------------------------------------------
307 template<jit::float_scalar T, bool SAFE_MATH=false>
309 const T scale,
310 const T offset,
311 const size_t length) {
312 auto temp = std::make_shared<argument_node<T, SAFE_MATH>> (x, scale,
313 offset,
314 length)->reduce();
315// Test for hash collisions.
316 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
317 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
320 return temp;
321 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
323 }
324 }
325#if defined(__clang__) || defined(__GNUC__)
327#else
328 assert(false && "Should never reach.");
329#endif
330 }
331
333 template<jit::float_scalar T, bool SAFE_MATH=false>
334 using shared_argument = std::shared_ptr<argument_node<T, SAFE_MATH>>;
335
336//------------------------------------------------------------------------------
344//------------------------------------------------------------------------------
345 template<jit::float_scalar T, bool SAFE_MATH=false>
347 return std::dynamic_pointer_cast<argument_node<T, SAFE_MATH>> (x);
348 }
349
350//******************************************************************************
351// 1D Piecewise node.
352//******************************************************************************
353//------------------------------------------------------------------------------
386//------------------------------------------------------------------------------
387 template<jit::float_scalar T, bool SAFE_MATH=false>
388 class piecewise_1D_node final : public straight_node<T, SAFE_MATH> {
389 private:
390//------------------------------------------------------------------------------
395//------------------------------------------------------------------------------
396 static std::string to_string(const backend::buffer<T> &d) {
397 std::string temp;
398 for (size_t i = 0, ie = d.size(); i < ie; i++) {
400 }
401
402 return temp;
403 }
404
405//------------------------------------------------------------------------------
411//------------------------------------------------------------------------------
412 static std::string to_string(const backend::buffer<T> &d,
414 return piecewise_1D_node::to_string(d) +
415 jit::format_to_string(x->get_hash());
416 }
417
418//------------------------------------------------------------------------------
423//------------------------------------------------------------------------------
424 static size_t hash_data(const backend::buffer<T> &d) {
425 const size_t h = std::hash<std::string>{} (piecewise_1D_node::to_string(d));
426 for (size_t i = h; i < std::numeric_limits<size_t>::max(); i++) {
427 if (leaf_node<T, SAFE_MATH>::caches.backends.find(i) ==
428 leaf_node<T, SAFE_MATH>::caches.backends.end()) {
430 return i;
431 } else if (d == leaf_node<T, SAFE_MATH>::caches.backends[i]) {
432 return i;
433 }
434 }
435#if defined(__clang__) || defined(__GNUC__)
437#else
438 assert(false && "Should never reach.");
439#endif
440 }
441
443 const size_t data_hash;
444
445 public:
446//------------------------------------------------------------------------------
451//------------------------------------------------------------------------------
454 straight_node<T, SAFE_MATH> (x, piecewise_1D_node::to_string(d, x)),
455 data_hash(piecewise_1D_node::hash_data(d)) {}
456
457//------------------------------------------------------------------------------
465//------------------------------------------------------------------------------
467 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash];
468 }
469
470//------------------------------------------------------------------------------
477//------------------------------------------------------------------------------
479 if (constant_cast(this->arg).get()) {
480 const size_t i = std::real(this->arg->evaluate().at(0));
481 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i]);
482 }
483
484 if (evaluate().is_same()) {
485 return constant<T, SAFE_MATH> (evaluate().at(0));
486 }
487 return this->shared_from_this();
488 }
489
490//------------------------------------------------------------------------------
495//------------------------------------------------------------------------------
497 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
498 }
499
500//------------------------------------------------------------------------------
511//------------------------------------------------------------------------------
512 virtual void compile_preamble(std::ostringstream &stream,
513 jit::register_map &registers,
518 jit::preamble_map &pre_funcs,
519 int &avail_const_mem) {
520 if (!visited.contains(this)) {
521 this->arg->compile_preamble(stream, registers,
522 visited, usage,
524 pre_funcs, avail_const_mem);
525
526 if (registers.find(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()) == registers.end()) {
527 registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] =
528 jit::to_string('a', leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data());
529 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
530 if constexpr (jit::use_metal<T> ()) {
531 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
532 length);
533#ifdef USE_CUDA_TEXTURES
534 } else if constexpr (jit::use_cuda()) {
535 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
536 length);
537#endif
538 } else {
539 if constexpr (jit::use_cuda()) {
540 const int buffer_size = length*sizeof(T);
541 if (avail_const_mem - buffer_size > 0) {
543 stream << "__constant__ ";
544 }
545 }
546 stream << "const ";
547 jit::add_type<T> (stream);
548 stream << " " << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] << "[] = {";
549 if constexpr (jit::complex_scalar<T>) {
550 jit::add_type<T> (stream);
551 }
552 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][0];
553 for (size_t i = 1; i < length; i++) {
554 stream << ", ";
555 if constexpr (jit::complex_scalar<T>) {
556 jit::add_type<T> (stream);
557 }
558 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i];
559 }
560 stream << "};" << std::endl;
561 }
562 } else {
563// When using textures, the register can be defined in a previous kernel. We
564// need to add the textures again.
565 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
566 if constexpr (jit::use_metal<T> ()) {
567 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
568 length);
569#ifdef USE_CUDA_TEXTURES
570 } else if constexpr (jit::use_cuda()) {
571 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
572 length);
573#endif
574 }
575 }
576 visited.insert(this);
577#ifdef SHOW_USE_COUNT
578 usage[this] = 1;
579 } else {
580 ++usage[this];
581#endif
582 }
583 }
584
585//------------------------------------------------------------------------------
605//------------------------------------------------------------------------------
607 compile(std::ostringstream &stream,
608 jit::register_map &registers,
610 const jit::register_usage &usage) {
611 if (registers.find(this) == registers.end()) {
612 auto a = this->arg->compile(stream, registers,
614
615 registers[this] = jit::to_string('r', this);
616 stream << " const ";
617 jit::add_type<T> (stream);
618 stream << " " << registers[this] << " = ";
619#ifdef USE_CUDA_TEXTURES
620 if constexpr (jit::use_cuda()) {
621 if constexpr (jit::float_base<T>) {
622 if constexpr (complex_scalar<T>) {
623 stream << "to_cmp_float(tex1D<float2> (";
624 } else {
625 stream << "tex1D<float> (";
626 }
627 } else {
628 if constexpr (complex_scalar<T>) {
629 stream << "to_cmp_double(tex1D<uint4> (";
630 } else {
631 stream << "to_double(tex1D<uint2> (";
632 }
633 }
634 }
635#endif
636 stream << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()];
637 if constexpr (jit::use_metal<T> ()) {
638 stream << ".read("
639 << registers[a.get()]
640 << ").r";
641#ifdef USE_CUDA_TEXTURES
642 } else if constexpr (jit::use_cuda()) {
643 stream << ", "
644 << registers[a.get()]
646 stream << ")";
647 }
648 stream << ")";
649#endif
650 } else {
651 stream << "["
652 << registers[a.get()]
653 << "]";
654 }
655 this->endline(stream, usage);
656 }
657
658 return this->shared_from_this();
659 }
660
661//------------------------------------------------------------------------------
669//------------------------------------------------------------------------------
671 auto x_cast = piecewise_1D_cast(x);
672
673 return x_cast.get() &&
674 this->data_hash == x_cast->data_hash &&
675 this->arg->is_match(x_cast->get_arg());
676 }
677
678//------------------------------------------------------------------------------
686//------------------------------------------------------------------------------
688 auto x_cast = piecewise_1D_cast(x);
689
690 return x_cast.get() &&
691 this->arg->is_match(x_cast->get_arg());
692 }
693
694//------------------------------------------------------------------------------
696//------------------------------------------------------------------------------
697 virtual void to_latex() const {
698 std::cout << "r\\_" << reinterpret_cast<size_t> (this) << "_{i}";
699 }
700
701//------------------------------------------------------------------------------
707//------------------------------------------------------------------------------
708 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
709 jit::register_map &registers) {
710 if (registers.find(this) == registers.end()) {
711 const std::string name = jit::to_string('r', this);
712 registers[this] = name;
713 stream << " " << name
714 << " [label = \"r_" << reinterpret_cast<size_t> (this)
715 << "_{i}\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
716
717 auto a = this->arg->to_vizgraph(stream, registers);
718 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
719 }
720
721 return this->shared_from_this();
722 }
723
724//------------------------------------------------------------------------------
728//------------------------------------------------------------------------------
729 virtual bool is_constant() const {
730 return true;
731 }
732
733//------------------------------------------------------------------------------
741//------------------------------------------------------------------------------
742 virtual bool is_all_variables() const {
743 return false;
744 }
745
746//------------------------------------------------------------------------------
750//------------------------------------------------------------------------------
751 virtual bool has_constant_zero() const {
752 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].has_zero();
753 }
754
755//------------------------------------------------------------------------------
759//------------------------------------------------------------------------------
760 virtual bool is_power_like() const {
761 return true;
762 }
763
764//------------------------------------------------------------------------------
768//------------------------------------------------------------------------------
770 return this->shared_from_this();
771 }
772
773//------------------------------------------------------------------------------
777//------------------------------------------------------------------------------
779 return one<T, SAFE_MATH> ();
780 }
781 };
782
783//------------------------------------------------------------------------------
792//------------------------------------------------------------------------------
793 template<jit::float_scalar T, bool SAFE_MATH=false>
796 auto temp = std::make_shared<piecewise_1D_node<T, SAFE_MATH>> (d, x)->reduce();
797// Test for hash collisions.
798 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
799 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
802 return temp;
803 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
805 }
806 }
807#if defined(__clang__) || defined(__GNUC__)
809#else
810 assert(false && "Should never reach.");
811#endif
812 }
813
814//------------------------------------------------------------------------------
825//------------------------------------------------------------------------------
826 template<jit::float_scalar T, bool SAFE_MATH=false>
829 const T scale,
830 const T offset) {
831 return piecewise_1D<T, SAFE_MATH> (d, argument(x, scale,
832 offset, d.size()));
833 }
834
836 template<jit::float_scalar T, bool SAFE_MATH=false>
837 using shared_piecewise_1D = std::shared_ptr<piecewise_1D_node<T, SAFE_MATH>>;
838
839//------------------------------------------------------------------------------
847//------------------------------------------------------------------------------
848 template<jit::float_scalar T, bool SAFE_MATH=false>
850 return std::dynamic_pointer_cast<piecewise_1D_node<T, SAFE_MATH>> (x);
851 }
852
853//******************************************************************************
854// 2D Piecewise node.
855//******************************************************************************
856//------------------------------------------------------------------------------
896//------------------------------------------------------------------------------
897 template<jit::float_scalar T, bool SAFE_MATH=false>
898 class piecewise_2D_node final : public branch_node<T, SAFE_MATH> {
899 private:
900//------------------------------------------------------------------------------
905//------------------------------------------------------------------------------
906 static std::string to_string(const backend::buffer<T> &d) {
907 std::string temp;
908 for (size_t i = 0, ie = d.size(); i < ie; i++) {
910 }
911
912 return temp;
913 }
914
915//------------------------------------------------------------------------------
922//------------------------------------------------------------------------------
923 static std::string to_string(const backend::buffer<T> &d,
926 return piecewise_2D_node::to_string(d) +
927 jit::format_to_string(x->get_hash()) +
928 jit::format_to_string(y->get_hash());
929 }
930
931//------------------------------------------------------------------------------
936//------------------------------------------------------------------------------
937 static size_t hash_data(const backend::buffer<T> &d) {
938 const size_t h = std::hash<std::string>{} (piecewise_2D_node::to_string(d));
939 for (size_t i = h; i < std::numeric_limits<size_t>::max(); i++) {
940 if (leaf_node<T, SAFE_MATH>::caches.backends.find(i) ==
941 leaf_node<T, SAFE_MATH>::caches.backends.end()) {
943 return i;
944 } else if (d == leaf_node<T, SAFE_MATH>::caches.backends[i]) {
945 return i;
946 }
947 }
948#if defined(__clang__) || defined(__GNUC__)
950#else
951 assert(false && "Should never reach.");
952#endif
953 }
954
956 const size_t data_hash;
958 const size_t num_columns;
959
960 public:
961//------------------------------------------------------------------------------
968//------------------------------------------------------------------------------
970 const size_t n,
973 branch_node<T, SAFE_MATH> (x, y,
974 piecewise_2D_node::to_string(d, x, y)),
975 data_hash(piecewise_2D_node::hash_data(d)), num_columns(n) {
976 assert(d.size()%get_num_columns() == 0 &&
977 "Expected the data buffer to be a multiple of the number of columns.");
978 }
979
980//------------------------------------------------------------------------------
984//------------------------------------------------------------------------------
985 size_t get_num_columns() const {
986 return num_columns;
987 }
988
989//------------------------------------------------------------------------------
993//------------------------------------------------------------------------------
994 size_t get_num_rows() const {
995 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size()/num_columns;
996 }
997
998//------------------------------------------------------------------------------
1006//------------------------------------------------------------------------------
1008 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash];
1009 }
1010
1011//------------------------------------------------------------------------------
1018//------------------------------------------------------------------------------
1020 if (constant_cast(this->left).get() &&
1021 constant_cast(this->right).get()) {
1022 const size_t i = std::real(this->left->evaluate().at(0));
1023 const size_t j = std::real(this->right->evaluate().at(0));
1024
1025 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i*this->get_num_columns() + j]);
1026 } else if (constant_cast(this->left).get()) {
1027 const size_t i = std::real(this->left->evaluate().at(0));
1028
1029 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_row(i, this->get_num_columns()),
1030 this->right);
1031 } else if (constant_cast(this->right).get()) {
1032 const size_t j = std::real(this->right->evaluate().at(0));
1033
1034 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_column(j, this->get_num_columns()),
1035 this->left);
1036 }
1037
1038 if (evaluate().is_same()) {
1039 return constant<T, SAFE_MATH> (evaluate().at(0));
1040 }
1041
1042 return this->shared_from_this();
1043 }
1044
1045//------------------------------------------------------------------------------
1050//------------------------------------------------------------------------------
1052 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
1053 }
1054
1055//------------------------------------------------------------------------------
1066//------------------------------------------------------------------------------
1067 virtual void compile_preamble(std::ostringstream &stream,
1068 jit::register_map &registers,
1073 jit::preamble_map &pre_funcs,
1074 int &avail_const_mem) {
1075 if (!visited.contains(this)) {
1076 this->left->compile_preamble(stream, registers,
1077 visited, usage,
1079 pre_funcs, avail_const_mem);
1080 this->right->compile_preamble(stream, registers,
1081 visited, usage,
1083 pre_funcs, avail_const_mem);
1084
1085 if (registers.find(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()) == registers.end()) {
1086 registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] =
1087 jit::to_string('a', leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data());
1088 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
1089 if constexpr (jit::use_metal<T> ()) {
1090 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1091 std::array<size_t, 2> ({
1092 length/this->get_num_columns(),
1093 this->get_num_columns()
1094 }));
1095#ifdef USE_CUDA_TEXTURES
1096 } else if constexpr (jit::use_cuda()) {
1097 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1098 std::array<size_t, 2> ({
1099 length/this->get_num_columns(), this->get_num_columns()
1100 }));
1101#endif
1102 } else {
1103 if constexpr (jit::use_cuda()) {
1104 const int buffer_size = length*sizeof(T);
1105 if (avail_const_mem - buffer_size > 0) {
1107 stream << "__constant__ ";
1108 }
1109 }
1110 stream << "const ";
1111 jit::add_type<T> (stream);
1112 stream << " " << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] << "[] = {";
1113 if constexpr (jit::complex_scalar<T>) {
1114 jit::add_type<T> (stream);
1115 }
1116 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][0];
1117 for (size_t i = 1; i < length; i++) {
1118 stream << ", ";
1119 if constexpr (jit::complex_scalar<T>) {
1120 jit::add_type<T> (stream);
1121 }
1122 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i];
1123 }
1124 stream << "};" << std::endl;
1125 }
1126 } else {
1127// When using textures, the register can be defined in a previous kernel. We
1128// need to add the textures again.
1129 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
1130 if constexpr (jit::use_metal<T> ()) {
1131 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1132 std::array<size_t, 2> ({
1133 length/this->get_num_columns(),
1134 this->get_num_columns()
1135 }));
1136#ifdef USE_CUDA_TEXTURES
1137 } else if constexpr (jit::use_cuda()) {
1138 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1139 std::array<size_t, 2> ({
1140 length/this->get_num_columns(),
1141 this->get_num_columns()
1142 }));
1143#endif
1144 }
1145 }
1146 visited.insert(this);
1147#ifdef SHOW_USE_COUNT
1148 usage[this] = 1;
1149 } else {
1150 ++usage[this];
1151#endif
1152 }
1153 }
1154
1155//------------------------------------------------------------------------------
1188//------------------------------------------------------------------------------
1190 compile(std::ostringstream &stream,
1191 jit::register_map &registers,
1193 const jit::register_usage &usage) {
1194 if (registers.find(this) == registers.end()) {
1195 auto x = this->left->compile(stream, registers,
1196 thread_mem, usage);
1197 auto y = this->right->compile(stream, registers,
1198 thread_mem, usage);
1199
1200 auto temp = x*static_cast<T> (this->get_num_columns()) + y;
1201 if constexpr (!jit::use_metal<T> ()) {
1202 if (registers.find(temp.get()) == registers.end()) {
1203#ifndef USE_CUDA_TEXTURES
1204#ifdef USE_INDEX_CACHE
1205 registers[temp.get()] = jit::to_string('i', temp.get());
1206 stream << " const "
1207 << jit::smallest_uint_type<T> (this->get_num_columns()*this->get_num_rows())
1208 << " " << registers[temp.get()] << " = ";
1209 compile_2D_index<T> (stream, registers[x.get()], registers[y.get()],
1210 this->get_num_columns());
1211 this->endline(stream, usage);
1212#else
1213 std::ostringstream source_buffer;
1214 temp->compile(source_buffer,
1215 registers,
1216 thread_mem,
1217 usage);
1218 registers[temp.get()] = source_buffer.str();
1219#endif
1220#endif
1221 }
1222 }
1223
1224 registers[this] = jit::to_string('r', this);
1225 stream << " const ";
1226 jit::add_type<T> (stream);
1227 stream << " " << registers[this] << " = ";
1228#ifdef USE_CUDA_TEXTURES
1229 if constexpr (jit::use_cuda()) {
1230 if constexpr (jit::float_base<T>) {
1231 if constexpr (complex_scalar<T>) {
1232 stream << "to_cmp_float(tex1D<float2> (";
1233 } else {
1234 stream << "tex1D<float> (";
1235 }
1236 } else {
1237 if constexpr (complex_scalar<T>) {
1238 stream << "to_cmp_double(tex1D<uint4> (";
1239 } else {
1240 stream << "to_double(tex1D<uint2> (";
1241 }
1242 }
1243 }
1244#endif
1245 stream << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()];
1246
1247 if constexpr (jit::use_metal<T> ()) {
1248 stream << ".read("
1249 << jit::smallest_uint_type<T> (std::max(this->get_num_rows(),
1250 this->get_num_columns()))
1251 << "2("
1252 << registers[y.get()]
1253 << ","
1254 << registers[x.get()]
1255 << ")).r";
1256#ifdef USE_CUDA_TEXTURES
1257 } else if constexpr (jit::use_cuda()) {
1258 stream << ", "
1259 << registers[y.get()]
1260 << ", "
1261 << registers[x.get()];
1263 stream << ")";
1264 }
1265 stream << ")";
1266#endif
1267 } else {
1268 stream << "[" << registers[temp.get()] << "]";
1269 }
1270
1271 this->endline(stream, usage);
1272 }
1273
1274 return this->shared_from_this();
1275 }
1276
1277//------------------------------------------------------------------------------
1284//------------------------------------------------------------------------------
1286 auto x_cast = piecewise_2D_cast(x);
1287
1288 return x_cast.get() &&
1289 this->data_hash == x_cast->data_hash &&
1290 this->num_columns == x_cast->get_num_columns() &&
1291 this->left->is_match(x_cast->get_left()) &&
1292 this->right->is_match(x_cast->get_right());
1293 }
1294
1295//------------------------------------------------------------------------------
1302//------------------------------------------------------------------------------
1304 auto x_cast = piecewise_2D_cast(x);
1305
1306 return x_cast.get() &&
1307 this->num_columns == x_cast->get_num_columns() &&
1308 this->left->is_match(x_cast->get_left()) &&
1309 this->right->is_match(x_cast->get_right());
1310 }
1311
1312//------------------------------------------------------------------------------
1316//------------------------------------------------------------------------------
1317 virtual void to_latex() const {
1318 std::cout << "r\\_" << reinterpret_cast<size_t> (this) << "_{ij}";
1319 }
1320
1321//------------------------------------------------------------------------------
1327//------------------------------------------------------------------------------
1328 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1329 jit::register_map &registers) {
1330 if (registers.find(this) == registers.end()) {
1331 const std::string name = jit::to_string('r', this);
1332 registers[this] = name;
1333 stream << " " << name
1334 << " [label = \"r_" << reinterpret_cast<size_t> (this)
1335 << "_{ij}\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
1336
1337 auto l = this->left->to_vizgraph(stream, registers);
1338 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1339 auto r = this->right->to_vizgraph(stream, registers);
1340 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1341 }
1342
1343 return this->shared_from_this();
1344 }
1345
1346//------------------------------------------------------------------------------
1350//------------------------------------------------------------------------------
1351 virtual bool is_constant() const {
1352 return true;
1353 }
1354
1355//------------------------------------------------------------------------------
1363//------------------------------------------------------------------------------
1364 virtual bool is_all_variables() const {
1365 return false;
1366 }
1367
1368//------------------------------------------------------------------------------
1372//------------------------------------------------------------------------------
1373 virtual bool has_constant_zero() const {
1374 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].has_zero();
1375 }
1376
1377//------------------------------------------------------------------------------
1381//------------------------------------------------------------------------------
1382 virtual bool is_power_like() const {
1383 return true;
1384 }
1385
1386//------------------------------------------------------------------------------
1390//------------------------------------------------------------------------------
1392 return this->shared_from_this();
1393 }
1394
1395//------------------------------------------------------------------------------
1399//------------------------------------------------------------------------------
1401 return one<T, SAFE_MATH> ();
1402 }
1403
1404//------------------------------------------------------------------------------
1409//------------------------------------------------------------------------------
1411 auto temp = piecewise_1D_cast(x);
1412 return temp.get() && this->left->is_match(temp->get_arg());
1413 }
1414
1415//------------------------------------------------------------------------------
1422//------------------------------------------------------------------------------
1424 auto temp = piecewise_1D_cast(x);
1425 return temp.get() && this->right->is_match(temp->get_arg());
1426 }
1427 };
1428
1429//------------------------------------------------------------------------------
1440//------------------------------------------------------------------------------
1441 template<jit::float_scalar T, bool SAFE_MATH=false>
1443 const size_t n,
1446 auto temp = std::make_shared<piecewise_2D_node<T, SAFE_MATH>> (d, n, x, y)->reduce();
1447// Test for hash collisions.
1448 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
1449 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1450 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1452 return temp;
1453 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1454 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1455 }
1456 }
1457#if defined(__clang__) || defined(__GNUC__)
1459#else
1460 assert(false && "Should never reach.");
1461#endif
1462 }
1463
1464//------------------------------------------------------------------------------
1479//------------------------------------------------------------------------------
1480 template<jit::float_scalar T, bool SAFE_MATH=false>
1482 const size_t n,
1484 const T x_scale,
1485 const T x_offset,
1487 const T y_scale,
1488 const T y_offset) {
1490 argument(x, x_scale, x_offset, d.size()/n),
1491 argument(y, y_scale, y_offset, n))->reduce();
1492 }
1493
1495 template<jit::float_scalar T, bool SAFE_MATH=false>
1496 using shared_piecewise_2D = std::shared_ptr<piecewise_2D_node<T, SAFE_MATH>>;
1497
1498//------------------------------------------------------------------------------
1506//------------------------------------------------------------------------------
1507 template<jit::float_scalar T, bool SAFE_MATH=false>
1509 return std::dynamic_pointer_cast<piecewise_2D_node<T, SAFE_MATH>> (x);
1510 }
1511
1512//******************************************************************************
1513// 1D Index node.
1514//******************************************************************************
1515//------------------------------------------------------------------------------
1526//------------------------------------------------------------------------------
1527 template<jit::float_scalar T, bool SAFE_MATH=false>
1528 class index_1D_node final : public branch_node<T, SAFE_MATH> {
1529 private:
1530//------------------------------------------------------------------------------
1536//------------------------------------------------------------------------------
1537 static std::string to_string(shared_leaf<T, SAFE_MATH> v,
1539 return jit::format_to_string(v->get_hash()) +
1540 jit::format_to_string(x->get_hash());
1541 }
1542
1543 public:
1544//------------------------------------------------------------------------------
1549//------------------------------------------------------------------------------
1554
1555//------------------------------------------------------------------------------
1563//------------------------------------------------------------------------------
1565 return this->left->evaluate();
1566 }
1567
1568//------------------------------------------------------------------------------
1573//------------------------------------------------------------------------------
1575 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
1576 }
1577
1578//------------------------------------------------------------------------------
1591//------------------------------------------------------------------------------
1593 compile(std::ostringstream &stream,
1594 jit::register_map &registers,
1596 const jit::register_usage &usage) {
1597 if (registers.find(this) == registers.end()) {
1598 auto a = this->right->compile(stream, registers,
1599 thread_mem, usage);
1600 auto var = this->left->compile(stream, registers,
1601 thread_mem, usage);
1602
1603 registers[this] = jit::to_string('r', this);
1604 stream << " const ";
1605 jit::add_type<T> (stream);
1606 stream << " " << registers[this] << " = ";
1607 if (thread_mem.contains(var.get())) {
1608 stream << thread_mem.at(var.get());
1609 } else {
1610 stream << jit::to_string('v', var.get());
1611 }
1612 stream << "[" << registers[a.get()] << "]";
1613
1614 this->endline(stream, usage);
1615 }
1616
1617 return this->shared_from_this();
1618 }
1619
1620//------------------------------------------------------------------------------
1627//------------------------------------------------------------------------------
1629 auto x_cast = index_1D_cast(x);
1630
1631 return x_cast.get() &&
1632 this->left->is_match(x_cast->get_left()) &&
1633 this->is_arg_match(x);
1634 }
1635
1636//------------------------------------------------------------------------------
1638//------------------------------------------------------------------------------
1639 virtual void to_latex() const {
1640 std::cout << "v\\_" << reinterpret_cast<size_t> (this->left.get())
1641 << "\\left[i\\_"
1642 << reinterpret_cast<size_t> (this->right.get())
1643 << "\\right]";
1644 }
1645
1646//------------------------------------------------------------------------------
1652//------------------------------------------------------------------------------
1653 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1654 jit::register_map &registers) {
1655 if (registers.find(this) == registers.end()) {
1656 const std::string name = jit::to_string('r', this);
1657 registers[this] = name;
1658 stream << " " << name
1659 << " [label = \"r_" << reinterpret_cast<size_t> (this->left.get())
1660 << "\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
1661
1662 auto l = this->left->to_vizgraph(stream, registers);
1663 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1664 auto r = this->right->to_vizgraph(stream, registers);
1665 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1666 }
1667
1668 return this->shared_from_this();
1669 }
1670
1671//------------------------------------------------------------------------------
1675//------------------------------------------------------------------------------
1676 virtual bool is_power_like() const {
1677 return true;
1678 }
1679
1680//------------------------------------------------------------------------------
1684//------------------------------------------------------------------------------
1686 return one<T, SAFE_MATH> ();
1687 }
1688
1689//------------------------------------------------------------------------------
1694//------------------------------------------------------------------------------
1696 auto temp = index_1D_cast(x);
1697 return temp.get() && this->right->is_match(temp->get_right());
1698 }
1699 };
1700
1701//------------------------------------------------------------------------------
1710//------------------------------------------------------------------------------
1711 template<jit::float_scalar T, bool SAFE_MATH=false>
1714 assert(argument_cast(x).get() &&
1715 "index_1D requires a argument node for second arg.");
1716 auto temp = std::make_shared<index_1D_node<T, SAFE_MATH>> (v, x)->reduce();
1717// Test for hash collisions.
1718 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
1719 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1720 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1722 return temp;
1723 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1724 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1725 }
1726 }
1727#if defined(__clang__) || defined(__GNUC__)
1729#else
1730 assert(false && "Should never reach.");
1731#endif
1732 }
1733
1734//------------------------------------------------------------------------------
1745//------------------------------------------------------------------------------
1746 template<jit::float_scalar T, bool SAFE_MATH=false>
1749 const T scale,
1750 const T offset) {
1751 assert(variable_cast(v).get() &&
1752 "index_1D requires a variable node for first arg.");
1753 return index_1D<T, SAFE_MATH> (v, argument(x, scale, offset, variable_cast(v)->size()));
1754 }
1755
1757 template<jit::float_scalar T, bool SAFE_MATH=false>
1758 using shared_index_1D = std::shared_ptr<index_1D_node<T, SAFE_MATH>>;
1759
1760//------------------------------------------------------------------------------
1768//------------------------------------------------------------------------------
1769 template<jit::float_scalar T, bool SAFE_MATH=false>
1771 return std::dynamic_pointer_cast<index_1D_node<T, SAFE_MATH>> (x);
1772 }
1773
1774//******************************************************************************
1775// 2D Index node.
1776//******************************************************************************
1777//------------------------------------------------------------------------------
1789//------------------------------------------------------------------------------
1790 template<jit::float_scalar T, bool SAFE_MATH=false>
1791 class index_2D_node final : public triple_node<T, SAFE_MATH> {
1792 private:
1793//------------------------------------------------------------------------------
1800//------------------------------------------------------------------------------
1801 static std::string to_string(shared_leaf<T, SAFE_MATH> v,
1804 return jit::format_to_string(v->get_hash()) +
1805 jit::format_to_string(x->get_hash()) +
1806 jit::format_to_string(y->get_hash());
1807 }
1808
1810 const size_t num_columns;
1811
1812 public:
1813//------------------------------------------------------------------------------
1820//------------------------------------------------------------------------------
1822 const size_t n,
1825 triple_node<T, SAFE_MATH> (var, x, y,
1826 index_2D_node::to_string(var, x, y)),
1827 num_columns(n) {}
1828
1829//------------------------------------------------------------------------------
1833//------------------------------------------------------------------------------
1834 size_t get_num_columns() const {
1835 return num_columns;
1836 }
1837
1838//------------------------------------------------------------------------------
1842//------------------------------------------------------------------------------
1843 size_t get_num_rows() const {
1844 return variable_cast(this->left)->size()/num_columns;
1845 }
1846
1847//------------------------------------------------------------------------------
1855//------------------------------------------------------------------------------
1857 return this->left->evaluate();
1858 }
1859
1860//------------------------------------------------------------------------------
1865//------------------------------------------------------------------------------
1867 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
1868 }
1869
1870//------------------------------------------------------------------------------
1884//------------------------------------------------------------------------------
1886 compile(std::ostringstream &stream,
1887 jit::register_map &registers,
1889 const jit::register_usage &usage) {
1890 if (registers.find(this) == registers.end()) {
1891 auto x = this->middle->compile(stream, registers,
1892 thread_mem, usage);
1893 auto y = this->right->compile(stream, registers,
1894 thread_mem, usage);
1895
1896 auto temp = x*static_cast<T> (this->get_num_columns())
1897 + y;
1898
1899 if (registers.find(temp.get()) == registers.end()) {
1900#ifdef USE_INDEX_CACHE
1901 registers[temp.get()] = jit::to_string('i', temp.get());
1902 stream << " const "
1903 << jit::smallest_uint_type<T> (this->get_num_columns()*this->get_num_rows())
1904 << " " << registers[temp.get()] << " = ";
1905 compile_2D_index<T> (stream, registers[x.get()], registers[y.get()],
1906 this->get_num_columns());
1907 this->endline(stream, usage);
1908
1909#else
1910 std::ostringstream source_buffer;
1911 compile_2D_index<T> (source_buffer, registers[x.get()], registers[y.get()],
1912 this->get_num_columns());
1913 registers[temp.get()] = source_buffer.str();
1914#endif
1915 }
1916
1917 auto var = this->left->compile(stream, registers,
1918 thread_mem, usage);
1919
1920
1921 registers[this] = jit::to_string('r', this);
1922 stream << " const ";
1923 jit::add_type<T> (stream);
1924 stream << " " << registers[this] << " = ";
1925 if (thread_mem.contains(var.get())) {
1926 stream << thread_mem.at(var.get());
1927 } else {
1928 stream << jit::to_string('v', var.get());
1929 }
1930 stream << "[" << registers[temp.get()] << "]";
1931
1932 this->endline(stream, usage);
1933 }
1934
1935 return this->shared_from_this();
1936 }
1937
1938//------------------------------------------------------------------------------
1945//------------------------------------------------------------------------------
1947 auto x_cast = index_2D_cast(x);
1948
1949 return x_cast.get() &&
1950 this->left->is_match(x_cast->get_left()) &&
1951 this->middle->is_match(x_cast->get_middle()) &&
1952 this->right->is_match(x_cast->get_right()) &&
1953 this->num_columns == x_cast->get_num_columns();
1954 }
1955
1956//------------------------------------------------------------------------------
1958//------------------------------------------------------------------------------
1959 virtual void to_latex() const {
1960 std::cout << "r\\_" << reinterpret_cast<size_t> (this->left.get())
1961 << "\\left[i\\_"
1962 << reinterpret_cast<size_t> (this->middle.get())
1963 << ",j\\_"
1964 << reinterpret_cast<size_t> (this->right.get())
1965 << "\\right]";
1966 }
1967
1968//------------------------------------------------------------------------------
1974//------------------------------------------------------------------------------
1975 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1976 jit::register_map &registers) {
1977 if (registers.find(this) == registers.end()) {
1978 const std::string name = jit::to_string('r', this);
1979 registers[this] = name;
1980 stream << " " << name
1981 << " [label = \"r_" << reinterpret_cast<size_t> (this->left.get())
1982 << "\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
1983
1984 auto l = this->left->to_vizgraph(stream, registers);
1985 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1986 auto m = this->middle->to_vizgraph(stream, registers);
1987 stream << " " << name << " -- " << registers[m.get()] << ";" << std::endl;
1988 auto r = this->right->to_vizgraph(stream, registers);
1989 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1990 }
1991
1992 return this->shared_from_this();
1993 }
1994
1995//------------------------------------------------------------------------------
1999//------------------------------------------------------------------------------
2000 virtual bool is_power_like() const {
2001 return true;
2002 }
2003
2004//------------------------------------------------------------------------------
2008//------------------------------------------------------------------------------
2010 return one<T, SAFE_MATH> ();
2011 }
2012
2013//------------------------------------------------------------------------------
2018//------------------------------------------------------------------------------
2020 auto temp = index_2D_cast(x);
2021 return temp.get() &&
2022 this->middle->is_match(temp->get_middle()) &&
2023 this->right->is_match(temp->get_right());
2024 }
2025 };
2026
2027//------------------------------------------------------------------------------
2038//------------------------------------------------------------------------------
2039 template<jit::float_scalar T, bool SAFE_MATH=false>
2041 const size_t n,
2044 assert(argument_cast(x).get() &&
2045 "index_2D requires a argument node for second arg.");
2046 assert(argument_cast(y).get() &&
2047 "index_2D requires a argument node for third arg.");
2048 auto temp = std::make_shared<index_2D_node<T, SAFE_MATH>> (v, n, x, y)->reduce();
2049// Test for hash collisions.
2050 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
2051 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
2052 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
2054 return temp;
2055 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
2056 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
2057 }
2058 }
2059#if defined(__clang__) || defined(__GNUC__)
2061#else
2062 assert(false && "Should never reach.");
2063#endif
2064 }
2065
2066//------------------------------------------------------------------------------
2081//------------------------------------------------------------------------------
2082 template<jit::float_scalar T, bool SAFE_MATH=false>
2084 const size_t n,
2086 const T x_scale,
2087 const T x_offset,
2089 const T y_scale,
2090 const T y_offset) {
2091 assert(variable_cast(v).get() &&
2092 "index_2D requires a variable node for first arg.");
2093 return index_2D<T, SAFE_MATH> (v, n,
2095 variable_cast(v)->size()/n),
2096 argument(y, y_scale,
2097 y_offset, n))->reduce();
2098 }
2099
2101 template<jit::float_scalar T, bool SAFE_MATH=false>
2102 using shared_index_2D = std::shared_ptr<index_2D_node<T, SAFE_MATH>>;
2103
2104//------------------------------------------------------------------------------
2112//------------------------------------------------------------------------------
2113 template<jit::float_scalar T, bool SAFE_MATH=false>
2115 return std::dynamic_pointer_cast<index_2D_node<T, SAFE_MATH>> (x);
2116 }
2117
2118//******************************************************************************
2119// 1D Atomic Accumulate.
2120//******************************************************************************
2121//------------------------------------------------------------------------------
2133//------------------------------------------------------------------------------
2134 template<jit::float_scalar T, bool SAFE_MATH=false>
2135 class atomic_accumulate_1D_node final : public triple_node<T, SAFE_MATH> {
2136 private:
2137//------------------------------------------------------------------------------
2144//------------------------------------------------------------------------------
2145 static std::string to_string(shared_leaf<T, SAFE_MATH> v,
2148 return jit::format_to_string(v->get_hash()) +
2149 jit::format_to_string(i->get_hash()) +
2150 jit::format_to_string(x->get_hash());
2151 }
2152
2153 public:
2154//------------------------------------------------------------------------------
2160//------------------------------------------------------------------------------
2166
2167//------------------------------------------------------------------------------
2175//------------------------------------------------------------------------------
2177 return this->left->evaluate();
2178 }
2179
2180//------------------------------------------------------------------------------
2193//------------------------------------------------------------------------------
2195 return constant<T, SAFE_MATH> (static_cast<T> (this->left->is_match(x))) +
2196 this->right->df(x);
2197 }
2198
2199//------------------------------------------------------------------------------
2225//------------------------------------------------------------------------------
2227 compile(std::ostringstream &stream,
2228 jit::register_map &registers,
2230 const jit::register_usage &usage) {
2231 if (registers.find(this) == registers.end()) {
2232 auto a = this->left->compile(stream, registers,
2233 thread_mem, usage);
2234 auto index = this->middle->compile(stream, registers,
2235 thread_mem, usage);
2236 auto r = this->right->compile(stream, registers,
2237 thread_mem, usage);
2238
2239 registers[this] = jit::to_string('v', a.get())
2240 + " + "
2241 + registers[index.get()];
2242 stream << " atomic";
2243 if constexpr (jit::use_cuda()) {
2244 stream << "Add(";
2245 } else if constexpr (jit::use_metal<T> ()){
2246 stream << "_fetch_add_explicit(";
2247 } else {
2248 stream << "_ref(*(";
2249 }
2250 stream << registers[this];
2251 if constexpr (jit::use_cuda() ||
2252 jit::use_metal<T> ()) {
2253 stream << ", ";
2254 } else {
2255 stream << ")).fetch_add(";
2256 }
2257 stream << registers[r.get()];
2258 if constexpr (jit::use_cuda()) {
2259 stream << ")";
2260 } else {
2261 stream << ", memory_order_relaxed)";
2262 }
2263 this->endline(stream, usage);
2264 }
2265
2266 return this->shared_from_this();
2267 }
2268
2269//------------------------------------------------------------------------------
2276//------------------------------------------------------------------------------
2279
2280 return x_cast.get() &&
2281 this->left->is_match(x_cast->get_left()) &&
2282 this->is_arg_match(x) &&
2283 this->right->is_match(x_cast->get_right());
2284 }
2285
2286//------------------------------------------------------------------------------
2294//------------------------------------------------------------------------------
2297
2298 return x_cast.get() &&
2299 this->middle->is_match(x_cast->get_middle());
2300 }
2301
2302//------------------------------------------------------------------------------
2304//------------------------------------------------------------------------------
2305 virtual void to_latex() const {
2306 std::cout << "v\\_" << reinterpret_cast<size_t> (this->left.get())
2307 << "\\left[i\\_"
2308 << reinterpret_cast<size_t> (this->middle.get())
2309 << "\\right] + ";
2310 this->right->to_latex();
2311 }
2312
2313//------------------------------------------------------------------------------
2319//------------------------------------------------------------------------------
2320 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
2321 jit::register_map &registers) {
2322 if (registers.find(this) == registers.end()) {
2323 const std::string name = jit::to_string('r', this);
2324 registers[this] = name;
2325 stream << " " << name
2326 << " [label = \"r_" << reinterpret_cast<size_t> (this->left.get())
2327 << "\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
2328
2329 auto l = this->left->to_vizgraph(stream, registers);
2330 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
2331 auto m = this->middle->to_vizgraph(stream, registers);
2332 stream << " " << name << " -- " << registers[m.get()] << ";" << std::endl;
2333 auto r = this->right->to_vizgraph(stream, registers);
2334 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
2335 }
2336
2337 return this->shared_from_this();
2338 }
2339
2340//------------------------------------------------------------------------------
2344//------------------------------------------------------------------------------
2346 return one<T, SAFE_MATH> ();
2347 }
2348 };
2349
2350//------------------------------------------------------------------------------
2360//------------------------------------------------------------------------------
2361 template<jit::float_scalar T, bool SAFE_MATH=false>
2366 "atomic_accumulate_1D requires a argument node for second arg.");
2367 auto temp = std::make_shared<atomic_accumulate_1D_node<T, SAFE_MATH>> (v, i, x)->reduce();
2368// Test for hash collisions.
2369 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
2370 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
2371 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
2373 return temp;
2374 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
2375 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
2376 }
2377 }
2378#if defined(__clang__) || defined(__GNUC__)
2380#else
2381 assert(false && "Should never reach.");
2382#endif
2383 }
2384
2385//------------------------------------------------------------------------------
2397//------------------------------------------------------------------------------
2398 template<jit::float_scalar T, bool SAFE_MATH=false>
2401 const T scale,
2402 const T offset,
2404 assert(variable_cast(v).get() &&
2405 "atomic_accumulate_1D requires a variable node for first arg.");
2406 auto index = argument(x, scale, offset, variable_cast(v)->size());
2408 }
2409
2411 template<jit::float_scalar T, bool SAFE_MATH=false>
2413 std::shared_ptr<atomic_accumulate_1D_node<T, SAFE_MATH>>;
2414
2415//------------------------------------------------------------------------------
2423//------------------------------------------------------------------------------
2424 template<jit::float_scalar T, bool SAFE_MATH=false>
2427 return std::dynamic_pointer_cast<atomic_accumulate_1D_node<T, SAFE_MATH>> (x);
2428 }
2429}
2430
2431#endif /* piecewise_h */
Class representing a generic buffer.
Definition backend.hpp:29
void real()
Take cos.
Definition backend.hpp:244
Node class to contain the index argument.
Definition piecewise.hpp:102
T get_scale() const
Get argument scale.
Definition piecewise.hpp:250
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduction method.
Definition piecewise.hpp:180
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:236
size_t get_size() const
Get the size of the array.
Definition piecewise.hpp:268
T get_offset() const
Get argument offset.
Definition piecewise.hpp:259
argument_node(shared_leaf< T, SAFE_MATH > x, const T scale, const T offset, const size_t length)
Construct an Argument node.
Definition piecewise.hpp:139
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:279
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:200
virtual backend::buffer< T > evaluate()
Evaluate the argument.
Definition piecewise.hpp:158
Class representing a 1D accumulated array.
Definition piecewise.hpp:2135
virtual backend::buffer< T > evaluate()
Evaluate the results of accumulate.
Definition piecewise.hpp:2176
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:2277
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:2305
virtual bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes arguments match.
Definition piecewise.hpp:2295
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:2227
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:2320
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:2194
atomic_accumulate_1D_node(shared_leaf< T, SAFE_MATH > var, shared_leaf< T, SAFE_MATH > index, shared_leaf< T, SAFE_MATH > x)
Construct a 1D index.
Definition piecewise.hpp:2161
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:2345
Class representing a branch node.
Definition node.hpp:1337
shared_leaf< T, SAFE_MATH > right
Right branch of the tree.
Definition node.hpp:1342
shared_leaf< T, SAFE_MATH > left
Left branch of the tree.
Definition node.hpp:1340
Class representing a 1D index.
Definition piecewise.hpp:1528
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:1685
virtual backend::buffer< T > evaluate()
Evaluate the results of the 1D index.
Definition piecewise.hpp:1564
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:1676
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:1695
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:1593
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1628
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:1653
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:1574
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:1639
index_1D_node(shared_leaf< T, SAFE_MATH > var, shared_leaf< T, SAFE_MATH > x)
Construct a 1D index.
Definition piecewise.hpp:1550
Class representing a 2D index.
Definition piecewise.hpp:1791
size_t get_num_columns() const
Get the number of columns.
Definition piecewise.hpp:1834
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:1866
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:2000
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:1856
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1946
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:1959
index_2D_node(shared_leaf< T, SAFE_MATH > var, const size_t n, shared_leaf< T, SAFE_MATH > x, shared_leaf< T, SAFE_MATH > y)
Construct a 2D index.
Definition piecewise.hpp:1821
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:2009
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:2019
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
the node.
Definition piecewise.hpp:1886
size_t get_num_rows() const
Get the number of columns.
Definition piecewise.hpp:1843
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:1975
Class representing a node leaf.
Definition node.hpp:371
virtual void endline(std::ostringstream &stream, const jit::register_usage &usage, const char end=';') const
End a line in the kernel source.
Definition node.hpp:653
Nodes without derivatives.
Definition node.hpp:1713
Class representing a 1D piecewise constant.
Definition piecewise.hpp:388
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:760
virtual void compile_preamble(std::ostringstream &stream, jit::register_map &registers, jit::visiter_map &visited, jit::register_usage &usage, jit::texture1d_list &textures1d, jit::texture2d_list &textures2d, jit::preamble_map &pre_funcs, int &avail_const_mem)
Compile preamble.
Definition piecewise.hpp:512
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:729
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:670
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:778
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduction method.
Definition piecewise.hpp:478
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:466
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:496
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:697
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition piecewise.hpp:769
virtual bool has_constant_zero() const
Test the constant node has a zero.
Definition piecewise.hpp:751
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:708
virtual bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes arguments match.
Definition piecewise.hpp:687
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:742
piecewise_1D_node(const backend::buffer< T > &d, shared_leaf< T, SAFE_MATH > x)
Construct 1D a piecewise constant node.
Definition piecewise.hpp:452
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:607
Class representing a 2D piecewise constant.
Definition piecewise.hpp:898
virtual void compile_preamble(std::ostringstream &stream, jit::register_map &registers, jit::visiter_map &visited, jit::register_usage &usage, jit::texture1d_list &textures1d, jit::texture2d_list &textures2d, jit::preamble_map &pre_funcs, int &avail_const_mem)
Compile preamble.
Definition piecewise.hpp:1067
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:1190
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:1051
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:1382
piecewise_2D_node(const backend::buffer< T > &d, const size_t n, shared_leaf< T, SAFE_MATH > x, shared_leaf< T, SAFE_MATH > y)
Construct 2D a piecewise constant node.
Definition piecewise.hpp:969
size_t get_num_columns() const
Get the number of columns.
Definition piecewise.hpp:985
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition piecewise.hpp:1391
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1285
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:1364
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:1351
size_t get_num_rows() const
Get the number of columns.
Definition piecewise.hpp:994
bool is_col_match(shared_leaf< T, SAFE_MATH > x)
Do the columns match.
Definition piecewise.hpp:1423
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:1317
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:1328
bool is_row_match(shared_leaf< T, SAFE_MATH > x)
Do the rows match.
Definition piecewise.hpp:1410
virtual bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1303
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:1400
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduction method.
Definition piecewise.hpp:1019
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:1007
virtual bool has_constant_zero() const
Test the constant node has a zero.
Definition piecewise.hpp:1373
Class representing a straight node.
Definition node.hpp:1219
shared_leaf< T, SAFE_MATH > arg
Argument.
Definition node.hpp:1222
Class representing a triple branch node.
Definition node.hpp:1467
shared_leaf< T, SAFE_MATH > middle
Middle branch of the tree.
Definition node.hpp:1470
Complex scalar concept.
Definition register.hpp:25
Double base concept.
Definition register.hpp:43
float base concept.
Definition register.hpp:38
subroutine assert(test, message)
Assert check.
Definition f_binding_test.f90:38
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
Name space for graph nodes.
Definition arithmetic.hpp:13
shared_piecewise_2D< T, SAFE_MATH > piecewise_2D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a piecewise 2D node.
Definition piecewise.hpp:1508
std::shared_ptr< argument_node< T, SAFE_MATH > > shared_argument
Convenience type alias for shared argument nodes.
Definition piecewise.hpp:334
constexpr shared_leaf< T, SAFE_MATH > zero()
Forward declare for zero.
Definition node.hpp:1154
shared_index_2D< T, SAFE_MATH > index_2D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a index 2D node.
Definition piecewise.hpp:2114
void compile_2D_index(std::ostringstream &stream, const std::string &x_register_name, const std::string &y_register_name, const size_t num_columns)
Compile an 2D index.
Definition piecewise.hpp:84
shared_leaf< T, SAFE_MATH > index()
Construct an index.
Definition node.hpp:856
shared_atomic_accumulate_1D< T, SAFE_MATH > atomic_accumulate_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a atomic accumulate 1D node.
Definition piecewise.hpp:2426
std::shared_ptr< index_2D_node< T, SAFE_MATH > > shared_index_2D
Convenience type alias for shared index 2D nodes.
Definition piecewise.hpp:2102
shared_leaf< T, SAFE_MATH > atomic_accumulate_1D(shared_leaf< T, SAFE_MATH > v, shared_leaf< T, SAFE_MATH > i, shared_leaf< T, SAFE_MATH > x)
Define atomic_accumulate_1D convenience function.
Definition piecewise.hpp:2362
shared_piecewise_1D< T, SAFE_MATH > piecewise_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a piecewise 1D node.
Definition piecewise.hpp:849
std::shared_ptr< piecewise_2D_node< T, SAFE_MATH > > shared_piecewise_2D
Convenience type alias for shared piecewise 2D nodes.
Definition piecewise.hpp:1496
shared_constant< T, SAFE_MATH > constant_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a constant node.
Definition node.hpp:1202
shared_variable< T, SAFE_MATH > variable_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a variable node.
Definition node.hpp:2169
std::shared_ptr< piecewise_1D_node< T, SAFE_MATH > > shared_piecewise_1D
Convenience type alias for shared piecewise 1D nodes.
Definition piecewise.hpp:837
constexpr T i
Convenience type for imaginary constant.
Definition node.hpp:1186
shared_argument< T, SAFE_MATH > argument_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a argument node.
Definition piecewise.hpp:346
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:691
shared_leaf< T, SAFE_MATH > argument(shared_leaf< T, SAFE_MATH > x, const T scale, const T offset, const size_t length)
Define argument convenience function.
Definition piecewise.hpp:308
std::shared_ptr< index_1D_node< T, SAFE_MATH > > shared_index_1D
Convenience type alias for shared index 1D nodes.
Definition piecewise.hpp:1758
void compile_index(std::ostringstream &stream, const std::string &register_name, const size_t length, const T scale, const T offset)
Compile an index.
Definition piecewise.hpp:26
std::shared_ptr< atomic_accumulate_1D_node< T, SAFE_MATH > > shared_atomic_accumulate_1D
Convenience type alias for shared atomic accumulate 1D nodes.
Definition piecewise.hpp:2413
shared_index_1D< T, SAFE_MATH > index_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a index 1D node.
Definition piecewise.hpp:1770
std::unordered_set< void * > visiter_map
Type alias for listing visited nodes.
Definition register.hpp:263
std::string format_to_string(const T value)
Convert a value to a string while avoiding locale.
Definition register.hpp:213
std::unordered_map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:261
std::unordered_set< std::string > preamble_map
Type alias for preamble defined functions.
Definition register.hpp:269
std::unordered_map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:259
constexpr bool use_cuda()
Test to use Cuda.
Definition register.hpp:68
std::unordered_map< void *, std::array< size_t, 2 > > texture2d_list
Type alias for indexing 2D textures.
Definition register.hpp:267
std::unordered_map< void *, size_t > texture1d_list
Type alias for indexing 1D textures.
Definition register.hpp:265
std::string to_string(const char prefix, const NODE *pointer)
Convert a graph::leaf_node pointer to a string.
Definition register.hpp:247
Base nodes of graph computation framework.
void index_2D()
Tests for 2D index nodes.
Definition piecewise_test.cpp:870
void piecewise_1D()
Tests for 1D piecewise nodes.
Definition piecewise_test.cpp:82
void index_1D()
Tests for 1D index nodes.
Definition piecewise_test.cpp:836
void piecewise_2D()
Tests for 2D piecewise nodes.
Definition piecewise_test.cpp:321