Sleipnir C++ API
Loading...
Searching...
No Matches
expression.hpp
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <stdint.h>
6
7#include <algorithm>
8#include <cmath>
9#include <memory>
10#include <numbers>
11#include <string_view>
12#include <type_traits>
13#include <utility>
14
15#include <gch/small_vector.hpp>
16
17#include "sleipnir/autodiff/expression_type.hpp"
18#include "sleipnir/util/function_ref.hpp"
19#include "sleipnir/util/intrusive_shared_ptr.hpp"
20#include "sleipnir/util/pool.hpp"
21
22namespace slp::detail {
23
24#ifdef _WIN32
25inline constexpr bool USE_POOL_ALLOCATOR = false;
26#else
27inline constexpr bool USE_POOL_ALLOCATOR = true;
28#endif
29
30template <typename Scalar>
31struct Expression;
32
36template <typename Scalar>
37using ExpressionPtr = IntrusiveSharedPtr<Expression<Scalar>>;
38
44template <typename T, typename... Args>
45static ExpressionPtr<typename T::Scalar> make_expression_ptr(Args&&... args) {
46 if constexpr (USE_POOL_ALLOCATOR) {
47 return allocate_intrusive_shared<T>(global_pool_allocator<T>(),
48 std::forward<Args>(args)...);
49 } else {
50 return make_intrusive_shared<T>(std::forward<Args>(args)...);
51 }
52}
53
54template <typename Scalar, ExpressionType T>
55struct BinaryMinusExpression;
56
57template <typename Scalar, ExpressionType T>
58struct BinaryPlusExpression;
59
60template <typename Scalar, ExpressionType T>
61struct DivExpression;
62
63template <typename Scalar, ExpressionType T>
64struct MultExpression;
65
66template <typename Scalar, ExpressionType T>
67struct UnaryMinusExpression;
68
73template <typename Scalar>
74ExpressionPtr<Scalar> constant_ptr(Scalar value);
75
79template <typename Scalar_>
80struct Expression {
82 using Scalar = Scalar_;
83
86
89
93
99 bool is_leaf = false;
100
111
114
116 constexpr Expression() = default;
117
121 explicit constexpr Expression(Scalar value) : val{value}, is_leaf{true} {}
122
123 virtual ~Expression() = default;
124
129 constexpr bool is_constant(Scalar constant) const {
130 return type() == ExpressionType::CONSTANT && val == constant;
131 }
132
138 const ExpressionPtr<Scalar>& rhs) {
139 using enum ExpressionType;
140
141 // Prune expression
142 if (lhs->is_constant(Scalar(0))) {
143 // Return zero, which lhs currently is
144 return lhs;
145 } else if (rhs->is_constant(Scalar(0))) {
146 // Return zero, which rhs currently is
147 return rhs;
148 } else if (lhs->is_constant(Scalar(1))) {
149 // Return rhs unmodified
150 return rhs;
151 } else if (rhs->is_constant(Scalar(1))) {
152 // Return lhs unmodified
153 return lhs;
154 }
155
156 // Evaluate constant
157 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
158 return constant_ptr(lhs->val * rhs->val);
159 }
160
161 // Evaluate expression type
162 if (lhs->type() == CONSTANT) {
163 if (rhs->type() == LINEAR) {
165 } else if (rhs->type() == QUADRATIC) {
167 } else {
169 }
170 } else if (rhs->type() == CONSTANT) {
171 if (lhs->type() == LINEAR) {
173 } else if (lhs->type() == QUADRATIC) {
175 } else {
177 }
178 } else if (lhs->type() == LINEAR && rhs->type() == LINEAR) {
180 } else {
182 }
183 }
184
190 const ExpressionPtr<Scalar>& rhs) {
191 using enum ExpressionType;
192
193 // Prune expression
194 if (lhs->is_constant(Scalar(0))) {
195 // Return zero, which lhs currently is
196 return lhs;
197 } else if (rhs->is_constant(Scalar(1))) {
198 // Return lhs unmodified
199 return lhs;
200 }
201
202 // Evaluate constant
203 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
204 return constant_ptr(lhs->val / rhs->val);
205 }
206
207 // Evaluate expression type
208 if (rhs->type() == CONSTANT) {
209 if (lhs->type() == LINEAR) {
211 } else if (lhs->type() == QUADRATIC) {
213 } else {
215 }
216 } else {
218 }
219 }
220
226 const ExpressionPtr<Scalar>& rhs) {
227 using enum ExpressionType;
228
229 // Prune expression. We check for nullptr because operator+ is used in
230 // adjoint accumulation, and child nodes can be null.
231 if (lhs == nullptr || lhs->is_constant(Scalar(0))) {
232 // Return rhs unmodified
233 return rhs;
234 } else if (rhs == nullptr || rhs->is_constant(Scalar(0))) {
235 // Return lhs unmodified
236 return lhs;
237 }
238
239 // Evaluate constant
240 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
241 return constant_ptr(lhs->val + rhs->val);
242 }
243
244 auto type = std::max(lhs->type(), rhs->type());
245 if (type == LINEAR) {
247 rhs);
248 } else if (type == QUADRATIC) {
250 rhs);
251 } else {
253 rhs);
254 }
255 }
256
262 const ExpressionPtr<Scalar>& rhs) {
263 return lhs = lhs + rhs;
264 }
265
271 const ExpressionPtr<Scalar>& rhs) {
272 using enum ExpressionType;
273
274 // Prune expression
275 if (lhs->is_constant(Scalar(0))) {
276 if (rhs->is_constant(Scalar(0))) {
277 // Return zero, which rhs currently is
278 return rhs;
279 } else {
280 // Return rhs negated
281 return -rhs;
282 }
283 } else if (rhs->is_constant(Scalar(0))) {
284 // Return lhs unmodified
285 return lhs;
286 }
287
288 // Evaluate constant
289 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
290 return constant_ptr(lhs->val - rhs->val);
291 }
292
293 auto type = std::max(lhs->type(), rhs->type());
294 if (type == LINEAR) {
296 rhs);
297 } else if (type == QUADRATIC) {
299 rhs);
300 } else {
302 rhs);
303 }
304 }
305
310 using enum ExpressionType;
311
312 // Prune expression
313 if (lhs->is_constant(Scalar(0))) {
314 // Return zero, which lhs currently is
315 return lhs;
316 }
317
318 // Evaluate constant
319 if (lhs->type() == CONSTANT) {
320 return constant_ptr(-lhs->val);
321 }
322
323 if (lhs->type() == LINEAR) {
325 } else if (lhs->type() == QUADRATIC) {
327 } else {
329 }
330 }
331
336 return lhs;
337 }
338
342 virtual void visit_args(
344 }
345
351 virtual Scalar value() const = 0;
352
357 virtual ExpressionType type() const = 0;
358
362 virtual std::string_view name() const = 0;
363
365 virtual void accumulate_adjoints() const {}
366
368 virtual void accumulate_adjoints_expr() const {}
369};
370
375template <typename Scalar, ExpressionType T>
379
382
390
392 function_ref<void(Expression<Scalar>* arg)> func) const override {
393 func(lhs.get());
394 func(rhs.get());
395 }
396
397 Scalar value() const override { return lhs->val - rhs->val; }
398
399 ExpressionType type() const override { return T; }
400
401 std::string_view name() const override { return "binary minus"; }
402
403 void accumulate_adjoints() const override {
404 lhs->adj += grad_l();
405 rhs->adj += grad_r();
406 }
407
408 void accumulate_adjoints_expr() const override {
409 lhs->adj_expr += grad_expr_l();
410 rhs->adj_expr += grad_expr_r();
411 }
412
413 private:
414 Scalar grad_l() const { return this->adj; }
415
416 Scalar grad_r() const { return -this->adj; }
417
418 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr; }
419
420 ExpressionPtr<Scalar> grad_expr_r() const { return -this->adj_expr; }
421};
422
427template <typename Scalar, ExpressionType T>
431
434
442
444 function_ref<void(Expression<Scalar>* arg)> func) const override {
445 func(lhs.get());
446 func(rhs.get());
447 }
448
449 Scalar value() const override { return lhs->val + rhs->val; }
450
451 ExpressionType type() const override { return T; }
452
453 std::string_view name() const override { return "binary plus"; }
454
455 void accumulate_adjoints() const override {
456 lhs->adj += grad_l();
457 rhs->adj += grad_r();
458 }
459
460 void accumulate_adjoints_expr() const override {
461 lhs->adj_expr += grad_expr_l();
462 rhs->adj_expr += grad_expr_r();
463 }
464
465 private:
466 Scalar grad_l() const { return this->adj; }
467
468 Scalar grad_r() const { return this->adj; }
469
470 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr; }
471
472 ExpressionPtr<Scalar> grad_expr_r() const { return this->adj_expr; }
473};
474
478template <typename Scalar>
482
487 : x{std::move(x)} {}
488
490 function_ref<void(Expression<Scalar>* arg)> func) const override {
491 func(x.get());
492 }
493
494 Scalar value() const override {
495 using std::cbrt;
496 return cbrt(x->val);
497 }
498
499 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
500
501 std::string_view name() const override { return "cbrt"; }
502
503 void accumulate_adjoints() const override { x->adj += grad_l(); }
504
505 void accumulate_adjoints_expr() const override {
506 x->adj_expr += grad_expr_l();
507 }
508
509 private:
510 Scalar grad_l() const {
511 using std::cbrt;
512
513 Scalar c = cbrt(x->val);
514 return this->adj / (Scalar(3) * c * c);
515 }
516
517 ExpressionPtr<Scalar> grad_expr_l() const {
518 auto c = cbrt(x);
519 return this->adj_expr / (constant_ptr(Scalar(3)) * c * c);
520 }
521};
522
527template <typename Scalar>
528ExpressionPtr<Scalar> cbrt(const ExpressionPtr<Scalar>& x) {
529 using enum ExpressionType;
530 using std::cbrt;
531
532 // Evaluate constant
533 if (x->type() == CONSTANT) {
534 if (x->val == Scalar(0)) {
535 // Return zero
536 return x;
537 } else if (x->val == Scalar(-1) || x->val == Scalar(1)) {
538 return x;
539 } else {
540 return constant_ptr(cbrt(x->val));
541 }
542 }
543
544 return make_expression_ptr<CbrtExpression<Scalar>>(x);
545}
546
550template <typename Scalar>
555 explicit constexpr ConstantExpression(Scalar value)
556 : Expression<Scalar>{value} {}
557
558 Scalar value() const override { return this->val; }
559
560 ExpressionType type() const override { return ExpressionType::CONSTANT; }
561
562 std::string_view name() const override { return "constant"; }
563};
564
565template <typename Scalar>
566ExpressionPtr<Scalar> constant_ptr(Scalar value) {
568}
569
573template <typename Scalar>
577
583
584 Scalar value() const override { return this->val; }
585
586 ExpressionType type() const override { return ExpressionType::LINEAR; }
587
588 std::string_view name() const override { return "decision variable"; }
589};
590
595template <typename Scalar, ExpressionType T>
599
602
609
611 function_ref<void(Expression<Scalar>* arg)> func) const override {
612 func(lhs.get());
613 func(rhs.get());
614 }
615
616 Scalar value() const override { return lhs->val / rhs->val; }
617
618 ExpressionType type() const override { return T; }
619
620 std::string_view name() const override { return "division"; }
621
622 void accumulate_adjoints() const override {
623 lhs->adj += grad_l();
624 rhs->adj += grad_r();
625 }
626
627 void accumulate_adjoints_expr() const override {
628 lhs->adj_expr += grad_expr_l();
629 rhs->adj_expr += grad_expr_r();
630 }
631
632 private:
633 Scalar grad_l() const { return this->adj / rhs->val; };
634
635 Scalar grad_r() const {
636 return this->adj * -lhs->val / (rhs->val * rhs->val);
637 }
638
639 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr / rhs; }
640
641 ExpressionPtr<Scalar> grad_expr_r() const {
642 return this->adj_expr * -lhs / (rhs * rhs);
643 }
644};
645
650template <typename Scalar, ExpressionType T>
654
657
664
666 function_ref<void(Expression<Scalar>* arg)> func) const override {
667 func(lhs.get());
668 func(rhs.get());
669 }
670
671 Scalar value() const override { return lhs->val * rhs->val; }
672
673 ExpressionType type() const override { return T; }
674
675 std::string_view name() const override { return "multiplication"; }
676
677 void accumulate_adjoints() const override {
678 lhs->adj += grad_l();
679 rhs->adj += grad_r();
680 }
681
682 void accumulate_adjoints_expr() const override {
683 lhs->adj_expr += grad_expr_l();
684 rhs->adj_expr += grad_expr_r();
685 }
686
687 private:
688 Scalar grad_l() const { return this->adj * rhs->val; }
689
690 Scalar grad_r() const { return this->adj * lhs->val; }
691
692 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * rhs; }
693
694 ExpressionPtr<Scalar> grad_expr_r() const { return this->adj_expr * lhs; }
695};
696
701template <typename Scalar, ExpressionType T>
705
710 : lhs{std::move(lhs)} {}
711
713 function_ref<void(Expression<Scalar>* arg)> func) const override {
714 func(lhs.get());
715 }
716
717 Scalar value() const override { return -lhs->val; }
718
719 ExpressionType type() const override { return T; }
720
721 std::string_view name() const override { return "unary minus"; }
722
723 void accumulate_adjoints() const override { lhs->adj += grad_l(); }
724
725 void accumulate_adjoints_expr() const override {
726 lhs->adj_expr += grad_expr_l();
727 }
728
729 private:
730 Scalar grad_l() const { return -this->adj; }
731
732 ExpressionPtr<Scalar> grad_expr_l() const { return -this->adj_expr; }
733};
734
739template <typename Scalar>
740constexpr void inc_ref_count(Expression<Scalar>* expr) {
741 ++expr->ref_count;
742}
743
748template <typename Scalar>
749constexpr void dec_ref_count(Expression<Scalar>* expr) {
750 // If a deeply nested tree is being deallocated all at once, calling the
751 // Expression destructor when expr's refcount reaches zero can cause a stack
752 // overflow. Instead, we iterate over its children to decrement their
753 // refcounts and deallocate them.
754 gch::small_vector<Expression<Scalar>*> stack;
755 stack.emplace_back(expr);
756
757 while (!stack.empty()) {
758 auto elem = stack.back();
759 stack.pop_back();
760
761 // Decrement the current node's refcount. If it reaches zero, deallocate the
762 // node and enqueue its children so their refcounts are decremented too.
763 if (--elem->ref_count == 0) {
764 if (elem->adj_expr != nullptr) {
765 stack.emplace_back(elem->adj_expr.get());
766 }
767 elem->visit_args([&stack](const auto& arg) { stack.emplace_back(arg); });
768
769 // Not calling the destructor here is safe because it only decrements
770 // refcounts, which was already done above.
771 if constexpr (USE_POOL_ALLOCATOR) {
772 auto alloc = global_pool_allocator<Expression<Scalar>>();
773 std::allocator_traits<decltype(alloc)>::deallocate(alloc, elem, 1);
774 } else {
775 operator delete(elem);
776 }
777 }
778 }
779}
780
784template <typename Scalar>
788
792 explicit constexpr AbsExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
793
795 function_ref<void(Expression<Scalar>* arg)> func) const override {
796 func(x.get());
797 }
798
799 Scalar value() const override {
800 using std::abs;
801 return abs(x->val);
802 }
803
804 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
805
806 std::string_view name() const override { return "abs"; }
807
808 void accumulate_adjoints() const override { x->adj += grad_l(); }
809
810 void accumulate_adjoints_expr() const override {
811 x->adj_expr += grad_expr_l();
812 }
813
814 private:
815 Scalar grad_l() const {
816 if (x->val < Scalar(0)) {
817 return -this->adj;
818 } else if (x->val > Scalar(0)) {
819 return this->adj;
820 } else {
821 return Scalar(0);
822 }
823 }
824
825 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * sign(x); }
826};
827
832template <typename Scalar>
833ExpressionPtr<Scalar> abs(const ExpressionPtr<Scalar>& x) {
834 using enum ExpressionType;
835 using std::abs;
836
837 // Prune expression
838 if (x->is_constant(Scalar(0))) {
839 // Return zero, which x currently is
840 return x;
841 }
842
843 // Evaluate constant
844 if (x->type() == CONSTANT) {
845 return constant_ptr(abs(x->val));
846 }
847
848 return make_expression_ptr<AbsExpression<Scalar>>(x);
849}
850
854template <typename Scalar>
858
863 : x{std::move(x)} {}
864
866 function_ref<void(Expression<Scalar>* arg)> func) const override {
867 func(x.get());
868 }
869
870 Scalar value() const override {
871 using std::acos;
872 return acos(x->val);
873 }
874
875 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
876
877 std::string_view name() const override { return "acos"; }
878
879 void accumulate_adjoints() const override { x->adj += grad_l(); }
880
881 void accumulate_adjoints_expr() const override {
882 x->adj_expr += grad_expr_l();
883 }
884
885 private:
886 Scalar grad_l() const {
887 using std::sqrt;
888 return -this->adj / sqrt(Scalar(1) - x->val * x->val);
889 }
890
891 ExpressionPtr<Scalar> grad_expr_l() const {
892 return -this->adj_expr / sqrt(constant_ptr(Scalar(1)) - x * x);
893 }
894};
895
900template <typename Scalar>
901ExpressionPtr<Scalar> acos(const ExpressionPtr<Scalar>& x) {
902 using enum ExpressionType;
903 using std::acos;
904
905 // Prune expression
906 if (x->is_constant(Scalar(0))) {
907 return constant_ptr(Scalar(std::numbers::pi) / Scalar(2));
908 }
909
910 // Evaluate constant
911 if (x->type() == CONSTANT) {
912 return constant_ptr(acos(x->val));
913 }
914
915 return make_expression_ptr<AcosExpression<Scalar>>(x);
916}
917
921template <typename Scalar>
925
930 : x{std::move(x)} {}
931
933 function_ref<void(Expression<Scalar>* arg)> func) const override {
934 func(x.get());
935 }
936
937 Scalar value() const override {
938 using std::asin;
939 return asin(x->val);
940 }
941
942 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
943
944 std::string_view name() const override { return "asin"; }
945
946 void accumulate_adjoints() const override { x->adj += grad_l(); }
947
948 void accumulate_adjoints_expr() const override {
949 x->adj_expr += grad_expr_l();
950 }
951
952 private:
953 Scalar grad_l() const {
954 using std::sqrt;
955 return this->adj / sqrt(Scalar(1) - x->val * x->val);
956 }
957
958 ExpressionPtr<Scalar> grad_expr_l() const {
959 return this->adj_expr / sqrt(constant_ptr(Scalar(1)) - x * x);
960 }
961};
962
967template <typename Scalar>
968ExpressionPtr<Scalar> asin(const ExpressionPtr<Scalar>& x) {
969 using enum ExpressionType;
970 using std::asin;
971
972 // Prune expression
973 if (x->is_constant(Scalar(0))) {
974 // Return zero, which x currently is
975 return x;
976 }
977
978 // Evaluate constant
979 if (x->type() == CONSTANT) {
980 return constant_ptr(asin(x->val));
981 }
982
983 return make_expression_ptr<AsinExpression<Scalar>>(x);
984}
985
989template <typename Scalar>
993
998 : x{std::move(x)} {}
999
1001 function_ref<void(Expression<Scalar>* arg)> func) const override {
1002 func(x.get());
1003 }
1004
1005 Scalar value() const override {
1006 using std::atan;
1007 return atan(x->val);
1008 }
1009
1010 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1011
1012 std::string_view name() const override { return "atan"; }
1013
1014 void accumulate_adjoints() const override { x->adj += grad_l(); }
1015
1016 void accumulate_adjoints_expr() const override {
1017 x->adj_expr += grad_expr_l();
1018 }
1019
1020 private:
1021 Scalar grad_l() const { return this->adj / (Scalar(1) + x->val * x->val); }
1022
1023 ExpressionPtr<Scalar> grad_expr_l() const {
1024 return this->adj_expr / (constant_ptr(Scalar(1)) + x * x);
1025 }
1026};
1027
1032template <typename Scalar>
1033ExpressionPtr<Scalar> atan(const ExpressionPtr<Scalar>& x) {
1034 using enum ExpressionType;
1035 using std::atan;
1036
1037 // Prune expression
1038 if (x->is_constant(Scalar(0))) {
1039 // Return zero, which x currently is
1040 return x;
1041 }
1042
1043 // Evaluate constant
1044 if (x->type() == CONSTANT) {
1045 return constant_ptr(atan(x->val));
1046 }
1047
1048 return make_expression_ptr<AtanExpression<Scalar>>(x);
1049}
1050
1054template <typename Scalar>
1058
1061
1068
1070 function_ref<void(Expression<Scalar>* arg)> func) const override {
1071 func(y.get());
1072 func(x.get());
1073 }
1074
1075 Scalar value() const override {
1076 using std::atan2;
1077 return atan2(y->val, x->val);
1078 }
1079
1080 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1081
1082 std::string_view name() const override { return "atan2"; }
1083
1084 void accumulate_adjoints() const override {
1085 y->adj += grad_l();
1086 x->adj += grad_r();
1087 }
1088
1089 void accumulate_adjoints_expr() const override {
1090 y->adj_expr += grad_expr_l();
1091 x->adj_expr += grad_expr_r();
1092 }
1093
1094 private:
1095 Scalar grad_l() const {
1096 return this->adj * x->val / (y->val * y->val + x->val * x->val);
1097 }
1098
1099 Scalar grad_r() const {
1100 return this->adj * -y->val / (y->val * y->val + x->val * x->val);
1101 }
1102
1103 ExpressionPtr<Scalar> grad_expr_l() const {
1104 return this->adj_expr * x / (y * y + x * x);
1105 }
1106
1107 ExpressionPtr<Scalar> grad_expr_r() const {
1108 return this->adj_expr * -y / (y * y + x * x);
1109 }
1110};
1111
1117template <typename Scalar>
1118ExpressionPtr<Scalar> atan2(const ExpressionPtr<Scalar>& y,
1119 const ExpressionPtr<Scalar>& x) {
1120 using enum ExpressionType;
1121 using std::atan2;
1122
1123 // Evaluate constant
1124 if (y->type() == CONSTANT && x->type() == CONSTANT) {
1125 return constant_ptr(atan2(y->val, x->val));
1126 }
1127
1128 return make_expression_ptr<Atan2Expression<Scalar>>(y, x);
1129}
1130
1134template <typename Scalar>
1138
1142 explicit constexpr CosExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
1143
1145 function_ref<void(Expression<Scalar>* arg)> func) const override {
1146 func(x.get());
1147 }
1148
1149 Scalar value() const override {
1150 using std::cos;
1151 return cos(x->val);
1152 }
1153
1154 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1155
1156 std::string_view name() const override { return "cos"; }
1157
1158 void accumulate_adjoints() const override { x->adj += grad_l(); }
1159
1160 void accumulate_adjoints_expr() const override {
1161 x->adj_expr += grad_expr_l();
1162 }
1163
1164 private:
1165 Scalar grad_l() const {
1166 using std::sin;
1167 return this->adj * -sin(x->val);
1168 }
1169
1170 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * -sin(x); }
1171};
1172
1177template <typename Scalar>
1178ExpressionPtr<Scalar> cos(const ExpressionPtr<Scalar>& x) {
1179 using enum ExpressionType;
1180 using std::cos;
1181
1182 // Prune expression
1183 if (x->is_constant(Scalar(0))) {
1184 return constant_ptr(Scalar(1));
1185 }
1186
1187 // Evaluate constant
1188 if (x->type() == CONSTANT) {
1189 return constant_ptr(cos(x->val));
1190 }
1191
1192 return make_expression_ptr<CosExpression<Scalar>>(x);
1193}
1194
1198template <typename Scalar>
1202
1207 : x{std::move(x)} {}
1208
1210 function_ref<void(Expression<Scalar>* arg)> func) const override {
1211 func(x.get());
1212 }
1213
1214 Scalar value() const override {
1215 using std::cosh;
1216 return cosh(x->val);
1217 }
1218
1219 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1220
1221 std::string_view name() const override { return "cosh"; }
1222
1223 void accumulate_adjoints() const override { x->adj += grad_l(); }
1224
1225 void accumulate_adjoints_expr() const override {
1226 x->adj_expr += grad_expr_l();
1227 }
1228
1229 private:
1230 Scalar grad_l() const {
1231 using std::sinh;
1232 return this->adj * sinh(x->val);
1233 }
1234
1235 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * sinh(x); }
1236};
1237
1242template <typename Scalar>
1243ExpressionPtr<Scalar> cosh(const ExpressionPtr<Scalar>& x) {
1244 using enum ExpressionType;
1245 using std::cosh;
1246
1247 // Prune expression
1248 if (x->is_constant(Scalar(0))) {
1249 return constant_ptr(Scalar(1));
1250 }
1251
1252 // Evaluate constant
1253 if (x->type() == CONSTANT) {
1254 return constant_ptr(cosh(x->val));
1255 }
1256
1257 return make_expression_ptr<CoshExpression<Scalar>>(x);
1258}
1259
1263template <typename Scalar>
1267
1271 explicit constexpr ErfExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
1272
1274 function_ref<void(Expression<Scalar>* arg)> func) const override {
1275 func(x.get());
1276 }
1277
1278 Scalar value() const override {
1279 using std::erf;
1280 return erf(x->val);
1281 }
1282
1283 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1284
1285 std::string_view name() const override { return "erf"; }
1286
1287 void accumulate_adjoints() const override { x->adj += grad_l(); }
1288
1289 void accumulate_adjoints_expr() const override {
1290 x->adj_expr += grad_expr_l();
1291 }
1292
1293 private:
1294 Scalar grad_l() const {
1295 using std::exp;
1296 return this->adj * Scalar(2.0 * std::numbers::inv_sqrtpi) *
1297 exp(-x->val * x->val);
1298 }
1299
1300 ExpressionPtr<Scalar> grad_expr_l() const {
1301 return this->adj_expr *
1302 constant_ptr(Scalar(2.0 * std::numbers::inv_sqrtpi)) * exp(-x * x);
1303 }
1304};
1305
1310template <typename Scalar>
1311ExpressionPtr<Scalar> erf(const ExpressionPtr<Scalar>& x) {
1312 using enum ExpressionType;
1313 using std::erf;
1314
1315 // Prune expression
1316 if (x->is_constant(Scalar(0))) {
1317 // Return zero, which x currently is
1318 return x;
1319 }
1320
1321 // Evaluate constant
1322 if (x->type() == CONSTANT) {
1323 return constant_ptr(erf(x->val));
1324 }
1325
1326 return make_expression_ptr<ErfExpression<Scalar>>(x);
1327}
1328
1332template <typename Scalar>
1336
1340 explicit constexpr ExpExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
1341
1343 function_ref<void(Expression<Scalar>* arg)> func) const override {
1344 func(x.get());
1345 }
1346
1347 Scalar value() const override {
1348 using std::exp;
1349 return exp(x->val);
1350 }
1351
1352 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1353
1354 std::string_view name() const override { return "exp"; }
1355
1356 void accumulate_adjoints() const override { x->adj += grad_l(); }
1357
1358 void accumulate_adjoints_expr() const override {
1359 x->adj_expr += grad_expr_l();
1360 }
1361
1362 private:
1363 Scalar grad_l() const {
1364 using std::exp;
1365 return this->adj * exp(x->val);
1366 }
1367
1368 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * exp(x); }
1369};
1370
1375template <typename Scalar>
1376ExpressionPtr<Scalar> exp(const ExpressionPtr<Scalar>& x) {
1377 using enum ExpressionType;
1378 using std::exp;
1379
1380 // Prune expression
1381 if (x->is_constant(Scalar(0))) {
1382 return constant_ptr(Scalar(1));
1383 }
1384
1385 // Evaluate constant
1386 if (x->type() == CONSTANT) {
1387 return constant_ptr(exp(x->val));
1388 }
1389
1390 return make_expression_ptr<ExpExpression<Scalar>>(x);
1391}
1392
1393template <typename Scalar>
1394ExpressionPtr<Scalar> hypot(const ExpressionPtr<Scalar>& x,
1395 const ExpressionPtr<Scalar>& y);
1396
1400template <typename Scalar>
1404
1407
1414
1416 function_ref<void(Expression<Scalar>* arg)> func) const override {
1417 func(x.get());
1418 func(y.get());
1419 }
1420
1421 Scalar value() const override {
1422 using std::hypot;
1423 return hypot(x->val, y->val);
1424 }
1425
1426 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1427
1428 std::string_view name() const override { return "hypot"; }
1429
1430 void accumulate_adjoints() const override {
1431 using std::hypot;
1432 Scalar norm = hypot(x->val, y->val);
1433 x->adj += this->adj * x->val / norm;
1434 y->adj += this->adj * y->val / norm;
1435 }
1436
1437 void accumulate_adjoints_expr() const override {
1438 auto norm = hypot(x, y);
1439 x->adj_expr += this->adj_expr * x / norm;
1440 y->adj_expr += this->adj_expr * y / norm;
1441 }
1442};
1443
1449template <typename Scalar>
1451 const ExpressionPtr<Scalar>& y) {
1452 using enum ExpressionType;
1453 using std::hypot;
1454
1455 // Prune expression
1456 if (x->is_constant(Scalar(0))) {
1457 return abs(y);
1458 } else if (y->is_constant(Scalar(0))) {
1459 return abs(x);
1460 }
1461
1462 // Evaluate constant
1463 if (x->type() == CONSTANT && y->type() == CONSTANT) {
1464 return constant_ptr(hypot(x->val, y->val));
1465 }
1466
1467 return make_expression_ptr<Hypot2Expression<Scalar>>(x, y);
1468}
1469
1470template <typename Scalar>
1471ExpressionPtr<Scalar> hypot(const ExpressionPtr<Scalar>& x,
1472 const ExpressionPtr<Scalar>& y,
1473 const ExpressionPtr<Scalar>& z);
1474
1478template <typename Scalar>
1482
1485
1488
1497
1499 function_ref<void(Expression<Scalar>* arg)> func) const override {
1500 func(x.get());
1501 func(y.get());
1502 func(z.get());
1503 }
1504
1505 Scalar value() const override {
1506 using std::hypot;
1507 return hypot(x->val, y->val, z->val);
1508 }
1509
1510 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1511
1512 std::string_view name() const override { return "hypot"; }
1513
1514 void accumulate_adjoints() const override {
1515 using std::hypot;
1516 Scalar norm = hypot(x->val, y->val, z->val);
1517 x->adj += this->adj * x->val / norm;
1518 y->adj += this->adj * y->val / norm;
1519 z->adj += this->adj * z->val / norm;
1520 }
1521
1522 void accumulate_adjoints_expr() const override {
1523 auto norm = hypot(x, y, z);
1524 x->adj_expr += this->adj_expr * x / norm;
1525 y->adj_expr += this->adj_expr * y / norm;
1526 z->adj_expr += this->adj_expr * z / norm;
1527 }
1528};
1529
1536template <typename Scalar>
1538 const ExpressionPtr<Scalar>& y,
1539 const ExpressionPtr<Scalar>& z) {
1540 using enum ExpressionType;
1541 using std::hypot;
1542
1543 // Prune expression
1544 if (x->is_constant(Scalar(0))) {
1545 return hypot(y, z);
1546 } else if (y->is_constant(Scalar(0))) {
1547 return hypot(x, z);
1548 } else if (z->is_constant(Scalar(0))) {
1549 return hypot(x, y);
1550 }
1551
1552 // Evaluate constant
1553 if (x->type() == CONSTANT && y->type() == CONSTANT && z->type() == CONSTANT) {
1554 return constant_ptr(hypot(x->val, y->val, z->val));
1555 }
1556
1557 return make_expression_ptr<Hypot3Expression<Scalar>>(x, y, z);
1558}
1559
1565template <typename Scalar>
1569
1572
1575
1578
1581
1589 constexpr IfElseExpression(bool (*cond)(Scalar a, Scalar b),
1592 : cond{cond},
1593 a{std::move(a)},
1594 b{std::move(b)},
1595 t{std::move(t)},
1596 f{std::move(f)} {}
1597
1599 function_ref<void(Expression<Scalar>* arg)> func) const override {
1600 func(a.get());
1601 func(b.get());
1602 func(t.get());
1603 func(f.get());
1604 }
1605
1606 Scalar value() const override {
1607 return cond(a->val, b->val) ? t->val : f->val;
1608 }
1609
1610 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1611
1612 std::string_view name() const override { return "if-else"; }
1613
1614 // a and b have zero gradient, so only t and f accumulate adjoints
1615 void accumulate_adjoints() const override {
1616 if (cond(a->val, b->val)) {
1617 t->adj += this->adj;
1618 } else {
1619 f->adj += this->adj;
1620 }
1621 }
1622
1623 void accumulate_adjoints_expr() const override {
1624 t->adj_expr += grad_expr_t();
1625 f->adj_expr += grad_expr_f();
1626 }
1627
1628 private:
1629 ExpressionPtr<Scalar> grad_expr_t() const {
1630 // adjoint if cond(a, b), otherwise 0
1631 return if_else(cond, a, b, this->adj_expr, constant_ptr(Scalar(0)));
1632 }
1633
1634 ExpressionPtr<Scalar> grad_expr_f() const {
1635 // 0 if cond(a, b), otherwise adjoint
1636 return if_else(cond, a, b, constant_ptr(Scalar(0)), this->adj_expr);
1637 }
1638};
1639
1648template <typename Scalar>
1649ExpressionPtr<Scalar> if_else(
1650 std::type_identity_t<bool (*)(Scalar a, Scalar b)> cond,
1651 const ExpressionPtr<Scalar>& a, const ExpressionPtr<Scalar>& b,
1652 const ExpressionPtr<Scalar>& t, const ExpressionPtr<Scalar>& f) {
1653 using enum ExpressionType;
1654
1655 // Prune expression
1656 if (t == f) {
1657 // Return t, which both branches currently are
1658 return t;
1659 } else if (t->type() == CONSTANT && f->type() == CONSTANT &&
1660 t->val == f->val) {
1661 // Return t, which both branches currently equal
1662 return t;
1663 }
1664
1665 // Evaluate constant condition
1666 if (a->type() == CONSTANT && b->type() == CONSTANT) {
1667 return cond(a->val, b->val) ? t : f;
1668 }
1669
1670 return make_expression_ptr<IfElseExpression<Scalar>>(cond, a, b, t, f);
1671}
1672
1676template <typename Scalar>
1680
1684 explicit constexpr LogExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
1685
1687 function_ref<void(Expression<Scalar>* arg)> func) const override {
1688 func(x.get());
1689 }
1690
1691 Scalar value() const override {
1692 using std::log;
1693 return log(x->val);
1694 }
1695
1696 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1697
1698 std::string_view name() const override { return "log"; }
1699
1700 void accumulate_adjoints() const override { x->adj += grad_l(); }
1701
1702 void accumulate_adjoints_expr() const override {
1703 x->adj_expr += grad_expr_l();
1704 }
1705
1706 private:
1707 Scalar grad_l() const { return this->adj / x->val; }
1708
1709 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr / x; }
1710};
1711
1716template <typename Scalar>
1717ExpressionPtr<Scalar> log(const ExpressionPtr<Scalar>& x) {
1718 using enum ExpressionType;
1719 using std::log;
1720
1721 // Prune expression
1722 if (x->is_constant(Scalar(0))) {
1723 // Return zero, which x currently is
1724 return x;
1725 }
1726
1727 // Evaluate constant
1728 if (x->type() == CONSTANT) {
1729 return constant_ptr(log(x->val));
1730 }
1731
1732 return make_expression_ptr<LogExpression<Scalar>>(x);
1733}
1734
1738template <typename Scalar>
1742
1747 : x{std::move(x)} {}
1748
1750 function_ref<void(Expression<Scalar>* arg)> func) const override {
1751 func(x.get());
1752 }
1753
1754 Scalar value() const override {
1755 using std::log10;
1756 return log10(x->val);
1757 }
1758
1759 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1760
1761 std::string_view name() const override { return "log10"; }
1762
1763 void accumulate_adjoints() const override { x->adj += grad_l(); }
1764
1765 void accumulate_adjoints_expr() const override {
1766 x->adj_expr += grad_expr_l();
1767 }
1768
1769 private:
1770 Scalar grad_l() const {
1771 return this->adj / (Scalar(std::numbers::ln10) * x->val);
1772 }
1773
1774 ExpressionPtr<Scalar> grad_expr_l() const {
1775 return this->adj_expr / (constant_ptr(Scalar(std::numbers::ln10)) * x);
1776 }
1777};
1778
1783template <typename Scalar>
1784ExpressionPtr<Scalar> log10(const ExpressionPtr<Scalar>& x) {
1785 using enum ExpressionType;
1786 using std::log10;
1787
1788 // Prune expression
1789 if (x->is_constant(Scalar(0))) {
1790 // Return zero, which x currently is
1791 return x;
1792 }
1793
1794 // Evaluate constant
1795 if (x->type() == CONSTANT) {
1796 return constant_ptr(log10(x->val));
1797 }
1798
1799 return make_expression_ptr<Log10Expression<Scalar>>(x);
1800}
1801
1807template <typename Scalar>
1811
1814
1821
1823 function_ref<void(Expression<Scalar>* arg)> func) const override {
1824 func(a.get());
1825 func(b.get());
1826 }
1827
1828 Scalar value() const override {
1829 using std::max;
1830 return max(a->val, b->val);
1831 }
1832
1833 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1834
1835 std::string_view name() const override { return "max"; }
1836
1837 void accumulate_adjoints() const override {
1838 a->adj += grad_l();
1839 b->adj += grad_r();
1840 }
1841
1842 void accumulate_adjoints_expr() const override {
1843 a->adj_expr += grad_expr_l();
1844 b->adj_expr += grad_expr_r();
1845 }
1846
1847 private:
1848 Scalar grad_l() const { return a->val >= b->val ? this->adj : Scalar(0); }
1849
1850 Scalar grad_r() const { return a->val >= b->val ? Scalar(0) : this->adj; }
1851
1852 ExpressionPtr<Scalar> grad_expr_l() const {
1853 // adjoint if a >= b, otherwise 0
1854 return if_else([](Scalar a, Scalar b) { return a >= b; }, a, b,
1855 this->adj_expr, constant_ptr(Scalar(0)));
1856 }
1857
1858 ExpressionPtr<Scalar> grad_expr_r() const {
1859 // 0 if a >= b, otherwise adjoint
1860 return if_else([](Scalar a, Scalar b) { return a >= b; }, a, b,
1861 constant_ptr(Scalar(0)), this->adj_expr);
1862 }
1863};
1864
1870template <typename Scalar>
1871ExpressionPtr<Scalar> max(const ExpressionPtr<Scalar>& a,
1872 const ExpressionPtr<Scalar>& b) {
1873 using enum ExpressionType;
1874 using std::max;
1875
1876 // Evaluate constant
1877 if (a->type() == CONSTANT && b->type() == CONSTANT) {
1878 return constant_ptr(max(a->val, b->val));
1879 }
1880
1881 return make_expression_ptr<MaxExpression<Scalar>>(a, b);
1882}
1883
1889template <typename Scalar>
1893
1896
1903
1905 function_ref<void(Expression<Scalar>* arg)> func) const override {
1906 func(a.get());
1907 func(b.get());
1908 }
1909
1910 Scalar value() const override {
1911 using std::min;
1912 return min(a->val, b->val);
1913 }
1914
1915 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1916
1917 std::string_view name() const override { return "min"; }
1918
1919 void accumulate_adjoints() const override {
1920 a->adj += grad_l();
1921 b->adj += grad_r();
1922 }
1923
1924 void accumulate_adjoints_expr() const override {
1925 a->adj_expr += grad_expr_l();
1926 b->adj_expr += grad_expr_r();
1927 }
1928
1929 private:
1930 Scalar grad_l() const { return a->val <= b->val ? this->adj : Scalar(0); }
1931
1932 Scalar grad_r() const { return a->val <= b->val ? Scalar(0) : this->adj; }
1933
1934 ExpressionPtr<Scalar> grad_expr_l() const {
1935 // adjoint if a <= b, otherwise 0
1936 return if_else([](Scalar a, Scalar b) { return a <= b; }, a, b,
1937 this->adj_expr, constant_ptr(Scalar(0)));
1938 }
1939
1940 ExpressionPtr<Scalar> grad_expr_r() const {
1941 // 0 if a <= b, otherwise adjoint
1942 return if_else([](Scalar a, Scalar b) { return a <= b; }, a, b,
1943 constant_ptr(Scalar(0)), this->adj_expr);
1944 }
1945};
1946
1952template <typename Scalar>
1953ExpressionPtr<Scalar> min(const ExpressionPtr<Scalar>& a,
1954 const ExpressionPtr<Scalar>& b) {
1955 using enum ExpressionType;
1956 using std::min;
1957
1958 // Evaluate constant
1959 if (a->type() == CONSTANT && b->type() == CONSTANT) {
1960 return constant_ptr(min(a->val, b->val));
1961 }
1962
1963 return make_expression_ptr<MinExpression<Scalar>>(a, b);
1964}
1965
1966template <typename Scalar>
1967ExpressionPtr<Scalar> pow(const ExpressionPtr<Scalar>& base,
1968 const ExpressionPtr<Scalar>& power);
1969
1974template <typename Scalar, ExpressionType T>
1978
1981
1989
1991 function_ref<void(Expression<Scalar>* arg)> func) const override {
1992 func(base.get());
1993 func(power.get());
1994 }
1995
1996 Scalar value() const override {
1997 using std::pow;
1998 return pow(base->val, power->val);
1999 }
2000
2001 ExpressionType type() const override { return T; }
2002
2003 std::string_view name() const override { return "pow"; }
2004
2005 void accumulate_adjoints() const override {
2006 base->adj += grad_l();
2007 power->adj += grad_r();
2008 }
2009
2010 void accumulate_adjoints_expr() const override {
2011 base->adj_expr += grad_expr_l();
2012 power->adj_expr += grad_expr_r();
2013 }
2014
2015 private:
2016 Scalar grad_l() const {
2017 using std::pow;
2018 return this->adj * pow(base->val, power->val - Scalar(1)) * power->val;
2019 }
2020
2021 Scalar grad_r() const {
2022 using std::log;
2023 using std::pow;
2024
2025 return this->adj * pow(base->val, power->val) * log(base->val);
2026 }
2027
2028 ExpressionPtr<Scalar> grad_expr_l() const {
2029 return this->adj_expr * pow(base, power - constant_ptr(Scalar(1))) * power;
2030 }
2031
2032 ExpressionPtr<Scalar> grad_expr_r() const {
2033 return this->adj_expr * pow(base, power) * log(base);
2034 }
2035};
2036
2042template <typename Scalar>
2043ExpressionPtr<Scalar> pow(const ExpressionPtr<Scalar>& base,
2044 const ExpressionPtr<Scalar>& power) {
2045 using enum ExpressionType;
2046 using std::pow;
2047
2048 // Prune expression
2049 if (base->is_constant(Scalar(0))) {
2050 // Return zero, which base currently is
2051 return base;
2052 } else if (base->is_constant(Scalar(1))) {
2053 // Return one, which base currently is
2054 return base;
2055 }
2056 if (power->is_constant(Scalar(0))) {
2057 return constant_ptr(Scalar(1));
2058 } else if (power->is_constant(Scalar(1))) {
2059 // Return base unmodified
2060 return base;
2061 }
2062
2063 // Evaluate constant
2064 if (base->type() == CONSTANT && power->type() == CONSTANT) {
2065 return constant_ptr(pow(base->val, power->val));
2066 }
2067
2068 if (power->is_constant(Scalar(2))) {
2069 if (base->type() == LINEAR) {
2070 return make_expression_ptr<MultExpression<Scalar, QUADRATIC>>(base, base);
2071 } else {
2072 return make_expression_ptr<MultExpression<Scalar, NONLINEAR>>(base, base);
2073 }
2074 }
2075
2076 return make_expression_ptr<PowExpression<Scalar, NONLINEAR>>(base, power);
2077}
2078
2082template <typename Scalar>
2086
2091 : x{std::move(x)} {}
2092
2094 function_ref<void(Expression<Scalar>* arg)> func) const override {
2095 func(x.get());
2096 }
2097
2098 Scalar value() const override {
2099 if (x->val < Scalar(0)) {
2100 return Scalar(-1);
2101 } else if (x->val == Scalar(0)) {
2102 return Scalar(0);
2103 } else {
2104 return Scalar(1);
2105 }
2106 }
2107
2108 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2109
2110 std::string_view name() const override { return "sign"; }
2111};
2112
2117template <typename Scalar>
2119 using enum ExpressionType;
2120
2121 // Evaluate constant
2122 if (x->type() == CONSTANT) {
2123 if (x->val < Scalar(0)) {
2124 return constant_ptr(Scalar(-1));
2125 } else if (x->val == Scalar(0)) {
2126 // Return zero
2127 return x;
2128 } else {
2129 return constant_ptr(Scalar(1));
2130 }
2131 }
2132
2133 return make_expression_ptr<SignExpression<Scalar>>(x);
2134}
2135
2139template <typename Scalar>
2143
2147 explicit constexpr SinExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
2148
2150 function_ref<void(Expression<Scalar>* arg)> func) const override {
2151 func(x.get());
2152 }
2153
2154 Scalar value() const override {
2155 using std::sin;
2156 return sin(x->val);
2157 }
2158
2159 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2160
2161 std::string_view name() const override { return "sin"; }
2162
2163 void accumulate_adjoints() const override { x->adj += grad_l(); }
2164
2165 void accumulate_adjoints_expr() const override {
2166 x->adj_expr += grad_expr_l();
2167 }
2168
2169 private:
2170 Scalar grad_l() const {
2171 using std::cos;
2172 return this->adj * cos(x->val);
2173 }
2174
2175 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * cos(x); }
2176};
2177
2182template <typename Scalar>
2183ExpressionPtr<Scalar> sin(const ExpressionPtr<Scalar>& x) {
2184 using enum ExpressionType;
2185 using std::sin;
2186
2187 // Prune expression
2188 if (x->is_constant(Scalar(0))) {
2189 // Return zero, which x currently is
2190 return x;
2191 }
2192
2193 // Evaluate constant
2194 if (x->type() == CONSTANT) {
2195 return constant_ptr(sin(x->val));
2196 }
2197
2198 return make_expression_ptr<SinExpression<Scalar>>(x);
2199}
2200
2204template <typename Scalar>
2208
2213 : x{std::move(x)} {}
2214
2216 function_ref<void(Expression<Scalar>* arg)> func) const override {
2217 func(x.get());
2218 }
2219
2220 Scalar value() const override {
2221 using std::sinh;
2222 return sinh(x->val);
2223 }
2224
2225 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2226
2227 std::string_view name() const override { return "sinh"; }
2228
2229 void accumulate_adjoints() const override { x->adj += grad_l(); }
2230
2231 void accumulate_adjoints_expr() const override {
2232 x->adj_expr += grad_expr_l();
2233 }
2234
2235 private:
2236 Scalar grad_l() const {
2237 using std::cosh;
2238 return this->adj * cosh(x->val);
2239 }
2240
2241 ExpressionPtr<Scalar> grad_expr_l() const { return this->adj_expr * cosh(x); }
2242};
2243
2248template <typename Scalar>
2249ExpressionPtr<Scalar> sinh(const ExpressionPtr<Scalar>& x) {
2250 using enum ExpressionType;
2251 using std::sinh;
2252
2253 // Prune expression
2254 if (x->is_constant(Scalar(0))) {
2255 // Return zero, which x currently is
2256 return x;
2257 }
2258
2259 // Evaluate constant
2260 if (x->type() == CONSTANT) {
2261 return constant_ptr(sinh(x->val));
2262 }
2263
2264 return make_expression_ptr<SinhExpression<Scalar>>(x);
2265}
2266
2270template <typename Scalar>
2274
2279 : x{std::move(x)} {}
2280
2282 function_ref<void(Expression<Scalar>* arg)> func) const override {
2283 func(x.get());
2284 }
2285
2286 Scalar value() const override {
2287 using std::sqrt;
2288 return sqrt(x->val);
2289 }
2290
2291 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2292
2293 std::string_view name() const override { return "sqrt"; }
2294
2295 void accumulate_adjoints() const override { x->adj += grad_l(); }
2296
2297 void accumulate_adjoints_expr() const override {
2298 x->adj_expr += grad_expr_l();
2299 }
2300
2301 private:
2302 Scalar grad_l() const {
2303 using std::sqrt;
2304 return this->adj / (Scalar(2) * sqrt(x->val));
2305 }
2306
2307 ExpressionPtr<Scalar> grad_expr_l() const {
2308 return this->adj_expr / (constant_ptr(Scalar(2)) * sqrt(x));
2309 }
2310};
2311
2316template <typename Scalar>
2317ExpressionPtr<Scalar> sqrt(const ExpressionPtr<Scalar>& x) {
2318 using enum ExpressionType;
2319 using std::sqrt;
2320
2321 // Evaluate constant
2322 if (x->type() == CONSTANT) {
2323 if (x->val == Scalar(0)) {
2324 // Return zero
2325 return x;
2326 } else if (x->val == Scalar(1)) {
2327 return x;
2328 } else {
2329 return constant_ptr(sqrt(x->val));
2330 }
2331 }
2332
2333 return make_expression_ptr<SqrtExpression<Scalar>>(x);
2334}
2335
2339template <typename Scalar>
2343
2347 explicit constexpr TanExpression(ExpressionPtr<Scalar> x) : x{std::move(x)} {}
2348
2350 function_ref<void(Expression<Scalar>* arg)> func) const override {
2351 func(x.get());
2352 }
2353
2354 Scalar value() const override {
2355 using std::tan;
2356 return tan(x->val);
2357 }
2358
2359 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2360
2361 std::string_view name() const override { return "tan"; }
2362
2363 void accumulate_adjoints() const override { x->adj += grad_l(); }
2364
2365 void accumulate_adjoints_expr() const override {
2366 x->adj_expr += grad_expr_l();
2367 }
2368
2369 private:
2370 Scalar grad_l() const {
2371 using std::cos;
2372
2373 auto c = cos(x->val);
2374 return this->adj / (c * c);
2375 }
2376
2377 ExpressionPtr<Scalar> grad_expr_l() const {
2378 auto c = cos(x);
2379 return this->adj_expr / (c * c);
2380 }
2381};
2382
2387template <typename Scalar>
2388ExpressionPtr<Scalar> tan(const ExpressionPtr<Scalar>& x) {
2389 using enum ExpressionType;
2390 using std::tan;
2391
2392 // Prune expression
2393 if (x->is_constant(Scalar(0))) {
2394 // Return zero, which x currently is
2395 return x;
2396 }
2397
2398 // Evaluate constant
2399 if (x->type() == CONSTANT) {
2400 return constant_ptr(tan(x->val));
2401 }
2402
2403 return make_expression_ptr<TanExpression<Scalar>>(x);
2404}
2405
2409template <typename Scalar>
2413
2418 : x{std::move(x)} {}
2419
2421 function_ref<void(Expression<Scalar>* arg)> func) const override {
2422 func(x.get());
2423 }
2424
2425 Scalar value() const override {
2426 using std::tanh;
2427 return tanh(x->val);
2428 }
2429
2430 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2431
2432 std::string_view name() const override { return "tanh"; }
2433
2434 void accumulate_adjoints() const override { x->adj += grad_l(); }
2435
2436 void accumulate_adjoints_expr() const override {
2437 x->adj_expr += grad_expr_l();
2438 }
2439
2440 private:
2441 Scalar grad_l() const {
2442 using std::cosh;
2443
2444 auto c = cosh(x->val);
2445 return this->adj / (c * c);
2446 }
2447
2448 ExpressionPtr<Scalar> grad_expr_l() const {
2449 auto c = cosh(x);
2450 return this->adj_expr / (c * c);
2451 }
2452};
2453
2458template <typename Scalar>
2459ExpressionPtr<Scalar> tanh(const ExpressionPtr<Scalar>& x) {
2460 using enum ExpressionType;
2461 using std::tanh;
2462
2463 // Prune expression
2464 if (x->is_constant(Scalar(0))) {
2465 // Return zero, which x currently is
2466 return x;
2467 }
2468
2469 // Evaluate constant
2470 if (x->type() == CONSTANT) {
2471 return constant_ptr(tanh(x->val));
2472 }
2473
2474 return make_expression_ptr<TanhExpression<Scalar>>(x);
2475}
2476
2477} // namespace slp::detail
Definition intrusive_shared_ptr.hpp:27
constexpr T * get() const noexcept
Definition intrusive_shared_ptr.hpp:178
Definition function_ref.hpp:13
Definition expression.hpp:785
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:794
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:787
std::string_view name() const override
Definition expression.hpp:806
constexpr AbsExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:792
ExpressionType type() const override
Definition expression.hpp:804
Scalar value() const override
Definition expression.hpp:799
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:808
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:810
Definition expression.hpp:855
constexpr AcosExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:862
ExpressionType type() const override
Definition expression.hpp:875
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:857
Scalar value() const override
Definition expression.hpp:870
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:879
std::string_view name() const override
Definition expression.hpp:877
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:881
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:865
Definition expression.hpp:922
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:948
constexpr AsinExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:929
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:924
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:932
Scalar value() const override
Definition expression.hpp:937
std::string_view name() const override
Definition expression.hpp:944
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:946
ExpressionType type() const override
Definition expression.hpp:942
Definition expression.hpp:1055
constexpr Atan2Expression(ExpressionPtr< Scalar > y, ExpressionPtr< Scalar > x)
Definition expression.hpp:1066
ExpressionPtr< Scalar > y
Binary operator's left operand.
Definition expression.hpp:1057
std::string_view name() const override
Definition expression.hpp:1082
Scalar value() const override
Definition expression.hpp:1075
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1089
ExpressionPtr< Scalar > x
Binary operator's right operand.
Definition expression.hpp:1060
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1084
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1069
ExpressionType type() const override
Definition expression.hpp:1080
Definition expression.hpp:990
std::string_view name() const override
Definition expression.hpp:1012
Scalar value() const override
Definition expression.hpp:1005
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1014
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:992
constexpr AtanExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:997
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1000
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1016
ExpressionType type() const override
Definition expression.hpp:1010
Definition expression.hpp:376
constexpr BinaryMinusExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:387
Scalar value() const override
Definition expression.hpp:397
ExpressionPtr< Scalar > lhs
Binary operator's left operand.
Definition expression.hpp:378
ExpressionPtr< Scalar > rhs
Binary operator's right operand.
Definition expression.hpp:381
std::string_view name() const override
Definition expression.hpp:401
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:403
ExpressionType type() const override
Definition expression.hpp:399
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:391
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:408
Definition expression.hpp:428
ExpressionPtr< Scalar > rhs
Binary operator's right operand.
Definition expression.hpp:433
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:460
ExpressionPtr< Scalar > lhs
Binary operator's left operand.
Definition expression.hpp:430
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:455
constexpr BinaryPlusExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:439
ExpressionType type() const override
Definition expression.hpp:451
Scalar value() const override
Definition expression.hpp:449
std::string_view name() const override
Definition expression.hpp:453
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:443
Definition expression.hpp:479
std::string_view name() const override
Definition expression.hpp:501
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:481
constexpr CbrtExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:486
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:505
ExpressionType type() const override
Definition expression.hpp:499
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:503
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:489
Scalar value() const override
Definition expression.hpp:494
Definition expression.hpp:551
ExpressionType type() const override
Definition expression.hpp:560
Scalar value() const override
Definition expression.hpp:558
std::string_view name() const override
Definition expression.hpp:562
constexpr ConstantExpression(Scalar value)
Definition expression.hpp:555
Definition expression.hpp:1135
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1160
ExpressionType type() const override
Definition expression.hpp:1154
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1144
Scalar value() const override
Definition expression.hpp:1149
std::string_view name() const override
Definition expression.hpp:1156
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1137
constexpr CosExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1142
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1158
Definition expression.hpp:1199
ExpressionType type() const override
Definition expression.hpp:1219
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1209
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1225
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1223
Scalar value() const override
Definition expression.hpp:1214
std::string_view name() const override
Definition expression.hpp:1221
constexpr CoshExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1206
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1201
Definition expression.hpp:574
Scalar value() const override
Definition expression.hpp:584
std::string_view name() const override
Definition expression.hpp:588
constexpr DecisionVariableExpression(Scalar value)
Definition expression.hpp:581
ExpressionType type() const override
Definition expression.hpp:586
constexpr DecisionVariableExpression()
Constructs a decision variable expression with a value of zero.
Definition expression.hpp:576
Definition expression.hpp:596
Scalar value() const override
Definition expression.hpp:616
constexpr DivExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:607
ExpressionPtr< Scalar > lhs
Definition expression.hpp:598
ExpressionType type() const override
Definition expression.hpp:618
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:622
ExpressionPtr< Scalar > rhs
Definition expression.hpp:601
std::string_view name() const override
Definition expression.hpp:620
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:627
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:610
Definition expression.hpp:1264
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1289
std::string_view name() const override
Definition expression.hpp:1285
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1266
Scalar value() const override
Definition expression.hpp:1278
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1273
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1287
ExpressionType type() const override
Definition expression.hpp:1283
constexpr ErfExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1271
Definition expression.hpp:1333
Scalar value() const override
Definition expression.hpp:1347
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1358
constexpr ExpExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1340
std::string_view name() const override
Definition expression.hpp:1354
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1356
ExpressionType type() const override
Definition expression.hpp:1352
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1335
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1342
Definition expression.hpp:80
Scalar val
The value of the expression node.
Definition expression.hpp:85
virtual Scalar value() const =0
ExpressionPtr< Scalar > adj_expr
Definition expression.hpp:92
friend ExpressionPtr< Scalar > operator-(const ExpressionPtr< Scalar > &lhs)
Definition expression.hpp:309
virtual void accumulate_adjoints() const
Accumulates the child adjoints as Scalars.
Definition expression.hpp:365
uint32_t ref_count
Reference count for intrusive shared pointer.
Definition expression.hpp:113
friend ExpressionPtr< Scalar > operator+(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:225
int32_t scratch
Definition expression.hpp:110
constexpr bool is_constant(Scalar constant) const
Definition expression.hpp:129
Scalar adj
The adjoint of the expression node, used during autodiff.
Definition expression.hpp:88
constexpr Expression()=default
Constructs a constant expression with a value of zero.
Scalar_ Scalar
Scalar type alias.
Definition expression.hpp:82
virtual ExpressionType type() const =0
friend ExpressionPtr< Scalar > operator/(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:189
friend ExpressionPtr< Scalar > operator-(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:270
friend ExpressionPtr< Scalar > operator*(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:137
virtual std::string_view name() const =0
bool is_leaf
Definition expression.hpp:99
virtual void accumulate_adjoints_expr() const
Accumulates the child adjoints as Expressions.
Definition expression.hpp:368
virtual void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const
Definition expression.hpp:342
friend ExpressionPtr< Scalar > operator+=(ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:261
constexpr Expression(Scalar value)
Definition expression.hpp:121
friend ExpressionPtr< Scalar > operator+(const ExpressionPtr< Scalar > &lhs)
Definition expression.hpp:335
Definition expression.hpp:1401
constexpr Hypot2Expression(ExpressionPtr< Scalar > x, ExpressionPtr< Scalar > y)
Definition expression.hpp:1412
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1430
ExpressionPtr< Scalar > y
Binary operator's right operand.
Definition expression.hpp:1406
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1437
std::string_view name() const override
Definition expression.hpp:1428
Scalar value() const override
Definition expression.hpp:1421
ExpressionType type() const override
Definition expression.hpp:1426
ExpressionPtr< Scalar > x
Binary operator's left operand.
Definition expression.hpp:1403
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1415
Definition expression.hpp:1479
ExpressionPtr< Scalar > x
Ternary operator's first operand.
Definition expression.hpp:1481
ExpressionPtr< Scalar > y
Ternary operator's second operand.
Definition expression.hpp:1484
constexpr Hypot3Expression(ExpressionPtr< Scalar > x, ExpressionPtr< Scalar > y, ExpressionPtr< Scalar > z)
Definition expression.hpp:1494
std::string_view name() const override
Definition expression.hpp:1512
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1498
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1514
Scalar value() const override
Definition expression.hpp:1505
ExpressionPtr< Scalar > z
Ternary operator's third operand.
Definition expression.hpp:1487
ExpressionType type() const override
Definition expression.hpp:1510
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1522
Definition expression.hpp:1566
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1598
constexpr IfElseExpression(bool(*cond)(Scalar a, Scalar b), ExpressionPtr< Scalar > a, ExpressionPtr< Scalar > b, ExpressionPtr< Scalar > t, ExpressionPtr< Scalar > f)
Definition expression.hpp:1589
ExpressionPtr< Scalar > a
The condition's first argument.
Definition expression.hpp:1571
bool(* cond)(Scalar a, Scalar b)
Condition evaluated on a and b.
Definition expression.hpp:1568
ExpressionPtr< Scalar > b
The condition's second argument.
Definition expression.hpp:1574
ExpressionPtr< Scalar > t
Value selected when cond(a, b) is true.
Definition expression.hpp:1577
std::string_view name() const override
Definition expression.hpp:1612
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1615
ExpressionType type() const override
Definition expression.hpp:1610
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1623
ExpressionPtr< Scalar > f
Value selected when cond(a, b) is false.
Definition expression.hpp:1580
Scalar value() const override
Definition expression.hpp:1606
Definition expression.hpp:1739
std::string_view name() const override
Definition expression.hpp:1761
constexpr Log10Expression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1746
ExpressionType type() const override
Definition expression.hpp:1759
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1765
Scalar value() const override
Definition expression.hpp:1754
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1763
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1749
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1741
Definition expression.hpp:1677
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:1679
Scalar value() const override
Definition expression.hpp:1691
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1702
constexpr LogExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1684
ExpressionType type() const override
Definition expression.hpp:1696
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1686
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1700
std::string_view name() const override
Definition expression.hpp:1698
Definition expression.hpp:1808
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1842
ExpressionPtr< Scalar > b
Binary operator's right operand.
Definition expression.hpp:1813
Scalar value() const override
Definition expression.hpp:1828
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1822
constexpr MaxExpression(ExpressionPtr< Scalar > a, ExpressionPtr< Scalar > b)
Definition expression.hpp:1819
ExpressionPtr< Scalar > a
Binary operator's left operand.
Definition expression.hpp:1810
ExpressionType type() const override
Definition expression.hpp:1833
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1837
std::string_view name() const override
Definition expression.hpp:1835
Definition expression.hpp:1890
std::string_view name() const override
Definition expression.hpp:1917
ExpressionPtr< Scalar > b
Binary operator's right operand.
Definition expression.hpp:1895
ExpressionPtr< Scalar > a
Binary operator's left operand.
Definition expression.hpp:1892
constexpr MinExpression(ExpressionPtr< Scalar > a, ExpressionPtr< Scalar > b)
Definition expression.hpp:1901
ExpressionType type() const override
Definition expression.hpp:1915
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1904
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:1919
Scalar value() const override
Definition expression.hpp:1910
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:1924
Definition expression.hpp:651
ExpressionPtr< Scalar > lhs
Binary operator's left operand.
Definition expression.hpp:653
Scalar value() const override
Definition expression.hpp:671
constexpr MultExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:662
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:677
ExpressionType type() const override
Definition expression.hpp:673
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:682
std::string_view name() const override
Definition expression.hpp:675
ExpressionPtr< Scalar > rhs
Binary operator's right operand.
Definition expression.hpp:656
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:665
Definition expression.hpp:1975
ExpressionPtr< Scalar > base
Binary operator's left operand.
Definition expression.hpp:1977
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2010
constexpr PowExpression(ExpressionPtr< Scalar > base, ExpressionPtr< Scalar > power)
Definition expression.hpp:1986
ExpressionPtr< Scalar > power
Binary operator's right operand.
Definition expression.hpp:1980
ExpressionType type() const override
Definition expression.hpp:2001
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2005
Scalar value() const override
Definition expression.hpp:1996
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:1990
std::string_view name() const override
Definition expression.hpp:2003
Definition expression.hpp:2083
constexpr SignExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2090
Scalar value() const override
Definition expression.hpp:2098
ExpressionType type() const override
Definition expression.hpp:2108
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2093
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2085
std::string_view name() const override
Definition expression.hpp:2110
Definition expression.hpp:2140
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2149
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2163
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2142
std::string_view name() const override
Definition expression.hpp:2161
Scalar value() const override
Definition expression.hpp:2154
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2165
ExpressionType type() const override
Definition expression.hpp:2159
constexpr SinExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2147
Definition expression.hpp:2205
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2215
std::string_view name() const override
Definition expression.hpp:2227
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2207
ExpressionType type() const override
Definition expression.hpp:2225
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2231
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2229
constexpr SinhExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2212
Scalar value() const override
Definition expression.hpp:2220
Definition expression.hpp:2271
ExpressionType type() const override
Definition expression.hpp:2291
constexpr SqrtExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2278
std::string_view name() const override
Definition expression.hpp:2293
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2297
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2281
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2295
Scalar value() const override
Definition expression.hpp:2286
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2273
Definition expression.hpp:2340
constexpr TanExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2347
Scalar value() const override
Definition expression.hpp:2354
std::string_view name() const override
Definition expression.hpp:2361
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2365
ExpressionType type() const override
Definition expression.hpp:2359
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2363
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2349
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2342
Definition expression.hpp:2410
ExpressionPtr< Scalar > x
Unary operator's operand.
Definition expression.hpp:2412
Scalar value() const override
Definition expression.hpp:2425
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:2436
ExpressionType type() const override
Definition expression.hpp:2430
std::string_view name() const override
Definition expression.hpp:2432
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:2420
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:2434
constexpr TanhExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:2417
Definition expression.hpp:702
constexpr UnaryMinusExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:709
void accumulate_adjoints() const override
Accumulates the child adjoints as Scalars.
Definition expression.hpp:723
ExpressionType type() const override
Definition expression.hpp:719
void visit_args(function_ref< void(Expression< Scalar > *arg)> func) const override
Definition expression.hpp:712
void accumulate_adjoints_expr() const override
Accumulates the child adjoints as Expressions.
Definition expression.hpp:725
ExpressionPtr< Scalar > lhs
Unary operator's operand.
Definition expression.hpp:704
Scalar value() const override
Definition expression.hpp:717
std::string_view name() const override
Definition expression.hpp:721