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 <array>
9#include <cmath>
10#include <memory>
11#include <numbers>
12#include <string_view>
13#include <utility>
14
15#include <gch/small_vector.hpp>
16
17#include "sleipnir/autodiff/expression_type.hpp"
18#include "sleipnir/util/intrusive_shared_ptr.hpp"
19#include "sleipnir/util/pool.hpp"
20
21namespace slp::detail {
22
23// The global pool allocator uses a thread-local static pool resource, which
24// isn't guaranteed to be initialized properly across DLL boundaries on Windows
25#ifdef _WIN32
26inline constexpr bool USE_POOL_ALLOCATOR = false;
27#else
28inline constexpr bool USE_POOL_ALLOCATOR = true;
29#endif
30
31template <typename Scalar>
32struct Expression;
33
34template <typename Scalar>
35constexpr void inc_ref_count(Expression<Scalar>* expr);
36template <typename Scalar>
37constexpr void dec_ref_count(Expression<Scalar>* expr);
38
42template <typename Scalar>
43using ExpressionPtr = IntrusiveSharedPtr<Expression<Scalar>>;
44
50template <typename T, typename... Args>
51static ExpressionPtr<typename T::Scalar> make_expression_ptr(Args&&... args) {
52 if constexpr (USE_POOL_ALLOCATOR) {
53 return allocate_intrusive_shared<T>(global_pool_allocator<T>(),
54 std::forward<Args>(args)...);
55 } else {
56 return make_intrusive_shared<T>(std::forward<Args>(args)...);
57 }
58}
59
60template <typename Scalar, ExpressionType T>
61struct BinaryMinusExpression;
62
63template <typename Scalar, ExpressionType T>
64struct BinaryPlusExpression;
65
66template <typename Scalar>
67struct ConstantExpression;
68
69template <typename Scalar, ExpressionType T>
70struct DivExpression;
71
72template <typename Scalar, ExpressionType T>
73struct MultExpression;
74
75template <typename Scalar, ExpressionType T>
76struct UnaryMinusExpression;
77
82template <typename Scalar>
83ExpressionPtr<Scalar> constant_ptr(Scalar value);
84
88template <typename Scalar_>
89struct Expression {
91 using Scalar = Scalar_;
92
95
98
102
104 std::array<ExpressionPtr<Scalar>, 2> args{nullptr, nullptr};
105
116
119
121 constexpr Expression() = default;
122
126 explicit constexpr Expression(Scalar value) : val{value} {}
127
132 : args{std::move(lhs), nullptr} {}
133
140
141 virtual ~Expression() = default;
142
147 constexpr bool is_constant(Scalar constant) const {
148 return type() == ExpressionType::CONSTANT && val == constant;
149 }
150
156 const ExpressionPtr<Scalar>& rhs) {
157 using enum ExpressionType;
158
159 // Prune expression
160 if (lhs->is_constant(Scalar(0))) {
161 // Return zero, which lhs currently is
162 return lhs;
163 } else if (rhs->is_constant(Scalar(0))) {
164 // Return zero, which rhs currently is
165 return rhs;
166 } else if (lhs->is_constant(Scalar(1))) {
167 // Return rhs unmodified
168 return rhs;
169 } else if (rhs->is_constant(Scalar(1))) {
170 // Return lhs unmodified
171 return lhs;
172 }
173
174 // Evaluate constant
175 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
176 return constant_ptr(lhs->val * rhs->val);
177 }
178
179 // Evaluate expression type
180 if (lhs->type() == CONSTANT) {
181 if (rhs->type() == LINEAR) {
183 } else if (rhs->type() == QUADRATIC) {
185 } else {
187 }
188 } else if (rhs->type() == CONSTANT) {
189 if (lhs->type() == LINEAR) {
191 } else if (lhs->type() == QUADRATIC) {
193 } else {
195 }
196 } else if (lhs->type() == LINEAR && rhs->type() == LINEAR) {
198 } else {
200 }
201 }
202
208 const ExpressionPtr<Scalar>& rhs) {
209 using enum ExpressionType;
210
211 // Prune expression
212 if (lhs->is_constant(Scalar(0))) {
213 // Return zero, which lhs currently is
214 return lhs;
215 } else if (rhs->is_constant(Scalar(1))) {
216 // Return lhs unmodified
217 return lhs;
218 }
219
220 // Evaluate constant
221 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
222 return constant_ptr(lhs->val / rhs->val);
223 }
224
225 // Evaluate expression type
226 if (rhs->type() == CONSTANT) {
227 if (lhs->type() == LINEAR) {
229 } else if (lhs->type() == QUADRATIC) {
231 } else {
233 }
234 } else {
236 }
237 }
238
244 const ExpressionPtr<Scalar>& rhs) {
245 using enum ExpressionType;
246
247 // Prune expression. We check for nullptr because operator+ is used in
248 // adjoint accumulation, and child nodes can be null.
249 if (lhs == nullptr || lhs->is_constant(Scalar(0))) {
250 // Return rhs unmodified
251 return rhs;
252 } else if (rhs == nullptr || rhs->is_constant(Scalar(0))) {
253 // Return lhs unmodified
254 return lhs;
255 }
256
257 // Evaluate constant
258 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
259 return constant_ptr(lhs->val + rhs->val);
260 }
261
262 auto type = std::max(lhs->type(), rhs->type());
263 if (type == LINEAR) {
265 rhs);
266 } else if (type == QUADRATIC) {
268 rhs);
269 } else {
271 rhs);
272 }
273 }
274
283
289 const ExpressionPtr<Scalar>& rhs) {
290 using enum ExpressionType;
291
292 // Prune expression
293 if (lhs->is_constant(Scalar(0))) {
294 if (rhs->is_constant(Scalar(0))) {
295 // Return zero, which rhs currently is
296 return rhs;
297 } else {
298 // Return rhs negated
299 return -rhs;
300 }
301 } else if (rhs->is_constant(Scalar(0))) {
302 // Return lhs unmodified
303 return lhs;
304 }
305
306 // Evaluate constant
307 if (lhs->type() == CONSTANT && rhs->type() == CONSTANT) {
308 return constant_ptr(lhs->val - rhs->val);
309 }
310
311 auto type = std::max(lhs->type(), rhs->type());
312 if (type == LINEAR) {
314 rhs);
315 } else if (type == QUADRATIC) {
317 rhs);
318 } else {
320 rhs);
321 }
322 }
323
328 using enum ExpressionType;
329
330 // Prune expression
331 if (lhs->is_constant(Scalar(0))) {
332 // Return zero, which lhs currently is
333 return lhs;
334 }
335
336 // Evaluate constant
337 if (lhs->type() == CONSTANT) {
338 return constant_ptr(-lhs->val);
339 }
340
341 if (lhs->type() == LINEAR) {
343 } else if (lhs->type() == QUADRATIC) {
345 } else {
347 }
348 }
349
354 return lhs;
355 }
356
365 [[maybe_unused]] Scalar rhs) const = 0;
366
371 virtual ExpressionType type() const = 0;
372
376 virtual std::string_view name() const = 0;
377
384 [[maybe_unused]] Scalar rhs) const {
385 return Scalar(0);
386 }
387
394 [[maybe_unused]] Scalar rhs) const {
395 return Scalar(0);
396 }
397
405 [[maybe_unused]] const ExpressionPtr<Scalar>& rhs) const {
406 return constant_ptr(Scalar(0));
407 }
408
416 [[maybe_unused]] const ExpressionPtr<Scalar>& rhs) const {
417 return constant_ptr(Scalar(0));
418 }
419};
420
421template <typename Scalar>
422ExpressionPtr<Scalar> constant_ptr(Scalar value) {
424}
425
426template <typename Scalar>
427ExpressionPtr<Scalar> cbrt(const ExpressionPtr<Scalar>& x);
428template <typename Scalar>
429ExpressionPtr<Scalar> exp(const ExpressionPtr<Scalar>& x);
430template <typename Scalar>
431ExpressionPtr<Scalar> sign(const ExpressionPtr<Scalar>& x);
432template <typename Scalar>
433ExpressionPtr<Scalar> sin(const ExpressionPtr<Scalar>& x);
434template <typename Scalar>
435ExpressionPtr<Scalar> sinh(const ExpressionPtr<Scalar>& x);
436template <typename Scalar>
437ExpressionPtr<Scalar> sqrt(const ExpressionPtr<Scalar>& x);
438
443template <typename Scalar, ExpressionType T>
452
453 Scalar value(Scalar lhs, Scalar rhs) const override { return lhs - rhs; }
454
455 ExpressionType type() const override { return T; }
456
457 std::string_view name() const override { return "binary minus"; }
458
459 Scalar grad_l(Scalar, Scalar) const override { return this->adjoint; }
460
461 Scalar grad_r(Scalar, Scalar) const override { return -this->adjoint; }
462
465 const ExpressionPtr<Scalar>&) const override {
466 return this->adjoint_expr;
467 }
468
471 const ExpressionPtr<Scalar>&) const override {
472 return -this->adjoint_expr;
473 }
474};
475
480template <typename Scalar, ExpressionType T>
489
490 Scalar value(Scalar lhs, Scalar rhs) const override { return lhs + rhs; }
491
492 ExpressionType type() const override { return T; }
493
494 std::string_view name() const override { return "binary plus"; }
495
496 Scalar grad_l(Scalar, Scalar) const override { return this->adjoint; }
497
498 Scalar grad_r(Scalar, Scalar) const override { return this->adjoint; }
499
502 const ExpressionPtr<Scalar>&) const override {
503 return this->adjoint_expr;
504 }
505
508 const ExpressionPtr<Scalar>&) const override {
509 return this->adjoint_expr;
510 }
511};
512
516template <typename Scalar>
522 : Expression<Scalar>{std::move(lhs)} {}
523
524 Scalar value(Scalar x, Scalar) const override {
525 using std::cbrt;
526 return cbrt(x);
527 }
528
529 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
530
531 std::string_view name() const override { return "cbrt"; }
532
533 Scalar grad_l(Scalar x, Scalar) const override {
534 using std::cbrt;
535
536 Scalar c = cbrt(x);
537 return this->adjoint / (Scalar(3) * c * c);
538 }
539
541 const ExpressionPtr<Scalar>& x,
542 const ExpressionPtr<Scalar>&) const override {
543 auto c = cbrt(x);
544 return this->adjoint_expr / (constant_ptr(Scalar(3)) * c * c);
545 }
546};
547
552template <typename Scalar>
554 using enum ExpressionType;
555 using std::cbrt;
556
557 // Evaluate constant
558 if (x->type() == CONSTANT) {
559 if (x->val == Scalar(0)) {
560 // Return zero
561 return x;
562 } else if (x->val == Scalar(-1) || x->val == Scalar(1)) {
563 return x;
564 } else {
565 return constant_ptr(cbrt(x->val));
566 }
567 }
568
569 return make_expression_ptr<CbrtExpression<Scalar>>(x);
570}
571
575template <typename Scalar>
580 explicit constexpr ConstantExpression(Scalar value)
581 : Expression<Scalar>{value} {}
582
583 Scalar value(Scalar, Scalar) const override { return this->val; }
584
585 ExpressionType type() const override { return ExpressionType::CONSTANT; }
586
587 std::string_view name() const override { return "constant"; }
588};
589
593template <typename Scalar>
596 constexpr DecisionVariableExpression() = default;
597
603
604 Scalar value(Scalar, Scalar) const override { return this->val; }
605
606 ExpressionType type() const override { return ExpressionType::LINEAR; }
607
608 std::string_view name() const override { return "decision variable"; }
609};
610
615template <typename Scalar, ExpressionType T>
623
624 Scalar value(Scalar lhs, Scalar rhs) const override { return lhs / rhs; }
625
626 ExpressionType type() const override { return T; }
627
628 std::string_view name() const override { return "division"; }
629
630 Scalar grad_l(Scalar, Scalar rhs) const override {
631 return this->adjoint / rhs;
632 };
633
634 Scalar grad_r(Scalar lhs, Scalar rhs) const override {
635 return this->adjoint * -lhs / (rhs * rhs);
636 }
637
640 const ExpressionPtr<Scalar>& rhs) const override {
641 return this->adjoint_expr / rhs;
642 }
643
646 const ExpressionPtr<Scalar>& rhs) const override {
647 return this->adjoint_expr * -lhs / (rhs * rhs);
648 }
649};
650
655template <typename Scalar, ExpressionType T>
663
664 Scalar value(Scalar lhs, Scalar rhs) const override { return lhs * rhs; }
665
666 ExpressionType type() const override { return T; }
667
668 std::string_view name() const override { return "multiplication"; }
669
671 return this->adjoint * rhs;
672 }
673
675 return this->adjoint * lhs;
676 }
677
680 const ExpressionPtr<Scalar>& rhs) const override {
681 return this->adjoint_expr * rhs;
682 }
683
686 [[maybe_unused]] const ExpressionPtr<Scalar>& rhs) const override {
687 return this->adjoint_expr * lhs;
688 }
689};
690
695template <typename Scalar, ExpressionType T>
701 : Expression<Scalar>{std::move(lhs)} {}
702
703 Scalar value(Scalar lhs, Scalar) const override { return -lhs; }
704
705 ExpressionType type() const override { return T; }
706
707 std::string_view name() const override { return "unary minus"; }
708
709 Scalar grad_l(Scalar, Scalar) const override { return -this->adjoint; }
710
713 const ExpressionPtr<Scalar>&) const override {
714 return -this->adjoint_expr;
715 }
716};
717
722template <typename Scalar>
723constexpr void inc_ref_count(Expression<Scalar>* expr) {
724 ++expr->ref_count;
725}
726
731template <typename Scalar>
732constexpr void dec_ref_count(Expression<Scalar>* expr) {
733 // If a deeply nested tree is being deallocated all at once, calling the
734 // Expression destructor when expr's refcount reaches zero can cause a stack
735 // overflow. Instead, we iterate over its children to decrement their
736 // refcounts and deallocate them.
737 gch::small_vector<Expression<Scalar>*> stack;
738 stack.emplace_back(expr);
739
740 while (!stack.empty()) {
741 auto elem = stack.back();
742 stack.pop_back();
743
744 // Decrement the current node's refcount. If it reaches zero, deallocate the
745 // node and enqueue its children so their refcounts are decremented too.
746 if (--elem->ref_count == 0) {
747 if (elem->adjoint_expr != nullptr) {
748 stack.emplace_back(elem->adjoint_expr.get());
749 }
750 for (auto& arg : elem->args) {
751 if (arg != nullptr) {
752 stack.emplace_back(arg.get());
753 }
754 }
755
756 // Not calling the destructor here is safe because it only decrements
757 // refcounts, which was already done above.
758 if constexpr (USE_POOL_ALLOCATOR) {
759 auto alloc = global_pool_allocator<Expression<Scalar>>();
760 std::allocator_traits<decltype(alloc)>::deallocate(
761 alloc, elem, sizeof(Expression<Scalar>));
762 } else {
763 operator delete(elem);
764 }
765 }
766 }
767}
768
772template <typename Scalar>
778 : Expression<Scalar>{std::move(lhs)} {}
779
780 Scalar value(Scalar x, Scalar) const override {
781 using std::abs;
782 return abs(x);
783 }
784
785 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
786
787 std::string_view name() const override { return "abs"; }
788
789 Scalar grad_l(Scalar x, Scalar) const override {
790 if (x < Scalar(0)) {
791 return -this->adjoint;
792 } else if (x > Scalar(0)) {
793 return this->adjoint;
794 } else {
795 return Scalar(0);
796 }
797 }
798
800 const ExpressionPtr<Scalar>& x,
801 const ExpressionPtr<Scalar>&) const override {
802 return this->adjoint_expr * sign(x);
803 }
804};
805
810template <typename Scalar>
812 using enum ExpressionType;
813 using std::abs;
814
815 // Prune expression
816 if (x->is_constant(Scalar(0))) {
817 // Return zero, which x currently is
818 return x;
819 }
820
821 // Evaluate constant
822 if (x->type() == CONSTANT) {
823 return constant_ptr(abs(x->val));
824 }
825
826 return make_expression_ptr<AbsExpression<Scalar>>(x);
827}
828
832template <typename Scalar>
838 : Expression<Scalar>{std::move(lhs)} {}
839
840 Scalar value(Scalar x, Scalar) const override {
841 using std::acos;
842 return acos(x);
843 }
844
845 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
846
847 std::string_view name() const override { return "acos"; }
848
849 Scalar grad_l(Scalar x, Scalar) const override {
850 using std::sqrt;
851 return -this->adjoint / sqrt(Scalar(1) - x * x);
852 }
853
855 const ExpressionPtr<Scalar>& x,
856 const ExpressionPtr<Scalar>&) const override {
857 return -this->adjoint_expr / sqrt(constant_ptr(Scalar(1)) - x * x);
858 }
859};
860
865template <typename Scalar>
867 using enum ExpressionType;
868 using std::acos;
869
870 // Prune expression
871 if (x->is_constant(Scalar(0))) {
872 return constant_ptr(Scalar(std::numbers::pi) / Scalar(2));
873 }
874
875 // Evaluate constant
876 if (x->type() == CONSTANT) {
877 return constant_ptr(acos(x->val));
878 }
879
880 return make_expression_ptr<AcosExpression<Scalar>>(x);
881}
882
886template <typename Scalar>
892 : Expression<Scalar>{std::move(lhs)} {}
893
894 Scalar value(Scalar x, Scalar) const override {
895 using std::asin;
896 return asin(x);
897 }
898
899 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
900
901 std::string_view name() const override { return "asin"; }
902
903 Scalar grad_l(Scalar x, Scalar) const override {
904 using std::sqrt;
905 return this->adjoint / sqrt(Scalar(1) - x * x);
906 }
907
909 const ExpressionPtr<Scalar>& x,
910 const ExpressionPtr<Scalar>&) const override {
911 return this->adjoint_expr / sqrt(constant_ptr(Scalar(1)) - x * x);
912 }
913};
914
919template <typename Scalar>
921 using enum ExpressionType;
922 using std::asin;
923
924 // Prune expression
925 if (x->is_constant(Scalar(0))) {
926 // Return zero, which x currently is
927 return x;
928 }
929
930 // Evaluate constant
931 if (x->type() == CONSTANT) {
932 return constant_ptr(asin(x->val));
933 }
934
935 return make_expression_ptr<AsinExpression<Scalar>>(x);
936}
937
941template <typename Scalar>
947 : Expression<Scalar>{std::move(lhs)} {}
948
949 Scalar value(Scalar x, Scalar) const override {
950 using std::atan;
951 return atan(x);
952 }
953
954 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
955
956 std::string_view name() const override { return "atan"; }
957
958 Scalar grad_l(Scalar x, Scalar) const override {
959 return this->adjoint / (Scalar(1) + x * x);
960 }
961
963 const ExpressionPtr<Scalar>& x,
964 const ExpressionPtr<Scalar>&) const override {
965 return this->adjoint_expr / (constant_ptr(Scalar(1)) + x * x);
966 }
967};
968
973template <typename Scalar>
975 using enum ExpressionType;
976 using std::atan;
977
978 // Prune expression
979 if (x->is_constant(Scalar(0))) {
980 // Return zero, which x currently is
981 return x;
982 }
983
984 // Evaluate constant
985 if (x->type() == CONSTANT) {
986 return constant_ptr(atan(x->val));
987 }
988
989 return make_expression_ptr<AtanExpression<Scalar>>(x);
990}
991
995template <typename Scalar>
1003 : Expression<Scalar>{std::move(lhs), std::move(rhs)} {}
1004
1005 Scalar value(Scalar y, Scalar x) const override {
1006 using std::atan2;
1007 return atan2(y, x);
1008 }
1009
1010 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1011
1012 std::string_view name() const override { return "atan2"; }
1013
1014 Scalar grad_l(Scalar y, Scalar x) const override {
1015 return this->adjoint * x / (y * y + x * x);
1016 }
1017
1018 Scalar grad_r(Scalar y, Scalar x) const override {
1019 return this->adjoint * -y / (y * y + x * x);
1020 }
1021
1023 const ExpressionPtr<Scalar>& y,
1024 const ExpressionPtr<Scalar>& x) const override {
1025 return this->adjoint_expr * x / (y * y + x * x);
1026 }
1027
1029 const ExpressionPtr<Scalar>& y,
1030 const ExpressionPtr<Scalar>& x) const override {
1031 return this->adjoint_expr * -y / (y * y + x * x);
1032 }
1033};
1034
1040template <typename Scalar>
1042 const ExpressionPtr<Scalar>& x) {
1043 using enum ExpressionType;
1044 using std::atan2;
1045
1046 // Evaluate constant
1047 if (y->type() == CONSTANT && x->type() == CONSTANT) {
1048 return constant_ptr(atan2(y->val, x->val));
1049 }
1050
1051 return make_expression_ptr<Atan2Expression<Scalar>>(y, x);
1052}
1053
1057template <typename Scalar>
1063 : Expression<Scalar>{std::move(lhs)} {}
1064
1065 Scalar value(Scalar x, Scalar) const override {
1066 using std::cos;
1067 return cos(x);
1068 }
1069
1070 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1071
1072 std::string_view name() const override { return "cos"; }
1073
1074 Scalar grad_l(Scalar x, Scalar) const override {
1075 using std::sin;
1076 return this->adjoint * -sin(x);
1077 }
1078
1080 const ExpressionPtr<Scalar>& x,
1081 const ExpressionPtr<Scalar>&) const override {
1082 return this->adjoint_expr * -sin(x);
1083 }
1084};
1085
1090template <typename Scalar>
1092 using enum ExpressionType;
1093 using std::cos;
1094
1095 // Prune expression
1096 if (x->is_constant(Scalar(0))) {
1097 return constant_ptr(Scalar(1));
1098 }
1099
1100 // Evaluate constant
1101 if (x->type() == CONSTANT) {
1102 return constant_ptr(cos(x->val));
1103 }
1104
1105 return make_expression_ptr<CosExpression<Scalar>>(x);
1106}
1107
1111template <typename Scalar>
1117 : Expression<Scalar>{std::move(lhs)} {}
1118
1119 Scalar value(Scalar x, Scalar) const override {
1120 using std::cosh;
1121 return cosh(x);
1122 }
1123
1124 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1125
1126 std::string_view name() const override { return "cosh"; }
1127
1128 Scalar grad_l(Scalar x, Scalar) const override {
1129 using std::sinh;
1130 return this->adjoint * sinh(x);
1131 }
1132
1134 const ExpressionPtr<Scalar>& x,
1135 const ExpressionPtr<Scalar>&) const override {
1136 return this->adjoint_expr * sinh(x);
1137 }
1138};
1139
1144template <typename Scalar>
1146 using enum ExpressionType;
1147 using std::cosh;
1148
1149 // Prune expression
1150 if (x->is_constant(Scalar(0))) {
1151 return constant_ptr(Scalar(1));
1152 }
1153
1154 // Evaluate constant
1155 if (x->type() == CONSTANT) {
1156 return constant_ptr(cosh(x->val));
1157 }
1158
1159 return make_expression_ptr<CoshExpression<Scalar>>(x);
1160}
1161
1165template <typename Scalar>
1171 : Expression<Scalar>{std::move(lhs)} {}
1172
1173 Scalar value(Scalar x, Scalar) const override {
1174 using std::erf;
1175 return erf(x);
1176 }
1177
1178 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1179
1180 std::string_view name() const override { return "erf"; }
1181
1182 Scalar grad_l(Scalar x, Scalar) const override {
1183 using std::exp;
1184 return this->adjoint * Scalar(2.0 * std::numbers::inv_sqrtpi) * exp(-x * x);
1185 }
1186
1188 const ExpressionPtr<Scalar>& x,
1189 const ExpressionPtr<Scalar>&) const override {
1190 return this->adjoint_expr *
1191 constant_ptr(Scalar(2.0 * std::numbers::inv_sqrtpi)) * exp(-x * x);
1192 }
1193};
1194
1199template <typename Scalar>
1201 using enum ExpressionType;
1202 using std::erf;
1203
1204 // Prune expression
1205 if (x->is_constant(Scalar(0))) {
1206 // Return zero, which x currently is
1207 return x;
1208 }
1209
1210 // Evaluate constant
1211 if (x->type() == CONSTANT) {
1212 return constant_ptr(erf(x->val));
1213 }
1214
1215 return make_expression_ptr<ErfExpression<Scalar>>(x);
1216}
1217
1221template <typename Scalar>
1227 : Expression<Scalar>{std::move(lhs)} {}
1228
1229 Scalar value(Scalar x, Scalar) const override {
1230 using std::exp;
1231 return exp(x);
1232 }
1233
1234 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1235
1236 std::string_view name() const override { return "exp"; }
1237
1238 Scalar grad_l(Scalar x, Scalar) const override {
1239 using std::exp;
1240 return this->adjoint * exp(x);
1241 }
1242
1244 const ExpressionPtr<Scalar>& x,
1245 const ExpressionPtr<Scalar>&) const override {
1246 return this->adjoint_expr * exp(x);
1247 }
1248};
1249
1254template <typename Scalar>
1256 using enum ExpressionType;
1257 using std::exp;
1258
1259 // Prune expression
1260 if (x->is_constant(Scalar(0))) {
1261 return constant_ptr(Scalar(1));
1262 }
1263
1264 // Evaluate constant
1265 if (x->type() == CONSTANT) {
1266 return constant_ptr(exp(x->val));
1267 }
1268
1269 return make_expression_ptr<ExpExpression<Scalar>>(x);
1270}
1271
1272template <typename Scalar>
1273ExpressionPtr<Scalar> hypot(const ExpressionPtr<Scalar>& x,
1274 const ExpressionPtr<Scalar>& y);
1275
1279template <typename Scalar>
1287 : Expression<Scalar>{std::move(lhs), std::move(rhs)} {}
1288
1289 Scalar value(Scalar x, Scalar y) const override {
1290 using std::hypot;
1291 return hypot(x, y);
1292 }
1293
1294 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1295
1296 std::string_view name() const override { return "hypot"; }
1297
1298 Scalar grad_l(Scalar x, Scalar y) const override {
1299 using std::hypot;
1300 return this->adjoint * x / hypot(x, y);
1301 }
1302
1303 Scalar grad_r(Scalar x, Scalar y) const override {
1304 using std::hypot;
1305 return this->adjoint * y / hypot(x, y);
1306 }
1307
1309 const ExpressionPtr<Scalar>& x,
1310 const ExpressionPtr<Scalar>& y) const override {
1311 return this->adjoint_expr * x / hypot(x, y);
1312 }
1313
1315 const ExpressionPtr<Scalar>& x,
1316 const ExpressionPtr<Scalar>& y) const override {
1317 return this->adjoint_expr * y / hypot(x, y);
1318 }
1319};
1320
1326template <typename Scalar>
1328 const ExpressionPtr<Scalar>& y) {
1329 using enum ExpressionType;
1330 using std::hypot;
1331
1332 // Prune expression
1333 if (x->is_constant(Scalar(0))) {
1334 return abs(y);
1335 } else if (y->is_constant(Scalar(0))) {
1336 return abs(x);
1337 }
1338
1339 // Evaluate constant
1340 if (x->type() == CONSTANT && y->type() == CONSTANT) {
1341 return constant_ptr(hypot(x->val, y->val));
1342 }
1343
1344 return make_expression_ptr<HypotExpression<Scalar>>(x, y);
1345}
1346
1350template <typename Scalar>
1356 : Expression<Scalar>{std::move(x)} {}
1357
1358 Scalar value(Scalar x, Scalar) const override {
1359 return x >= Scalar(0) ? Scalar(1) : Scalar(0);
1360 }
1361
1362 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1363
1364 std::string_view name() const override { return "is nonnegative"; }
1365};
1366
1371template <typename Scalar>
1372ExpressionPtr<Scalar> is_nonnegative(const ExpressionPtr<Scalar>& x) {
1373 if (x->type() == ExpressionType::CONSTANT) {
1374 return constant_ptr(x->val >= Scalar(0) ? Scalar(1) : Scalar(0));
1375 }
1376
1377 return make_expression_ptr<IsNonnegativeExpression<Scalar>>(x);
1378}
1379
1383template <typename Scalar>
1389 : Expression<Scalar>{std::move(x)} {}
1390
1391 Scalar value(Scalar x, Scalar) const override {
1392 return x > Scalar(0) ? Scalar(1) : Scalar(0);
1393 }
1394
1395 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1396
1397 std::string_view name() const override { return "is positive"; }
1398};
1399
1404template <typename Scalar>
1405ExpressionPtr<Scalar> is_positive(const ExpressionPtr<Scalar>& x) {
1406 if (x->type() == ExpressionType::CONSTANT) {
1407 return constant_ptr(x->val > Scalar(0) ? Scalar(1) : Scalar(0));
1408 }
1409
1410 return make_expression_ptr<IsPositiveExpression<Scalar>>(x);
1411}
1412
1416template <typename Scalar>
1422 : Expression<Scalar>{std::move(lhs)} {}
1423
1424 Scalar value(Scalar x, Scalar) const override {
1425 using std::log;
1426 return log(x);
1427 }
1428
1429 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1430
1431 std::string_view name() const override { return "log"; }
1432
1433 Scalar grad_l(Scalar x, Scalar) const override { return this->adjoint / x; }
1434
1436 const ExpressionPtr<Scalar>& x,
1437 const ExpressionPtr<Scalar>&) const override {
1438 return this->adjoint_expr / x;
1439 }
1440};
1441
1446template <typename Scalar>
1448 using enum ExpressionType;
1449 using std::log;
1450
1451 // Prune expression
1452 if (x->is_constant(Scalar(0))) {
1453 // Return zero, which x currently is
1454 return x;
1455 }
1456
1457 // Evaluate constant
1458 if (x->type() == CONSTANT) {
1459 return constant_ptr(log(x->val));
1460 }
1461
1462 return make_expression_ptr<LogExpression<Scalar>>(x);
1463}
1464
1468template <typename Scalar>
1474 : Expression<Scalar>{std::move(lhs)} {}
1475
1476 Scalar value(Scalar x, Scalar) const override {
1477 using std::log10;
1478 return log10(x);
1479 }
1480
1481 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1482
1483 std::string_view name() const override { return "log10"; }
1484
1485 Scalar grad_l(Scalar x, Scalar) const override {
1486 return this->adjoint / (Scalar(std::numbers::ln10) * x);
1487 }
1488
1490 const ExpressionPtr<Scalar>& x,
1491 const ExpressionPtr<Scalar>&) const override {
1492 return this->adjoint_expr / (constant_ptr(Scalar(std::numbers::ln10)) * x);
1493 }
1494};
1495
1500template <typename Scalar>
1502 using enum ExpressionType;
1503 using std::log10;
1504
1505 // Prune expression
1506 if (x->is_constant(Scalar(0))) {
1507 // Return zero, which x currently is
1508 return x;
1509 }
1510
1511 // Evaluate constant
1512 if (x->type() == CONSTANT) {
1513 return constant_ptr(log10(x->val));
1514 }
1515
1516 return make_expression_ptr<Log10Expression<Scalar>>(x);
1517}
1518
1524template <typename Scalar>
1532
1533 Scalar value(Scalar a, Scalar b) const override {
1534 using std::max;
1535 return max(a, b);
1536 }
1537
1538 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1539
1540 std::string_view name() const override { return "max"; }
1541
1542 Scalar grad_l(Scalar a, Scalar b) const override {
1543 return a >= b ? this->adjoint : Scalar(0);
1544 }
1545
1546 Scalar grad_r(Scalar a, Scalar b) const override {
1547 return a >= b ? Scalar(0) : this->adjoint;
1548 }
1549
1551 const ExpressionPtr<Scalar>& a,
1552 const ExpressionPtr<Scalar>& b) const override {
1553 // adjoint * (a >= b)
1554 // adjoint * (a - b >= 0)
1555 return this->adjoint_expr * is_nonnegative(a - b);
1556 }
1557
1559 const ExpressionPtr<Scalar>& a,
1560 const ExpressionPtr<Scalar>& b) const override {
1561 // adjoint * !(a >= b)
1562 // adjoint * (a < b)
1563 // adjoint * (b > a)
1564 // adjoint * (b - a > 0)
1565 return this->adjoint_expr * is_positive(b - a);
1566 }
1567};
1568
1574template <typename Scalar>
1576 const ExpressionPtr<Scalar>& b) {
1577 using enum ExpressionType;
1578 using std::max;
1579
1580 // Evaluate constant
1581 if (a->type() == CONSTANT && b->type() == CONSTANT) {
1582 return constant_ptr(max(a->val, b->val));
1583 }
1584
1585 return make_expression_ptr<MaxExpression<Scalar>>(a, b);
1586}
1587
1593template <typename Scalar>
1601
1602 Scalar value(Scalar a, Scalar b) const override {
1603 using std::min;
1604 return min(a, b);
1605 }
1606
1607 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1608
1609 std::string_view name() const override { return "min"; }
1610
1611 Scalar grad_l(Scalar a, Scalar b) const override {
1612 return a <= b ? this->adjoint : Scalar(0);
1613 }
1614
1616 [[maybe_unused]] Scalar b) const override {
1617 return a <= b ? Scalar(0) : this->adjoint;
1618 }
1619
1621 const ExpressionPtr<Scalar>& a,
1622 const ExpressionPtr<Scalar>& b) const override {
1623 // adjoint * (a <= b)
1624 // adjoint * (b >= a)
1625 // adjoint * (b - a >= 0)
1626 return this->adjoint_expr * is_nonnegative(b - a);
1627 }
1628
1630 const ExpressionPtr<Scalar>& a,
1631 const ExpressionPtr<Scalar>& b) const override {
1632 // adjoint * !(a <= b)
1633 // adjoint * (a > b)
1634 // adjoint * (a - b > 0)
1635 return this->adjoint_expr * is_positive(a - b);
1636 }
1637};
1638
1644template <typename Scalar>
1646 const ExpressionPtr<Scalar>& b) {
1647 using enum ExpressionType;
1648 using std::min;
1649
1650 // Evaluate constant
1651 if (a->type() == CONSTANT && b->type() == CONSTANT) {
1652 return constant_ptr(min(a->val, b->val));
1653 }
1654
1655 return make_expression_ptr<MinExpression<Scalar>>(a, b);
1656}
1657
1658template <typename Scalar>
1659ExpressionPtr<Scalar> pow(const ExpressionPtr<Scalar>& base,
1660 const ExpressionPtr<Scalar>& power);
1661
1666template <typename Scalar, ExpressionType T>
1674
1675 Scalar value(Scalar base, Scalar power) const override {
1676 using std::pow;
1677 return pow(base, power);
1678 }
1679
1680 ExpressionType type() const override { return T; }
1681
1682 std::string_view name() const override { return "pow"; }
1683
1685 using std::pow;
1686 return this->adjoint * pow(base, power - Scalar(1)) * power;
1687 }
1688
1690 using std::log;
1691 using std::pow;
1692
1693 return this->adjoint * pow(base, power) * log(base);
1694 }
1695
1698 const ExpressionPtr<Scalar>& power) const override {
1699 return this->adjoint_expr * pow(base, power - constant_ptr(Scalar(1))) *
1700 power;
1701 }
1702
1705 const ExpressionPtr<Scalar>& power) const override {
1706 return this->adjoint_expr * pow(base, power) * log(base);
1707 }
1708};
1709
1715template <typename Scalar>
1718 using enum ExpressionType;
1719 using std::pow;
1720
1721 // Prune expression
1722 if (base->is_constant(Scalar(0))) {
1723 // Return zero, which base currently is
1724 return base;
1725 } else if (base->is_constant(Scalar(1))) {
1726 // Return one, which base currently is
1727 return base;
1728 }
1729 if (power->is_constant(Scalar(0))) {
1730 return constant_ptr(Scalar(1));
1731 } else if (power->is_constant(Scalar(1))) {
1732 // Return base unmodified
1733 return base;
1734 }
1735
1736 // Evaluate constant
1737 if (base->type() == CONSTANT && power->type() == CONSTANT) {
1738 return constant_ptr(pow(base->val, power->val));
1739 }
1740
1741 if (power->is_constant(Scalar(2))) {
1742 if (base->type() == LINEAR) {
1743 return make_expression_ptr<MultExpression<Scalar, QUADRATIC>>(base, base);
1744 } else {
1745 return make_expression_ptr<MultExpression<Scalar, NONLINEAR>>(base, base);
1746 }
1747 }
1748
1749 return make_expression_ptr<PowExpression<Scalar, NONLINEAR>>(base, power);
1750}
1751
1755template <typename Scalar>
1761 : Expression<Scalar>{std::move(lhs)} {}
1762
1763 Scalar value(Scalar x, Scalar) const override {
1764 if (x < Scalar(0)) {
1765 return Scalar(-1);
1766 } else if (x == Scalar(0)) {
1767 return Scalar(0);
1768 } else {
1769 return Scalar(1);
1770 }
1771 }
1772
1773 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1774
1775 std::string_view name() const override { return "sign"; }
1776};
1777
1782template <typename Scalar>
1784 using enum ExpressionType;
1785
1786 // Evaluate constant
1787 if (x->type() == CONSTANT) {
1788 if (x->val < Scalar(0)) {
1789 return constant_ptr(Scalar(-1));
1790 } else if (x->val == Scalar(0)) {
1791 // Return zero
1792 return x;
1793 } else {
1794 return constant_ptr(Scalar(1));
1795 }
1796 }
1797
1798 return make_expression_ptr<SignExpression<Scalar>>(x);
1799}
1800
1804template <typename Scalar>
1810 : Expression<Scalar>{std::move(lhs)} {}
1811
1812 Scalar value(Scalar x, Scalar) const override {
1813 using std::sin;
1814 return sin(x);
1815 }
1816
1817 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1818
1819 std::string_view name() const override { return "sin"; }
1820
1821 Scalar grad_l(Scalar x, Scalar) const override {
1822 using std::cos;
1823 return this->adjoint * cos(x);
1824 }
1825
1827 const ExpressionPtr<Scalar>& x,
1828 const ExpressionPtr<Scalar>&) const override {
1829 return this->adjoint_expr * cos(x);
1830 }
1831};
1832
1837template <typename Scalar>
1839 using enum ExpressionType;
1840 using std::sin;
1841
1842 // Prune expression
1843 if (x->is_constant(Scalar(0))) {
1844 // Return zero, which x currently is
1845 return x;
1846 }
1847
1848 // Evaluate constant
1849 if (x->type() == CONSTANT) {
1850 return constant_ptr(sin(x->val));
1851 }
1852
1853 return make_expression_ptr<SinExpression<Scalar>>(x);
1854}
1855
1859template <typename Scalar>
1865 : Expression<Scalar>{std::move(lhs)} {}
1866
1867 Scalar value(Scalar x, Scalar) const override {
1868 using std::sinh;
1869 return sinh(x);
1870 }
1871
1872 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1873
1874 std::string_view name() const override { return "sinh"; }
1875
1876 Scalar grad_l(Scalar x, Scalar) const override {
1877 using std::cosh;
1878 return this->adjoint * cosh(x);
1879 }
1880
1882 const ExpressionPtr<Scalar>& x,
1883 const ExpressionPtr<Scalar>&) const override {
1884 return this->adjoint_expr * cosh(x);
1885 }
1886};
1887
1892template <typename Scalar>
1894 using enum ExpressionType;
1895 using std::sinh;
1896
1897 // Prune expression
1898 if (x->is_constant(Scalar(0))) {
1899 // Return zero, which x currently is
1900 return x;
1901 }
1902
1903 // Evaluate constant
1904 if (x->type() == CONSTANT) {
1905 return constant_ptr(sinh(x->val));
1906 }
1907
1908 return make_expression_ptr<SinhExpression<Scalar>>(x);
1909}
1910
1914template <typename Scalar>
1920 : Expression<Scalar>{std::move(lhs)} {}
1921
1922 Scalar value(Scalar x, Scalar) const override {
1923 using std::sqrt;
1924 return sqrt(x);
1925 }
1926
1927 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1928
1929 std::string_view name() const override { return "sqrt"; }
1930
1931 Scalar grad_l(Scalar x, Scalar) const override {
1932 using std::sqrt;
1933 return this->adjoint / (Scalar(2) * sqrt(x));
1934 }
1935
1937 const ExpressionPtr<Scalar>& x,
1938 const ExpressionPtr<Scalar>&) const override {
1939 return this->adjoint_expr / (constant_ptr(Scalar(2)) * sqrt(x));
1940 }
1941};
1942
1947template <typename Scalar>
1949 using enum ExpressionType;
1950 using std::sqrt;
1951
1952 // Evaluate constant
1953 if (x->type() == CONSTANT) {
1954 if (x->val == Scalar(0)) {
1955 // Return zero
1956 return x;
1957 } else if (x->val == Scalar(1)) {
1958 return x;
1959 } else {
1960 return constant_ptr(sqrt(x->val));
1961 }
1962 }
1963
1964 return make_expression_ptr<SqrtExpression<Scalar>>(x);
1965}
1966
1970template <typename Scalar>
1976 : Expression<Scalar>{std::move(lhs)} {}
1977
1978 Scalar value(Scalar x, Scalar) const override {
1979 using std::tan;
1980 return tan(x);
1981 }
1982
1983 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
1984
1985 std::string_view name() const override { return "tan"; }
1986
1987 Scalar grad_l(Scalar x, Scalar) const override {
1988 using std::cos;
1989
1990 auto c = cos(x);
1991 return this->adjoint / (c * c);
1992 }
1993
1995 const ExpressionPtr<Scalar>& x,
1996 const ExpressionPtr<Scalar>&) const override {
1997 auto c = cos(x);
1998 return this->adjoint_expr / (c * c);
1999 }
2000};
2001
2006template <typename Scalar>
2008 using enum ExpressionType;
2009 using std::tan;
2010
2011 // Prune expression
2012 if (x->is_constant(Scalar(0))) {
2013 // Return zero, which x currently is
2014 return x;
2015 }
2016
2017 // Evaluate constant
2018 if (x->type() == CONSTANT) {
2019 return constant_ptr(tan(x->val));
2020 }
2021
2022 return make_expression_ptr<TanExpression<Scalar>>(x);
2023}
2024
2028template <typename Scalar>
2034 : Expression<Scalar>{std::move(lhs)} {}
2035
2036 Scalar value(Scalar x, Scalar) const override {
2037 using std::tanh;
2038 return tanh(x);
2039 }
2040
2041 ExpressionType type() const override { return ExpressionType::NONLINEAR; }
2042
2043 std::string_view name() const override { return "tanh"; }
2044
2045 Scalar grad_l(Scalar x, Scalar) const override {
2046 using std::cosh;
2047
2048 auto c = cosh(x);
2049 return this->adjoint / (c * c);
2050 }
2051
2053 const ExpressionPtr<Scalar>& x,
2054 const ExpressionPtr<Scalar>&) const override {
2055 auto c = cosh(x);
2056 return this->adjoint_expr / (c * c);
2057 }
2058};
2059
2064template <typename Scalar>
2066 using enum ExpressionType;
2067 using std::tanh;
2068
2069 // Prune expression
2070 if (x->is_constant(Scalar(0))) {
2071 // Return zero, which x currently is
2072 return x;
2073 }
2074
2075 // Evaluate constant
2076 if (x->type() == CONSTANT) {
2077 return constant_ptr(tanh(x->val));
2078 }
2079
2080 return make_expression_ptr<TanhExpression<Scalar>>(x);
2081}
2082
2083} // namespace slp::detail
Definition intrusive_shared_ptr.hpp:27
Definition expression.hpp:773
std::string_view name() const override
Definition expression.hpp:787
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:799
constexpr AbsExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:777
ExpressionType type() const override
Definition expression.hpp:785
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:789
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:780
Definition expression.hpp:833
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:840
constexpr AcosExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:837
ExpressionType type() const override
Definition expression.hpp:845
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:849
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:854
std::string_view name() const override
Definition expression.hpp:847
Definition expression.hpp:887
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:894
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:903
std::string_view name() const override
Definition expression.hpp:901
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:908
ExpressionType type() const override
Definition expression.hpp:899
constexpr AsinExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:891
Definition expression.hpp:996
std::string_view name() const override
Definition expression.hpp:1012
Scalar value(Scalar y, Scalar x) const override
Definition expression.hpp:1005
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &y, const ExpressionPtr< Scalar > &x) const override
Definition expression.hpp:1022
constexpr Atan2Expression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:1001
Scalar grad_l(Scalar y, Scalar x) const override
Definition expression.hpp:1014
Scalar grad_r(Scalar y, Scalar x) const override
Definition expression.hpp:1018
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &y, const ExpressionPtr< Scalar > &x) const override
Definition expression.hpp:1028
ExpressionType type() const override
Definition expression.hpp:1010
Definition expression.hpp:942
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:962
std::string_view name() const override
Definition expression.hpp:956
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:958
constexpr AtanExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:946
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:949
ExpressionType type() const override
Definition expression.hpp:954
Definition expression.hpp:444
constexpr BinaryMinusExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:449
std::string_view name() const override
Definition expression.hpp:457
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:469
Scalar grad_r(Scalar, Scalar) const override
Definition expression.hpp:461
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:463
Scalar value(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:453
ExpressionType type() const override
Definition expression.hpp:455
Scalar grad_l(Scalar, Scalar) const override
Definition expression.hpp:459
Definition expression.hpp:481
Scalar value(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:490
Scalar grad_r(Scalar, Scalar) const override
Definition expression.hpp:498
Scalar grad_l(Scalar, Scalar) const override
Definition expression.hpp:496
constexpr BinaryPlusExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:486
ExpressionType type() const override
Definition expression.hpp:492
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:506
std::string_view name() const override
Definition expression.hpp:494
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:500
Definition expression.hpp:517
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:540
std::string_view name() const override
Definition expression.hpp:531
constexpr CbrtExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:521
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:533
ExpressionType type() const override
Definition expression.hpp:529
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:524
Definition expression.hpp:576
ExpressionType type() const override
Definition expression.hpp:585
Scalar value(Scalar, Scalar) const override
Definition expression.hpp:583
std::string_view name() const override
Definition expression.hpp:587
constexpr ConstantExpression(Scalar value)
Definition expression.hpp:580
Definition expression.hpp:1058
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1065
ExpressionType type() const override
Definition expression.hpp:1070
constexpr CosExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1062
std::string_view name() const override
Definition expression.hpp:1072
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1074
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1079
Definition expression.hpp:1112
ExpressionType type() const override
Definition expression.hpp:1124
std::string_view name() const override
Definition expression.hpp:1126
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1119
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1133
constexpr CoshExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1116
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1128
Definition expression.hpp:594
constexpr DecisionVariableExpression()=default
Constructs a decision variable expression with a value of zero.
std::string_view name() const override
Definition expression.hpp:608
Scalar value(Scalar, Scalar) const override
Definition expression.hpp:604
constexpr DecisionVariableExpression(Scalar value)
Definition expression.hpp:601
ExpressionType type() const override
Definition expression.hpp:606
Definition expression.hpp:616
constexpr DivExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:621
ExpressionType type() const override
Definition expression.hpp:626
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs) const override
Definition expression.hpp:644
std::string_view name() const override
Definition expression.hpp:628
Scalar value(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:624
Scalar grad_l(Scalar, Scalar rhs) const override
Definition expression.hpp:630
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &rhs) const override
Definition expression.hpp:638
Scalar grad_r(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:634
Definition expression.hpp:1166
std::string_view name() const override
Definition expression.hpp:1180
constexpr ErfExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1170
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1182
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1187
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1173
ExpressionType type() const override
Definition expression.hpp:1178
Definition expression.hpp:1222
std::string_view name() const override
Definition expression.hpp:1236
ExpressionType type() const override
Definition expression.hpp:1234
constexpr ExpExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1226
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1238
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1243
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1229
Definition expression.hpp:89
Scalar val
The value of the expression node.
Definition expression.hpp:94
friend ExpressionPtr< Scalar > operator-(const ExpressionPtr< Scalar > &lhs)
Definition expression.hpp:327
virtual Scalar grad_r(Scalar lhs, Scalar rhs) const
Definition expression.hpp:393
std::array< ExpressionPtr< Scalar >, 2 > args
Expression arguments.
Definition expression.hpp:104
uint32_t ref_count
Reference count for intrusive shared pointer.
Definition expression.hpp:118
constexpr Expression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:131
Scalar adjoint
The adjoint of the expression node, used during autodiff.
Definition expression.hpp:97
friend ExpressionPtr< Scalar > operator+(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:243
int32_t scratch
Definition expression.hpp:115
virtual Scalar grad_l(Scalar lhs, Scalar rhs) const
Definition expression.hpp:383
constexpr bool is_constant(Scalar constant) const
Definition expression.hpp:147
constexpr Expression()=default
Constructs a constant expression with a value of zero.
constexpr Expression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:138
virtual ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs) const
Definition expression.hpp:403
ExpressionPtr< Scalar > adjoint_expr
Definition expression.hpp:101
Scalar_ Scalar
Scalar type alias.
Definition expression.hpp:91
virtual ExpressionType type() const =0
friend ExpressionPtr< Scalar > operator/(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:207
friend ExpressionPtr< Scalar > operator-(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:288
friend ExpressionPtr< Scalar > operator*(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:155
virtual Scalar value(Scalar lhs, Scalar rhs) const =0
virtual std::string_view name() const =0
virtual ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs) const
Definition expression.hpp:414
friend ExpressionPtr< Scalar > operator+=(ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs)
Definition expression.hpp:279
constexpr Expression(Scalar value)
Definition expression.hpp:126
friend ExpressionPtr< Scalar > operator+(const ExpressionPtr< Scalar > &lhs)
Definition expression.hpp:353
Definition expression.hpp:1280
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &y) const override
Definition expression.hpp:1308
constexpr HypotExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:1285
ExpressionType type() const override
Definition expression.hpp:1294
std::string_view name() const override
Definition expression.hpp:1296
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &y) const override
Definition expression.hpp:1314
Scalar value(Scalar x, Scalar y) const override
Definition expression.hpp:1289
Scalar grad_r(Scalar x, Scalar y) const override
Definition expression.hpp:1303
Scalar grad_l(Scalar x, Scalar y) const override
Definition expression.hpp:1298
Definition expression.hpp:1351
ExpressionType type() const override
Definition expression.hpp:1362
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1358
std::string_view name() const override
Definition expression.hpp:1364
constexpr IsNonnegativeExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1355
Definition expression.hpp:1384
std::string_view name() const override
Definition expression.hpp:1397
ExpressionType type() const override
Definition expression.hpp:1395
constexpr IsPositiveExpression(ExpressionPtr< Scalar > x)
Definition expression.hpp:1388
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1391
Definition expression.hpp:1469
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1476
std::string_view name() const override
Definition expression.hpp:1483
constexpr Log10Expression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1473
ExpressionType type() const override
Definition expression.hpp:1481
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1489
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1485
Definition expression.hpp:1417
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1435
ExpressionType type() const override
Definition expression.hpp:1429
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1433
std::string_view name() const override
Definition expression.hpp:1431
constexpr LogExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1421
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1424
Definition expression.hpp:1525
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &a, const ExpressionPtr< Scalar > &b) const override
Definition expression.hpp:1550
Scalar value(Scalar a, Scalar b) const override
Definition expression.hpp:1533
Scalar grad_r(Scalar a, Scalar b) const override
Definition expression.hpp:1546
constexpr MaxExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:1530
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &a, const ExpressionPtr< Scalar > &b) const override
Definition expression.hpp:1558
Scalar grad_l(Scalar a, Scalar b) const override
Definition expression.hpp:1542
ExpressionType type() const override
Definition expression.hpp:1538
std::string_view name() const override
Definition expression.hpp:1540
Definition expression.hpp:1594
std::string_view name() const override
Definition expression.hpp:1609
Scalar value(Scalar a, Scalar b) const override
Definition expression.hpp:1602
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &a, const ExpressionPtr< Scalar > &b) const override
Definition expression.hpp:1620
ExpressionType type() const override
Definition expression.hpp:1607
constexpr MinExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:1599
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &a, const ExpressionPtr< Scalar > &b) const override
Definition expression.hpp:1629
Scalar grad_l(Scalar a, Scalar b) const override
Definition expression.hpp:1611
Scalar grad_r(Scalar a, Scalar b) const override
Definition expression.hpp:1615
Definition expression.hpp:656
Scalar grad_l(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:670
Scalar value(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:664
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs) const override
Definition expression.hpp:678
constexpr MultExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:661
ExpressionType type() const override
Definition expression.hpp:666
std::string_view name() const override
Definition expression.hpp:668
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &lhs, const ExpressionPtr< Scalar > &rhs) const override
Definition expression.hpp:684
Scalar grad_r(Scalar lhs, Scalar rhs) const override
Definition expression.hpp:674
Definition expression.hpp:1667
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &base, const ExpressionPtr< Scalar > &power) const override
Definition expression.hpp:1696
Scalar value(Scalar base, Scalar power) const override
Definition expression.hpp:1675
ExpressionType type() const override
Definition expression.hpp:1680
Scalar grad_l(Scalar base, Scalar power) const override
Definition expression.hpp:1684
ExpressionPtr< Scalar > grad_expr_r(const ExpressionPtr< Scalar > &base, const ExpressionPtr< Scalar > &power) const override
Definition expression.hpp:1703
Scalar grad_r(Scalar base, Scalar power) const override
Definition expression.hpp:1689
std::string_view name() const override
Definition expression.hpp:1682
constexpr PowExpression(ExpressionPtr< Scalar > lhs, ExpressionPtr< Scalar > rhs)
Definition expression.hpp:1672
Definition expression.hpp:1756
constexpr SignExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1760
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1763
ExpressionType type() const override
Definition expression.hpp:1773
std::string_view name() const override
Definition expression.hpp:1775
Definition expression.hpp:1805
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1812
std::string_view name() const override
Definition expression.hpp:1819
ExpressionType type() const override
Definition expression.hpp:1817
constexpr SinExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1809
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1826
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1821
Definition expression.hpp:1860
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1876
std::string_view name() const override
Definition expression.hpp:1874
ExpressionType type() const override
Definition expression.hpp:1872
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1881
constexpr SinhExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1864
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1867
Definition expression.hpp:1915
ExpressionType type() const override
Definition expression.hpp:1927
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1931
std::string_view name() const override
Definition expression.hpp:1929
constexpr SqrtExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1919
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1922
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1936
Definition expression.hpp:1971
std::string_view name() const override
Definition expression.hpp:1985
constexpr TanExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:1975
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:1987
ExpressionType type() const override
Definition expression.hpp:1983
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:1994
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:1978
Definition expression.hpp:2029
Scalar grad_l(Scalar x, Scalar) const override
Definition expression.hpp:2045
ExpressionType type() const override
Definition expression.hpp:2041
std::string_view name() const override
Definition expression.hpp:2043
Scalar value(Scalar x, Scalar) const override
Definition expression.hpp:2036
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &x, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:2052
constexpr TanhExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:2033
Definition expression.hpp:696
Scalar grad_l(Scalar, Scalar) const override
Definition expression.hpp:709
constexpr UnaryMinusExpression(ExpressionPtr< Scalar > lhs)
Definition expression.hpp:700
ExpressionPtr< Scalar > grad_expr_l(const ExpressionPtr< Scalar > &, const ExpressionPtr< Scalar > &) const override
Definition expression.hpp:711
ExpressionType type() const override
Definition expression.hpp:705
Scalar value(Scalar lhs, Scalar) const override
Definition expression.hpp:703
std::string_view name() const override
Definition expression.hpp:707