lec22.mws

L-22 MCS 320 Monday 17 October 2005

> restart;

1. Array

An array is a composite data structure, used in linear algebra.  Compared to a list, an array has a fixed length.  We use a list if we do not know in advance how many elements we will need.  In Linear Algebra, we know the dimensions in advance, and then we better use arrays.

> A := array(0..1,1..2,[[a,b],[c,d]]);

A := ARRAY([0 .. 1, 1 .. 2], [(0, 1) = a, (0, 2) = b, (1, 1) = c, (1, 2) = d])

We declared a two dimensional array (also called a matrix), whose rows are indexed from 0 to 1, and the columns from 1 to 2.

> A[0,1]; A[0,2];

a

b

As this is a basic data structure, we can choose our own indexing.  The reason for not continueing to work with these arrays, it the linear algebra operations.  Suppose we want to compute the determinant of this two-by-two matrix, we would like to use the determinant operation:

> LinearAlgebra[Determinant](A);

Error, (in Determinant) invalid input: Determinant expects its 1st argument, table( [( 1, 1 ) = c, ( 1, 2 ) = d, ( 0, 1 ) = a, ( 0, 2 ) = b ] ), to be of type Matrix(square) but received A

> M := convert(A,Matrix);

M := Matrix([[a, b], [c, d]])

> M[1,1]; # notice the difference with indexing

a

> M1 := Matrix(2,2,[[a,b],[c,d]]);

M1 := Matrix([[a, b], [c, d]])

If we declare a Matrix, then we can only specify the dimensions, not the index range.  Objects of type Matrix always start indexing rows and columns at 1.  With the convert from an array to a Matrix, Maple automatically converts the ranges.

> LinearAlgebra[Determinant](M);

a*d-b*c

We can define matrices, using a formula.

> hf := (i,j) -> 1/(i+j-1);

hf := proc (i, j) options operator, arrow; 1/(i+j-1) end proc

The function hf defines the recipe for the Hilbert matrix, telling what the (i,j)-th element is.

This is a so-called "index function".

> h4 := Matrix(4,4,hf);

h4 := Matrix([[1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]])

> hfdata := [seq([seq(hf(i,j),j=1..4)],i=1..4)];

hfdata := [[1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]]

> h4a := array(1..4,1..4,hfdata);

h4a := matrix([[1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]])

2. Table

We have encountered tables as remember tables:

> diff(exp(sin(a*x)),x);

cos(a*x)*a*exp(sin(a*x))

> T := op(4,eval(diff));

T := TABLE([(exp(sin(a*x)), x) = cos(a*x)*a*exp(sin(a*x)), (a*x, x) = a, (sin(a*x), x) = cos(a*x)*a])

> indices(T)

[exp(sin(a*x)), x], [a*x, x], [sin(a*x), x]

> ;

> entries(T);

[cos(a*x)*a*exp(sin(a*x))], [a], [cos(a*x)*a]

The remember table of a Maple procedure is indexed by the arguments of the function call.

The entries (the data) are the results of the Maple procedures for the corresponding indices.

> T[a*x,x]; # a direct lookup in the table

a

Tables are used as lookup tables, for example as in currency convertions.

> T[a*x,x] := b; # changing the remember table

T[a*x, x] := b

> diff(exp(sin(a*x)),x); # this is a simple lookup

cos(a*x)*a*exp(sin(a*x))

> diff(a*x,x); # here we see the result of the changed remember table

b

> diff(exp(cos(a*x)),x);

-sin(a*x)*b*exp(cos(a*x))

Observe the change in results.  The last result is wrong because of the assignment in the remember table.

3. Last Name Evaluation

Last name evaluation became a bit obsolete with the introduction of the LinearAlgebra package since Maple 7.  The last name evaluation is relevant in use with the older linalg package.

4. Function Call

This is a composite data structure which is perhaps typical the delayed execution in symbolic computation.  We have already encountered the RootOf.  Depending on the type of application, we may compute with the contents of RootOf symbolically (formally), or we can apply evalf and work with a numerical approximation of the root.

> a := interval(3,5);

a := interval(3, 5)

> whattype(a);

function

> op(1,a); op(2,a); op(0,a);

3

5

interval

Using function call as a composite data type, the user can define interval arithmetic.

Another example are polar representations of complex numbers.

> c := polar(3,Pi/3);

c := polar(3, 1/3*Pi)

The variable c is a complex number of radius 3 with angle Pi/3.

> d := evalc(c); # rectangular representation of c

d := 3/2+3/2*I*3^(1/2)

> whattype(c);

function

> convert(d,polar);

polar(3, 1/3*Pi)

In converting the rectangular representation of a complex number, Maple has computed the radius (or the modulus of the complex number d) and the argument, the angle d makes with the real axis.

> interface(verboseproc=3);

> print(convert);

proc () option builtin; 170 end proc

The convert recognizes the complex type and converted to polar representations.  See the lecture note for the explicit conversion.

5. Conversions

We can convert -- just as we converted lists and sets into the more basic sequences -- matrices and arrays to list of lists.

> whattype(h4a);

symbol

> whattype(eval(h4a));

array

With eval, we force evaluation.  The h4a is just a name for the array.

> convert(h4a,listlist);

[[1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]]

> whattype(%);

list

These conversion to listlist are useful for lower level data manipulations.

As an application, suppose we would like the know the number of different numbers in a 4-by-4 Hilbert matrix.  We can solve this problem by a conversion a set:

> l := convert(h4,listlist);

l := [[1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]]

> s1 := op(l);

s1 := [1, 1/2, 1/3, 1/4], [1/2, 1/3, 1/4, 1/5], [1/3, 1/4, 1/5, 1/6], [1/4, 1/5, 1/6, 1/7]

Now we still need to convert the lists in the sequences to sequences.

> s2 := map(t->op(t),[s1]);

s2 := [1, 1/2, 1/3, 1/4, 1/2, 1/3, 1/4, 1/5, 1/3, 1/4, 1/5, 1/6, 1/4, 1/5, 1/6, 1/7]

A shorter way is to avoid the first conversion, because the map operates only on lists.

> sl := map(t->op(t),l);

sl := [1, 1/2, 1/3, 1/4, 1/2, 1/3, 1/4, 1/5, 1/3, 1/4, 1/5, 1/6, 1/4, 1/5, 1/6, 1/7]

> s := {op(sl)};

s := {1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7}

> nops(s);

7

We first converted the matrix h4 into a list of lists l.  Then we applied the op operator to convert every list in l to a sequence, using the map command.  Next we convert this list into a set via the op command followed by the curly braces.  The nops on the set gives us the distinct elements in the 4-by-4 Hilbert matrix.