Gauss-Laguerre Quadrature Evaluation Points and Weights
This example shows how to solve polynomial equations and systems of equations, and work with the results using Symbolic Math Toolbox™.
Gaussian quadrature rules approximate an integral by sums . Here, the and are parameters of the method, depending on but not on . They follow from the choice of the weight function , as follows. Associated to the weight function is a family of orthogonal polynomials. The polynomials' roots are the evaluation points . Finally, the weights are determined by the condition that the method be correct for polynomials of small degree. Consider the weight function on the interval . This case is known as the Gauss-Laguerre quadrature.
syms t
n = 4;
w(t) = exp(-t);
Assume you know the first members of the family of orthogonal polynomials. In case of the quadrature rule considered here, they turn out to be the Laguerre polynomials.
F = laguerreL(0:n-1, t)
F =
Let L
be the st polynomial, the coefficients of which are still to be determined.
X = sym('X', [1, n+1])
X =
L = poly2sym(X, t)
L =
Represent the orthogonality relations between the Laguerre polynomials F
and L
in a system of equations sys
.
sys = [int(F.*L.*w(t), t, 0, inf) == 0]
sys =
Add the condition that the polynomial have norm 1.
sys = [sys, int(L^2.*w(t), 0, inf) == 1]
sys =
Solve for the coefficients of L
.
S = solve(sys, X)
S = struct with fields:
X1: [2x1 sym]
X2: [2x1 sym]
X3: [2x1 sym]
X4: [2x1 sym]
X5: [2x1 sym]
solve
returns the two solutions in a structure array. Display the solutions.
structfun(@display, S)
ans =
ans =
ans =
ans =
ans =
Make the solution unique by imposing an extra condition that the first coefficient be positive:
sys = [sys, X(1)>0]; S = solve(sys, X)
S = struct with fields:
X1: 1/24
X2: -2/3
X3: 3
X4: -4
X5: 1
Substitute the solution into L
.
L = subs(L, S)
L =
As expected, this polynomial is the |n|th Laguerre polynomial:
laguerreL(n, t)
ans =
The evaluation points are the roots of the polynomial L
. Solve L
for the evaluation points. The roots are expressed in terms of the root
function.
x = solve(L)
x =
The form of the solutions might suggest that nothing has been achieved, but various operations are available on them. Compute floating-point approximations using vpa
:
vpa(x)
ans =
Some spurious imaginary parts might occur. Prove symbolically that the roots are real numbers:
isAlways(in(x, 'real'))
ans = 4x1 logical array
1
1
1
1
For polynomials of degree less than or equal to 4, you can use MaxDegree
to obtain the solutions in terms of nested radicals instead in terms of root
. However, subsequent operations on results of this form would be slow.
xradical = solve(L, 'MaxDegree', 4)
xradical =
The weights are given by the condition that for polynomials of degree less than , the quadrature rule must produce exact results. It is sufficient if this holds for a basis of the vector space of these polynomials. This condition results in a system of four equations in four variables.
y = sym('y', [n, 1]); sys = sym(zeros(n)); for k=0:n-1 sys(k+1) = sum(y.*(x.^k)) == int(t^k * w(t), t, 0, inf); end sys
sys =
Solve the system both numerically and symbolically. The solution is the desired vector of weights .
[a1, a2, a3, a4] = vpasolve(sys, y)
a1 =
a2 =
a3 =
a4 =
[alpha1, alpha2, alpha3, alpha4] = solve(sys, y)
alpha1 =
alpha2 =
alpha3 =
alpha4 =
Alternatively, you can also obtain the solution as a structure by giving only one output argument.
S = solve(sys, y)
S = struct with fields:
y1: -(root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 3) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 4) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 3)*root(z...
y2: (root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 3) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 4) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 3)*root(z^...
y3: (root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 4) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2)*root(z^...
y4: -(root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 1)*root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 3) + root(z^4 - 16*z^3 + 72*z^2 - 96*z + 24, z, 2)*root(z...
structfun(@double, S)
ans = 4×1
0.6032
0.3574
0.0389
0.0005
Convert the structure S
to a symbolic array:
Scell = struct2cell(S); alpha = transpose([Scell{:}])
alpha =
The symbolic solution looks complicated. Simplify it, and convert it into a floating point vector:
alpha = simplify(alpha)
alpha =
vpa(alpha)
ans =
Increase the readability by replacing the occurrences of the roots x
in alpha
by abbreviations:
subs(alpha, x, sym('R', [4, 1]))
ans =
Sum the weights to show that their sum equals 1:
simplify(sum(alpha))
ans =
A different method to obtain the weights of a quadrature rule is to compute them using the formula . Do this for . It leads to the same result as the other method:
int(w(t) * prod((t - x(2:4)) ./ (x(1) - x(2:4))), t, 0, inf)
ans =
The quadrature rule produces exact results even for all polynomials of degree less than or equal to , but not for .
simplify(sum(alpha.*(x.^(2*n-1))) -int(t^(2*n-1)*w(t), t, 0, inf))
ans =
simplify(sum(alpha.*(x.^(2*n))) -int(t^(2*n)*w(t), t, 0, inf))
ans =
Apply the quadrature rule to the cosine, and compare with the exact result:
vpa(sum(alpha.*(cos(x))))
ans =
int(cos(t)*w(t), t, 0, inf)
ans =
For powers of the cosine, the error oscillates between odd and even powers:
errors = zeros(1, 20); for k=1:20 errors(k) = double(sum(alpha.*(cos(x).^k)) -int(cos(t)^k*w(t), t, 0, inf)); end plot(real(errors))