8#include "lmmc/quadrature.h"
23 const std::string& operation) {
25 if (!
value.value().is_finite() || !std::isfinite(
value.value().value)) {
28 "numeric evaluation did not produce a finite double",
35 const std::shared_ptr<SymbolicExpr>& expr,
37 const std::string& operation) {
47 const std::shared_ptr<SymbolicExpr>&
function,
49 const std::shared_ptr<SymbolicExpr>&
lower,
50 const std::shared_ptr<SymbolicExpr>&
upper,
51 const std::string& operation) {
55 "integrand and bounds must be non-null",
61 "integration variable must not be empty",
74 const std::shared_ptr<SymbolicExpr>&
lower,
75 const std::shared_ptr<SymbolicExpr>&
upper,
77 const std::string& operation) {
95 const std::shared_ptr<SymbolicExpr>*
function =
nullptr;
104 if (callback.error)
return std::numeric_limits<double>::quiet_NaN();
106 bindings.emplace(*callback.variable, x);
111 callback.error =
value.error();
112 return std::numeric_limits<double>::quiet_NaN();
114 return value.value();
119 if (status == LMMC_STATUS_ALLOCATION_FAILED ||
120 status == LMMC_STATUS_REFERENCE_LIMIT ||
121 status == LMMC_STATUS_WARNING_MAX_DEPTH) {
139 double estimated_error,
141 const std::string& operation) {
143 estimated_error = std::abs(estimated_error);
144 if (!std::isfinite(
value) || !std::isfinite(estimated_error)) {
147 "quadrature accumulation or error estimate is non-finite",
159 const std::shared_ptr<SymbolicExpr>&
function,
161 const std::shared_ptr<SymbolicExpr>&
lower,
162 const std::shared_ptr<SymbolicExpr>&
upper,
165 constexpr const char* operation =
"quadrature_simpson";
166 auto valid = validate_quadrature_args(
169 if (subdivisions <= 0 || subdivisions % 2 != 0) {
172 "Simpson subinterval count must be positive and even",
175 if (subdivisions > std::numeric_limits<int>::max() / 2) {
178 "Simpson refinement count overflows",
186 const auto refined_subdivisions =
187 static_cast<std::size_t
>(subdivisions) * 2;
189 static_cast<std::size_t
>(subdivisions) + 1 +
190 refined_subdivisions + 1;
191 auto budget =
context.consume_steps(samples, operation);
195 QuadratureCallback callback{
198 auto status = lmmc_quad_simpson(
199 evaluate_quadrature_callback, &callback,
201 static_cast<std::size_t
>(subdivisions), &
value);
203 if (status != LMMC_STATUS_OK) {
204 return quadrature_failure<QuadratureEstimate>(status, operation);
207 double refined_value = 0.0;
208 status = lmmc_quad_simpson(
209 evaluate_quadrature_callback, &callback,
211 refined_subdivisions, &refined_value);
213 if (status != LMMC_STATUS_OK) {
214 return quadrature_failure<QuadratureEstimate>(status, operation);
216 const double correction = (refined_value -
value) / 15.0;
217 const double extrapolated_value = refined_value + correction;
218 return estimated_quadrature_result(
219 extrapolated_value, std::abs(correction),
224 const std::shared_ptr<SymbolicExpr>&
function,
226 const std::shared_ptr<SymbolicExpr>&
lower,
227 const std::shared_ptr<SymbolicExpr>&
upper,
235 const std::shared_ptr<SymbolicExpr>&
function,
237 const std::shared_ptr<SymbolicExpr>&
lower,
238 const std::shared_ptr<SymbolicExpr>&
upper,
241 constexpr const char* operation =
"quadrature_gaussian";
242 auto valid = validate_quadrature_args(
248 "Gaussian quadrature order must be in [1, 20]",
256 const int comparison_order =
order == 20 ? 19 :
order + 1;
257 auto budget =
context.consume_steps(
258 static_cast<std::size_t
>(
order + comparison_order + 2), operation);
262 QuadratureCallback callback{
265 auto status = lmmc_quad_gauss_legendre(
266 evaluate_quadrature_callback, &callback,
270 if (status != LMMC_STATUS_OK) {
271 return quadrature_failure<QuadratureEstimate>(status, operation);
275 status = lmmc_quad_gauss_legendre(
276 evaluate_quadrature_callback, &callback,
280 if (status != LMMC_STATUS_OK) {
281 return quadrature_failure<QuadratureEstimate>(status, operation);
283 return estimated_quadrature_result(
289 const std::shared_ptr<SymbolicExpr>&
function,
291 const std::shared_ptr<SymbolicExpr>&
lower,
292 const std::shared_ptr<SymbolicExpr>&
upper,
300 const std::shared_ptr<SymbolicExpr>&
function,
302 const std::shared_ptr<SymbolicExpr>&
lower,
303 const std::shared_ptr<SymbolicExpr>&
upper,
307 constexpr const char* operation =
"adaptive_simpson";
308 auto valid = validate_quadrature_args(
311 if (!(tolerance > 0.0) || !std::isfinite(tolerance)) {
314 "tolerance must be finite and positive",
320 "maximum recursion depth must be non-negative",
328 auto recursion =
context.enter_recursion(operation);
330 struct RecursionGuard {
332 ~RecursionGuard() {
context.leave_recursion(); }
334 const std::size_t remaining_depth =
336 ?
context.limits().max_recursion_depth -
context.recursion_depth()
338 const std::size_t effective_depth = std::min(
339 static_cast<std::size_t
>(max_depth), remaining_depth);
342 QuadratureCallback callback{
344 lmmc_quad_result_t backend_result{};
345 const auto status = lmmc_quad_adaptive(
346 evaluate_quadrature_callback, &callback,
348 tolerance, 0.0, effective_depth, &backend_result);
350 if (status == LMMC_STATUS_WARNING_MAX_DEPTH) {
353 "adaptive Simpson recursion limit reached before meeting tolerance",
356 if (status != LMMC_STATUS_OK) {
357 return quadrature_failure<QuadratureEstimate>(status, operation);
362 std::numeric_limits<double>::epsilon() *
363 std::max(1.0, std::abs(result.
value)) * 16.0;
367 "adaptive Simpson result is not finite",
374 const std::shared_ptr<SymbolicExpr>&
function,
376 const std::shared_ptr<SymbolicExpr>&
lower,
377 const std::shared_ptr<SymbolicExpr>&
upper,
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
CasErrc quadrature_error_code(lmmc_status_t status)
Result< QuadratureEstimate > estimated_quadrature_result(double value, double estimated_error, double sign, const std::string &operation)
Result< NormalizedInterval > evaluate_interval(const std::shared_ptr< SymbolicExpr > &lower, const std::shared_ptr< SymbolicExpr > &upper, ComputationContext &context, const std::string &operation)
Result< double > eval_bound_checked(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context, const std::string &operation)
Result< double > checked_finite_value(Result< ApproxReal > value, const std::string &operation)
QuadratureEstimate zero_quadrature_result()
Result< void > validate_quadrature_args(const std::shared_ptr< SymbolicExpr > &function, const std::string &variable, const std::shared_ptr< SymbolicExpr > &lower, const std::shared_ptr< SymbolicExpr > &upper, const std::string &operation)
ComputationContext * context
const std::shared_ptr< SymbolicExpr > * function
std::optional< CasError > error
const std::string * variable
double evaluate_quadrature_callback(double x, void *user_data)
Result< T > quadrature_failure(lmmc_status_t status, const std::string &operation)
void ensure_lmmc_lifecycle() noexcept
ExprResult comparison_value(const ExprPtr &expression, ComputationContext &context)
const std::string & variable
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
const std::vector< FGLMPoly > const MonomialOrder & order
const std::vector< Binding > & bindings
Result< QuadratureEstimate > quadrature_simpson_numeric(const std::shared_ptr< SymbolicExpr > &function, const std::string &variable, const std::shared_ptr< SymbolicExpr > &lower, const std::shared_ptr< SymbolicExpr > &upper, ComputationContext &context, int subdivisions)
Result< QuadratureEstimate > adaptive_simpson_numeric(const std::shared_ptr< SymbolicExpr > &function, const std::string &variable, const std::shared_ptr< SymbolicExpr > &lower, const std::shared_ptr< SymbolicExpr > &upper, ComputationContext &context, double tolerance, int max_depth)
const std::string const ExprPtr & value
Result< QuadratureEstimate > quadrature_gaussian_numeric(const std::shared_ptr< SymbolicExpr > &function, const std::string &variable, const std::shared_ptr< SymbolicExpr > &lower, const std::shared_ptr< SymbolicExpr > &upper, ComputationContext &context, int order)
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
std::unordered_map< std::string, double > NumericBindings
数值积分算法:辛普森法则和高斯求积(符号-数值混合桥接).
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.