limes 3.1.0
Composable Calculus Expressions for C++20
Loading...
Searching...
No Matches
antiderivatives.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4#include <cstddef>
5#include "nodes/const.hpp"
6#include "nodes/var.hpp"
7#include "nodes/binary.hpp"
8#include "nodes/unary.hpp"
9#include "nodes/pow.hpp"
10#include "nodes/primitives.hpp"
11
12namespace limes::expr {
13
14// =============================================================================
15// Antiderivative Trait: Check if expression has known symbolic antiderivative
16// =============================================================================
17
18// Primary template: assume no antiderivative is known
19template<typename E, std::size_t Dim, typename = void>
20struct has_antiderivative : std::false_type {};
21
22// Helper variable template
23template<typename E, std::size_t Dim>
25
26// =============================================================================
27// Specializations for known antiderivatives
28// =============================================================================
29
30// ∫ c dx = c*x (constant with respect to integration variable)
31template<typename T, std::size_t Dim>
32struct has_antiderivative<Const<T>, Dim> : std::true_type {};
33
34// ∫ 0 dx = 0
35template<typename T, std::size_t Dim>
36struct has_antiderivative<Zero<T>, Dim> : std::true_type {};
37
38// ∫ 1 dx = x
39template<typename T, std::size_t Dim>
40struct has_antiderivative<One<T>, Dim> : std::true_type {};
41
42// ∫ x dx = x²/2 (when integrating Var<Dim> over Dim)
43template<std::size_t N, typename T, std::size_t Dim>
44struct has_antiderivative<Var<N, T>, Dim>
45 : std::bool_constant<N == Dim> {};
46
47// ∫ x^n dx = x^(n+1)/(n+1) for integer n ≠ -1
48template<typename E, int N, std::size_t Dim>
49struct has_antiderivative<Pow<E, N>, Dim,
50 std::enable_if_t<N != -1 && has_antiderivative_v<E, Dim> &&
51 std::is_same_v<E, Var<Dim, typename E::value_type>>>>
52 : std::true_type {};
53
54// ∫ sin(x) dx = -cos(x)
55template<typename E, std::size_t Dim>
57 std::enable_if_t<std::is_same_v<E, Var<Dim, typename E::value_type>>>>
58 : std::true_type {};
59
60// ∫ cos(x) dx = sin(x)
61template<typename E, std::size_t Dim>
63 std::enable_if_t<std::is_same_v<E, Var<Dim, typename E::value_type>>>>
64 : std::true_type {};
65
66// ∫ exp(x) dx = exp(x)
67template<typename E, std::size_t Dim>
69 std::enable_if_t<std::is_same_v<E, Var<Dim, typename E::value_type>>>>
70 : std::true_type {};
71
72// ∫ 1/x dx = ln|x| (as Binary<Div, One, Var>)
73// This is tricky - we'd need pattern matching for 1/x
74
75// ∫ (f + g) dx = ∫f dx + ∫g dx
76template<typename L, typename R, std::size_t Dim>
77struct has_antiderivative<Binary<Add, L, R>, Dim>
78 : std::bool_constant<has_antiderivative_v<L, Dim> && has_antiderivative_v<R, Dim>> {};
79
80// ∫ (f - g) dx = ∫f dx - ∫g dx
81template<typename L, typename R, std::size_t Dim>
82struct has_antiderivative<Binary<Sub, L, R>, Dim>
83 : std::bool_constant<has_antiderivative_v<L, Dim> && has_antiderivative_v<R, Dim>> {};
84
85// ∫ c*f dx = c * ∫f dx (when c is constant w.r.t. Dim)
86template<typename L, typename R, std::size_t Dim>
87struct has_antiderivative<Binary<Mul, L, R>, Dim,
88 std::enable_if_t<
89 // L is constant and R has antiderivative
90 (is_const_expr_v<L> || is_zero_v<L> || is_one_v<L> ||
91 (is_expr_node_v<L> && !std::is_same_v<L, Var<Dim, typename L::value_type>> &&
92 L::arity_v <= Dim)) &&
93 has_antiderivative_v<R, Dim>
94 >> : std::true_type {};
95
96// ∫ f*c dx = ∫f dx * c (when c is constant w.r.t. Dim)
97template<typename L, typename R, std::size_t Dim>
98struct has_antiderivative<Binary<Mul, L, R>, Dim,
99 std::enable_if_t<
100 has_antiderivative_v<L, Dim> &&
101 (is_const_expr_v<R> || is_zero_v<R> || is_one_v<R>) &&
102 !is_const_expr_v<L> && !is_zero_v<L> && !is_one_v<L>
103 >> : std::true_type {};
104
105// ∫ -f dx = -∫f dx
106template<typename E, std::size_t Dim>
108 : std::bool_constant<has_antiderivative_v<E, Dim>> {};
109
110// =============================================================================
111// Antiderivative Computation
112// =============================================================================
113
114// Primary template declaration (defined via specialization)
115template<std::size_t Dim, typename E>
117
118// Helper function
119template<std::size_t Dim, typename E>
120[[nodiscard]] constexpr auto antiderivative(E expr) {
121 static_assert(has_antiderivative_v<E, Dim>,
122 "No symbolic antiderivative known for this expression");
124}
125
126// =============================================================================
127// Antiderivative Implementations
128// =============================================================================
129
130// ∫ c dx = c*x
131template<std::size_t Dim, typename T>
132struct antiderivative_impl<Dim, Const<T>> {
133 static constexpr auto compute(Const<T> c) {
134 auto x = Var<Dim, T>{};
135 return c * x;
136 }
137};
138
139// ∫ 0 dx = 0
140template<std::size_t Dim, typename T>
141struct antiderivative_impl<Dim, Zero<T>> {
142 static constexpr auto compute(Zero<T>) {
143 return Zero<T>{};
144 }
145};
146
147// ∫ 1 dx = x
148template<std::size_t Dim, typename T>
149struct antiderivative_impl<Dim, One<T>> {
150 static constexpr auto compute(One<T>) {
151 return Var<Dim, T>{};
152 }
153};
154
155// ∫ x dx = x²/2
156template<std::size_t Dim, typename T>
157struct antiderivative_impl<Dim, Var<Dim, T>> {
158 static constexpr auto compute(Var<Dim, T>) {
159 auto x = Var<Dim, T>{};
160 auto half = Const<T>{T(0.5)};
161 return half * x * x;
162 }
163};
164
165// ∫ x^n dx = x^(n+1)/(n+1)
166template<std::size_t Dim, typename T, int N>
167struct antiderivative_impl<Dim, Pow<Var<Dim, T>, N>> {
168 static constexpr auto compute(Pow<Var<Dim, T>, N>) {
169 auto x = Var<Dim, T>{};
170 constexpr int new_exp = N + 1;
171 auto coeff = Const<T>{T(1) / T(new_exp)};
172 return coeff * pow<new_exp>(x);
173 }
174};
175
176// ∫ sin(x) dx = -cos(x)
177template<std::size_t Dim, typename T>
178struct antiderivative_impl<Dim, UnaryFunc<SinTag, Var<Dim, T>>> {
179 static constexpr auto compute(UnaryFunc<SinTag, Var<Dim, T>>) {
180 auto x = Var<Dim, T>{};
181 return -cos(x);
182 }
183};
184
185// ∫ cos(x) dx = sin(x)
186template<std::size_t Dim, typename T>
187struct antiderivative_impl<Dim, UnaryFunc<CosTag, Var<Dim, T>>> {
188 static constexpr auto compute(UnaryFunc<CosTag, Var<Dim, T>>) {
189 auto x = Var<Dim, T>{};
190 return sin(x);
191 }
192};
193
194// ∫ exp(x) dx = exp(x)
195template<std::size_t Dim, typename T>
196struct antiderivative_impl<Dim, UnaryFunc<ExpTag, Var<Dim, T>>> {
197 static constexpr auto compute(UnaryFunc<ExpTag, Var<Dim, T>>) {
198 auto x = Var<Dim, T>{};
199 return exp(x);
200 }
201};
202
203// ∫ (f + g) dx = ∫f dx + ∫g dx
204template<std::size_t Dim, typename L, typename R>
205struct antiderivative_impl<Dim, Binary<Add, L, R>> {
206 static constexpr auto compute(Binary<Add, L, R> expr) {
207 auto F = antiderivative<Dim>(expr.left);
208 auto G = antiderivative<Dim>(expr.right);
209 return F + G;
210 }
211};
212
213// ∫ (f - g) dx = ∫f dx - ∫g dx
214template<std::size_t Dim, typename L, typename R>
215struct antiderivative_impl<Dim, Binary<Sub, L, R>> {
216 static constexpr auto compute(Binary<Sub, L, R> expr) {
217 auto F = antiderivative<Dim>(expr.left);
218 auto G = antiderivative<Dim>(expr.right);
219 return F - G;
220 }
221};
222
223// ∫ c*f dx = c * ∫f dx (Const * Expr)
224template<std::size_t Dim, typename T, typename R>
225struct antiderivative_impl<Dim, Binary<Mul, Const<T>, R>> {
226 static constexpr auto compute(Binary<Mul, Const<T>, R> expr) {
227 auto F = antiderivative<Dim>(expr.right);
228 return expr.left * F;
229 }
230};
231
232// ∫ f*c dx = ∫f dx * c (Expr * Const)
233template<std::size_t Dim, typename L, typename T>
234struct antiderivative_impl<Dim, Binary<Mul, L, Const<T>>> {
235 static constexpr auto compute(Binary<Mul, L, Const<T>> expr) {
236 auto F = antiderivative<Dim>(expr.left);
237 return F * expr.right;
238 }
239};
240
241// ∫ -f dx = -∫f dx
242template<std::size_t Dim, typename E>
243struct antiderivative_impl<Dim, Unary<Neg, E>> {
244 static constexpr auto compute(Unary<Neg, E> expr) {
245 auto F = antiderivative<Dim>(expr.child);
246 return -F;
247 }
248};
249
250// =============================================================================
251// Definite Integral using Fundamental Theorem of Calculus
252// =============================================================================
253
254// Evaluate definite integral symbolically: ∫[a,b] f dx = F(b) - F(a)
255template<std::size_t Dim, typename E, typename T>
256[[nodiscard]] constexpr T definite_integral_symbolic(E expr, T a, T b) {
257 static_assert(has_antiderivative_v<E, Dim>,
258 "No symbolic antiderivative known for this expression");
259
260 auto F = antiderivative<Dim>(expr);
261
262 // Evaluate F at bounds
263 std::array<T, Dim + 1> args_b{};
264 args_b[Dim] = b;
265 T F_b = F.eval(std::span<T const>{args_b});
266
267 std::array<T, Dim + 1> args_a{};
268 args_a[Dim] = a;
269 T F_a = F.eval(std::span<T const>{args_a});
270
271 return F_b - F_a;
272}
273
274} // namespace limes::expr
Expression layer for composable calculus.
Definition analysis.hpp:7
constexpr bool has_antiderivative_v
constexpr auto cos(E e)
constexpr auto antiderivative(E expr)
constexpr T definite_integral_symbolic(E expr, T a, T b)
constexpr auto sin(E e)
constexpr auto exp(E e)
constexpr Var< 0, T > x
Definition var.hpp:46
static constexpr auto compute(Binary< Add, L, R > expr)
static constexpr auto compute(Binary< Mul, Const< T >, R > expr)
static constexpr auto compute(Binary< Mul, L, Const< T > > expr)
static constexpr auto compute(Binary< Sub, L, R > expr)
static constexpr auto compute(Pow< Var< Dim, T >, N >)
static constexpr auto compute(UnaryFunc< CosTag, Var< Dim, T > >)
static constexpr auto compute(UnaryFunc< ExpTag, Var< Dim, T > >)
static constexpr auto compute(UnaryFunc< SinTag, Var< Dim, T > >)
static constexpr auto compute(Unary< Neg, E > expr)