Introduction

A list is an ordered collection of objects.  The objects are also called elements of the list.  A list is quit similar to the notion of a set.  The only difference is that sets are unordered collections of objects.  For those familiar with programming, you can think of a list as a vector or array of objects.  In earlier chapters we have used lists in Mathematica.  In particular we have used the Table command to create lists and the ListPlot command to graph lists of ordered pairs (which are also two element lists in Mathematica).

In this chapter we will explore lists in more detail.

Lists in Mathematica

It is relatively simple to enter a list into Mathematica.  For example we may have a data set of the form:

list1={{-1.0,0.5},{-0.65,1.1},{-0.1,0.75},{0.4,0.3},{1.0,-0.2}}

This defines a list of ordered pairs.  The list of ordered pairs can be thought of as a list of lists:  a list whose elements are simple, two-member lists.  The curly brackets around the ordered pairs are recognized as a list in the software.  Recall that we can also interpret this list of lists as a matrix and could view it as a matrix using the MatrixForm command.  We can graph this list or ordered pairs by using the ListPlot command:

ListPlot[list1]

The default in the ListPlot command is not to join the points with line segments.  If we wanted to see the points joined, a different size and a different color we could include the following options:

ListPlot[list1,Joined->True,PlotStyle->Red,PlotMarkers->{Automatic,Small}]

The default point symbol is a point of size Tiny.  Other symbols can be used:

ListPlot[list1,PlotStyle->Purple,PlotMarkers->{"☺",Small}, PlotRange->{{-1.5,1.5},{-.4,1.4}}]

In the above list we have distinct points forming a function.  That is, the x coordinate of each point is unique in the list.  Suppose we have date taken from several repetitions of performing the same experiment.  For instance, let's say we perform some experiment twice and collect date at the same x values for both experiments, say as follows:

list2={{{-1.0,0.5},{-0.65,1.1},{-0.1,0.75},{0.4,0.3},{1.0,-0.2}},{{-1.0,0.5},{-0.65,1.03},{-0.1,0.74},{0.4,0.25},{1.0,-0.25}}}

In this case we have a list of lists of lists, or a list of two lists of ordered pairs.  We could look at the two lists of ordered pairs individually by

list2[[1]]

list2[[2]]

If we wanted the x coordinate of the third point in the second list we would do

list2[[2]][[3]][[1]]

or

list2[[2,3,1]]

If we wanted to graph both list simultaneously we would do the following:

p1=ListPlot[list2[[1]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Red,PlotMarkers->{"o",Small}];
p2=ListPlot[list2[[2]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Red,PlotMarkers->{"o",Small}];
Show[p1,p2]

Here it is hard to tell which point belongs to which list.  We could use different colors:

p1=ListPlot[list2[[1]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Red,PlotMarkers->{"o",Small}];
p2=ListPlot[list2[[2]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Blue,PlotMarkers->{"o",Small}];
Show[p1,p2]

That helps some, but what if you need to print it out in black and white?  We could use different symbols:

p1=ListPlot[list2[[1]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Red,PlotMarkers->{"o",Small}];
p2=ListPlot[list2[[2]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Blue,PlotMarkers->{"+",Small}];
Show[p1,p2]

We still have problems with some of the points.  In this case it might be better to play connect the dot:

p1=ListPlot[list2[[1]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},Joined->True,PlotStyle->Red,PlotMarkers->{"o",Small}];
p2=ListPlot[list2[[2]],PlotRange->{{-1.5,1.5},{-0.5,1.5}},Joined->True,PlotStyle->Blue,PlotMarkers->{"+",Small}];
Show[p1,p2]

Note that the PlotStyle option effects both the line color and the marker color.  However, even with black and white we could determine that two sets of data are plotted.  If we wish to combine the two sets of data into one list we could do the following:

list3=Union[list2[[1]],list2[[2]]]

Notice that we lose redundant data points, namely {-1.0, 0.5}, by using the Union command.  If we wish to keep all copies of the data points we could using the Join command instead:

list3=Join[list2[[1]],list2[[2]]]

ListPlot[list3,PlotRange->{{-1.5,1.5},{-0.5,1.5}},Joined->True,PlotStyle->Red,PlotMarkers->{"x",Small}]

ListPlot[list3,PlotRange->{{-1.5,1.5},{-0.5,1.5}},PlotStyle->Blue,PlotMarkers->{"x",Small}]

Note in the first graph the individual points were joined by straight line segments, while in the second the individual points were graphed without the connecting line segments.

We can also pull out the x and y coordinates of the data points.  For instance on list1 we have:

list1

n=Length[list1]

xvals=list1[[1;;n,1]]

yvals=list1[[1;;n,2]]

Note: the Length command gives the number of elements in a list and the 1;;n notation gives a range of values for that index position.

Data at Distinct points and Interpolating Polynomials

To start, consider interpolation of the input data.  Interpolation is when you build a function whose graph passes through all data points.  Because interpolation is done with functions the data must represent a function.  In the above examples, list1 is a function while list3 is not.

Suppose that a set of data comes from some function, f, and we wish to define an interpolating function, g, for that data.  That is, the data has the form ((Subscript[x, i]),f((Subscript[x, i]))) and we want to define g such that

g((Subscript[x, i]))=f((Subscript[x, i])).

So the interpolating function must have the same values as the original function at the data points.  There are many ways of defining interpolating functions.  In fact, one could define g just to be the piecewise linear function connecting each data point, like the joined graphs above.  The problem with this approach is that piecewise linear functions usually are not differentiable at the joints.  If the data comes from a smooth process, then we should probably keep the interpolating function differentiable.  Since we want differentiability (maybe), we can try to use polynomials to interpolate the data.

That is, let (Subscript[p, n-1])(x) be a polynomial of degree n-1.  Then p has n degrees of freedom (n coefficients).  Thus, we can find the coefficients that satisfy

(Subscript[p, n-1])((Subscript[x, i]))=f((Subscript[x, i])) for 0 < i ⩽ n.

Theorem: If (Subscript[x, 1]),...,(Subscript[x, n]) are distinct real numbers, then for arbitrary values f((Subscript[x, 1])),... ,f((Subscript[x, n])) there is a unique polynomial, (Subscript[p, n-1]), of degree at most n - 1 such that (Subscript[p, n-1])((Subscript[x, i]))=f((Subscript[x, i])) for i = 1, ..., n.

The proof of this theorem  is constructive.  That is, the proof gives a method for finding the coefficients.  One form of this polynomial is the Lagrange interpolating polynomial.  Given the data from the theorem, we start by constructing the cardinal functions of the form:

(Subscript[l, i])(x)=(∏_(j=1)^n)(((x-(Subscript[x, j]))/((Subscript[x, i])-(Subscript[x, j])))), j ≠ i.

Then define

g(x)=(∑_(i=1)^n)f((Subscript[x, i]))(Subscript[l, i])(x)

What has happened here is that we have defined separate n - 1 degree polynomials (the (Subscript[l, i])) which are zero at all of the data points except the (i^th) data point, where they are one.  The sum of all of these polynomials, weighted with the correct values of f((Subscript[x, i])), fives us a polynomial of the correct degree with the precisely desired value at each (Subscript[x, i]).

We can have Mathematica generate this type of polynomial as follows:

Clear[x,y,xd,yd]
ndat=5;
xdat=Array[xd,ndat];
ydat=Array[yd,ndat];
l[i_,x_]:=Product[(x-xdat[[j]])/(xdat[[i]]-xdat[[j]]),{j,1,i-1}]*Product[(x-xdat[[j]])/(xdat[[i]]-xdat[[j]]),{j,i+1,ndat}]

This defines the cardinal functions (Subscript[l, i]).  Let's look at a couple of them.

l[1,x]

l[3,x]

l[ndat,x]

Then the interpolating polynomial of degree 4 is

g[x_]:=Sum[ydat[[k]]*l[k,x],{k,1,ndat}]

g[x]

Now let's see what happens when we define the data (we will use our first list):

xdat=list1[[1;;ndat,1]]
ydat=list1[[1;;ndat,2]]

Now the polynomial is

g[x]

We could graph the data and this interpolating polynomial as follows.

p3=Plot[g[x],{x,-1.5,1.5},PlotRange->{-1.5,1.5},PlotStyle->Red];
p4=ListPlot[list1,PlotRange->{{-1.5,1.5},{-1.5,1.5}},PlotMarkers->{Automatic,Small}];
Show[p3,p4]

Is the interpolating polynomial a "good" description of the function that generated the data?  There is no way to answer this question without knowing more about how the data was generated or what physical meaning the data represents.  Interpolating polynomials (curves) will always pass through the data, provided the data forms a function, but the interpolating function may not be the same as the real function that produced the data.  To see this, suppose we generate data from a known function such as the following:

f[x_]:=x^2*Exp[Pi*x]-Sin[x]
xdat=Table[-1+0.5*(k-1),{k,1,ndat}];
ydat=Table[f[xdat[[k]]],{k,1,ndat}];
list4=Table[{xdat[[k]],ydat[[k]]},{k,1,ndat}]

Note that we have redefined our data so the polynomial definition has changed.  Also note that we have put the data into a list of ordered pairs as well as separate lists for x and y values.  Now look at the graphs of the original function, the interpolating polynomial and the data:

p5=Plot[f[x],{x,-1,1},PlotRange->{-1,2},PlotStyle->Blue];
p6=Plot[g[x],{x,-1,1},PlotRange->{-1,2},PlotStyle->Red];
p7=ListPlot[list4,PlotRange->{{-1,1},{-1,2}},PlotMarkers->{Automatic,Small}];
Show[p5,p6,p7]

Note that the original function (in blue) and the interpolating polynomial (in red) match at the sample data points, but they do not match "well" overall.  Mathematica also has a command to find interpolating polynomials, namely the InterpolatingPolynomial command.

Mg[x_]=InterpolatingPolynomial[list4,x]

We could compare the Mathematica version with our version:

Expand[g[x]]
Expand[Mg[x]]

Notice the small difference in the constant term.  This is due to the method used and round-off error.  Other than that, they are the same, as we would expect, since the theorem said that the interpolating polynomial is unique.  Note that do to possible round off error, generating the interpolating polynomial in two different ways may lead to two different, but similar answers.  In any case, all correct methods for generating interpolating polynomials should be the same up to round off errors.

Exercise 7

Given the following data use Lagrange interpolating polynomials and then the InterpolatingPolynomial command to compute the interpolating polynomials through the data sets.  Compare the graphs of the polynomials to the graphs of the data.  Show that the Lagrange polynomials and the results of the InterpolatingPolynomial command are the same.

1.

data1={{-1.0,1.0},{-0.75,1.0},{-0.5,1.0},{0.5,-1.0},{0.75,-1.0},{1.0,-1.0}};

2.

data2={{-1.0,1.0},{-0.75,1.0},{-0.1,1.0},{0.1,-1.0},{0.75,-1.0},{1.0,-1.0}};

3.

data3={{-1.0,1.0},{-0.75,1.0},{-0.01,1.0},{0.01,-1.0},{0.75,-1.0},{1.0,-1.0}};

Comment on how well you think the interpolating polynomial captured the "essence" of the data in each case.  Comment on any "interesting" features of the graphs that you observe.