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//------------------------------------------------------------------------------
25template<jit::float_scalar T>
26void 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 stream << "<" << type << ">";
35 }
36 stream << "(max";
37 if constexpr (!jit::use_metal<T> ()) {
38 stream << "<" << type << ">";
39 }
40 stream << "(";
41 if constexpr (jit::complex_scalar<T>) {
42 stream << "real(";
43 }
44 stream << "(" << register_name << " - ";
45 if constexpr (jit::complex_scalar<T>) {
47 }
48 stream << offset << ")/";
49 if constexpr (jit::complex_scalar<T>) {
51 }
52 stream << scale;
53 if constexpr (jit::complex_scalar<T>) {
54 stream << ")";
55 }
56 stream << ",";
57 if constexpr (jit::use_metal<T> ()) {
58 stream << "(" << type << ")";
59 }
60 stream << "0),";
61 if constexpr (jit::use_metal<T> ()) {
62 stream << "(" << type << ")";
63 }
64 stream << length - 1 << ")";
65}
66
67//******************************************************************************
68// 1D Piecewise node.
69//******************************************************************************
70//------------------------------------------------------------------------------
103//------------------------------------------------------------------------------
104 template<jit::float_scalar T, bool SAFE_MATH=false>
105 class piecewise_1D_node final : public straight_node<T, SAFE_MATH> {
106 private:
108 const T scale;
110 const T offset;
111
112//------------------------------------------------------------------------------
117//------------------------------------------------------------------------------
118 static std::string to_string(const backend::buffer<T> &d) {
119 std::string temp;
120 for (size_t i = 0, ie = d.size(); i < ie; i++) {
122 }
123
124 return temp;
125 }
126
127//------------------------------------------------------------------------------
135//------------------------------------------------------------------------------
136 static std::string to_string(const backend::buffer<T> &d,
138 const T scale,
139 const T offset) {
140 return piecewise_1D_node::to_string(d) +
141 jit::format_to_string(x->get_hash()) +
142 jit::format_to_string(scale) +
143 jit::format_to_string(offset);
144 }
145
146//------------------------------------------------------------------------------
151//------------------------------------------------------------------------------
152 static size_t hash_data(const backend::buffer<T> &d) {
153 const size_t h = std::hash<std::string>{} (piecewise_1D_node::to_string(d));
154 for (size_t i = h; i < std::numeric_limits<size_t>::max(); i++) {
155 if (leaf_node<T, SAFE_MATH>::caches.backends.find(i) ==
156 leaf_node<T, SAFE_MATH>::caches.backends.end()) {
158 return i;
159 } else if (d == leaf_node<T, SAFE_MATH>::caches.backends[i]) {
160 return i;
161 }
162 }
163#if defined(__clang__) || defined(__GNUC__)
165#else
166 assert(false && "Should never reach.");
167#endif
168 }
169
171 const size_t data_hash;
172
173 public:
174//------------------------------------------------------------------------------
181//------------------------------------------------------------------------------
184 const T scale,
185 const T offset) :
186 straight_node<T, SAFE_MATH> (x, piecewise_1D_node::to_string(d, x,
187 scale,
188 offset)),
189 data_hash(piecewise_1D_node::hash_data(d)), scale(scale),
190 offset(offset) {}
191
192//------------------------------------------------------------------------------
200//------------------------------------------------------------------------------
202 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash];
203 }
204
205//------------------------------------------------------------------------------
212//------------------------------------------------------------------------------
214 if (constant_cast(this->arg).get()) {
215 const T arg = (this->arg->evaluate().at(0) + offset)/scale;
216 if constexpr (jit::float_base<T>) {
217 const size_t i = std::max<float> (std::min<float> (std::real(arg),
218 this->get_size() - 1),
219 0);
220 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i]);
221 } else {
222 const size_t i = std::max<double> (std::min<double> (std::real(arg),
223 this->get_size() - 1),
224 0);
225 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i]);
226 }
227 }
228
229 if (evaluate().is_same()) {
230 return constant<T, SAFE_MATH> (evaluate().at(0));
231 }
232 return this->shared_from_this();
233 }
234
235//------------------------------------------------------------------------------
240//------------------------------------------------------------------------------
242 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
243 }
244
245//------------------------------------------------------------------------------
255//------------------------------------------------------------------------------
256 virtual void compile_preamble(std::ostringstream &stream,
257 jit::register_map &registers,
262 int &avail_const_mem) {
263 if (visited.find(this) == visited.end()) {
264 this->arg->compile_preamble(stream, registers,
265 visited, usage,
268 if (registers.find(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()) == registers.end()) {
269 registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] =
270 jit::to_string('a', leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data());
271 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
272 if constexpr (jit::use_metal<T> ()) {
273 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
274 length);
275#ifdef USE_CUDA_TEXTURES
276 } else if constexpr (jit::use_cuda()) {
277 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
278 length);
279#endif
280 } else {
281 if constexpr (jit::use_cuda()) {
282 const int buffer_size = length*sizeof(T);
283 if (avail_const_mem - buffer_size > 0) {
285 stream << "__constant__ ";
286 }
287 }
288 stream << "const ";
289 jit::add_type<T> (stream);
290 stream << " " << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] << "[] = {";
291 if constexpr (jit::complex_scalar<T>) {
292 jit::add_type<T> (stream);
293 }
294 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][0];
295 for (size_t i = 1; i < length; i++) {
296 stream << ", ";
297 if constexpr (jit::complex_scalar<T>) {
298 jit::add_type<T> (stream);
299 }
300 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i];
301 }
302 stream << "};" << std::endl;
303 }
304 } else {
305// When using textures, the register can be defined in a previous kernel. We
306// need to add the textures again.
307 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
308 if constexpr (jit::use_metal<T> ()) {
309 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
310 length);
311#ifdef USE_CUDA_TEXTURES
312 } else if constexpr (jit::use_cuda()) {
313 textures1d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
314 length);
315#endif
316 }
317 }
318 visited.insert(this);
319#ifdef SHOW_USE_COUNT
320 usage[this] = 1;
321 } else {
322 ++usage[this];
323#endif
324 }
325 }
326
327//------------------------------------------------------------------------------
347//------------------------------------------------------------------------------
349 compile(std::ostringstream &stream,
350 jit::register_map &registers,
352 const jit::register_usage &usage) {
353 if (registers.find(this) == registers.end()) {
354#ifdef USE_INDEX_CACHE
355 if (indices.find(this->arg.get()) == indices.end()) {
356#endif
357 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
358 shared_leaf<T, SAFE_MATH> a = this->arg->compile(stream,
359 registers,
360 indices,
361 usage);
362#ifdef USE_INDEX_CACHE
363 indices[a.get()] = jit::to_string('i', a.get());
364 stream << " const "
365 << jit::smallest_uint_type<T> (length) << " "
366 << indices[a.get()] << " = ";
367 compile_index<T> (stream, registers[a.get()], length,
368 scale, offset);
369 a->endline(stream, usage);
370 }
371#endif
372
373 registers[this] = jit::to_string('r', this);
374 stream << " const ";
375 jit::add_type<T> (stream);
376 stream << " " << registers[this] << " = ";
377#ifdef USE_CUDA_TEXTURES
378 if constexpr (jit::use_cuda()) {
379 if constexpr (jit::float_base<T>) {
380 if constexpr (complex_scalar<T>) {
381 stream << "to_cmp_float(tex1D<float2> (";
382 } else {
383 stream << "tex1D<float> (";
384 }
385 } else {
386 if constexpr (complex_scalar<T>) {
387 stream << "to_cmp_double(tex1D<uint4> (";
388 } else {
389 stream << "to_double(tex1D<uint2> (";
390 }
391 }
392 }
393#endif
394 stream << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()];
395 if constexpr (jit::use_metal<T> ()) {
396#ifdef USE_INDEX_CACHE
397 stream << ".read("
398 << indices[this->arg.get()]
399 << ").r";
400#else
401 stream << ".read(";
402 compile_index<T> (stream, registers[a.get()], length,
403 scale, offset);
404 stream << ").r";
405#endif
406#ifdef USE_CUDA_TEXTURES
407 } else if constexpr (jit::use_cuda()) {
408#ifdef USE_INDEX_CACHE
409 stream << ", "
410 << indices[this->arg.get()];
411#else
412 stream << ", ";
413 compile_index<T> (stream, registers[a.get()], length,
414 scale, offset);
415#endif
417 stream << ")";
418 }
419 stream << ")";
420#endif
421 } else {
422#ifdef USE_INDEX_CACHE
423 stream << "["
424 << indices[this->arg.get()]
425 << "]";
426#else
427 stream << "[";
428 compile_index<T> (stream, registers[a.get()], length,
429 scale, offset);
430 stream << "]";
431#endif
432 }
433 this->endline(stream, usage);
434 }
435
436 return this->shared_from_this();
437 }
438
439//------------------------------------------------------------------------------
447//------------------------------------------------------------------------------
449 auto x_cast = piecewise_1D_cast(x);
450
451 if (x_cast.get()) {
452 return this->data_hash == x_cast->data_hash &&
453 this->is_arg_match(x);
454 }
455
456 return false;
457 }
458
459//------------------------------------------------------------------------------
461//------------------------------------------------------------------------------
462 virtual void to_latex() const {
463 std::cout << "r\\_" << reinterpret_cast<size_t> (this) << "_{i}";
464 }
465
466//------------------------------------------------------------------------------
472//------------------------------------------------------------------------------
473 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
474 jit::register_map &registers) {
475 if (registers.find(this) == registers.end()) {
476 const std::string name = jit::to_string('r', this);
477 registers[this] = name;
478 stream << " " << name
479 << " [label = \"r_" << reinterpret_cast<size_t> (this)
480 << "_{i}\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
481
482 auto a = this->arg->to_vizgraph(stream, registers);
483 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
484 }
485
486 return this->shared_from_this();
487 }
488
489//------------------------------------------------------------------------------
493//------------------------------------------------------------------------------
494 virtual bool is_constant() const {
495 return true;
496 }
497
498//------------------------------------------------------------------------------
502//------------------------------------------------------------------------------
503 virtual bool has_constant_zero() const {
504 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].has_zero();
505 }
506
507//------------------------------------------------------------------------------
511//------------------------------------------------------------------------------
512 virtual bool is_all_variables() const {
513 return false;
514 }
515
516//------------------------------------------------------------------------------
520//------------------------------------------------------------------------------
521 virtual bool is_power_like() const {
522 return true;
523 }
524
525//------------------------------------------------------------------------------
529//------------------------------------------------------------------------------
531 return this->shared_from_this();
532 }
533
534//------------------------------------------------------------------------------
538//------------------------------------------------------------------------------
540 return one<T, SAFE_MATH> ();
541 }
542
543//------------------------------------------------------------------------------
548//------------------------------------------------------------------------------
550 auto temp = piecewise_1D_cast(x);
551 return temp.get() &&
552 this->arg->is_match(temp->get_arg()) &&
553 (temp->get_size() == this->get_size()) &&
554 (temp->get_scale() == this->scale) &&
555 (temp->get_offset() == this->offset);
556 }
557
558//------------------------------------------------------------------------------
562//------------------------------------------------------------------------------
563 T get_scale() const {
564 return scale;
565 }
566
567//------------------------------------------------------------------------------
571//------------------------------------------------------------------------------
572 T get_offset() const {
573 return offset;
574 }
575
576//------------------------------------------------------------------------------
580//------------------------------------------------------------------------------
581 size_t get_size() const {
582 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
583 }
584 };
585
586//------------------------------------------------------------------------------
597//------------------------------------------------------------------------------
598 template<jit::float_scalar T, bool SAFE_MATH=false>
601 const T scale,
602 const T offset) {
603 auto temp = std::make_shared<piecewise_1D_node<T, SAFE_MATH>> (d, x,
604 scale,
605 offset)->reduce();
606// Test for hash collisions.
607 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
608 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
611 return temp;
612 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
614 }
615 }
616#if defined(__clang__) || defined(__GNUC__)
618#else
619 assert(false && "Should never reach.");
620#endif
621 }
622
624 template<jit::float_scalar T, bool SAFE_MATH=false>
625 using shared_piecewise_1D = std::shared_ptr<piecewise_1D_node<T, SAFE_MATH>>;
626
627//------------------------------------------------------------------------------
635//------------------------------------------------------------------------------
636 template<jit::float_scalar T, bool SAFE_MATH=false>
638 return std::dynamic_pointer_cast<piecewise_1D_node<T, SAFE_MATH>> (x);
639 }
640
641//******************************************************************************
642// 2D Piecewise node.
643//******************************************************************************
644//------------------------------------------------------------------------------
684//------------------------------------------------------------------------------
685 template<jit::float_scalar T, bool SAFE_MATH=false>
686 class piecewise_2D_node final : public branch_node<T, SAFE_MATH> {
687 private:
689 const T x_scale;
691 const T x_offset;
693 const T y_scale;
695 const T y_offset;
696
697//------------------------------------------------------------------------------
702//------------------------------------------------------------------------------
703 static std::string to_string(const backend::buffer<T> &d) {
704 std::string temp;
705 for (size_t i = 0, ie = d.size(); i < ie; i++) {
707 }
708
709 return temp;
710 }
711
712//------------------------------------------------------------------------------
723//------------------------------------------------------------------------------
724 static std::string to_string(const backend::buffer<T> &d,
726 const T x_scale,
727 const T x_offset,
729 const T y_scale,
730 const T y_offset) {
731 return piecewise_2D_node::to_string(d) +
732 jit::format_to_string(x->get_hash()) +
733 jit::format_to_string(x_scale) +
734 jit::format_to_string(x_offset) +
735 jit::format_to_string(y->get_hash()) +
736 jit::format_to_string(y_scale) +
737 jit::format_to_string(y_offset);
738 }
739
740//------------------------------------------------------------------------------
745//------------------------------------------------------------------------------
746 static size_t hash_data(const backend::buffer<T> &d) {
747 const size_t h = std::hash<std::string>{} (piecewise_2D_node::to_string(d));
748 for (size_t i = h; i < std::numeric_limits<size_t>::max(); i++) {
749 if (leaf_node<T, SAFE_MATH>::caches.backends.find(i) ==
750 leaf_node<T, SAFE_MATH>::caches.backends.end()) {
752 return i;
753 } else if (d == leaf_node<T, SAFE_MATH>::caches.backends[i]) {
754 return i;
755 }
756 }
757#if defined(__clang__) || defined(__GNUC__)
759#else
760 assert(false && "Should never reach.");
761#endif
762 }
763
765 const size_t data_hash;
767 const size_t num_columns;
768
769 public:
770//------------------------------------------------------------------------------
781//------------------------------------------------------------------------------
783 const size_t n,
785 const T x_scale,
786 const T x_offset,
788 const T y_scale,
789 const T y_offset) :
790 branch_node<T, SAFE_MATH> (x, y,
791 piecewise_2D_node::to_string(d,
792 x, x_scale, x_offset,
793 y, y_scale, y_offset)),
794 data_hash(piecewise_2D_node::hash_data(d)),
795 num_columns(n), x_scale(x_scale), x_offset(x_offset), y_scale(y_scale),
796 y_offset(y_offset) {
797 assert(d.size()%n == 0 &&
798 "Expected the data buffer to be a multiple of the number of columns.");
799 }
800
801//------------------------------------------------------------------------------
805//------------------------------------------------------------------------------
806 size_t get_num_columns() const {
807 return num_columns;
808 }
809
810//------------------------------------------------------------------------------
814//------------------------------------------------------------------------------
815 size_t get_num_rows() const {
816 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size() /
817 num_columns;
818 }
819
820//------------------------------------------------------------------------------
824//------------------------------------------------------------------------------
825 T get_x_scale() const {
826 return x_scale;
827 }
828
829//------------------------------------------------------------------------------
833//------------------------------------------------------------------------------
834 T get_x_offset() const {
835 return x_offset;
836 }
837
838//------------------------------------------------------------------------------
842//------------------------------------------------------------------------------
843 T get_y_scale() const {
844 return y_scale;
845 }
846
847//------------------------------------------------------------------------------
851//------------------------------------------------------------------------------
852 T get_y_offset() const {
853 return y_offset;
854 }
855
856//------------------------------------------------------------------------------
864//------------------------------------------------------------------------------
866 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash];
867 }
868
869//------------------------------------------------------------------------------
876//------------------------------------------------------------------------------
878 if (constant_cast(this->left).get() &&
879 constant_cast(this->right).get()) {
880 const T l = (this->left->evaluate().at(0) + x_offset)/x_scale;
881 const T r = (this->right->evaluate().at(0) + y_offset)/y_scale;
882
883 if constexpr (jit::float_base<T>) {
884 const size_t i = std::max<float> (std::min<float> (std::real(l),
885 this->get_num_rows() - 1),
886 0);
887 const size_t j = std::max<float> (std::min<float> (std::real(r),
888 this->get_num_columns() - 1),
889 0);
890 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i*this->get_num_columns() + j]);
891 } else {
892 const size_t i = std::max<double> (std::min<double> (std::real(l),
893 this->get_num_rows() - 1),
894 0);
895 const size_t j = std::max<double> (std::min<double> (std::real(r),
896 this->get_num_columns() - 1),
897 0);
898 return constant<T, SAFE_MATH> (leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i*this->get_num_columns() + j]);
899 }
900 } else if (constant_cast(this->left).get()) {
901 const T l = (this->left->evaluate().at(0) + x_offset)/x_scale;
902
903 if constexpr (jit::float_base<T>) {
904 const size_t i = std::max<float> (std::min<float> (std::real(l),
905 this->get_num_rows() - 1),
906 0);
907 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_row(i, this->get_num_columns()),
908 this->right, y_scale, y_offset);
909 } else {
910 const size_t i = std::max<double> (std::min<double> (std::real(l),
911 this->get_num_rows() - 1),
912 0);
913 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_row(i, this->get_num_columns()),
914 this->right, y_scale, y_offset);
915 }
916 } else if (constant_cast(this->right).get()) {
917 const T r = (this->right->evaluate().at(0) + y_offset)/y_scale;
918
919 if constexpr (jit::float_base<T>) {
920 const size_t j = std::max<float> (std::min<float> (std::real(r),
921 this->get_num_columns() - 1),
922 0);
923 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_column(j, this->get_num_columns()),
924 this->left, x_scale, x_offset);
925 } else {
926 const size_t j = std::max<double> (std::min<double> (std::real(r),
927 this->get_num_columns() - 1),
928 0);
929 return piecewise_1D(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].index_column(j, this->get_num_columns()),
930 this->left, x_scale, x_offset);
931 }
932 }
933
934 if (evaluate().is_same()) {
935 return constant<T, SAFE_MATH> (evaluate().at(0));
936 }
937
938 return this->shared_from_this();
939 }
940
941//------------------------------------------------------------------------------
946//------------------------------------------------------------------------------
948 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
949 }
950
951//------------------------------------------------------------------------------
961//------------------------------------------------------------------------------
962 virtual void compile_preamble(std::ostringstream &stream,
963 jit::register_map &registers,
968 int &avail_const_mem) {
969 if (visited.find(this) == visited.end()) {
970 this->left->compile_preamble(stream, registers,
971 visited, usage,
974 this->right->compile_preamble(stream, registers,
975 visited, usage,
978 if (registers.find(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()) == registers.end()) {
979 registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] =
980 jit::to_string('a', leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data());
981 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
982 if constexpr (jit::use_metal<T> ()) {
983 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
984 std::array<size_t, 2> ({length/num_columns, num_columns}));
985#ifdef USE_CUDA_TEXTURES
986 } else if constexpr (jit::use_cuda()) {
987 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
988 std::array<size_t, 2> ({length/num_columns, num_columns}));
989#endif
990 } else {
991 if constexpr (jit::use_cuda()) {
992 const int buffer_size = length*sizeof(T);
993 if (avail_const_mem - buffer_size > 0) {
995 stream << "__constant__ ";
996 }
997 }
998 stream << "const ";
999 jit::add_type<T> (stream);
1000 stream << " " << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()] << "[] = {";
1001 if constexpr (jit::complex_scalar<T>) {
1002 jit::add_type<T> (stream);
1003 }
1004 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][0];
1005 for (size_t i = 1; i < length; i++) {
1006 stream << ", ";
1007 if constexpr (jit::complex_scalar<T>) {
1008 jit::add_type<T> (stream);
1009 }
1010 stream << leaf_node<T, SAFE_MATH>::caches.backends[data_hash][i];
1011 }
1012 stream << "};" << std::endl;
1013 }
1014 } else {
1015// When using textures, the register can be defined in a previous kernel. We
1016// need to add the textures again.
1017 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
1018 if constexpr (jit::use_metal<T> ()) {
1019 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1020 std::array<size_t, 2> ({length/num_columns, num_columns}));
1021#ifdef USE_CUDA_TEXTURES
1022 } else if constexpr (jit::use_cuda()) {
1023 textures2d.try_emplace(leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data(),
1024 std::array<size_t, 2> ({length/num_columns, num_columns}));
1025#endif
1026 }
1027 }
1028 visited.insert(this);
1029#ifdef SHOW_USE_COUNT
1030 usage[this] = 1;
1031 } else {
1032 ++usage[this];
1033#endif
1034 }
1035 }
1036
1037//------------------------------------------------------------------------------
1070//------------------------------------------------------------------------------
1072 compile(std::ostringstream &stream,
1073 jit::register_map &registers,
1075 const jit::register_usage &usage) {
1076 if (registers.find(this) == registers.end()) {
1077 const size_t length = leaf_node<T, SAFE_MATH>::caches.backends[data_hash].size();
1078 const size_t num_rows = length/num_columns;
1079
1080 shared_leaf<T, SAFE_MATH> x = this->left->compile(stream,
1081 registers,
1082 indices,
1083 usage);
1084 shared_leaf<T, SAFE_MATH> y = this->right->compile(stream,
1085 registers,
1086 indices,
1087 usage);
1088
1089#ifdef USE_INDEX_CACHE
1090 if (indices.find(x.get()) == indices.end()) {
1091 indices[x.get()] = jit::to_string('i', x.get());
1092 stream << " const "
1093 << jit::smallest_uint_type<T> (num_rows) << " "
1094 << indices[x.get()] << " = ";
1095 compile_index<T> (stream, registers[x.get()], num_rows,
1096 x_scale, x_offset);
1097 x->endline(stream, usage);
1098 }
1099 if (indices.find(y.get()) == indices.end()) {
1100 indices[y.get()] = jit::to_string('i', y.get());
1101 stream << " const "
1102 << jit::smallest_uint_type<T> (num_columns) << " "
1103 << indices[y.get()] << " = ";
1104 compile_index<T> (stream, registers[y.get()], num_columns,
1105 y_scale, y_offset);
1106 y->endline(stream, usage);
1107 }
1108
1109 auto temp = this->left + this->right;
1110 if constexpr (!jit::use_metal<T> ()
1111#ifdef USE_CUDA_TEXTURES
1112 || !jit::use_cuda()
1113#endif
1114 ) {
1115 if (indices.find(temp.get()) == indices.end()) {
1116 indices[temp.get()] = jit::to_string('i', temp.get());
1117 stream << " const "
1118 << jit::smallest_uint_type<T> (length) << " "
1119 << indices[temp.get()] << " = "
1120 << indices[x.get()]
1121 << "*" << num_columns << " + "
1122 << indices[y.get()]
1123 << ";" << std::endl;
1124 }
1125 }
1126#endif
1127
1128 registers[this] = jit::to_string('r', this);
1129 stream << " const ";
1130 jit::add_type<T> (stream);
1131 stream << " " << registers[this] << " = ";
1132#ifdef USE_CUDA_TEXTURES
1133 if constexpr (jit::use_cuda()) {
1134 if constexpr (jit::float_base<T>) {
1135 if constexpr (complex_scalar<T>) {
1136 stream << "to_cmp_float(tex1D<float2> (";
1137 } else {
1138 stream << "tex1D<float> (";
1139 }
1140 } else {
1141 if constexpr (complex_scalar<T>) {
1142 stream << "to_cmp_double(tex1D<uint4> (";
1143 } else {
1144 stream << "to_double(tex1D<uint2> (";
1145 }
1146 }
1147 }
1148#endif
1149 stream << registers[leaf_node<T, SAFE_MATH>::caches.backends[data_hash].data()];
1150 if constexpr (jit::use_metal<T> ()) {
1151#ifdef USE_INDEX_CACHE
1152 stream << ".read("
1153 << jit::smallest_uint_type<T> (std::max(num_rows,
1154 num_columns))
1155 << "2("
1156 << indices[y.get()]
1157 << ","
1158 << indices[x.get()]
1159 << ")).r";
1160#else
1161 stream << ".read(uint2(";
1162 compile_index<T> (stream, registers[y.get()], num_columns,
1163 y_scale, y_offset);
1164 stream << ",";
1165 compile_index<T> (stream, registers[x.get()], num_rows,
1166 x_scale, x_offset);
1167 stream << ")).r";
1168#endif
1169#ifdef USE_CUDA_TEXTURES
1170 } else if constexpr (jit::use_cuda()) {
1171#ifdef USE_INDEX_CACHE
1172 stream << ", "
1173 << indices[y.get()]
1174 << ", "
1175 << indices[x.get()];
1176#else
1177 stream << ", ";
1178 compile_index<T> (stream, registers[y.get()], num_columns,
1179 y_scale, y_offset);
1180 stream << ", ";
1181 compile_index<T> (stream, registers[x.get()], num_rows,
1182 x_scale, x_offset);
1183#endif
1185 stream << ")";
1186 }
1187 stream << ")";
1188#endif
1189 } else {
1190#ifdef USE_INDEX_CACHE
1191 stream << "["
1192 << indices[temp.get()]
1193 << "]";
1194#else
1195 stream << "[";
1196 compile_index<T> (stream, registers[x.get()], num_rows,
1197 x_scale, x_offset);
1198 stream << "*" << num_columns << " + ";
1199 compile_index<T> (stream, registers[y.get()], num_columns,
1200 y_scale, y_offset);
1201 stream << "]";
1202#endif
1203 }
1204 this->endline(stream, usage);
1205 }
1206
1207 return this->shared_from_this();
1208 }
1209
1210//------------------------------------------------------------------------------
1217//------------------------------------------------------------------------------
1219 auto x_cast = piecewise_2D_cast(x);
1220
1221 if (x_cast.get()) {
1222 return this->data_hash == x_cast->data_hash &&
1223 this->is_arg_match(x);
1224 }
1225
1226 return false;
1227 }
1228
1229//------------------------------------------------------------------------------
1233//------------------------------------------------------------------------------
1234 virtual void to_latex() const {
1235 std::cout << "r\\_" << reinterpret_cast<size_t> (this) << "_{ij}";
1236 }
1237
1238//------------------------------------------------------------------------------
1244//------------------------------------------------------------------------------
1245 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1246 jit::register_map &registers) {
1247 if (registers.find(this) == registers.end()) {
1248 const std::string name = jit::to_string('r', this);
1249 registers[this] = name;
1250 stream << " " << name
1251 << " [label = \"r_" << reinterpret_cast<size_t> (this)
1252 << "_{ij}\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
1253
1254 auto l = this->left->to_vizgraph(stream, registers);
1255 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1256 auto r = this->right->to_vizgraph(stream, registers);
1257 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1258 }
1259
1260 return this->shared_from_this();
1261 }
1262
1263//------------------------------------------------------------------------------
1267//------------------------------------------------------------------------------
1268 virtual bool is_constant() const {
1269 return true;
1270 }
1271
1272//------------------------------------------------------------------------------
1276//------------------------------------------------------------------------------
1277 virtual bool has_constant_zero() const {
1278 return leaf_node<T, SAFE_MATH>::caches.backends[data_hash].has_zero();
1279 }
1280
1281//------------------------------------------------------------------------------
1285//------------------------------------------------------------------------------
1286 virtual bool is_all_variables() const {
1287 return false;
1288 }
1289
1290//------------------------------------------------------------------------------
1294//------------------------------------------------------------------------------
1295 virtual bool is_power_like() const {
1296 return true;
1297 }
1298
1299//------------------------------------------------------------------------------
1303//------------------------------------------------------------------------------
1305 return this->shared_from_this();
1306 }
1307
1308//------------------------------------------------------------------------------
1312//------------------------------------------------------------------------------
1314 return one<T, SAFE_MATH> ();
1315 }
1316
1317//------------------------------------------------------------------------------
1322//------------------------------------------------------------------------------
1324 auto temp = piecewise_2D_cast(x);
1325 return temp.get() &&
1326 this->left->is_match(temp->get_left()) &&
1327 this->right->is_match(temp->get_right()) &&
1328 (temp->get_num_rows() == this->get_num_rows()) &&
1329 (temp->get_num_columns() == this->get_num_columns()) &&
1330 (temp->get_x_scale() == this->x_scale) &&
1331 (temp->get_x_offset() == this->x_offset) &&
1332 (temp->get_y_scale() == this->y_scale) &&
1333 (temp->get_y_offset() == this->y_offset);
1334 }
1335
1336//------------------------------------------------------------------------------
1341//------------------------------------------------------------------------------
1343 auto temp = piecewise_1D_cast(x);
1344 return temp.get() &&
1345 this->left->is_match(temp->get_arg()) &&
1346 (temp->get_size() == this->get_num_rows()) &&
1347 (temp->get_scale() == this->x_scale) &&
1348 (temp->get_offset() == this->x_offset);
1349 }
1350
1351//------------------------------------------------------------------------------
1358//------------------------------------------------------------------------------
1360 auto temp = piecewise_1D_cast(x);
1361 return temp.get() &&
1362 this->right->is_match(temp->get_arg()) &&
1363 (temp->get_size() == this->get_num_columns()) &&
1364 (temp->get_scale() == this->y_scale) &&
1365 (temp->get_offset() == this->y_offset);
1366 }
1367 };
1368
1369//------------------------------------------------------------------------------
1384//------------------------------------------------------------------------------
1385 template<jit::float_scalar T, bool SAFE_MATH=false>
1387 const size_t n,
1389 const T x_scale,
1390 const T x_offset,
1392 const T y_scale,
1393 const T y_offset) {
1394 auto temp = std::make_shared<piecewise_2D_node<T, SAFE_MATH>> (d, n,
1395 x, x_scale, x_offset,
1396 y, y_scale, y_offset)->reduce();
1397// Test for hash collisions.
1398 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
1399 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1400 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1402 return temp;
1403 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1404 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1405 }
1406 }
1407#if defined(__clang__) || defined(__GNUC__)
1409#else
1410 assert(false && "Should never reach.");
1411#endif
1412 }
1413
1415 template<jit::float_scalar T, bool SAFE_MATH=false>
1416 using shared_piecewise_2D = std::shared_ptr<piecewise_2D_node<T, SAFE_MATH>>;
1417
1418//------------------------------------------------------------------------------
1426//------------------------------------------------------------------------------
1427 template<jit::float_scalar T, bool SAFE_MATH=false>
1429 return std::dynamic_pointer_cast<piecewise_2D_node<T, SAFE_MATH>> (x);
1430 }
1431
1432//******************************************************************************
1433// 1D Index node.
1434//******************************************************************************
1435//------------------------------------------------------------------------------
1446//------------------------------------------------------------------------------
1447 template<jit::float_scalar T, bool SAFE_MATH=false>
1448 class index_1D_node final : public branch_node<T, SAFE_MATH> {
1449 private:
1451 const T scale;
1453 const T offset;
1454
1455//------------------------------------------------------------------------------
1463//------------------------------------------------------------------------------
1464 static std::string to_string(shared_leaf<T, SAFE_MATH> v,
1466 const T scale,
1467 const T offset) {
1468 return jit::format_to_string(v->get_hash()) + "[" +
1469 jit::format_to_string(x->get_hash()) +
1470 jit::format_to_string(scale) +
1471 jit::format_to_string(offset) + "]";
1472 }
1473
1474 public:
1475//------------------------------------------------------------------------------
1482//------------------------------------------------------------------------------
1485 const T scale,
1486 const T offset) :
1487 branch_node<T, SAFE_MATH> (var, x,
1488 index_1D_node::to_string(var, x,
1489 scale, offset)),
1490 scale(scale), offset(offset) {}
1491
1492//------------------------------------------------------------------------------
1500//------------------------------------------------------------------------------
1502 return this->right->evaluate();
1503 }
1504
1505//------------------------------------------------------------------------------
1510//------------------------------------------------------------------------------
1512 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
1513 }
1514
1515//------------------------------------------------------------------------------
1528//------------------------------------------------------------------------------
1530 compile(std::ostringstream &stream,
1531 jit::register_map &registers,
1533 const jit::register_usage &usage) {
1534 if (registers.find(this) == registers.end()) {
1535#ifdef USE_INDEX_CACHE
1536 if (indices.find(this->right.get()) == indices.end()) {
1537#endif
1538 const size_t length = variable_cast(this->left)->size();
1539 shared_leaf<T, SAFE_MATH> a = this->right->compile(stream,
1540 registers,
1541 indices,
1542 usage);
1543#ifdef USE_INDEX_CACHE
1544 indices[a.get()] = jit::to_string('i', a.get());
1545 stream << " const "
1546 << jit::smallest_uint_type<T> (length) << " "
1547 << indices[a.get()] << " = ";
1548 compile_index<T> (stream, registers[a.get()], length,
1549 scale, offset);
1550 a->endline(stream, usage);
1551 }
1552#endif
1553
1554 registers[this] = jit::to_string('r', this);
1555 stream << " const ";
1556 jit::add_type<T> (stream);
1557 auto var = this->left->compile(stream,
1558 registers,
1559 indices,
1560 usage);
1561 stream << " " << registers[this] << " = "
1562 << jit::to_string('v', var.get());
1563#ifdef USE_INDEX_CACHE
1564 stream << "[" << indices[this->right.get()] << "]";
1565#else
1566 stream << "[";
1567 compile_index<T> (stream, registers[a.get()], length,
1568 scale, offset);
1569 stream << "]";
1570#endif
1571 this->endline(stream, usage);
1572 }
1573
1574 return this->shared_from_this();
1575 }
1576
1577//------------------------------------------------------------------------------
1584//------------------------------------------------------------------------------
1586 auto x_cast = index_1D_cast(x);
1587
1588 if (x_cast.get()) {
1589 return this->left->is_match(x_cast->get_left()) &&
1590 this->is_arg_match(x);
1591 }
1592
1593 return false;
1594 }
1595
1596//------------------------------------------------------------------------------
1598//------------------------------------------------------------------------------
1599 virtual void to_latex() const {
1600 std::cout << "r\\_" << reinterpret_cast<size_t> (this->left.get())
1601 << "\\left[i\\_"
1602 << reinterpret_cast<size_t> (this->right.get())
1603 << "\\right]";
1604 }
1605
1606//------------------------------------------------------------------------------
1612//------------------------------------------------------------------------------
1613 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1614 jit::register_map &registers) {
1615 if (registers.find(this) == registers.end()) {
1616 const std::string name = jit::to_string('r', this);
1617 registers[this] = name;
1618 stream << " " << name
1619 << " [label = \"r_" << reinterpret_cast<size_t> (this->left.get())
1620 << "\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
1621
1622 auto l = this->left->to_vizgraph(stream, registers);
1623 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1624 auto r = this->right->to_vizgraph(stream, registers);
1625 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1626 }
1627
1628 return this->shared_from_this();
1629 }
1630
1631//------------------------------------------------------------------------------
1635//------------------------------------------------------------------------------
1636 virtual bool is_constant() const {
1637 return false;
1638 }
1639
1640//------------------------------------------------------------------------------
1644//------------------------------------------------------------------------------
1645 virtual bool is_all_variables() const {
1646 return false;
1647 }
1648
1649//------------------------------------------------------------------------------
1653//------------------------------------------------------------------------------
1654 virtual bool is_power_like() const {
1655 return true;
1656 }
1657
1658//------------------------------------------------------------------------------
1662//------------------------------------------------------------------------------
1664 return one<T, SAFE_MATH> ();
1665 }
1666
1667//------------------------------------------------------------------------------
1672//------------------------------------------------------------------------------
1674 auto temp = index_1D_cast(x);
1675
1676 if (temp.get()) {
1677 return this->right->is_match(temp->get_right()) &&
1678 (temp->get_size() == this->get_size()) &&
1679 (temp->get_scale() == this->scale) &&
1680 (temp->get_offset() == this->offset);
1681 }
1682
1683 return false;
1684 }
1685
1686//------------------------------------------------------------------------------
1690//------------------------------------------------------------------------------
1691 T get_scale() const {
1692 return scale;
1693 }
1694
1695//------------------------------------------------------------------------------
1699//------------------------------------------------------------------------------
1700 T get_offset() const {
1701 return offset;
1702 }
1703
1704//------------------------------------------------------------------------------
1708//------------------------------------------------------------------------------
1709 size_t get_size() const {
1710 return variable_cast(this->left)->size();
1711 }
1712 };
1713
1714//------------------------------------------------------------------------------
1725//------------------------------------------------------------------------------
1726 template<jit::float_scalar T, bool SAFE_MATH=false>
1729 const T scale,
1730 const T offset) {
1732 "index_1D requires a variable node for first arg.");
1733 auto temp = std::make_shared<index_1D_node<T, SAFE_MATH>> (v, x,
1734 scale,
1735 offset)->reduce();
1736// Test for hash collisions.
1737 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
1738 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1739 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1741 return temp;
1742 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1743 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1744 }
1745 }
1746#if defined(__clang__) || defined(__GNUC__)
1748#else
1749 assert(false && "Should never reach.");
1750#endif
1751 }
1752
1754 template<jit::float_scalar T, bool SAFE_MATH=false>
1755 using shared_index_1D = std::shared_ptr<index_1D_node<T, SAFE_MATH>>;
1756
1757//------------------------------------------------------------------------------
1765//------------------------------------------------------------------------------
1766 template<jit::float_scalar T, bool SAFE_MATH=false>
1768 return std::dynamic_pointer_cast<index_1D_node<T, SAFE_MATH>> (x);
1769 }
1770
1771//******************************************************************************
1772// 2D Index node.
1773//******************************************************************************
1774//------------------------------------------------------------------------------
1786//------------------------------------------------------------------------------
1787 template<jit::float_scalar T, bool SAFE_MATH=false>
1788 class index_2D_node final : public triple_node<T, SAFE_MATH> {
1789 private:
1791 const T x_scale;
1793 const T x_offset;
1795 const T y_scale;
1797 const T y_offset;
1799 const size_t num_columns;
1800
1801//------------------------------------------------------------------------------
1812//------------------------------------------------------------------------------
1813 static std::string to_string(shared_leaf<T, SAFE_MATH> v,
1815 const T x_scale,
1816 const T x_offset,
1818 const T y_scale,
1819 const T y_offset) {
1820 return jit::format_to_string(v->get_hash()) + "[" +
1821 jit::format_to_string(x->get_hash()) +
1822 jit::format_to_string(x_scale) +
1823 jit::format_to_string(x_offset) + "," +
1824 jit::format_to_string(y->get_hash()) +
1825 jit::format_to_string(x_scale) +
1826 jit::format_to_string(x_offset) + "]";
1827 }
1828
1829 public:
1830//------------------------------------------------------------------------------
1841//------------------------------------------------------------------------------
1843 const size_t n,
1845 const T x_scale,
1846 const T x_offset,
1848 const T y_scale,
1849 const T y_offset) :
1850 triple_node<T, SAFE_MATH> (var, x, y,
1851 index_2D_node::to_string(var,
1852 x, x_scale, x_offset,
1853 y, y_scale, y_offset)),
1854 num_columns(n), x_scale(x_scale), x_offset(x_offset), y_scale(y_scale),
1855 y_offset(y_offset) {
1856 assert(variable_cast(this->left)->size()%n == 0 &&
1857 "Expected the data buffer to be a multiple of the number of columns.");
1858 }
1859
1860//------------------------------------------------------------------------------
1868//------------------------------------------------------------------------------
1870 return this->left->evaluate();
1871 }
1872
1873//------------------------------------------------------------------------------
1878//------------------------------------------------------------------------------
1880 return constant<T, SAFE_MATH> (static_cast<T> (this->is_match(x)));
1881 }
1882
1883//------------------------------------------------------------------------------
1897//------------------------------------------------------------------------------
1899 compile(std::ostringstream &stream,
1900 jit::register_map &registers,
1902 const jit::register_usage &usage) {
1903 if (registers.find(this) == registers.end()) {
1904 const size_t length = variable_cast(this->left)->size();
1905 const size_t num_rows = length/num_columns;
1906
1907 shared_leaf<T, SAFE_MATH> x = this->middle->compile(stream,
1908 registers,
1909 indices,
1910 usage);
1911 shared_leaf<T, SAFE_MATH> y = this->right->compile(stream,
1912 registers,
1913 indices,
1914 usage);
1915
1916#ifdef USE_INDEX_CACHE
1917 if (indices.find(x.get()) == indices.end()) {
1918 indices[x.get()] = jit::to_string('i', x.get());
1919 stream << " const "
1920 << jit::smallest_uint_type<T> (num_rows) << " "
1921 << indices[x.get()] << " = ";
1922 compile_index<T> (stream, registers[x.get()], num_rows,
1923 x_scale, x_offset);
1924 x->endline(stream, usage);
1925 }
1926 if (indices.find(y.get()) == indices.end()) {
1927 indices[y.get()] = jit::to_string('i', y.get());
1928 stream << " const "
1929 << jit::smallest_uint_type<T> (num_columns) << " "
1930 << indices[y.get()] << " = ";
1931 compile_index<T> (stream, registers[y.get()], num_columns,
1932 y_scale, y_offset);
1933 y->endline(stream, usage);
1934 }
1935
1936 auto temp = this->middle + this->right;
1937 if constexpr (!jit::use_metal<T> () ||
1938 !jit::use_cuda()) {
1939 if (indices.find(temp.get()) == indices.end()) {
1940 indices[temp.get()] = jit::to_string('i', temp.get());
1941 stream << " const "
1942 << jit::smallest_uint_type<T> (length) << " "
1943 << indices[temp.get()] << " = "
1944 << indices[x.get()]
1945 << "*" << num_columns << " + "
1946 << indices[y.get()]
1947 << ";" << std::endl;
1948 }
1949 }
1950#endif
1951
1952 registers[this] = jit::to_string('r', this);
1953 stream << " const ";
1954 jit::add_type<T> (stream);
1955 auto var = this->left->compile(stream,
1956 registers,
1957 indices,
1958 usage);
1959 stream << " " << registers[this] << " = "
1960 << jit::to_string('v', var.get());
1961#ifdef USE_INDEX_CACHE
1962 stream << "["
1963 << indices[temp.get()]
1964 << "]";
1965#else
1966 stream << "[";
1967 compile_index<T> (stream, registers[x.get()], num_rows,
1968 x_scale, x_offset);
1969 stream << "*" << num_columns << " + ";
1970 compile_index<T> (stream, registers[y.get()], num_columns,
1971 y_scale, y_offset);
1972 stream << "]";
1973#endif
1974 this->endline(stream, usage);
1975 }
1976
1977 return this->shared_from_this();
1978 }
1979
1980//------------------------------------------------------------------------------
1987//------------------------------------------------------------------------------
1989 auto x_cast = index_2D_cast(x);
1990
1991 if (x_cast.get()) {
1992 return this->left->is_match(x_cast->get_left()) &&
1993 this->is_arg_match(x);
1994 }
1995
1996 return false;
1997 }
1998
1999//------------------------------------------------------------------------------
2001//------------------------------------------------------------------------------
2002 virtual void to_latex() const {
2003 std::cout << "r\\_" << reinterpret_cast<size_t> (this->left.get())
2004 << "\\left[i\\_"
2005 << reinterpret_cast<size_t> (this->middle.get())
2006 << ",j\\_"
2007 << reinterpret_cast<size_t> (this->right.get())
2008 << "\\right]";
2009 }
2010
2011//------------------------------------------------------------------------------
2017//------------------------------------------------------------------------------
2018 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
2019 jit::register_map &registers) {
2020 if (registers.find(this) == registers.end()) {
2021 const std::string name = jit::to_string('r', this);
2022 registers[this] = name;
2023 stream << " " << name
2024 << " [label = \"r_" << reinterpret_cast<size_t> (this->left.get())
2025 << "\", shape = hexagon, style = filled, fillcolor = black, fontcolor = white];" << std::endl;
2026
2027 auto l = this->left->to_vizgraph(stream, registers);
2028 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
2029 auto m = this->middle->to_vizgraph(stream, registers);
2030 stream << " " << name << " -- " << registers[m.get()] << ";" << std::endl;
2031 auto r = this->right->to_vizgraph(stream, registers);
2032 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
2033 }
2034
2035 return this->shared_from_this();
2036 }
2037
2038//------------------------------------------------------------------------------
2042//------------------------------------------------------------------------------
2043 virtual bool is_constant() const {
2044 return false;
2045 }
2046
2047//------------------------------------------------------------------------------
2051//------------------------------------------------------------------------------
2052 virtual bool is_all_variables() const {
2053 return false;
2054 }
2055
2056//------------------------------------------------------------------------------
2060//------------------------------------------------------------------------------
2061 virtual bool is_power_like() const {
2062 return true;
2063 }
2064
2065//------------------------------------------------------------------------------
2069//------------------------------------------------------------------------------
2071 return one<T, SAFE_MATH> ();
2072 }
2073
2074//------------------------------------------------------------------------------
2079//------------------------------------------------------------------------------
2081 auto temp = index_2D_cast(x);
2082
2083 if (temp.get()) {
2084 return this->right->is_match(temp->get_right()) &&
2085 (temp->get_size() == this->get_size()) &&
2086 (temp->get_x_scale() == this->x_scale) &&
2087 (temp->get_x_offset() == this->x_offset) &&
2088 (temp->get_y_scale() == this->y_scale) &&
2089 (temp->get_y_offset() == this->y_offset);
2090 }
2091
2092 return false;
2093 }
2094
2095//------------------------------------------------------------------------------
2099//------------------------------------------------------------------------------
2100 T get_x_scale() const {
2101 return x_scale;
2102 }
2103
2104//------------------------------------------------------------------------------
2108//------------------------------------------------------------------------------
2109 T get_x_offset() const {
2110 return x_offset;
2111 }
2112
2113//------------------------------------------------------------------------------
2117//------------------------------------------------------------------------------
2118 T get_y_scale() const {
2119 return y_scale;
2120 }
2121
2122//------------------------------------------------------------------------------
2126//------------------------------------------------------------------------------
2127 T get_y_offset() const {
2128 return y_offset;
2129 }
2130
2131//------------------------------------------------------------------------------
2135//------------------------------------------------------------------------------
2136 size_t get_size() const {
2137 return variable_cast(this->left)->size();
2138 }
2139 };
2140
2141//------------------------------------------------------------------------------
2156//------------------------------------------------------------------------------
2157 template<jit::float_scalar T, bool SAFE_MATH=false>
2159 const size_t n,
2161 const T x_scale,
2162 const T x_offset,
2164 const T y_scale,
2165 const T y_offset) {
2167 "index_2D requires a variable node for first arg.");
2168 auto temp = std::make_shared<index_2D_node<T, SAFE_MATH>> (v, n,
2169 x, x_scale, x_offset,
2170 y, y_scale, y_offset)->reduce();
2171// Test for hash collisions.
2172 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
2173 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
2174 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
2176 return temp;
2177 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
2178 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
2179 }
2180 }
2181#if defined(__clang__) || defined(__GNUC__)
2183#else
2184 assert(false && "Should never reach.");
2185#endif
2186 }
2187
2189 template<jit::float_scalar T, bool SAFE_MATH=false>
2190 using shared_index_2D = std::shared_ptr<index_2D_node<T, SAFE_MATH>>;
2191
2192//------------------------------------------------------------------------------
2200//------------------------------------------------------------------------------
2201 template<jit::float_scalar T, bool SAFE_MATH=false>
2203 return std::dynamic_pointer_cast<index_2D_node<T, SAFE_MATH>> (x);
2204 }
2205}
2206
2207#endif /* piecewise_h */
Class representing a generic buffer.
Definition backend.hpp:29
Class representing a branch node.
Definition node.hpp:1165
shared_leaf< T, SAFE_MATH > right
Right branch of the tree.
Definition node.hpp:1170
shared_leaf< T, SAFE_MATH > left
Left branch of the tree.
Definition node.hpp:1168
Class representing a 1D index.
Definition piecewise.hpp:1448
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:1663
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:1501
size_t get_size() const
Get the size of the buffer.
Definition piecewise.hpp:1709
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:1654
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, jit::register_map &indices, const jit::register_usage &usage)
the node.
Definition piecewise.hpp:1530
T get_scale() const
Get x argument scale.
Definition piecewise.hpp:1691
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:1673
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1585
T get_offset() const
Get x argument offset.
Definition piecewise.hpp:1700
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:1613
index_1D_node(shared_leaf< T, SAFE_MATH > var, shared_leaf< T, SAFE_MATH > x, const T scale, const T offset)
Construct a 1D index.
Definition piecewise.hpp:1483
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:1645
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:1511
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:1636
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:1599
Class representing a 2D index.
Definition piecewise.hpp:1788
size_t get_size() const
Get the size of the buffer.
Definition piecewise.hpp:2136
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:1879
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:2061
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:1869
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1988
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:2002
T get_x_offset() const
Get x argument offset.
Definition piecewise.hpp:2109
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, jit::register_map &indices, const jit::register_usage &usage)
the node.
Definition piecewise.hpp:1899
T get_y_scale() const
Get y argument scale.
Definition piecewise.hpp:2118
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:2070
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:2080
T get_x_scale() const
Get x argument scale.
Definition piecewise.hpp:2100
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:2018
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:2052
T get_y_offset() const
Get y argument offset.
Definition piecewise.hpp:2127
index_2D_node(shared_leaf< T, SAFE_MATH > var, const size_t n, shared_leaf< T, SAFE_MATH > x, const T x_scale, const T x_offset, shared_leaf< T, SAFE_MATH > y, const T y_scale, const T y_offset)
Construct a 2D index.
Definition piecewise.hpp:1842
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:2043
Class representing a node leaf.
Definition node.hpp:364
virtual void endline(std::ostringstream &stream, const jit::register_usage &usage) const final
End a line in the kernel source.
Definition node.hpp:639
virtual std::shared_ptr< leaf_node< T, SAFE_MATH > > compile(std::ostringstream &stream, jit::register_map &registers, jit::register_map &indices, const jit::register_usage &usage)=0
Compile the node.
Class representing a 1D piecewise constant.
Definition piecewise.hpp:105
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, int &avail_const_mem)
Compile preamble.
Definition piecewise.hpp:256
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:521
piecewise_1D_node(const backend::buffer< T > &d, shared_leaf< T, SAFE_MATH > x, const T scale, const T offset)
Construct 1D a piecewise constant node.
Definition piecewise.hpp:182
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:494
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:448
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:539
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduction method.
Definition piecewise.hpp:213
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:201
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:241
T get_scale() const
Get x argument scale.
Definition piecewise.hpp:563
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:462
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition piecewise.hpp:530
size_t get_size() const
Get the size of the buffer.
Definition piecewise.hpp:581
virtual bool has_constant_zero() const
Test the constant node has a zero.
Definition piecewise.hpp:503
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:473
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, jit::register_map &indices, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:349
T get_offset() const
Get x argument offset.
Definition piecewise.hpp:572
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:512
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:549
Class representing a 2D piecewise constant.
Definition piecewise.hpp:686
T get_y_scale() const
Get y argument scale.
Definition piecewise.hpp:843
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition piecewise.hpp:947
bool is_arg_match(shared_leaf< T, SAFE_MATH > x)
Check if the args match.
Definition piecewise.hpp:1323
T get_y_offset() const
Get y argument offset.
Definition piecewise.hpp:852
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition piecewise.hpp:1295
T get_x_scale() const
Get x argument scale.
Definition piecewise.hpp:825
virtual shared_leaf< T, SAFE_MATH > compile(std::ostringstream &stream, jit::register_map &registers, jit::register_map &indices, const jit::register_usage &usage)
Compile the node.
Definition piecewise.hpp:1072
size_t get_num_columns() const
Get the number of columns.
Definition piecewise.hpp:806
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition piecewise.hpp:1304
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition piecewise.hpp:1218
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition piecewise.hpp:1286
virtual bool is_constant() const
Test if node is a constant.
Definition piecewise.hpp:1268
size_t get_num_rows() const
Get the number of columns.
Definition piecewise.hpp:815
bool is_col_match(shared_leaf< T, SAFE_MATH > x)
Do the columns match.
Definition piecewise.hpp:1359
T get_x_offset() const
Get x argument offset.
Definition piecewise.hpp:834
virtual void to_latex() const
Convert the node to latex.
Definition piecewise.hpp:1234
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition piecewise.hpp:1245
bool is_row_match(shared_leaf< T, SAFE_MATH > x)
Do the rows match.
Definition piecewise.hpp:1342
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition piecewise.hpp:1313
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduction method.
Definition piecewise.hpp:877
piecewise_2D_node(const backend::buffer< T > &d, const size_t n, shared_leaf< T, SAFE_MATH > x, const T x_scale, const T x_offset, shared_leaf< T, SAFE_MATH > y, const T y_scale, const T y_offset)
Construct 2D a piecewise constant node.
Definition piecewise.hpp:782
virtual backend::buffer< T > evaluate()
Evaluate the results of the piecewise constant.
Definition piecewise.hpp:865
virtual bool has_constant_zero() const
Test the constant node has a zero.
Definition piecewise.hpp:1277
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, int &avail_const_mem)
Compile preamble.
Definition piecewise.hpp:962
Class representing a straight node.
Definition node.hpp:1051
shared_leaf< T, SAFE_MATH > arg
Argument.
Definition node.hpp:1054
Class representing a triple branch node.
Definition node.hpp:1289
shared_leaf< T, SAFE_MATH > middle
Middle branch of the tree.
Definition node.hpp:1292
Complex scalar concept.
Definition register.hpp:24
Double base concept.
Definition register.hpp:42
float base concept.
Definition register.hpp:37
subroutine assert(test, message)
Assert check.
Definition f_binding_test.f90:38
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:1428
constexpr shared_leaf< T, SAFE_MATH > zero()
Forward declare for zero.
Definition node.hpp:986
shared_index_2D< T, SAFE_MATH > index_2D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a index 2D node.
Definition piecewise.hpp:2202
std::shared_ptr< index_2D_node< T, SAFE_MATH > > shared_index_2D
Convenience type alias for shared index 2D nodes.
Definition piecewise.hpp:2190
shared_piecewise_1D< T, SAFE_MATH > piecewise_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a piecewise 1D node.
Definition piecewise.hpp:637
std::shared_ptr< piecewise_2D_node< T, SAFE_MATH > > shared_piecewise_2D
Convenience type alias for shared piecewise 2D nodes.
Definition piecewise.hpp:1416
shared_constant< T, SAFE_MATH > constant_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a constant node.
Definition node.hpp:1034
shared_variable< T, SAFE_MATH > variable_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a variable node.
Definition node.hpp:1727
std::shared_ptr< piecewise_1D_node< T, SAFE_MATH > > shared_piecewise_1D
Convenience type alias for shared piecewise 1D nodes.
Definition piecewise.hpp:625
constexpr T i
Convenience type for imaginary constant.
Definition node.hpp:1018
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:676
std::shared_ptr< index_1D_node< T, SAFE_MATH > > shared_index_1D
Convenience type alias for shared index 1D nodes.
Definition piecewise.hpp:1755
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
shared_index_1D< T, SAFE_MATH > index_1D_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a index 1D node.
Definition piecewise.hpp:1767
std::map< void *, size_t > texture1d_list
Type alias for indexing 1D textures.
Definition register.hpp:263
std::string format_to_string(const T value)
Convert a value to a string while avoiding locale.
Definition register.hpp:212
std::map< void *, std::array< size_t, 2 > > texture2d_list
Type alias for indexing 2D textures.
Definition register.hpp:265
std::map< void *, size_t > register_usage
Type alias for counting register usage.
Definition register.hpp:259
std::map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:257
constexpr bool use_cuda()
Test to use Cuda.
Definition register.hpp:67
std::set< void * > visiter_map
Type alias for listing visited nodes.
Definition register.hpp:261
std::string to_string(const char prefix, const NODE *pointer)
Convert a graph::leaf_node pointer to a string.
Definition register.hpp:246
Base nodes of graph computation framework.
void index_2D()
Tests for 2D index nodes.
Definition piecewise_test.cpp:868
void piecewise_1D()
Tests for 1D piecewise nodes.
Definition piecewise_test.cpp:80
void index_1D()
Tests for 1D index nodes.
Definition piecewise_test.cpp:834
void piecewise_2D()
Tests for 2D piecewise nodes.
Definition piecewise_test.cpp:319