所以我正在尝试实现一个 Gauss-Kronrod 自适应正交。也就是说,我要计算
其中 f(x) 一次在多个点进行评估以提高效率。要记住的一个关键点是也是向量值的(这里可能与向量化的双重含义和使用混淆);在实践中,我同时整合了复数被积函数的实部和虚部,或者被积函数可以是 3D 矢量(电场)等。
我已经制定了 R 中的基本求积步骤(最终将使用 Armadillo 库移植到 C++,任何类似 Matlab 的矩阵语法都可以用于讨论),我首先将积分分成 N 部分,并评估对应于 Gauss 和 Kronrod 节点的加权和。
## nodes and weights borrowed from Octave source code
abscissa = c(-0.9914553711208126e+00, -0.9491079123427585e+00,
-0.8648644233597691e+00, -0.7415311855993944e+00,
-0.5860872354676911e+00, -0.4058451513773972e+00,
-0.2077849550078985e+00, 0.0000000000000000e+00,
0.2077849550078985e+00, 0.4058451513773972e+00,
0.5860872354676911e+00, 0.7415311855993944e+00,
0.8648644233597691e+00, 0.9491079123427585e+00,
0.9914553711208126e+00)
weights15 = c(0.2293532201052922e-01, 0.6309209262997855e-01,
0.1047900103222502e+00, 0.1406532597155259e+00,
0.1690047266392679e+00, 0.1903505780647854e+00,
0.2044329400752989e+00, 0.2094821410847278e+00,
0.2044329400752989e+00, 0.1903505780647854e+00,
0.1690047266392679e+00, 0.1406532597155259e+00,
0.1047900103222502e+00, 0.6309209262997855e-01,
0.2293532201052922e-01)
weights7 = c(0.1294849661688697e+00, 0.2797053914892767e+00,
0.3818300505051889e+00, 0.4179591836734694e+00,
0.3818300505051889e+00, 0.2797053914892767e+00,
0.1294849661688697e+00)
gauss_kronrod <- function(f, a, b, startN=10, dimf = 2, eps = 1e-3, ...){
Nquad <- length(abscissa)
intervals <- seq(a, b, length=startN)
## change of variable from [a, b] to [-1, 1]
shifts <- (intervals[-length(intervals)] + intervals[-1]) / 2
scalings <- diff(intervals) / 2
## scale the weights accordingly
weightsG <- tcrossprod(weights15, scalings)
weightsK <- tcrossprod(weights7, scalings)
## transformed node positions
x.scaled <- tcrossprod(abscissa, scalings) +
matrix(shifts, ncol=length(shifts), nrow=Nquad, byrow=TRUE)
## evaluate the function at all points
fvals <- f(c(x.scaled))
## function evaluations are reshaped into a 3D array
## rows correspond to dimf values of integrand
## columns are the Nquad evalution points in the sub-intervals
## slices correspond to the (startN - 1) sub-intervals
dim(fvals) = c(dimf, Nquad, startN-1)
## select which subset of fvals are used for the 7-points kronrod sum
ikron <- rep(c(FALSE, TRUE), length.out=Nquad)
gauss <- kronrod <- matrix(0, nrow=dimf, ncol=startN-1)
for (ii in seq.int(startN-1)){ # integrals for each sub-interval
gauss[,ii] <- fvals[,,ii] %*% weightsG[,ii]
kronrod[,ii] <- fvals[,ikron,ii] %*% weightsK[,ii]
}
## relative difference between the two rules
errors <- abs(gauss - kronrod) / abs(gauss)
test <- which(apply(errors, 2, max) > eps)
## net integral, just sum the partial sums...
rowSums(gauss)
}
# a vector-valued integrand...
f <- function(x) rbind(exp(x/(x+2))*sin(x), cos(x))
gauss_kronrod(f, 2, 110, startN=10)
我的问题是在尝试实施自适应方案时出现的;基本上,在每次迭代中,我想比较每个子区间的gauss
vs值kronrod
,并从那里决定在哪里进一步细分。什么是在迭代期间存储这些中间结果的好策略,并在最终求和中跟踪哪些子区间和去哪里等?
关于这项工作的更一般的建议也将不胜感激,我通常不热衷于自己实现这样的通用操作,但它似乎比将不同的库链接在一起更容易(最初我正在考虑cuture,因为我的最终目标是 2D一体化)。