// Copyright (c) 2025 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef _MathInteg_Multiple_HeaderFile #define _MathInteg_Multiple_HeaderFile #include "MathUtils_Types.hxx" #include "MathUtils_Config.hxx" #include "math_Vector.hxx" #include "math_IntegerVector.hxx" #include "math_Matrix.hxx" #include "MathUtils_GaussKronrodWeights.hxx" #include "NCollection_DynamicArray.hxx" #include #include namespace MathInteg { using namespace MathUtils; //! Configuration for multi-dimensional Gauss integration. struct MultipleConfig { int MaxOrder = 61; //!< Maximum integration order per dimension }; //! Gauss-Legendre integration of a multi-variable function. //! //! Computes the N-dimensional integral using tensor product of 1D //! Gauss-Legendre quadrature: //! I = integral_{Lower}^{Upper} F(x1,...,xN) dx1...dxN //! //! Uses recursive summation over all Gauss points in each dimension. //! //! @tparam Func function type with bool Value(const math_Vector&, double&) //! @param theFunc N-dimensional function to integrate //! @param theNVars number of variables //! @param theLower lower bounds for each variable //! @param theUpper upper bounds for each variable //! @param theOrder integration order for each variable (max 61) //! @param theConfig optional configuration //! @return IntegResult containing the integral value template IntegResult GaussMultiple(Func& theFunc, int theNVars, const math_Vector& theLower, const math_Vector& theUpper, const math_IntegerVector& theOrder, const MultipleConfig& theConfig = MultipleConfig()) { IntegResult aResult; // Validate inputs if (theNVars <= 0 || theLower.Length() != theNVars || theUpper.Length() != theNVars || theOrder.Length() != theNVars) { aResult.Status = Status::InvalidInput; return aResult; } const int aLowerL = theLower.Lower(); const int aLowerU = theUpper.Lower(); const int aLowerOr = theOrder.Lower(); // Find maximum order and clamp orders math_IntegerVector aOrd(0, theNVars - 1); int aMaxOrder = 0; for (int i = 0; i < theNVars; ++i) { aOrd(i) = std::min(theOrder(i + aLowerOr), theConfig.MaxOrder); aOrd(i) = std::max(aOrd(i), 1); if (aOrd(i) > aMaxOrder) { aMaxOrder = aOrd(i); } } // Compute midpoints and half-widths for coordinate transformation math_Vector aXm(0, theNVars - 1); math_Vector aXr(0, theNVars - 1); for (int i = 0; i < theNVars; ++i) { aXm(i) = 0.5 * (theLower(i + aLowerL) + theUpper(i + aLowerU)); aXr(i) = 0.5 * (theUpper(i + aLowerU) - theLower(i + aLowerL)); } // Get Gauss points and weights for each variable // Use NCollection_DynamicArray since math_Vector has no default constructor NCollection_DynamicArray aGaussPoints; NCollection_DynamicArray aGaussWeights; for (int i = 0; i < theNVars; ++i) { aGaussPoints.Append(math_Vector(0, aOrd(i) - 1)); aGaussWeights.Append(math_Vector(0, aOrd(i) - 1)); math_Vector aGP(1, aOrd(i)); math_Vector aGW(1, aOrd(i)); if (!GetOrderedGaussPointsAndWeights(aOrd(i), aGP, aGW)) { aResult.Status = Status::InvalidInput; return aResult; } for (int k = 0; k < aOrd(i); ++k) { aGaussPoints.ChangeValue(i)(k) = aGP(k + 1); aGaussWeights.ChangeValue(i)(k) = aGW(k + 1); } } // Recursive integration using lambda double aVal = 0.0; math_Vector aX(1, theNVars); math_Vector aDx(1, theNVars); // Index array for iteration math_IntegerVector aInc(0, theNVars - 1, 0); // Iterative approach using index array std::function aRecurse = [&](int theN) -> bool { if (theN == theNVars) { // Compute function value at current Gauss point for (int j = 0; j < theNVars; ++j) { aDx(j + 1) = aXr(j) * aGaussPoints.Value(j)(aInc(j)); aX(j + 1) = aXm(j) + aDx(j + 1); } double aF1; if (!theFunc.Value(aX, aF1)) { return false; } // Compute product of weights double aWeight = 1.0; for (int j = 0; j < theNVars; ++j) { aWeight *= aGaussWeights.Value(j)(aInc(j)); } aVal += aWeight * aF1; return true; } // Iterate over Gauss points for variable theN for (aInc(theN) = 0; aInc(theN) < aOrd(theN); ++aInc(theN)) { if (!aRecurse(theN + 1)) { return false; } } return true; }; if (!aRecurse(0)) { aResult.Status = Status::NotConverged; return aResult; } // Scale by half-widths for (int i = 0; i < theNVars; ++i) { aVal *= aXr(i); } aResult.Value = aVal; aResult.Status = Status::OK; return aResult; } //! Gauss-Legendre integration with uniform order for all variables. //! //! @tparam Func function type with bool Value(const math_Vector&, double&) //! @param theFunc N-dimensional function to integrate //! @param theNVars number of variables //! @param theLower lower bounds for each variable //! @param theUpper upper bounds for each variable //! @param theOrder integration order for all variables //! @return IntegResult containing the integral value template IntegResult GaussMultipleUniform(Func& theFunc, int theNVars, const math_Vector& theLower, const math_Vector& theUpper, int theOrder) { math_IntegerVector aOrders(0, theNVars - 1, theOrder); return GaussMultiple(theFunc, theNVars, theLower, theUpper, aOrders); } } // namespace MathInteg #endif // _MathInteg_Multiple_HeaderFile