With interpolation we were given a formula or data about a
function
, and we made a model
that passed through a
given set of data points. We now consider approximation, in
which we are still trying to build a model, but specify some condition
of ``closeness'' that the model must satisfy. It is still likely that
will be equal to the function
at some points, but we
will not know in advance which points.
As with interpolation, we build this model out of a set of basis
functions. The model is then a recipe, a set of coefficients
that
specify how much of each basis function to use when building the
model.
In this lab we will consider four different selections of basis
functions in the space
. The first is the usual
monomials
,
,
, and so on. In this case, the
coefficients
are exactly the coefficients Matlab uses to specify a
polynomial. The second is the set of Legendre polynomials, which will
yield the same approximations but will turn out to have better
numerical behavior. The third selection is the trigonometric
functions, and the final selection is a set of piecewise constant
functions.
Once we have our basis set, we will consider how we can determine
the approximating function
as the ``best possible'' approximate
for the given basis functions, and we will look at the
behavior of the approximation error. Since we are working in
,
we will use the
norm to measure error.
This kind of approximation requires evaluation of integrals. In most applications this evaluation is done using numerical integration, but we have not yet discussed numerical integration in general. On the other hand, you have seen the trapezoid rule for numerical integration in lecture, and we will be using a specialized application of this method.
It turns out that approximation by monomials results in a matrix
similar to the Hilbert matrix whose inversion can be quite inaccurate,
even for small sizes. This inaccuracy translates into poor
approximations. Use of orthogonal polynomials such as the
Legendre polynomials, results in a diagonal matrix that can
be inverted almost without error, but the right side is
inaccurate because of roundoff errors.
approximation is
improved but still not of high quality. Fourier approximation
substantially reduces the roundoff errors, but is slow to compute
and evaluate and still is subject to error for higher terms.
Approximation by piecewise constants is not subject to error
until ridiculously large numbers of pieces are employed.
Matlab has excellent symbolic capabilities, and it would be my preference to use the symbolic toolbox to do the integrals in this lab. Unfortunately, the symbolic toolbox does not work on the computers in GSCC, so we will not be using it.
We will be attempting to approximate several functions in this lab, all on the interval [-1,1]. These functions include:
function y=partly_quadratic(x) % y=partly_quadratic(x) % input x (possibly a vector or matrix) % output y, where % y=0 for x<=0 % y=4*x*(1-x) for x>0 % your name and the date % The Matlab expression for "true" evaluates to 1 and % "false" evaluates to 0. The following trick sets % y=0 when x<0 and works when x is a vector y=4*(x>0).*x.*(1-x);
function y=sawtooth9(x) % y=sawtooth9(x) % input x (possibly a vector or matrix) % output y, where % y=(x+1) for -1<x<0 % y=(x-1) for 0<=x<1 % The Matlab expression for "true" evaluates to 1 and % "false" evaluates to 0. y=(x+1)-2*(x>=0);
This lab will take four sessions. If you print this lab, you may prefer to use the pdf version.
You have seen the formula for integration using the trapezoid rule. Using N uniform subintervals of [a,b],
For the purpose of this lab, we will use Formula (3)
to compute the integral of a function represented as a vector of values
for
.
The Matlab function will be called trapsum
(trapezoid integration as a sum).
Because you will be
using trapsum to perform integrals in most of the exercises
below, it is essential to be sure it is well-tested. Also, you will
be using it with large values of
, so use vector syntax and the
Matlab sum function.
function I=trapsum(fValues,a,b) % comments % your name and the datethat implements Equation (3) with the integrand given by a vector of values fValues.
N Integral Error Err(N)/Err(2*N) 1000 _______ _______ ______ 2000 _______ _______ ______ 4000 _______ _______ ______ 8000 _______ _______
Remark: Getting both the correct answer and also the theoretical convergence rate is a pretty sure sign that your code is correct. The correct answer alone is often not good enough to eliminate all bugs. The only further test I might recommend is to check that the time the code takes scales correctly with size, but this kind of testing is beyond the scope of this lab.
The Legendre polynomials form an
-orthogonal set of polynomials.
You will see below why orthogonal polynomials make particularly
good choices for approximation.
In this section, we are going to write m-files to generate
the Legendre polynomials and we are going to confirm that they
form an orthogonal set in
. Throughout this section,
we will be representing polynomials as vectors of coefficients,
in the usual way in Matlab.
The Legendre polyonomials are a basis for the set of all polynomials,
just as the usual monomial powers of
are.
They are appropriate for use on the interval [-1,1] because they
are orthogonal when considered as members of
.
They are discussed in Atkinson starting on page 210, and the
first few Legendre polynomials are:
The value at
of any Legendre polynomial
can be determined using the following recursion:
function c = rlegendre ( k ) % comments if k==0 c = 1; elseif k==1 % WARNING: no space between else and if! c = [1 0]; else % look at this line carefully! c = ((2*k-1)*[rlegendre(k-1),0] - (k-1)*[0,0,rlegendre(k-2)])/k; endWarning: Some students trying to use the above code on PCs running MS-Windows, not Linux, have observed problems with the recursive statement above. If you observe these problems, use the following statements instead:
ca = (2*k-1)*[rlegendre(k-1),0]; cb = (k-1)*[0,0,rlegendre(k-2)]; c = (ca-cb)/k;
Compute rlegendre( 25 ), and time the computation. The sequence of commands is
tic; rlegendre( 25 ); toc(Putting all three commands on a single line guarantees that typing time is not what is being timed.) It should take less than 15 seconds for this computation on the black Dell computers in GSCC, but it could take much longer on a slower computer.
You can see in the previous exercise that recursive evaluation, although
short and ``elegant,'' can require significant computing time. Further,
the amount of time (in this example, but not in all cases)
increases rapidly with size. Do not try to wait
for rlegendre(35) to complete! The reason it takes so long is
that each call to rlegendre generates two more calls, albeit
with smaller values of k. Roughly speaking, then, a call to
rlegendre with i=25 generates a total of
calls,
most of which are with repeated values of k. It turns out that
this is a ``worst-case'' algorithm for recursion, and not all recursive
algorithms are nearly this bad.
One does not see very many recursive functions in scientific work, but you can use them when they can easily be written directly from the mathematical definition of the function. The trade-off is between ease of writing (and debugging) and potential inefficiency. In the next lab, you will see recursion used for an adaptive quadrature algorithm that would be difficult to write without recursion.
The alternative to recursive calculation of Legendre polynomials is one that uses loops. It is a general fact that any recursive algorithm can be implemented using a loop. In the following exercise, you will write a more efficient algorithm for Legendre polynomials.
function c = legendre ( k )and add appropriate comments.
The Legendre polynomials form a basis for the linear space of
polynomials. One thing we like any set of basis vectors to do is be
orthogonal. For functions, we use the standard
dot
product, and say that two functions
and
are
orthogonal if their dot product
You have computed the coefficients of the Legendre polynomials. In order to integrate them, you need to know the values of the polynomials. Recall that the polyval(c,xval) function will find the values of the polynomial with coefficient vector c at the values xval.
In the following exercise we will verify that the Legendre polynomials
form an orthogonal set in
.
I=trapsum(polyval(legendre(n),xval).*polyval(legendre(m),xval),-1,1);
Atkinson, in Section 4.3, discusses approximation in function spaces
such as
. The idea is to minimize the norm of the
difference between the given function and the approximation.
Given a function
and a set of approximating
functions (such as the monomials
),
for each vector of numbers
define a functional
for
Atkinson evaluates this expression in general. For completeness, it
is included here (using slightly different notation) for the case
of quadratic approximations (
). Consider the functional
![]() |
|||
![]() |
|||
![]() |
![]() |
![]() |
![]() |
![]() |
|||
![]() |
![]() |
![]() |
![]() |
|||
![]() |
![]() |
![]() |
![]() |
Equation (5) is related to
Atkinson's Equation (4.3.14), which was derived for the monomials
over the interval
. For an arbitrary value of
, Equation
(5) can be written in the following way,
where I have modified the indexing to
correspond with Matlab indexing (starting with 1 instead of 0) and
with the Matlab convention for coefficients of polynomials (first
coefficient is for the highest power of
.)
Examining Equation (6), there are two sets of integrals
that need to be evaluated in order to compute the coefficients
.
On the left side, the integrands involve the products
. On the right side, the integrands involve
the products
. Please note that these expressions
are made more complicated by the fact that they are indexed ``backwards.''
This is done to be consistent with Matlab's numbering scheme for
coefficients. Later in the lab when we switch to Legendre polynomials
and are free to number the coefficients as we wish, we will
switch to a simpler numbering scheme.
Once the coefficients
have been found, the Matlab polyval
function can be used to evaluate the resulting polynomials.
function c=approx_mon(f,n) % comments % f is the name of a function % your name and the dateand be called approx_mon.m (for approximation by monomials. It will solve the system (6) by constructing the matrix
function c=approx_mon(f,n) % f is the name of a function % comments NUM_INTEGRATION_PTS=25000; xval=linspace(-1,1,NUM_INTEGRATION_PTS);
H(k,ell)=trapsum(xval.^(2*n-k-ell),-1,1)(I try not to use the letter ``l'' as a variable because it looks so much like the number 1.)
c=approx_mon('partly_quadratic',n);
xtest=linspace(-1,1,2000);
ytest=polyval(c,xtest);
yexact=partly_quadratic(xtest);
plot(xtest,ytest,xtest,yexact)
% relative Euclidean norm is identical to using trapsum to compute
% integral least-squares (L2 norm)
relativeError=norm(yexact-ytest)/norm(yexact)
and use it to evaluate the approximation for
n=1 and n=5. Look at the plot and estimate by
eye if the area between the exact and approximate curves is divided
equally between ``above'' and ``below.'' Further, the error for
n=5 should be smaller than for n=1 and the plot should
look much better.
partly_quadratic
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
15 _______________
20 _______________
25 _______________
30 _______________
40 _______________
Runge
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
15 _______________
20 _______________
25 _______________
30 _______________
40 _______________
Why does this method fail as
gets large? It may not be obvious,
but the matrices
(5) and (6)
are related to the Hilbert matrix and are extremely difficult to
invert. The reason inversion is difficult is because the monomials
all start to look the same as
gets larger, that is, they become
almost parallel in the
sense. One way to make the
approximation problem easier might be to pick a better set of
functions than monomials. The following section discusses
a good alternative choice of polynomials.
In the following section we will use the Legendre polynomials to compute polynomial approximations.
Legendre polynomial approximation in
follows the same
recipe as monomial approximation:
function C=approx_leg(f,n) % comments % your name and the date
to compute the coefficients of the approximation as
.
function yval=eval_leg(C,xval) % comments % your name and the dateYou will probably find it convenient to use polyval inside eval_leg.
Runge
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
20 _______________
30 _______________
40 _______________
50 _______________
partly_quadratic
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
20 _______________
30 _______________
40 _______________
50 _______________
You should find the same values as for approximation by monomials
for small n, but you can get
larger values using Legendre polynomials than using monomials. However,
without more care (in computing
There is a different set of functions that are orthogonal
in the
sense. These are the trigonometric functions
The first
terms of the Fourier series for a function
is given as
Integrand value (1/sqrt(2))^2 ________ cos(pi*xval).^2 ________ sin(2*pi*xval).^2 ________ cos(3*pi*xval).^2 ________ cos(pi*xval).*sin(2*pi*xval) ________ cos(3*pi*xval).*sin(2*pi*xval) ________
function [z,s,c]=approx_fourier(f,n) % comments % your name and the date
to compute the first
coefficients of the Fourier series
using Equation (9).
function yval=eval_fourier(z,s,c,xval) % comments
Runge
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
20 _______________
30 _______________
40 _______________
100 _______________
200 _______________
400 _______________
partly_quadratic
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
20 _______________
30 _______________
40 _______________
100 _______________
200 _______________
400 _______________
1000 _______________
sawtooth9
n relative error
1 _______________
2 _______________
3 _______________
4 _______________
5 _______________
10 _______________
20 _______________
30 _______________
40 _______________
100 _______________
200 _______________
400 _______________
We have learned that approximation is best done using matrices that are easy to invert accurately, like diagonal matrices. This is the reason for using sets of orthogonal basis functions. We would also like to be able to perform the right side integrals easily as well. A large part of the reason that the orders of approximations in the exercises above have been restricted to relatively small numbers is that the integrals are difficult to perform accurately because they ``wiggle'' a lot, a major source of inaccuracy in the approximation.
In this section, we will look at approximation by piecewise constant functions. Approximation by piecewise linears or higher are also useful, but all the important steps are covered with piecewise constants. Furthermore, piecewise constants are easy to extend to higher dimensions.
Suppose that a number
is given and that the interval
is divided into
equal subintervals and
points
,
.
For
, a function
can be defined as
If a vector of coefficients
can be found to represent the
piecewise constant approximation to a function
,
then the approximation can be evaluated as
In the following exercise, we
will follow the same recipe as before to compute the coefficients
and the approximation to
.
function a=approx_pc(f,Npc) % comments % your name and the dateto compute the coefficients of the approximation as
![]() |
||
![]() |
![]() |
||
![]() |
||
![]() |
function yval=eval_pc(a,xval) % comments % your name and the dateTo write this function, you will need to use linspace to generate the points
partly quadratic
Npc relative error
4 _______________
8 _______________
16 _______________
32 _______________
64 _______________
256 _______________
1024 _______________
8192 _______________
This approximation may take longer to compute, but it does not
deteriorate as Npc gets large! In fact, you should observe
linear convergence. If you had the time, you could
choose Npc as large as you like and the approximation would
get as close as you like (within reason).
Remark: As you might imagine, approximation using
piecewise linear functions will converge more rapidly than using
piecewise constants. There are alternative approaches for using
piecewise linears: piecewise linear functions on each interval
with jumps at interval endpoints, as the piecewise constant functions
have; and, piecewise linear functions that are
continuous throughout whole interval. The first retains
orthogonality and the diagonal form of the coefficient matrix
. The second sacrifices the diagonal form for a tridiagonal
form (in one dimension) that is almost as easy to solve.
Continuity, however, can be worth the sacrifice, depending on
the application. Even higher order piecewise polynomial approximation
is possible, if the application can benefit.
Back to MATH2070 page.