Graph Framework
Loading...
Searching...
No Matches
math.hpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
4//------------------------------------------------------------------------------
5
6#ifndef math_h
7#define math_h
8
9#include <cmath>
10#include <numbers>
11
12#include "node.hpp"
13
14namespace graph {
15//******************************************************************************
16// Sqrt node.
17//******************************************************************************
18//------------------------------------------------------------------------------
25//------------------------------------------------------------------------------
26 template<jit::float_scalar T, bool SAFE_MATH=false>
27 class sqrt_node final : public straight_node<T, SAFE_MATH> {
28 private:
29//------------------------------------------------------------------------------
34//------------------------------------------------------------------------------
35 static std::string to_string(leaf_node<T, SAFE_MATH> *a) {
36 return "sqrt" + jit::format_to_string(reinterpret_cast<size_t> (a));
37 }
38
39 public:
40//------------------------------------------------------------------------------
44//------------------------------------------------------------------------------
47
48//------------------------------------------------------------------------------
54//------------------------------------------------------------------------------
56 backend::buffer<T> result = this->arg->evaluate();
57 result.sqrt();
58 return result;
59 }
60
61//------------------------------------------------------------------------------
65//------------------------------------------------------------------------------
67 auto ac = constant_cast(this->arg);
68
69 if (ac.get()) {
70 if (ac->is(0) || ac->is(1)) {
71 return this->arg;
72 }
73 return constant<T, SAFE_MATH> (this->evaluate());
74 }
75
76 auto ap1 = piecewise_1D_cast(this->arg);
77 if (ap1.get()) {
78 return piecewise_1D(this->evaluate(),
79 ap1->get_arg());
80 }
81
82 auto ap2 = piecewise_2D_cast(this->arg);
83 if (ap2.get()) {
84 return piecewise_2D(this->evaluate(),
85 ap2->get_num_columns(),
86 ap2->get_left(),
87 ap2->get_right());
88 }
89
90// Handle cases like sqrt(c*x) where c is constant or cases like sqrt((x^a)*y).
91// Note that we need to disable this reduction if C is a negative real or
92// a == 2.
93 auto am = multiply_cast(this->arg);
94 if (am.get()) {
95 if (am->get_left()->is_constant()) {
96 if constexpr (jit::complex_scalar<T>) {
97 return sqrt(am->get_left()) *
98 sqrt(am->get_right());
99 } else {
100 if (!am->get_left()->evaluate().is_negative()) {
101 return sqrt(am->get_left()) *
102 sqrt(am->get_right());
103 }
104 }
105 }
106
107 auto amlp = pow_cast(am->get_left());
108 auto amrp = pow_cast(am->get_right());
109 if (amlp.get()) {
110 auto amlprc = constant_cast(amlp->get_right());
111 if (amlprc.get() && !amlprc->is(2)) {
112 return sqrt(am->get_left()) *
113 sqrt(am->get_right());
114 }
115 } else if (amrp.get()) {
116 auto amrprc = constant_cast(amrp->get_right());
117 if (amrprc.get() && !amrprc->is(2)) {
118 return sqrt(am->get_left()) *
119 sqrt(am->get_right());
120 }
121 }
122 }
123
124 auto ad = divide_cast(this->arg);
125 if (ad.get()) {
126// sqrt((c1*x)/y) -> c2*sqrt(x/y)
127 auto alm = multiply_cast(ad->get_left());
128 if (alm.get() && alm->get_left()->is_constant()) {
129 return sqrt(alm->get_left()) *
130 sqrt(alm->get_right()/ad->get_right());
131 }
132
133// Handle cases like sqrt(x^a/b) and sqrt(a/x^b) or sqrt(c/b) and sqrt(a/c)
134// where c is a constant.
135 if (pow_cast(ad->get_left()).get() ||
136 ad->get_left()->is_constant() ||
137 pow_cast(ad->get_right()).get() ||
138 ad->get_right()->is_constant()) {
139 return sqrt(ad->get_left()) /
140 sqrt(ad->get_right());
141 }
142 }
143
144 return this->shared_from_this();
145 }
146
147//------------------------------------------------------------------------------
154//------------------------------------------------------------------------------
156 if (this->is_match(x)) {
157 return one<T, SAFE_MATH> ();
158 }
159
160 const size_t hash = reinterpret_cast<size_t> (x.get());
161 if (this->df_cache.find(hash) == this->df_cache.end()) {
162 this->df_cache[hash] = this->arg->df(x)
163 / (2.0*this->shared_from_this());
164 }
165 return this->df_cache[hash];
166 }
167
168//------------------------------------------------------------------------------
176//------------------------------------------------------------------------------
178 compile(std::ostringstream &stream,
179 jit::register_map &registers,
181 const jit::register_usage &usage) {
182 if (registers.find(this) == registers.end()) {
183 auto a = this->arg->compile(stream, registers,
185
186 registers[this] = jit::to_string('r', this);
187 stream << " const ";
188 jit::add_type<T> (stream);
189 stream << " " << registers[this] << " = sqrt("
190 << registers[a.get()] << ")";
191 this->endline(stream, usage);
192 }
193
194 return this->shared_from_this();
195 }
196
197//------------------------------------------------------------------------------
202//------------------------------------------------------------------------------
204 if (this == x.get()) {
205 return true;
206 }
207
208 auto x_cast = sqrt_cast(x);
209 if (x_cast.get()) {
210 return this->arg->is_match(x_cast->get_arg());
211 }
212
213 return false;
214 }
215
216//------------------------------------------------------------------------------
218//------------------------------------------------------------------------------
219 virtual void to_latex() const {
220 std::cout << "\\sqrt{";
221 this->arg->to_latex();
222 std::cout << "}";
223 }
224
225//------------------------------------------------------------------------------
229//------------------------------------------------------------------------------
230 virtual bool is_power_like() const {
231 return true;
232 }
233
234//------------------------------------------------------------------------------
238//------------------------------------------------------------------------------
240 return this->arg;
241 }
242
243//------------------------------------------------------------------------------
247//------------------------------------------------------------------------------
249 return constant<T, SAFE_MATH> (static_cast<T> (0.5));
250 }
251
252//------------------------------------------------------------------------------
256//------------------------------------------------------------------------------
258 if (this->has_pseudo()) {
259 return sqrt(this->arg->remove_pseudo());
260 }
261 return this->shared_from_this();
262 }
263
264//------------------------------------------------------------------------------
270//------------------------------------------------------------------------------
271 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
272 jit::register_map &registers) {
273 if (registers.find(this) == registers.end()) {
274 const std::string name = jit::to_string('r', this);
275 registers[this] = name;
276 stream << " " << name
277 << " [label = \"sqrt\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
278
279 auto a = this->arg->to_vizgraph(stream, registers);
280 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
281 }
282
283 return this->shared_from_this();
284 }
285 };
286
287//------------------------------------------------------------------------------
295//------------------------------------------------------------------------------
296 template<jit::float_scalar T, bool SAFE_MATH=false>
298 auto temp = std::make_shared<sqrt_node<T, SAFE_MATH>> (x)->reduce();
299// Test for hash collisions.
300 for (size_t i = temp->get_hash();
302 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
305 return temp;
306 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
308 }
309 }
310#if defined(__clang__) || defined(__GNUC__)
312#else
313 assert(false && "Should never reach.");
314#endif
315 }
316
318 template<jit::float_scalar T, bool SAFE_MATH=false>
319 using shared_sqrt = std::shared_ptr<sqrt_node<T, SAFE_MATH>>;
320
321//------------------------------------------------------------------------------
329//------------------------------------------------------------------------------
330 template<jit::float_scalar T, bool SAFE_MATH=false>
332 return std::dynamic_pointer_cast<sqrt_node<T, SAFE_MATH>> (x);
333 }
334
335//******************************************************************************
336// Exp node.
337//******************************************************************************
338//------------------------------------------------------------------------------
345//------------------------------------------------------------------------------
346 template<jit::float_scalar T, bool SAFE_MATH=false>
347 class exp_node final : public straight_node<T, SAFE_MATH> {
348 private:
349//------------------------------------------------------------------------------
354//------------------------------------------------------------------------------
355 static std::string to_string(leaf_node<T, SAFE_MATH> *a) {
356 return "exp" + jit::format_to_string(reinterpret_cast<size_t> (a));
357 }
358
359 public:
360//------------------------------------------------------------------------------
364//------------------------------------------------------------------------------
367
368//------------------------------------------------------------------------------
374//------------------------------------------------------------------------------
376 backend::buffer<T> result = this->arg->evaluate();
377 result.exp();
378 return result;
379 }
380
381//------------------------------------------------------------------------------
385//------------------------------------------------------------------------------
387 if (constant_cast(this->arg).get()) {
388 return constant<T, SAFE_MATH> (this->evaluate());
389 }
390
391 auto ap1 = piecewise_1D_cast(this->arg);
392 if (ap1.get()) {
393 return piecewise_1D(this->evaluate(),
394 ap1->get_arg());
395 }
396
397 auto ap2 = piecewise_2D_cast(this->arg);
398 if (ap2.get()) {
399 return piecewise_2D(this->evaluate(),
400 ap2->get_num_columns(),
401 ap2->get_left(),
402 ap2->get_right());
403 }
404
405// Reduce exp(log(x)) -> x
406 auto a = log_cast(this->arg);
407 if (a.get()) {
408 return a->get_arg();
409 }
410
411 return this->shared_from_this();
412 }
413
414//------------------------------------------------------------------------------
421//------------------------------------------------------------------------------
423 if (this->is_match(x)) {
424 return one<T, SAFE_MATH> ();
425 }
426
427 const size_t hash = reinterpret_cast<size_t> (x.get());
428 if (this->df_cache.find(hash) == this->df_cache.end()) {
429 this->df_cache[hash] = this->shared_from_this()*this->arg->df(x);
430 }
431 return this->df_cache[hash];
432 }
433
434//------------------------------------------------------------------------------
442//------------------------------------------------------------------------------
444 compile(std::ostringstream &stream,
445 jit::register_map &registers,
447 const jit::register_usage &usage) {
448 if (registers.find(this) == registers.end()) {
449 auto a = this->arg->compile(stream, registers,
451
452 registers[this] = jit::to_string('r', this);
453 stream << " const ";
454 jit::add_type<T> (stream);
455 stream << " " << registers[this] << " = ";
456 if constexpr (SAFE_MATH) {
457 if constexpr (jit::complex_scalar<T>) {
458 stream << "real(";
459 }
460 stream << registers[a.get()];
461 if constexpr (jit::complex_scalar<T>) {
462 stream << ")";
463 }
464 stream << " < 709.8 ? ";
465 }
466 stream << "exp(" << registers[a.get()] << ")";
467 if constexpr (SAFE_MATH) {
468 stream << " : ";
469 if constexpr (jit::complex_scalar<T>) {
470 jit::add_type<T> (stream);
471 stream << "(";
472 }
474 if constexpr (jit::complex_scalar<T>) {
475 stream << ")";
476 }
477 }
478 stream << "";
479 this->endline(stream, usage);
480 }
481
482 return this->shared_from_this();
483 }
484
485//------------------------------------------------------------------------------
490//------------------------------------------------------------------------------
492 if (this == x.get()) {
493 return true;
494 }
495
496 auto x_cast = exp_cast(x);
497 if (x_cast.get()) {
498 return this->arg->is_match(x_cast->get_arg());
499 }
500
501 return false;
502 }
503
504//------------------------------------------------------------------------------
506//------------------------------------------------------------------------------
507 virtual void to_latex() const {
508 std::cout << "e^{\\left(";
509 this->arg->to_latex();
510 std::cout << "\\right)}";
511 }
512
513//------------------------------------------------------------------------------
517//------------------------------------------------------------------------------
519 if (this->has_pseudo()) {
520 return exp(this->arg->remove_pseudo());
521 }
522 return this->shared_from_this();
523 }
524
525//------------------------------------------------------------------------------
531//------------------------------------------------------------------------------
532 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
533 jit::register_map &registers) {
534 if (registers.find(this) == registers.end()) {
535 const std::string name = jit::to_string('r', this);
536 registers[this] = name;
537 stream << " " << name
538 << " [label = \"exp\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
539
540 auto a = this->arg->to_vizgraph(stream, registers);
541 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
542 }
543
544 return this->shared_from_this();
545 }
546 };
547
548//------------------------------------------------------------------------------
556//------------------------------------------------------------------------------
557 template<jit::float_scalar T, bool SAFE_MATH=false>
559 auto temp = std::make_shared<exp_node<T, SAFE_MATH>> (x)->reduce();
560// Test for hash collisions.
561 for (size_t i = temp->get_hash();
563 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
566 return temp;
567 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
569 }
570 }
571#if defined(__clang__) || defined(__GNUC__)
573#else
574 assert(false && "Should never reach.");
575#endif
576 }
577
579 template<jit::float_scalar T, bool SAFE_MATH=false>
580 using shared_exp = std::shared_ptr<exp_node<T, SAFE_MATH>>;
581
582//------------------------------------------------------------------------------
590//------------------------------------------------------------------------------
591 template<jit::float_scalar T, bool SAFE_MATH=false>
593 return std::dynamic_pointer_cast<exp_node<T, SAFE_MATH>> (x);
594 }
595
596//******************************************************************************
597// Log node.
598//******************************************************************************
599//------------------------------------------------------------------------------
606//------------------------------------------------------------------------------
607 template<jit::float_scalar T, bool SAFE_MATH=false>
608 class log_node final : public straight_node<T, SAFE_MATH> {
609 private:
610//------------------------------------------------------------------------------
615//------------------------------------------------------------------------------
616 static std::string to_string(leaf_node<T, SAFE_MATH> *a) {
617 return "log" + jit::format_to_string(reinterpret_cast<size_t> (a));
618 }
619
620 public:
621//------------------------------------------------------------------------------
625//------------------------------------------------------------------------------
628
629//------------------------------------------------------------------------------
635//------------------------------------------------------------------------------
637 backend::buffer<T> result = this->arg->evaluate();
638 result.log();
639 return result;
640 }
641
642//------------------------------------------------------------------------------
646//------------------------------------------------------------------------------
648 if (constant_cast(this->arg).get()) {
649 return constant<T, SAFE_MATH> (this->evaluate());
650 }
651
652 auto ap1 = piecewise_1D_cast(this->arg);
653 if (ap1.get()) {
654 return piecewise_1D(this->evaluate(),
655 ap1->get_arg());
656 }
657
658 auto ap2 = piecewise_2D_cast(this->arg);
659 if (ap2.get()) {
660 return piecewise_2D(this->evaluate(),
661 ap2->get_num_columns(),
662 ap2->get_left(),
663 ap2->get_right());
664 }
665
666// Reduce log(exp(x)) -> x
667 auto a = exp_cast(this->arg);
668 if (a.get()) {
669 return a->get_arg();
670 }
671
672 return this->shared_from_this();
673 }
674
675//------------------------------------------------------------------------------
682//------------------------------------------------------------------------------
684 if (this->is_match(x)) {
685 return one<T, SAFE_MATH> ();
686 }
687
688 const size_t hash = reinterpret_cast<size_t> (x.get());
689 if (this->df_cache.find(hash) == this->df_cache.end()) {
690 this->df_cache[hash] = this->arg->df(x)/this->arg;
691 }
692 return this->df_cache[hash];
693 }
694
695//------------------------------------------------------------------------------
703//------------------------------------------------------------------------------
705 compile(std::ostringstream &stream,
706 jit::register_map &registers,
708 const jit::register_usage &usage) {
709 if (registers.find(this) == registers.end()) {
710 auto a = this->arg->compile(stream, registers,
712
713 registers[this] = jit::to_string('r', this);
714 stream << " const ";
715 jit::add_type<T> (stream);
716 stream << " " << registers[this] << " = log("
717 << registers[a.get()] << ")";
718 this->endline(stream, usage);
719 }
720
721 return this->shared_from_this();
722 }
723
724//------------------------------------------------------------------------------
729//------------------------------------------------------------------------------
731 if (this == x.get()) {
732 return true;
733 }
734
735 auto x_cast = log_cast(x);
736 if (x_cast.get()) {
737 return this->arg->is_match(x_cast->get_arg());
738 }
739
740 return false;
741 }
742
743//------------------------------------------------------------------------------
745//------------------------------------------------------------------------------
746 virtual void to_latex() const {
747 std::cout << "\\ln{\\left(";
748 this->arg->to_latex();
749 std::cout << "\\right)}";
750 }
751
752//------------------------------------------------------------------------------
756//------------------------------------------------------------------------------
758 if (this->has_pseudo()) {
759 return log(this->arg->remove_pseudo());
760 }
761 return this->shared_from_this();
762 }
763
764//------------------------------------------------------------------------------
770//------------------------------------------------------------------------------
771 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
772 jit::register_map &registers) {
773 if (registers.find(this) == registers.end()) {
774 const std::string name = jit::to_string('r', this);
775 registers[this] = name;
776 stream << " " << name
777 << " [label = \"log\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
778
779 auto a = this->arg->to_vizgraph(stream, registers);
780 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
781 }
782
783 return this->shared_from_this();
784 }
785 };
786
787//------------------------------------------------------------------------------
795//------------------------------------------------------------------------------
796 template<jit::float_scalar T, bool SAFE_MATH=false>
798 auto temp = std::make_shared<log_node<T, SAFE_MATH>> (x)->reduce();
799// Test for hash collisions.
800 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
801 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
804 return temp;
805 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
807 }
808 }
809#if defined(__clang__) || defined(__GNUC__)
811#else
812 assert(false && "Should never reach.");
813#endif
814 }
815
817 template<jit::float_scalar T, bool SAFE_MATH=false>
818 using shared_log = std::shared_ptr<log_node<T, SAFE_MATH>>;
819
820//------------------------------------------------------------------------------
828//------------------------------------------------------------------------------
829 template<jit::float_scalar T, bool SAFE_MATH=false>
831 return std::dynamic_pointer_cast<log_node<T, SAFE_MATH>> (x);
832 }
833
834//******************************************************************************
835// Pow node.
836//******************************************************************************
837//------------------------------------------------------------------------------
844//------------------------------------------------------------------------------
845 template<jit::float_scalar T, bool SAFE_MATH=false>
846 class pow_node final : public branch_node<T, SAFE_MATH> {
847 private:
848//------------------------------------------------------------------------------
854//------------------------------------------------------------------------------
855 static std::string to_string(leaf_node<T, SAFE_MATH> *l,
857 return "pow" + jit::format_to_string(reinterpret_cast<size_t> (l))
858 + jit::format_to_string(reinterpret_cast<size_t> (r));
859 }
860
861 public:
862//------------------------------------------------------------------------------
867//------------------------------------------------------------------------------
872
873//------------------------------------------------------------------------------
879//------------------------------------------------------------------------------
881 backend::buffer<T> l_result = this->left->evaluate();
882 backend::buffer<T> r_result = this->right->evaluate();
883 return backend::pow(l_result, r_result);
884 }
885
886//------------------------------------------------------------------------------
890//------------------------------------------------------------------------------
892 auto lc = constant_cast(this->left);
893 auto rc = constant_cast(this->right);
894
895 if (rc.get() && rc->is(0)) {
896 return one<T, SAFE_MATH> ();
897 } else if (rc.get() && rc->is(1)) {
898 return this->left;
899 } else if (rc.get() && rc->is(0.5)) {
900 return sqrt(this->left);
901 } else if (rc.get() && rc->is(2)){
902 auto sq = sqrt_cast(this->left);
903 if (sq.get()) {
904 return sq->get_arg();
905 }
906 }
907
908 if (lc.get() && rc.get()) {
909 return constant<T, SAFE_MATH> (this->evaluate());
910 }
911
912 auto pl1 = piecewise_1D_cast(this->left);
913 auto pr1 = piecewise_1D_cast(this->right);
914 if (pl1.get() && (rc.get() || pl1->is_arg_match(this->right))) {
915 return piecewise_1D(this->evaluate(), pl1->get_arg());
916 } else if (pr1.get() && (lc.get() || pr1->is_arg_match(this->left))) {
917 return piecewise_1D(this->evaluate(), pr1->get_arg());
918 }
919
920 auto pl2 = piecewise_2D_cast(this->left);
921 auto pr2 = piecewise_2D_cast(this->right);
922 if (pl2.get() && (rc.get() || pl2->is_arg_match(this->right))) {
923 return piecewise_2D(this->evaluate(),
924 pl2->get_num_columns(),
925 pl2->get_left(),
926 pl2->get_right());
927 } else if (pr2.get() && (lc.get() || pr2->is_arg_match(this->left))) {
928 return piecewise_2D(this->evaluate(),
929 pr2->get_num_columns(),
930 pr2->get_left(),
931 pr2->get_right());
932 }
933
934// Combine 2D and 1D piecewise constants if a row or column matches.
935 if (pr2.get() && pr2->is_row_match(this->left)) {
936 backend::buffer<T> result = pl1->evaluate();
937 result.pow_row(pr2->evaluate());
938 return piecewise_2D(result,
939 pr2->get_num_columns(),
940 pr2->get_left(),
941 pr2->get_right());
942 } else if (pr2.get() && pr2->is_col_match(this->left)) {
943 backend::buffer<T> result = pl1->evaluate();
944 result.pow_col(pr2->evaluate());
945 return piecewise_2D(result,
946 pr2->get_num_columns(),
947 pr2->get_left(),
948 pr2->get_right());
949 } else if (pl2.get() && pl2->is_row_match(this->right)) {
950 backend::buffer<T> result = pl2->evaluate();
951 result.pow_row(pr1->evaluate());
952 return piecewise_2D(result,
953 pl2->get_num_columns(),
954 pl2->get_left(),
955 pl2->get_right());
956 } else if (pl2.get() && pl2->is_col_match(this->right)) {
957 backend::buffer<T> result = pl2->evaluate();
958 result.pow_col(pr1->evaluate());
959 return piecewise_2D(result,
960 pl2->get_num_columns(),
961 pl2->get_left(),
962 pl2->get_right());
963 }
964
965 auto lp = pow_cast(this->left);
966// Only run this reduction if the right is an integer constant value.
967 if (lp.get() && rc.get() && rc->is_integer()) {
968 return pow(lp->get_left(), lp->get_right()*this->right);
969 }
970
971// Handle cases where (c*x)^a, (x*c)^a, (a*sqrt(b))^c and (a*b^c)^2.
972// These reductions only make sense if the power is constant.
973 auto lm = multiply_cast(this->left);
974 if (lm.get() && rc.get()) {
975 if (lm->get_left()->is_constant() ||
976 lm->get_right()->is_constant() ||
977 sqrt_cast(lm->get_left()).get() ||
978 sqrt_cast(lm->get_right()).get() ||
979 pow_cast(lm->get_left()).get() ||
980 pow_cast(lm->get_right()).get()) {
981 return pow(lm->get_left(), this->right) *
982 pow(lm->get_right(), this->right);
983 }
984
985// ((Sqrt(a)*b)*c)^d -> a^(d/2)*(b*c)^d
986// ((b*Sqrt(a))*c)^d -> a^(d/2)*(b*c)^d
987 auto lmlm = multiply_cast(lm->get_left());
988 if (lmlm.get()) {
989 if (lmlm->get_left()->is_constant() ||
990 lmlm->get_right()->is_constant() ||
991 sqrt_cast(lmlm->get_left()).get() ||
992 sqrt_cast(lmlm->get_right()).get() ||
993 pow_cast(lmlm->get_left()).get() ||
994 pow_cast(lmlm->get_right()).get()) {
995 return pow(lmlm->get_left(), this->right) *
996 pow(lmlm->get_right(), this->right) *
997 pow(lm->get_right(), this->right);
998 }
999 }
1000 }
1001
1002// These reductions only make sense if the power is constant.
1003 auto ld = divide_cast(this->left);
1004 if (ld.get() && rc.get()) {
1005// For even exponents e.
1006// (-a/b)^e -> (a/b)^e
1007 auto ldlm = multiply_cast(ld->get_left());
1008 if (ldlm.get()) {
1009 if (rc.get() &&
1010 rc->evaluate().is_even()) {
1011 if (ldlm->get_left()->is_constant()) {
1012 return pow(ldlm->get_left(), this->right) *
1013 pow(ldlm->get_right()/ld->get_right(),
1014 this->right);
1015 }
1016 }
1017 if (ldlm->get_left()->is_constant() ||
1018 ldlm->get_right()->is_constant() ||
1019 sqrt_cast(ldlm->get_left()).get() ||
1020 sqrt_cast(ldlm->get_right()).get() ||
1021 pow_cast(ldlm->get_left()).get() ||
1022 pow_cast(ldlm->get_right()).get()) {
1023 return pow(ldlm->get_left(), this->right) *
1024 pow(ldlm->get_right(), this->right)/
1025 pow(ld->get_right(), this->right);
1026 }
1027
1028 auto ldlmlm = multiply_cast(ldlm->get_left());
1029 if (ldlmlm.get()) {
1030 if (ldlmlm->get_left()->is_constant() ||
1031 ldlmlm->get_right()->is_constant() ||
1032 sqrt_cast(ldlmlm->get_left()).get() ||
1033 sqrt_cast(ldlmlm->get_right()).get() ||
1034 pow_cast(ldlmlm->get_left()).get() ||
1035 pow_cast(ldlmlm->get_right()).get()) {
1036 return (pow(ldlmlm->get_left(), this->right) *
1037 pow(ldlmlm->get_right(), this->right) *
1038 pow(ldlm->get_right(), this->right)) /
1039 pow(ld->get_right(), this->right);
1040 }
1041 }
1042
1043 auto ldlmrm = multiply_cast(ldlm->get_right());
1044 if (ldlmrm.get()) {
1045 if (ldlmrm->get_left()->is_constant() ||
1046 ldlmrm->get_right()->is_constant() ||
1047 sqrt_cast(ldlmrm->get_left()).get() ||
1048 sqrt_cast(ldlmrm->get_right()).get() ||
1049 pow_cast(ldlmrm->get_left()).get() ||
1050 pow_cast(ldlmrm->get_right()).get()) {
1051 return (pow(ldlmrm->get_left(), this->right) *
1052 pow(ldlmrm->get_right(), this->right) *
1053 pow(ldlm->get_left(), this->right)) /
1054 pow(ld->get_right(), this->right);
1055 }
1056 }
1057 }
1058
1059// Handle cases where (c/x)^a, (x/c)^a, (a/sqrt(b))^c and (a/b^c)^2.
1060 if (ld->get_left()->is_constant() ||
1061 ld->get_right()->is_constant() ||
1062 sqrt_cast(ld->get_left()).get() ||
1063 sqrt_cast(ld->get_right()).get() ||
1064 pow_cast(ld->get_left()).get() ||
1065 pow_cast(ld->get_right()).get()) {
1066 return pow(ld->get_left(), this->right) /
1067 pow(ld->get_right(), this->right);
1068 }
1069
1070// Handle cases where (a/(b*sqrt(c))), (a/(sqrt(c)*b)), (a/(b*c^d)), (a/(c^d*b))
1071 auto ldrm = multiply_cast(ld->get_right());
1072 if (ldrm.get()) {
1073 if (ldrm->get_left()->is_constant() ||
1074 ldrm->get_right()->is_constant() ||
1075 sqrt_cast(ldrm->get_left()).get() ||
1076 sqrt_cast(ldrm->get_right()).get() ||
1077 pow_cast(ldrm->get_left()).get() ||
1078 pow_cast(ldrm->get_right()).get()) {
1079 return pow(ld->get_left(), this->right) /
1080 (pow(ldrm->get_left(), this->right) *
1081 pow(ldrm->get_right(), this->right));
1082 }
1083
1084 auto ldrmlm = multiply_cast(ldrm->get_left());
1085 if (ldrmlm.get()) {
1086 if (ldrmlm->get_left()->is_constant() ||
1087 ldrmlm->get_right()->is_constant() ||
1088 sqrt_cast(ldrmlm->get_left()).get() ||
1089 sqrt_cast(ldrmlm->get_right()).get() ||
1090 pow_cast(ldrmlm->get_left()).get() ||
1091 pow_cast(ldrmlm->get_right()).get()) {
1092 return pow(ld->get_left(), this->right) /
1093 (pow(ldrmlm->get_left(), this->right) *
1094 pow(ldrmlm->get_right(), this->right) *
1095 pow(ldrm->get_right(), this->right));
1096 }
1097 }
1098
1099 auto ldrmrm = multiply_cast(ldrm->get_right());
1100 if (ldrmrm.get()) {
1101 if (ldrmrm->get_left()->is_constant() ||
1102 ldrmrm->get_right()->is_constant() ||
1103 sqrt_cast(ldrmrm->get_left()).get() ||
1104 sqrt_cast(ldrmrm->get_right()).get() ||
1105 pow_cast(ldrmrm->get_left()).get() ||
1106 pow_cast(ldrmrm->get_right()).get()) {
1107 return pow(ld->get_left(), this->right) /
1108 (pow(ldrmrm->get_left(), this->right) *
1109 pow(ldrmrm->get_right(), this->right) *
1110 pow(ldrm->get_left(), this->right));
1111 }
1112 }
1113 }
1114
1115 if (is_variable_combinable(ld->get_left(),
1116 ld->get_right())) {
1117 return pow(ld->get_left()->get_power_base(),
1118 this->right*(ld->get_left()->get_power_exponent() -
1119 ld->get_right()->get_power_exponent()));
1120 }
1121
1122 if (ldrm.get()) {
1123 auto ldrmlm = multiply_cast(ldrm->get_left());
1124 if (ldrmlm.get()) {
1125 if (is_variable_combinable(ldrm->get_right(),
1126 ldrmlm->get_right()->get_power_base())) {
1127 return pow(ld->get_left()/ldrmlm->get_left(),
1128 this->right) /
1129 pow(ldrm->get_right()*ldrmlm->get_right(),
1130 this->right);
1131 } else if (is_variable_combinable(ldrm->get_right(),
1132 ldrmlm->get_left()->get_power_base())) {
1133 return pow(ld->get_left()/ldrmlm->get_right(),
1134 this->right) /
1135 pow(ldrm->get_right()*ldrmlm->get_left(),
1136 this->right);
1137 } else if (is_variable_combinable(ldrmlm->get_left(),
1138 ldrmlm->get_right()->get_power_base()) ||
1139 is_variable_combinable(ldrmlm->get_right(),
1140 ldrmlm->get_left()->get_power_base())) {
1141 return pow(ld->get_left()/ldrm->get_right(),
1142 this->right) /
1143 pow(ldrmlm->get_left()*ldrmlm->get_right(),
1144 this->right);
1145 }
1146 }
1147 }
1148 }
1149
1150// Reduce sqrt(a)^b
1151 auto lsq = sqrt_cast(this->left);
1152 if (lsq.get()) {
1153 return pow(lsq->get_arg(),
1154 this->right/2.0);
1155 }
1156
1157// Reduce exp(x)^n -> exp(n*x) when x is an integer.
1158 auto temp = exp_cast(this->left);
1159 if (temp.get() && rc.get() && rc->is_integer()) {
1160 return exp(this->right*temp->get_arg());
1161 }
1162
1163 if constexpr (std::floating_point<T>) {
1164// hypot(a,b)^2 -> a^2 + b^2
1165 auto lhp = hypot_cast(this->left);
1166 if (lhp.get() && rc.get() && rc->is(2)) {
1167 return pow(lhp->get_left(), this->right) +
1168 pow(lhp->get_right(), this->right);
1169 }
1170
1171// (a/hypot(b,c))^2 -> a^2/(b^2 + c^2)
1172// (hypot(b,c)/a)^2 -> (b^2 + c^2)/a^2
1173 if (ld.get() && rc.get() && rc->is(2)) {
1174 auto ldlhp = hypot_cast(ld->get_left());
1175 auto ldrhp = hypot_cast(ld->get_right());
1176 if (ldlhp.get()) {
1177 return (pow(ldlhp->get_left(), static_cast<T> (2)) +
1178 pow(ldlhp->get_right(), static_cast<T> (2))) /
1179 pow(ld->get_right(), static_cast<T> (2));
1180 } else if (ldrhp.get()) {
1181 return pow(ld->get_left(), static_cast<T> (2)) /
1182 (pow(ldrhp->get_left(), static_cast<T> (2)) +
1183 pow(ldrhp->get_right(), static_cast<T> (2)));
1184 }
1185 }
1186 }
1187
1188 return this->shared_from_this();
1189 }
1190
1191//------------------------------------------------------------------------------
1198//------------------------------------------------------------------------------
1201 if (this->is_match(x)) {
1202 return one<T, SAFE_MATH> ();
1203 }
1204
1205 const size_t hash = reinterpret_cast<size_t> (x.get());
1206 if (this->df_cache.find(hash) == this->df_cache.end()) {
1207 this->df_cache[hash] = pow(this->left, this->right - 1.0)
1208 * (this->right*this->left->df(x) +
1209 this->left*log(this->left)*this->right->df(x));
1210 }
1211 return this->df_cache[hash];
1212 }
1213
1214//------------------------------------------------------------------------------
1222//------------------------------------------------------------------------------
1224 compile(std::ostringstream &stream,
1225 jit::register_map &registers,
1227 const jit::register_usage &usage) {
1228 if (registers.find(this) == registers.end()) {
1229 auto l = this->left->compile(stream, registers,
1230 thread_mem, usage);
1232 auto temp = constant_cast(this->right);
1233 if (!temp.get() || !temp->is_integer()) {
1234 r = this->right->compile(stream, registers,
1235 thread_mem, usage);
1236 }
1237
1238 registers[this] = jit::to_string('r', this);
1239 stream << " const ";
1240 jit::add_type<T> (stream);
1241 stream << " " << registers[this] << " = ";
1242 if (temp.get() && temp->is_integer()) {
1243 stream << registers[l.get()];
1244 const size_t end = static_cast<size_t> (std::real(this->right->evaluate().at(0)));
1245 for (size_t i = 1; i < end; i++) {
1246 stream << "*" << registers[l.get()];
1247 }
1248 } else {
1249 stream << "pow("
1250 << registers[l.get()] << ", "
1251 << registers[r.get()] << ")";
1252 }
1253 this->endline(stream, usage);
1254 }
1255
1256 return this->shared_from_this();
1257 }
1258
1259//------------------------------------------------------------------------------
1264//------------------------------------------------------------------------------
1266 if (this == x.get()) {
1267 return true;
1268 }
1269
1270 auto x_cast = pow_cast(x);
1271 if (x_cast.get()) {
1272 return this->left->is_match(x_cast->get_left()) &&
1273 this->right->is_match(x_cast->get_right());
1274 }
1275
1276 return false;
1277 }
1278
1279//------------------------------------------------------------------------------
1281//------------------------------------------------------------------------------
1282 virtual void to_latex() const {
1283 auto use_brackets = !constant_cast(this->left).get() &&
1284 !variable_cast(this->left).get();
1285
1286 if (use_brackets) {
1287 std::cout << "\\left(";
1288 }
1289 this->left->to_latex();
1290 if (use_brackets) {
1291 std::cout << "\\right)";
1292 }
1293 std::cout << "^{";
1294 this->right->to_latex();
1295 std::cout << "}";
1296 }
1297
1298//------------------------------------------------------------------------------
1304//------------------------------------------------------------------------------
1305 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1306 jit::register_map &registers) {
1307 if (registers.find(this) == registers.end()) {
1308 const std::string name = jit::to_string('r', this);
1309 registers[this] = name;
1310 stream << " " << name
1311 << " [label = \"pow\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
1312
1313 auto l = this->left->to_vizgraph(stream, registers);
1314 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
1315 auto r = this->right->to_vizgraph(stream, registers);
1316 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
1317 }
1318
1319 return this->shared_from_this();
1320 }
1321
1322//------------------------------------------------------------------------------
1326//------------------------------------------------------------------------------
1327 virtual bool is_all_variables() const {
1328 return this->left->is_all_variables() &&
1329 (this->right->is_all_variables() ||
1330 constant_cast(this->right).get());
1331 }
1332
1333//------------------------------------------------------------------------------
1337//------------------------------------------------------------------------------
1338 virtual bool is_power_like() const {
1339 return true;
1340 }
1341
1342//------------------------------------------------------------------------------
1346//------------------------------------------------------------------------------
1348 return this->left;
1349 }
1350
1351//------------------------------------------------------------------------------
1355//------------------------------------------------------------------------------
1357 return this->right;
1358 }
1359
1360//------------------------------------------------------------------------------
1364//------------------------------------------------------------------------------
1366 if (this->has_pseudo()) {
1367 return pow(this->left->remove_pseudo(),
1368 this->right->remove_pseudo());
1369 }
1370 return this->shared_from_this();
1371 }
1372 };
1373
1374//------------------------------------------------------------------------------
1382//------------------------------------------------------------------------------
1383 template<jit::float_scalar T, bool SAFE_MATH=false>
1386 auto temp = std::make_shared<pow_node<T, SAFE_MATH>> (l, r)->reduce();
1387// Test for hash collisions.
1388 for (size_t i = temp->get_hash();
1390 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1391 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1393 return temp;
1394 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1395 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1396 }
1397 }
1398#if defined(__clang__) || defined(__GNUC__)
1400#else
1401 assert(false && "Should never reach.");
1402#endif
1403 }
1404
1405//------------------------------------------------------------------------------
1414//------------------------------------------------------------------------------
1415 template<jit::float_scalar T, jit::float_scalar L, bool SAFE_MATH=false>
1418 return pow(constant<T, SAFE_MATH> (static_cast<T> (l)), r);
1419 }
1420
1421//------------------------------------------------------------------------------
1430//------------------------------------------------------------------------------
1431 template<jit::float_scalar T, jit::float_scalar R, bool SAFE_MATH=false>
1433 const R r) {
1434 return pow(l, constant<T, SAFE_MATH> (static_cast<T> (r)));
1435 }
1436
1438 template<jit::float_scalar T, bool SAFE_MATH=false>
1439 using shared_pow = std::shared_ptr<pow_node<T, SAFE_MATH>>;
1440
1441//------------------------------------------------------------------------------
1446//------------------------------------------------------------------------------
1447 template<jit::float_scalar T, bool SAFE_MATH=false>
1449 return std::dynamic_pointer_cast<pow_node<T, SAFE_MATH>> (x);
1450 }
1451
1452//******************************************************************************
1453// Erf node.
1454//******************************************************************************
1455//------------------------------------------------------------------------------
1462//------------------------------------------------------------------------------
1463 template<std::floating_point T, bool SAFE_MATH=false>
1464 class erf_node final : public straight_node<T, SAFE_MATH> {
1465 private:
1466//------------------------------------------------------------------------------
1471//------------------------------------------------------------------------------
1472 static std::string to_string(leaf_node<T, SAFE_MATH> *a) {
1473 return "erf" + jit::format_to_string(reinterpret_cast<size_t> (a));
1474 }
1475
1476 public:
1477//------------------------------------------------------------------------------
1481//------------------------------------------------------------------------------
1484
1485//------------------------------------------------------------------------------
1491//------------------------------------------------------------------------------
1493 backend::buffer<T> result = this->arg->evaluate();
1494 result.erf();
1495 return result;
1496 }
1497
1498//------------------------------------------------------------------------------
1502//------------------------------------------------------------------------------
1504 if (constant_cast(this->arg).get()) {
1505 return constant<T, SAFE_MATH> (this->evaluate());
1506 }
1507
1508 auto ap1 = piecewise_1D_cast(this->arg);
1509 if (ap1.get()) {
1510 return piecewise_1D(this->evaluate(),
1511 ap1->get_arg());
1512 }
1513
1514 auto ap2 = piecewise_2D_cast(this->arg);
1515 if (ap2.get()) {
1516 return piecewise_2D(this->evaluate(),
1517 ap2->get_num_columns(),
1518 ap2->get_left(),
1519 ap2->get_right());
1520 }
1521
1522 return this->shared_from_this();
1523 }
1524
1525//------------------------------------------------------------------------------
1532//------------------------------------------------------------------------------
1534 if (this->is_match(x)) {
1535 return one<T, SAFE_MATH> ();
1536 }
1537
1538 const size_t hash = reinterpret_cast<size_t> (x.get());
1539 if (this->df_cache.find(hash) == this->df_cache.end()) {
1540 this->df_cache[hash] = static_cast<T> (2)
1541 * std::numbers::inv_sqrtpi_v<T>
1542 * exp(this->arg*this->arg)*this->arg->df(x);
1543 }
1544 return this->df_cache[hash];
1545 }
1546
1547//------------------------------------------------------------------------------
1555//------------------------------------------------------------------------------
1557 compile(std::ostringstream &stream,
1558 jit::register_map &registers,
1560 const jit::register_usage &usage) {
1561 if (registers.find(this) == registers.end()) {
1562 auto a = this->arg->compile(stream, registers,
1563 thread_mem, usage);
1564
1565 registers[this] = jit::to_string('r', this);
1566 stream << " const ";
1567 jit::add_type<T> (stream);
1568 stream << " " << registers[this] << " = erf("
1569 << registers[a.get()] << ")";
1570 this->endline(stream, usage);
1571 }
1572
1573 return this->shared_from_this();
1574 }
1575
1576//------------------------------------------------------------------------------
1581//------------------------------------------------------------------------------
1583 if (this == x.get()) {
1584 return true;
1585 }
1586
1587 auto x_cast = erf_cast(x);
1588 if (x_cast.get()) {
1589 return this->arg->is_match(x_cast->get_arg());
1590 }
1591
1592 return false;
1593 }
1594
1595//------------------------------------------------------------------------------
1597//------------------------------------------------------------------------------
1598 virtual void to_latex() const {
1599 std::cout << "erf\\left(";
1600 this->arg->to_latex();
1601 std::cout << "\\right)";
1602 }
1603
1604//------------------------------------------------------------------------------
1608//------------------------------------------------------------------------------
1610 if (this->has_pseudo()) {
1611 return erf(this->arg->remove_pseudo());
1612 }
1613 return this->shared_from_this();
1614 }
1615
1616//------------------------------------------------------------------------------
1622//------------------------------------------------------------------------------
1623 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1624 jit::register_map &registers) {
1625 if (registers.find(this) == registers.end()) {
1626 const std::string name = jit::to_string('r', this);
1627 registers[this] = name;
1628 stream << " " << name
1629 << " [label = \"erf\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
1630
1631 auto a = this->arg->to_vizgraph(stream, registers);
1632 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
1633 }
1634
1635 return this->shared_from_this();
1636 }
1637 };
1638
1639//------------------------------------------------------------------------------
1647//------------------------------------------------------------------------------
1648 template<std::floating_point T, bool SAFE_MATH=false>
1650 auto temp = std::make_shared<erf_node<T, SAFE_MATH>> (x)->reduce();
1651// Test for hash collisions.
1652 for (size_t i = temp->get_hash();
1654 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1655 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1657 return temp;
1658 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1659 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1660 }
1661 }
1662#if defined(__clang__) || defined(__GNUC__)
1664#else
1665 assert(false && "Should never reach.");
1666#endif
1667 }
1668
1670 template<std::floating_point T, bool SAFE_MATH=false>
1671 using shared_erf = std::shared_ptr<erf_node<T, SAFE_MATH>>;
1672
1673//------------------------------------------------------------------------------
1681//------------------------------------------------------------------------------
1682 template<std::floating_point T, bool SAFE_MATH=false>
1684 return std::dynamic_pointer_cast<erf_node<T, SAFE_MATH>> (x);
1685 }
1686
1687//******************************************************************************
1688// Erfi node.
1689//******************************************************************************
1690//------------------------------------------------------------------------------
1697//------------------------------------------------------------------------------
1698 template<jit::complex_scalar T, bool SAFE_MATH=false>
1699 class erfi_node final : public straight_node<T, SAFE_MATH> {
1700 private:
1701//------------------------------------------------------------------------------
1706//------------------------------------------------------------------------------
1707 static std::string to_string(leaf_node<T, SAFE_MATH> *a) {
1708 return "erfi" + jit::format_to_string(reinterpret_cast<size_t> (a));
1709 }
1710
1711 public:
1712//------------------------------------------------------------------------------
1716//------------------------------------------------------------------------------
1719
1720//------------------------------------------------------------------------------
1726//------------------------------------------------------------------------------
1728 backend::buffer<T> result = this->arg->evaluate();
1729 result.erfi();
1730 return result;
1731 }
1732
1733//------------------------------------------------------------------------------
1737//------------------------------------------------------------------------------
1739 if (constant_cast(this->arg).get()) {
1740 return constant<T, SAFE_MATH> (this->evaluate());
1741 }
1742
1743 auto ap1 = piecewise_1D_cast(this->arg);
1744 if (ap1.get()) {
1745 return piecewise_1D(this->evaluate(),
1746 ap1->get_arg());
1747 }
1748
1749 auto ap2 = piecewise_2D_cast(this->arg);
1750 if (ap2.get()) {
1751 return piecewise_2D(this->evaluate(),
1752 ap2->get_num_columns(),
1753 ap2->get_left(),
1754 ap2->get_right());
1755 }
1756
1757 return this->shared_from_this();
1758 }
1759
1760//------------------------------------------------------------------------------
1767//------------------------------------------------------------------------------
1769 if (this->is_match(x)) {
1770 return one<T, SAFE_MATH> ();
1771 }
1772
1773 const size_t hash = reinterpret_cast<size_t> (x.get());
1774 if (this->df_cache.find(hash) == this->df_cache.end()) {
1775 T invsqpi;
1776 if constexpr(std::same_as<T, std::complex<float>>) {
1777 invsqpi = std::numbers::inv_sqrtpi_v<float>;
1778 } else {
1779 invsqpi = std::numbers::inv_sqrtpi_v<double>;
1780 }
1781 this->df_cache[hash] = static_cast<T> (2)
1782 * invsqpi
1783 * exp(this->arg*this->arg)*this->arg->df(x);
1784 }
1785 return this->df_cache[hash];
1786 }
1787
1788//------------------------------------------------------------------------------
1796//------------------------------------------------------------------------------
1798 compile(std::ostringstream &stream,
1799 jit::register_map &registers,
1801 const jit::register_usage &usage) {
1802 if (registers.find(this) == registers.end()) {
1803 auto a = this->arg->compile(stream, registers,
1804 thread_mem, usage);
1805
1806 registers[this] = jit::to_string('r', this);
1807 stream << " const ";
1808 jit::add_type<T> (stream);
1809 stream << " " << registers[this] << " = special::erfi("
1810 << registers[a.get()] << ")";
1811 this->endline(stream, usage);
1812 }
1813
1814 return this->shared_from_this();
1815 }
1816
1817//------------------------------------------------------------------------------
1822//------------------------------------------------------------------------------
1824 if (this == x.get()) {
1825 return true;
1826 }
1827
1828 auto x_cast = erfi_cast(x);
1829 if (x_cast.get()) {
1830 return this->arg->is_match(x_cast->get_arg());
1831 }
1832
1833 return false;
1834 }
1835
1836//------------------------------------------------------------------------------
1838//------------------------------------------------------------------------------
1839 virtual void to_latex() const {
1840 std::cout << "erfi\\left(";
1841 this->arg->to_latex();
1842 std::cout << "\\right)";
1843 }
1844
1845//------------------------------------------------------------------------------
1849//------------------------------------------------------------------------------
1851 if (this->has_pseudo()) {
1852 return erfi(this->arg->remove_pseudo());
1853 }
1854 return this->shared_from_this();
1855 }
1856
1857//------------------------------------------------------------------------------
1863//------------------------------------------------------------------------------
1864 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
1865 jit::register_map &registers) {
1866 if (registers.find(this) == registers.end()) {
1867 const std::string name = jit::to_string('r', this);
1868 registers[this] = name;
1869 stream << " " << name
1870 << " [label = \"erfi\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
1871
1872 auto a = this->arg->to_vizgraph(stream, registers);
1873 stream << " " << name << " -- " << registers[a.get()] << ";" << std::endl;
1874 }
1875
1876 return this->shared_from_this();
1877 }
1878 };
1879
1880//------------------------------------------------------------------------------
1888//------------------------------------------------------------------------------
1889 template<jit::complex_scalar T, bool SAFE_MATH=false>
1891 auto temp = std::make_shared<erfi_node<T, SAFE_MATH>> (x)->reduce();
1892// Test for hash collisions.
1893 for (size_t i = temp->get_hash();
1895 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
1896 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
1898 return temp;
1899 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
1900 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
1901 }
1902 }
1903#if defined(__clang__) || defined(__GNUC__)
1905#else
1906 assert(false && "Should never reach.");
1907#endif
1908 }
1909
1911 template<jit::complex_scalar T, bool SAFE_MATH=false>
1912 using shared_erfi = std::shared_ptr<erfi_node<T, SAFE_MATH>>;
1913
1914//------------------------------------------------------------------------------
1922//------------------------------------------------------------------------------
1923 template<jit::complex_scalar T, bool SAFE_MATH=false>
1925 return std::dynamic_pointer_cast<erfi_node<T, SAFE_MATH>> (x);
1926 }
1927
1928//******************************************************************************
1929// Hypot node.
1930//******************************************************************************
1931//------------------------------------------------------------------------------
1938//------------------------------------------------------------------------------
1939 template<std::floating_point T, bool SAFE_MATH=false>
1940 class hypot_node final : public branch_node<T, SAFE_MATH> {
1941 private:
1942//------------------------------------------------------------------------------
1948//------------------------------------------------------------------------------
1949 static std::string to_string(leaf_node<T, SAFE_MATH> *l,
1951 return "hypot" + jit::format_to_string(reinterpret_cast<size_t> (l))
1952 + jit::format_to_string(reinterpret_cast<size_t> (r));
1953 }
1954
1955 public:
1956//------------------------------------------------------------------------------
1961//------------------------------------------------------------------------------
1966
1967//------------------------------------------------------------------------------
1973//------------------------------------------------------------------------------
1975 backend::buffer<T> l_result = this->left->evaluate();
1976 backend::buffer<T> r_result = this->right->evaluate();
1977 return backend::hypot(l_result, r_result);
1978 }
1979
1980//------------------------------------------------------------------------------
1984//------------------------------------------------------------------------------
1986 auto lc = constant_cast(this->left);
1987 auto rc = constant_cast(this->right);
1988
1989 if (rc.get() && rc->is(0)) {
1990 return sqrt(pow(this->left, static_cast<T> (2)));
1991 } else if (lc.get() && lc->is(0)) {
1992 return sqrt(pow(this->right, static_cast<T> (2)));
1993 } else if (rc.get() && lc.get()) {
1994 return constant<T, SAFE_MATH> (this->evaluate());
1995 }
1996
1997 auto pl1 = piecewise_1D_cast(this->left);
1998 auto pr1 = piecewise_1D_cast(this->right);
1999 if (pl1.get() && (rc.get() || pl1->is_arg_match(this->right))) {
2000 return piecewise_1D(this->evaluate(), pl1->get_arg());
2001 } else if (pr1.get() && (lc.get() || pr1->is_arg_match(this->left))) {
2002 return piecewise_1D(this->evaluate(), pr1->get_arg());
2003 }
2004
2005 auto pl2 = piecewise_2D_cast(this->left);
2006 auto pr2 = piecewise_2D_cast(this->right);
2007 if (pl2.get() && (rc.get() || pl2->is_arg_match(this->right))) {
2008 return piecewise_2D(this->evaluate(),
2009 pl2->get_num_columns(),
2010 pl2->get_left(),
2011 pl2->get_right());
2012 } else if (pr2.get() && (lc.get() || pr2->is_arg_match(this->left))) {
2013 return piecewise_2D(this->evaluate(),
2014 pr2->get_num_columns(),
2015 pr2->get_left(),
2016 pr2->get_right());
2017 }
2018
2019// Combine 2D and 1D piecewise constants if a row or column matches.
2020 if (pr2.get() && pr2->is_row_match(this->left)) {
2021 backend::buffer<T> result = pl1->evaluate();
2022 result.hypot_row(pr2->evaluate());
2023 return piecewise_2D(result,
2024 pr2->get_num_columns(),
2025 pr2->get_left(),
2026 pr2->get_right());
2027 } else if (pr2.get() && pr2->is_col_match(this->left)) {
2028 backend::buffer<T> result = pl1->evaluate();
2029 result.hypot_col(pr2->evaluate());
2030 return piecewise_2D(result,
2031 pr2->get_num_columns(),
2032 pr2->get_left(),
2033 pr2->get_right());
2034 } else if (pl2.get() && pl2->is_row_match(this->right)) {
2035 backend::buffer<T> result = pl2->evaluate();
2036 result.hypot_row(pr1->evaluate());
2037 return piecewise_2D(result,
2038 pl2->get_num_columns(),
2039 pl2->get_left(),
2040 pl2->get_right());
2041 } else if (pl2.get() && pl2->is_col_match(this->right)) {
2042 backend::buffer<T> result = pl2->evaluate();
2043 result.hypot_col(pr1->evaluate());
2044 return piecewise_2D(result,
2045 pl2->get_num_columns(),
2046 pl2->get_left(),
2047 pl2->get_right());
2048 }
2049
2050// hypot(sqrt(a), sqrt(b)) -> sqrt(a + b)
2051// hypot(a, sqrt(b)) -> sqrt(a^2 + b)
2052// hypot(sqrt(a), b) -> sqrt(a + b^2)
2053 auto sql = sqrt_cast(this->left);
2054 auto sqr = sqrt_cast(this->right);
2055 if (sql.get() && sqr.get()) {
2056 return sqrt(sql->get_arg() + sqr->get_arg());
2057 } else if (sql.get()) {
2058 return sqrt(sql->get_arg() + pow(this->right,
2059 static_cast<T> (2)));
2060 } else if (sqr.get()) {
2061 return sqrt(sqr->get_arg() + pow(this->left,
2062 static_cast<T> (2)));
2063 }
2064
2065// hypoy(a,a) -> sqrt(2)sqrt(a^2)
2066 if (this->left->is_match(this->right)) {
2067 return std::numbers::sqrt2_v<T>*sqrt(pow(this->left,
2068 static_cast<T> (2)));
2069 }
2070
2071 return this->shared_from_this();
2072 }
2073
2074//------------------------------------------------------------------------------
2081//------------------------------------------------------------------------------
2084 if (this->is_match(x)) {
2085 return one<T, SAFE_MATH> ();
2086 }
2087
2088 const size_t hash = reinterpret_cast<size_t> (x.get());
2089 if (this->df_cache.find(hash) == this->df_cache.end()) {
2090 this->df_cache[hash] = (this->left*this->left->df(x) +
2091 this->right*this->right->df(x))
2092 / this->shared_from_this();
2093 }
2094 return this->df_cache[hash];
2095 }
2096
2097//------------------------------------------------------------------------------
2105//------------------------------------------------------------------------------
2107 compile(std::ostringstream &stream,
2108 jit::register_map &registers,
2110 const jit::register_usage &usage) {
2111 if (registers.find(this) == registers.end()) {
2112 auto l = this->left->compile(stream, registers,
2113 thread_mem, usage);
2114 auto r = this->right->compile(stream, registers,
2115 thread_mem, usage);
2116
2117 registers[this] = jit::to_string('r', this);
2118 stream << " const ";
2119 jit::add_type<T> (stream);
2120 stream << " " << registers[this] << " = ";
2121 if constexpr (jit::use_metal<T> ()) {
2122 stream << "length({";
2123 } else {
2124 stream << "hypot(";
2125 }
2126 stream << registers[l.get()] << ", " << registers[r.get()];
2127 if constexpr (jit::use_metal<T> ()) {
2128 stream << "})";
2129 } else {
2130 stream << ")";
2131 }
2132
2133 this->endline(stream, usage);
2134 }
2135
2136 return this->shared_from_this();
2137 }
2138
2139//------------------------------------------------------------------------------
2144//------------------------------------------------------------------------------
2146 if (this == x.get()) {
2147 return true;
2148 }
2149
2150 auto x_cast = hypot_cast(x);
2151 if (x_cast.get()) {
2152// Hypot is commutative.
2153 return (this->left->is_match(x_cast->get_left()) &&
2154 this->right->is_match(x_cast->get_right())) ||
2155 (this->right->is_match(x_cast->get_left()) &&
2156 this->left->is_match(x_cast->get_right()));
2157 }
2158
2159 return false;
2160 }
2161
2162//------------------------------------------------------------------------------
2164//------------------------------------------------------------------------------
2165 virtual void to_latex() const {
2166 std::cout << "hypot\\left(";
2167 this->left->to_latex();
2168 std::cout << ",";
2169 this->right->to_latex();
2170 std::cout << "\\right)";
2171 }
2172
2173//------------------------------------------------------------------------------
2177//------------------------------------------------------------------------------
2179 if (this->has_pseudo()) {
2180 return hypot(this->left->remove_pseudo(),
2181 this->right->remove_pseudo());
2182 }
2183 return this->shared_from_this();
2184 }
2185
2186//------------------------------------------------------------------------------
2192//------------------------------------------------------------------------------
2193 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
2194 jit::register_map &registers) {
2195 if (registers.find(this) == registers.end()) {
2196 const std::string name = jit::to_string('r', this);
2197 registers[this] = name;
2198 stream << " " << name
2199 << " [label = \"hypot\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
2200
2201 auto l = this->left->to_vizgraph(stream, registers);
2202 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
2203 auto r = this->right->to_vizgraph(stream, registers);
2204 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
2205 }
2206
2207 return this->shared_from_this();
2208 }
2209 };
2210
2211//------------------------------------------------------------------------------
2220//------------------------------------------------------------------------------
2221 template<std::floating_point T, bool SAFE_MATH=false>
2224 auto temp = std::make_shared<hypot_node<T, SAFE_MATH>> (l, r)->reduce();
2225// Test for hash collisions.
2226 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
2227 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
2228 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
2230 return temp;
2231 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
2232 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
2233 }
2234 }
2235#if defined(__clang__) || defined(__GNUC__)
2237#else
2238 assert(false && "Should never reach.");
2239#endif
2240 }
2241
2242//------------------------------------------------------------------------------
2252//------------------------------------------------------------------------------
2253 template<std::floating_point T, jit::float_scalar L, bool SAFE_MATH=false>
2256 return hypot(constant<T, SAFE_MATH> (static_cast<T> (l)), r);
2257 }
2258
2259//------------------------------------------------------------------------------
2269//------------------------------------------------------------------------------
2270 template<std::floating_point T, jit::float_scalar R, bool SAFE_MATH=false>
2272 const R r) {
2273 return hypot(l, constant<T, SAFE_MATH> (static_cast<T> (r)));
2274 }
2275
2277 template<std::floating_point T, bool SAFE_MATH=false>
2278 using shared_hypot = std::shared_ptr<hypot_node<T, SAFE_MATH>>;
2279
2280//------------------------------------------------------------------------------
2285//------------------------------------------------------------------------------
2286 template<std::floating_point T, bool SAFE_MATH=false>
2288 return std::dynamic_pointer_cast<hypot_node<T, SAFE_MATH>> (x);
2289 }
2290
2291//******************************************************************************
2292// copysign node.
2293//******************************************************************************
2294//------------------------------------------------------------------------------
2301//------------------------------------------------------------------------------
2302 template<std::floating_point T, bool SAFE_MATH=false>
2303 class copysign_node final : public no_derivative<T, SAFE_MATH,
2304 branch_node<T, SAFE_MATH>> {
2305 private:
2306//------------------------------------------------------------------------------
2312//------------------------------------------------------------------------------
2313 static std::string to_string(leaf_node<T, SAFE_MATH> *l,
2315 return "copysign" + jit::format_to_string(reinterpret_cast<size_t> (l))
2316 + jit::format_to_string(reinterpret_cast<size_t> (r));
2317 }
2318
2319 public:
2320//------------------------------------------------------------------------------
2325//------------------------------------------------------------------------------
2332
2333//------------------------------------------------------------------------------
2339//------------------------------------------------------------------------------
2341 backend::buffer<T> l_result = this->left->evaluate();
2342 backend::buffer<T> r_result = this->right->evaluate();
2344 }
2345
2346//------------------------------------------------------------------------------
2350//------------------------------------------------------------------------------
2352 auto lc = constant_cast(this->left);
2353 auto rc = constant_cast(this->right);
2354
2355 if (rc.get() && rc->is(0)) {
2356 return sqrt(pow(this->left, static_cast<T> (2)));
2357 } else if (lc.get() && lc->is(0)) {
2358 return sqrt(pow(this->right, static_cast<T> (2)));
2359 } else if (rc.get() && lc.get()) {
2360 return constant<T, SAFE_MATH> (this->evaluate());
2361 }
2362
2363 auto pl1 = piecewise_1D_cast(this->left);
2364 auto pr1 = piecewise_1D_cast(this->right);
2365 if (pl1.get() && (rc.get() || pl1->is_arg_match(this->right))) {
2366 return piecewise_1D(this->evaluate(), pl1->get_arg());
2367 } else if (pr1.get() && (lc.get() || pr1->is_arg_match(this->left))) {
2368 return piecewise_1D(this->evaluate(), pr1->get_arg());
2369 }
2370
2371 auto pl2 = piecewise_2D_cast(this->left);
2372 auto pr2 = piecewise_2D_cast(this->right);
2373 if (pl2.get() && (rc.get() || pl2->is_arg_match(this->right))) {
2374 return piecewise_2D(this->evaluate(),
2375 pl2->get_num_columns(),
2376 pl2->get_left(),
2377 pl2->get_right());
2378 } else if (pr2.get() && (lc.get() || pr2->is_arg_match(this->left))) {
2379 return piecewise_2D(this->evaluate(),
2380 pr2->get_num_columns(),
2381 pr2->get_left(),
2382 pr2->get_right());
2383 }
2384
2385// Combine 2D and 1D piecewise constants if a row or column matches.
2386 if (pr2.get() && pr2->is_row_match(this->left)) {
2387 backend::buffer<T> result = pl1->evaluate();
2388 result.copysign_row(pr2->evaluate());
2389 return piecewise_2D(result,
2390 pr2->get_num_columns(),
2391 pr2->get_left(),
2392 pr2->get_right());
2393 } else if (pr2.get() && pr2->is_col_match(this->left)) {
2394 backend::buffer<T> result = pl1->evaluate();
2395 result.copysign_col(pr2->evaluate());
2396 return piecewise_2D(result,
2397 pr2->get_num_columns(),
2398 pr2->get_left(),
2399 pr2->get_right());
2400 } else if (pl2.get() && pl2->is_row_match(this->right)) {
2401 backend::buffer<T> result = pl2->evaluate();
2402 result.copysign_row(pr1->evaluate());
2403 return piecewise_2D(result,
2404 pl2->get_num_columns(),
2405 pl2->get_left(),
2406 pl2->get_right());
2407 } else if (pl2.get() && pl2->is_col_match(this->right)) {
2408 backend::buffer<T> result = pl2->evaluate();
2409 result.copysign_col(pr1->evaluate());
2410 return piecewise_2D(result,
2411 pl2->get_num_columns(),
2412 pl2->get_left(),
2413 pl2->get_right());
2414 }
2415
2416 return this->shared_from_this();
2417 }
2418
2419//------------------------------------------------------------------------------
2427//------------------------------------------------------------------------------
2429 compile(std::ostringstream &stream,
2430 jit::register_map &registers,
2432 const jit::register_usage &usage) {
2433 if (registers.find(this) == registers.end()) {
2434 auto l = this->left->compile(stream, registers,
2435 thread_mem, usage);
2436 auto r = this->right->compile(stream, registers,
2437 thread_mem, usage);
2438
2439 registers[this] = jit::to_string('r', this);
2440 stream << " const ";
2441 jit::add_type<T> (stream);
2442 stream << " " << registers[this] << " = copysign("
2443 << registers[l.get()] << ", "
2444 << registers[r.get()] << ")";
2445
2446 this->endline(stream, usage);
2447 }
2448
2449 return this->shared_from_this();
2450 }
2451
2452//------------------------------------------------------------------------------
2457//------------------------------------------------------------------------------
2459 if (this == x.get()) {
2460 return true;
2461 }
2462
2463 auto x_cast = hypot_cast(x);
2464 if (x_cast.get()) {
2465 return (this->left->is_match(x_cast->get_left()) &&
2466 this->right->is_match(x_cast->get_right()));
2467 }
2468
2469 return false;
2470 }
2471
2472//------------------------------------------------------------------------------
2474//------------------------------------------------------------------------------
2475 virtual void to_latex() const {
2476 std::cout << "copysign\\left(";
2477 this->left->to_latex();
2478 std::cout << ",";
2479 this->right->to_latex();
2480 std::cout << "\\right)";
2481 }
2482
2483//------------------------------------------------------------------------------
2487//------------------------------------------------------------------------------
2489 if (this->has_pseudo()) {
2490 return copysign(this->left->remove_pseudo(),
2491 this->right->remove_pseudo());
2492 }
2493 return this->shared_from_this();
2494 }
2495
2496//------------------------------------------------------------------------------
2502//------------------------------------------------------------------------------
2503 virtual shared_leaf<T, SAFE_MATH> to_vizgraph(std::stringstream &stream,
2504 jit::register_map &registers) {
2505 if (registers.find(this) == registers.end()) {
2506 const std::string name = jit::to_string('r', this);
2507 registers[this] = name;
2508 stream << " " << name
2509 << " [label = \"copysign\", shape = oval, style = filled, fillcolor = blue, fontcolor = white];" << std::endl;
2510
2511 auto l = this->left->to_vizgraph(stream, registers);
2512 stream << " " << name << " -- " << registers[l.get()] << ";" << std::endl;
2513 auto r = this->right->to_vizgraph(stream, registers);
2514 stream << " " << name << " -- " << registers[r.get()] << ";" << std::endl;
2515 }
2516
2517 return this->shared_from_this();
2518 }
2519 };
2520
2521//------------------------------------------------------------------------------
2530//------------------------------------------------------------------------------
2531 template<std::floating_point T, bool SAFE_MATH=false>
2534 auto temp = std::make_shared<copysign_node<T, SAFE_MATH>> (l, r)->reduce();
2535// Test for hash collisions.
2536 for (size_t i = temp->get_hash(); i < std::numeric_limits<size_t>::max(); i++) {
2537 if (leaf_node<T, SAFE_MATH>::caches.nodes.find(i) ==
2538 leaf_node<T, SAFE_MATH>::caches.nodes.end()) {
2540 return temp;
2541 } else if (temp->is_match(leaf_node<T, SAFE_MATH>::caches.nodes[i])) {
2542 return leaf_node<T, SAFE_MATH>::caches.nodes[i];
2543 }
2544 }
2545#if defined(__clang__) || defined(__GNUC__)
2547#else
2548 assert(false && "Should never reach.");
2549#endif
2550 }
2551
2552//------------------------------------------------------------------------------
2562//------------------------------------------------------------------------------
2563 template<std::floating_point T, jit::float_scalar L, bool SAFE_MATH=false>
2566 return copysign(constant<T, SAFE_MATH> (static_cast<T> (l)), r);
2567 }
2568
2569//------------------------------------------------------------------------------
2579//------------------------------------------------------------------------------
2580 template<std::floating_point T, jit::float_scalar R, bool SAFE_MATH=false>
2582 const R r) {
2583 return copysign(l, constant<T, SAFE_MATH> (static_cast<T> (r)));
2584 }
2585
2587 template<std::floating_point T, bool SAFE_MATH=false>
2588 using shared_copysign = std::shared_ptr<copysign_node<T, SAFE_MATH>>;
2589
2590//------------------------------------------------------------------------------
2595//------------------------------------------------------------------------------
2596 template<std::floating_point T, bool SAFE_MATH=false>
2598 return std::dynamic_pointer_cast<copysign_node<T, SAFE_MATH>> (x);
2599 }
2600}
2601
2602#endif /* math_h */
Class representing a generic buffer.
Definition backend.hpp:29
void erfi()
Take erfi.
Definition backend.hpp:258
void copysign_col(const buffer< T > &x)
copysign col operation.
Definition backend.hpp:841
void log()
Take log.
Definition backend.hpp:223
void sqrt()
Take sqrt.
Definition backend.hpp:209
void hypot_row(const buffer< T > &x)
Hypot row operation.
Definition backend.hpp:733
void pow_col(const buffer< T > &x)
Pow col operation.
Definition backend.hpp:697
void erf()
Take erf.
Definition backend.hpp:251
void pow_row(const buffer< T > &x)
Pow row operation.
Definition backend.hpp:661
void copysign_row(const buffer< T > &x)
copysign row operation.
Definition backend.hpp:805
void hypot_col(const buffer< T > &x)
Hypot col operation.
Definition backend.hpp:769
void exp()
Take exp.
Definition backend.hpp:216
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
A copysign node.
Definition math.hpp:2304
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:2458
virtual backend::buffer< T > evaluate()
Evaluate the results of copysign.
Definition math.hpp:2340
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:2488
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 math.hpp:2429
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:2475
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:2503
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce a copysign node.
Definition math.hpp:2351
copysign_node(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Construct a hypot node.
Definition math.hpp:2326
An error function node.
Definition math.hpp:1464
virtual backend::buffer< T > evaluate()
Evaluate the results of erf.
Definition math.hpp:1492
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:1623
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:1598
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce the erf(x).
Definition math.hpp:1503
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:1609
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:1582
erf_node(shared_leaf< T, SAFE_MATH > x)
Construct a erf node.
Definition math.hpp:1482
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:1533
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 math.hpp:1557
An imaginary error function node.
Definition math.hpp:1699
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 math.hpp:1798
erfi_node(shared_leaf< T, SAFE_MATH > x)
Construct a erfi node.
Definition math.hpp:1717
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce the erfi(x).
Definition math.hpp:1738
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:1839
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:1850
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:1768
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:1823
virtual backend::buffer< T > evaluate()
Evaluate the results of erfi.
Definition math.hpp:1727
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:1864
A exp node.
Definition math.hpp:347
virtual backend::buffer< T > evaluate()
Evaluate the results of exp.
Definition math.hpp:375
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:422
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:491
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:518
exp_node(shared_leaf< T, SAFE_MATH > x)
Construct a exp node.
Definition math.hpp:365
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 math.hpp:444
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:507
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce the exp(x).
Definition math.hpp:386
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:532
A hypot node.
Definition math.hpp:1940
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:2145
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:2083
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:2165
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce a hypot node.
Definition math.hpp:1985
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 math.hpp:2107
hypot_node(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Construct a hypot node.
Definition math.hpp:1962
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:2193
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:2178
virtual backend::buffer< T > evaluate()
Evaluate the results of hypot.
Definition math.hpp:1974
Class representing a node leaf.
Definition node.hpp:371
virtual std::shared_ptr< leaf_node< T, SAFE_MATH > > compile(std::ostringstream &stream, jit::register_map &registers, const jit::register_map &thread_mem, const jit::register_usage &usage)=0
Compile the node.
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
virtual std::shared_ptr< leaf_node< T, SAFE_MATH > > to_vizgraph(std::stringstream &stream, jit::register_map &registers)=0
Convert the node to vizgraph.
virtual bool has_pseudo() const
Query if the node contains pseudo variables.
Definition node.hpp:633
const size_t hash
Hash for node.
Definition node.hpp:374
std::unordered_map< size_t, std::shared_ptr< leaf_node< T, SAFE_MATH > > > df_cache
Cache derivative terms.
Definition node.hpp:378
A log node.
Definition math.hpp:608
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 math.hpp:705
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:771
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:683
virtual backend::buffer< T > evaluate()
Evaluate the results of log.
Definition math.hpp:636
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:730
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce the log(x).
Definition math.hpp:647
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:746
log_node(shared_leaf< T, SAFE_MATH > x)
Construct a log node.
Definition math.hpp:626
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:757
Nodes without derivatives.
Definition node.hpp:1713
An power node.
Definition math.hpp:846
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:1305
virtual bool is_all_variables() const
Test if node acts like a variable.
Definition math.hpp:1327
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition math.hpp:1347
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 math.hpp:1224
virtual backend::buffer< T > evaluate()
Evaluate the results of pow.
Definition math.hpp:880
pow_node(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Construct a power node.
Definition math.hpp:868
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition math.hpp:1338
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:1365
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:1265
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition math.hpp:1356
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:1282
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce a power node.
Definition math.hpp:891
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:1200
A sqrt node.
Definition math.hpp:27
virtual shared_leaf< T, SAFE_MATH > get_power_exponent() const
Get the exponent of a power.
Definition math.hpp:248
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 math.hpp:178
virtual backend::buffer< T > evaluate()
Evaluate the results of sqrt.
Definition math.hpp:55
virtual shared_leaf< T, SAFE_MATH > reduce()
Reduce the sqrt(x).
Definition math.hpp:66
sqrt_node(shared_leaf< T, SAFE_MATH > x)
Construct a sqrt node.
Definition math.hpp:45
virtual bool is_power_like() const
Test if the node acts like a power of variable.
Definition math.hpp:230
virtual bool is_match(shared_leaf< T, SAFE_MATH > x)
Query if the nodes match.
Definition math.hpp:203
virtual shared_leaf< T, SAFE_MATH > remove_pseudo()
Remove pseudo variable nodes.
Definition math.hpp:257
virtual shared_leaf< T, SAFE_MATH > df(shared_leaf< T, SAFE_MATH > x)
Transform node to derivative.
Definition math.hpp:155
virtual shared_leaf< T, SAFE_MATH > to_vizgraph(std::stringstream &stream, jit::register_map &registers)
Convert the node to vizgraph.
Definition math.hpp:271
virtual void to_latex() const
Convert the node to latex.
Definition math.hpp:219
virtual shared_leaf< T, SAFE_MATH > get_power_base()
Get the base of a power.
Definition math.hpp:239
Class representing a straight node.
Definition node.hpp:1219
shared_leaf< T, SAFE_MATH > arg
Argument.
Definition node.hpp:1222
Complex scalar concept.
Definition register.hpp:25
subroutine assert(test, message)
Assert check.
Definition f_binding_test.f90:38
buffer< T > pow(buffer< T > &base, buffer< T > &exponent)
Take the power.
Definition backend.hpp:1537
buffer< T > copysign(buffer< T > &x, buffer< T > &y)
Copy the sign of x and apply it to y.
Definition backend.hpp:1654
buffer< T > hypot(buffer< T > &a, buffer< T > &b)
hypot operation.
Definition backend.hpp:1204
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
shared_leaf< T, SAFE_MATH > log(shared_leaf< T, SAFE_MATH > x)
Define log convenience function.
Definition math.hpp:797
shared_pow< T, SAFE_MATH > pow_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a power node.
Definition math.hpp:1448
constexpr shared_leaf< T, SAFE_MATH > zero()
Forward declare for zero.
Definition node.hpp:1154
shared_sqrt< T, SAFE_MATH > sqrt_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a sqrt node.
Definition math.hpp:331
std::shared_ptr< erf_node< T, SAFE_MATH > > shared_erf
Convenience type alias for shared erf nodes.
Definition math.hpp:1671
shared_leaf< T, SAFE_MATH > pow(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build power node.
Definition math.hpp:1384
shared_divide< T, SAFE_MATH > divide_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a divide node.
Definition arithmetic.hpp:3802
std::shared_ptr< erfi_node< T, SAFE_MATH > > shared_erfi
Convenience type alias for shared erfi nodes.
Definition math.hpp:1912
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
shared_multiply< T, SAFE_MATH > multiply_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a multiply node.
Definition arithmetic.hpp:2843
std::shared_ptr< hypot_node< T, SAFE_MATH > > shared_hypot
Convenience type alias for shared hypot nodes.
Definition math.hpp:2278
shared_leaf< T, SAFE_MATH > erf(shared_leaf< T, SAFE_MATH > x)
Define erf convenience function.
Definition math.hpp:1649
shared_leaf< T, SAFE_MATH > exp(shared_leaf< T, SAFE_MATH > x)
Define exp convenience function.
Definition math.hpp:558
shared_leaf< T, SAFE_MATH > copysign(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build copysign node.
Definition math.hpp:2532
shared_exp< T, SAFE_MATH > exp_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a exp node.
Definition math.hpp:592
shared_constant< T, SAFE_MATH > constant_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a constant node.
Definition node.hpp:1202
shared_leaf< T, SAFE_MATH > erfi(shared_leaf< T, SAFE_MATH > x)
Define erfi convenience function.
Definition math.hpp:1890
bool is_variable_combinable(shared_leaf< T, SAFE_MATH > a, shared_leaf< T, SAFE_MATH > b)
Check if the variable is combinable.
Definition arithmetic.hpp:75
shared_variable< T, SAFE_MATH > variable_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a variable node.
Definition node.hpp:2169
shared_erf< T, SAFE_MATH > erf_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a erf node.
Definition math.hpp:1683
constexpr T i
Convenience type for imaginary constant.
Definition node.hpp:1186
std::shared_ptr< copysign_node< T, SAFE_MATH > > shared_copysign
Convenience type alias for shared copysign nodes.
Definition math.hpp:2588
shared_erfi< T, SAFE_MATH > erfi_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a erfi node.
Definition math.hpp:1924
shared_leaf< T, SAFE_MATH > sqrt(shared_leaf< T, SAFE_MATH > x)
Define sqrt convenience function.
Definition math.hpp:297
std::shared_ptr< exp_node< T, SAFE_MATH > > shared_exp
Convenience type alias for shared exp nodes.
Definition math.hpp:580
shared_log< T, SAFE_MATH > log_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a exp node.
Definition math.hpp:830
std::shared_ptr< leaf_node< T, SAFE_MATH > > shared_leaf
Convenience type alias for shared leaf nodes.
Definition node.hpp:691
shared_hypot< T, SAFE_MATH > hypot_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a hypot node.
Definition math.hpp:2287
std::shared_ptr< log_node< T, SAFE_MATH > > shared_log
Convenience type alias for shared log nodes.
Definition math.hpp:818
shared_leaf< T, SAFE_MATH > hypot(shared_leaf< T, SAFE_MATH > l, shared_leaf< T, SAFE_MATH > r)
Build hypot node.
Definition math.hpp:2222
std::shared_ptr< pow_node< T, SAFE_MATH > > shared_pow
Convenience type alias for shared add nodes.
Definition math.hpp:1439
std::shared_ptr< sqrt_node< T, SAFE_MATH > > shared_sqrt
Convenience type alias for shared sqrt nodes.
Definition math.hpp:319
shared_copysign< T, SAFE_MATH > copysign_cast(shared_leaf< T, SAFE_MATH > x)
Cast to a copysign node.
Definition math.hpp:2597
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_map< void *, std::string > register_map
Type alias for mapping node pointers to register names.
Definition register.hpp:259
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 piecewise_1D()
Tests for 1D piecewise nodes.
Definition piecewise_test.cpp:82
void piecewise_2D()
Tests for 2D piecewise nodes.
Definition piecewise_test.cpp:321