limes 3.1.0
Composable Calculus Expressions for C++20
Loading...
Searching...
No Matches
product_integral.hpp
Go to the documentation of this file.
1#pragma once
2
44#include <type_traits>
45#include <cmath>
46#include <utility>
47#include "../algorithms/core/result.hpp"
48#include "analysis.hpp"
49
55namespace limes::expr {
56
57// Forward declarations
58template<typename E, std::size_t Dim, typename Lo, typename Hi>
59struct Integral;
60
61template<typename E, std::size_t Dims>
62struct BoxIntegral;
63
64template<typename I1, typename I2>
65struct ProductIntegral;
66
67// Helper to get variable set from any evaluable integral type
68namespace detail {
69
70template<typename T, typename = void>
71struct integral_variable_set {
72 static constexpr std::uint64_t value = 0;
73};
74
75// For types with integrand_type (Integral, BoxIntegral)
76template<typename T>
77struct integral_variable_set<T, std::void_t<typename T::integrand_type>> {
78 static constexpr std::uint64_t value = variable_set_v<typename T::integrand_type>;
79};
80
81// For ProductIntegral: combine the variable sets of both children
82template<typename I1, typename I2>
83struct integral_variable_set<ProductIntegral<I1, I2>> {
84 static constexpr std::uint64_t value =
85 integral_variable_set<I1>::value | integral_variable_set<I2>::value;
86};
87
88template<typename T>
89inline constexpr std::uint64_t integral_variable_set_v = integral_variable_set<T>::value;
90
91} // namespace detail
92
93// =============================================================================
94// ProductIntegral: Composition of independent integrals
95// =============================================================================
96
137template<typename I1, typename I2>
139 using value_type = typename I1::value_type;
140
143
144 // Verify independence at compile time
145 // The integrals must depend on disjoint sets of variables
146 static_assert(
147 (detail::integral_variable_set_v<I1> & detail::integral_variable_set_v<I2>) == 0,
148 "ProductIntegral requires integrals over independent variables. "
149 "The integrand variable sets must be disjoint."
150 );
151
152 constexpr ProductIntegral(I1 i1, I2 i2) noexcept
153 : left{i1}, right{i2} {}
154
156 [[nodiscard]] algorithms::integration_result<value_type>
157 eval() const {
158 return combine_results(left.eval(), right.eval());
159 }
160
162 template<typename... Args>
164 eval(Args&&... args) const {
165 return combine_results(
166 left.eval(std::forward<Args>(args)...),
167 right.eval(std::forward<Args>(args)...));
168 }
169
170private:
174 combine_results(algorithms::integration_result<value_type> const& r1,
176 value_type value = r1.value() * r2.value();
177 value_type error = std::abs(r2.value()) * r1.error()
178 + std::abs(r1.value()) * r2.error();
179 return {value, error,
180 r1.iterations() + r2.iterations(),
181 r1.evaluations() + r2.evaluations()};
182 }
183
184public:
185
187 [[nodiscard]] std::string to_string() const {
188 return "(product-integral " + left.to_string() + " " + right.to_string() + ")";
189 }
190
192 template<typename I3>
193 [[nodiscard]] constexpr auto operator*(I3 const& other) const {
194 return ProductIntegral<ProductIntegral, I3>{*this, other};
195 }
196};
197
198// =============================================================================
199// Type traits for ProductIntegral
200// =============================================================================
201
202template<typename T>
203struct is_product_integral : std::false_type {};
204
205template<typename I1, typename I2>
206struct is_product_integral<ProductIntegral<I1, I2>> : std::true_type {};
207
208template<typename T>
210
211// =============================================================================
212// Concepts for integral types
213// =============================================================================
214
216template<typename T>
217concept EvaluableIntegral = requires(T t) {
218 { t.eval() } -> std::same_as<algorithms::integration_result<typename T::value_type>>;
219};
220
221// =============================================================================
222// operator* for integrals (creates ProductIntegral)
223// =============================================================================
224
227template<typename I1, typename I2>
228 requires (is_integral_v<I1> && is_integral_v<I2>)
229[[nodiscard]] constexpr auto operator*(I1 const& i1, I2 const& i2) {
230 return ProductIntegral<I1, I2>{i1, i2};
231}
232
234template<typename I1, typename I2, typename I3>
235 requires is_integral_v<I3>
236[[nodiscard]] constexpr auto operator*(ProductIntegral<I1, I2> const& pi, I3 const& i3) {
237 return ProductIntegral<ProductIntegral<I1, I2>, I3>{pi, i3};
238}
239
241template<typename I1, typename I2, typename I3>
242 requires is_integral_v<I3>
243[[nodiscard]] constexpr auto operator*(I3 const& i3, ProductIntegral<I1, I2> const& pi) {
245}
246
247// =============================================================================
248// Separable integral detection and optimization
249// =============================================================================
250
252template<typename I1, typename I2>
253inline constexpr bool are_independent_integrals_v =
254 (detail::integral_variable_set_v<I1> & detail::integral_variable_set_v<I2>) == 0;
255
256// =============================================================================
257// Convenience: product() function
258// =============================================================================
259
274template<typename I1, typename I2>
276[[nodiscard]] constexpr auto product(I1 const& i1, I2 const& i2) {
277 return ProductIntegral<I1, I2>{i1, i2};
278}
279
293template<typename I1, typename I2, typename... Is>
294 requires (EvaluableIntegral<I1> && EvaluableIntegral<I2> && (EvaluableIntegral<Is> && ...))
295[[nodiscard]] constexpr auto product(I1 const& i1, I2 const& i2, Is const&... is) {
296 return product(ProductIntegral<I1, I2>{i1, i2}, is...);
297}
298
// end of expr_ops group
300
301} // namespace limes::expr
Concept for types that can be evaluated as integrals.
constexpr bool is_product_integral_v
constexpr bool are_independent_integrals_v
Check if multiplying integrals is valid (they must be over independent dimensions)
constexpr std::uint64_t integral_variable_set_v
Expression layer for composable calculus.
Definition analysis.hpp:7
constexpr auto operator*(L l, R r)
Definition binary.hpp:186
constexpr auto product(E body, int lo, int hi)
constexpr T error() const noexcept
Definition result.hpp:35
constexpr std::size_t iterations() const noexcept
Definition result.hpp:36
constexpr T value() const noexcept
Definition result.hpp:34
constexpr std::size_t evaluations() const noexcept
Definition result.hpp:37
Product of two independent integrals.
algorithms::integration_result< value_type > eval(Args &&... args) const
Evaluate with arguments (for integrals with free variables)
constexpr ProductIntegral(I1 i1, I2 i2) noexcept
std::string to_string() const
String representation.
constexpr auto operator*(I3 const &other) const
Multiply with another integral (chaining)
typename I1::value_type value_type
algorithms::integration_result< value_type > eval() const
Evaluate the product integral (no outer arguments)