Application Center - Maplesoft

App Preview:

Maple Programming: 3.1 & 3.2: Basic data structures in Maple

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

3.01and3.02.mws

Programming in Maple

Roger Kraft
Department of Mathematics, Computer Science, and Statistics
Purdue University Calumet

roger@calumet.purdue.edu

3.1. Introduction

We have mentioned many times that Maple makes a distinction between expressions and functions. Expressions are what computer scientists call data structures and functions are what they call procedures. To put it very briefly, a data structure is a collection of information and a procedure is a collection of instructions. In order to explain this difference better, in this and the next chapter we look at some elementary examples of data structures and procedures in Maple. In particular, in this chapter we look at some of Maple's basic data structures, at how a data structure can be manipulated, and at how Maple stores an expression as a data structure. In the next chapter we look at some simple examples of Maple procedures and how mathematical functions can be represented as procedures. In the last chapter we look at how a procedure can manipulate a data structure, and this will give us an idea of how Maple does its work. Many Maple commands (like factor , simplify , expand ) are procedures, written in the Maple programming language, that manipulate data structures. In fact, that is what much of programming and computer science is all about, procedures that manipulate data structures.

>   

3.2. Basic data structures in Maple

To really understand what makes expressions and functions different in Maple we need to get a sense of what data structures and procedures are. The rest of this worksheet is a very basic introduction to how Maple handles data structures.

Let us try to give a definition of a "data structure". Earlier we said that a data structure is a collection of information but this is an incomplete definition. Since information is the same as "data", we have left off the "structure" part of "data structure". A data structure is a collection of information that has been given a structure or organization. In addition, a data structure often has associated with it a special way of interpreting the data. As we will see below, the structure (and interpretation) aspect of a data structure is as important as the data aspect. Two different data structures can contain the exact same pieces of data but give that data different structures (or interpretations).

Now we will look at a few of the basic data types  in Maple.  Every data structure has a data type  which describes, or names, the kind of data structure it is. The three most basic kinds of data structures in Maple have the data types expression sequence , list , and set . Maple also has several numeric  data types which are used to represent different kinds of numbers. Each of these kinds of data structures, plus a few other important data types, are described in detail in the following subsections.

>   

3.2.1. Expression sequences

First we look at expression sequences . We said that a data structure is an organized collection of information (or data). An expression sequence in Maple is the simplest way that some data can be organized; it is a list of things separated by commas. The things (i.e. the pieces of data) in the expression sequence can be anything that Maple can work with,  e.g., numbers, expressions, functions, other data structures, etc.

Here is an example of an expression sequence with nine pieces of data in it.

>    1, 2, abc, x^2+1, `hi world`, Pi, x -> x^2, 1/2, 1;

1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

Let us give this expression sequence a name so that it is easier to work with.

>    stuff := %;

stuff := 1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

>    stuff;

1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

Maple's whattype  command is used to ask " what  is the data type " of a data structure .

>    whattype( stuff );

exprseq

Maple uses exprseq  as an abbreviation for " expr ession seq uence".

Maple's nops  command is used to ask how many pieces of data are in a data structure. The name nops  is an abbreviation of " n umber of op erand s " and the word "operand" is often used to mean a piece of a data structure. Notice that in the next command we need to put square brackets around the name stuff  in order to use nops . (Try removing the brackets.) In the next subsection we will see why these brackets need to be there.

>    nops( [stuff] );

9

Maple's op  command is used to access individual elements of a data structure (the name op  is of course an abbreviation of the word " op erands"). It can be used to access just one element or a range of elements from a data structure. The next command asks for the fifth thing in stuff .

>    op( 5, [stuff] );

`hi world`

The next command asks for the fifth through seventh things in stuff .

>    op( 5..7, [stuff] );

`hi world`, Pi, proc (x) options operator, arrow; x^2 end proc

Notice that the op  command used with a range returned an expression sequence which can be thought of as a subsequence of the original expression sequence. Here is another notation that allows us to access an individual piece of data from an expression sequence, a subsequences of data, or the whole sequence.

>    stuff[5];

`hi world`

>    stuff[5..7];

`hi world`, Pi, proc (x) options operator, arrow; x^2 end proc

>    stuff[];

1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

>   

There is no special interpretation associated to the data in an expression sequence. The only real organization that Maple gives to an expression sequence is that Maple remembers the order that the data items were given in. So the following two expression sequences are not considered the same data structure, even though they contain the exact same data items.

>    seq1 := a, b, c, d;

seq1 := a, b, c, d

>    seq2 := b, a, c, d;

seq2 := b, a, c, d

>    evalb( seq1=seq2 );

false

Remember, seq1=seq2  is an equation that could be either true or false. The Maple command evalb  is used to determine if the equation is true or false. Since the equation is false, the expression sequences are not the same data structure. Another way to put this is that seq1  and seq2  have the same data type ( exprseq ), and they contain the same data, but they are not the same data structure.

In the next two subsections we will see what brackets ( [] ) and braces ( {} ) mean to an expression sequence. Parentheses however are ignored by expression sequences. The following commands all define the same expression sequence.

>    the, very, same, thing;

>    (the, very), (same, thing);

>    (the, ((very, same), thing));

the, very, same, thing

the, very, same, thing

the, very, same, thing

>   

Expression sequences can be combined into larger expression sequences. Let us define two expression sequences.

>    seq1 := a, b, c, d;

seq1 := a, b, c, d

>    seq2 := u, v, w, x, y, z;

seq2 := u, v, w, x, y, z

Here is one way to combine these two into a third expression sequence.

>    seq3 := seq1, seq2;

seq3 := a, b, c, d, u, v, w, x, y, z

There are many ways to combine the data from two expression sequences into one expression sequence. What we just did was to concatenate   seq1  and seq2 . Here is another way to combine these two expression sequences.

>    seq3 := seq2[1..3], seq1, seq2[4..6];

seq3 := u, v, w, a, b, c, d, x, y, z

>   

Exercise : With seq1  and seq2  defined as above,

>    seq1 := a, b, c, d;

>    seq2 := u, v, w, x, y, z;

seq1 := a, b, c, d

seq2 := u, v, w, x, y, z

what are the differences between the following four commands

>    seq3 := seq1, seq2:

>    seq4 := seq1, 'seq2':

>    seq5 := 'seq1', 'seq2':

>    seq6 := 'seq1, seq2':

since they all seem to produce the same result.

>    seq3;

>    seq4;

>    seq5;

>    seq6;

a, b, c, d, u, v, w, x, y, z

a, b, c, d, u, v, w, x, y, z

a, b, c, d, u, v, w, x, y, z

a, b, c, d, u, v, w, x, y, z

>   

Exercise : With seq1  and seq2  still defined as above, what does the following command do?

>    seq1 := seq1, seq2;

seq1 := a, b, c, d, u, v, w, x, y, z

>   

There is one very important expression sequence that has a special name. The empty expression sequence is called NULL .

>    NULL;

When Maple evaluates the name NULL , the value it gets is the empty expression sequence, and since there is not much to print out for the empty expression sequence, Maple does not print anything.

>    whattype( 'NULL' );

symbol

>    whattype( NULL );

exprseq

>    nops( [NULL] );

0

The last three commands verify that NULL  is a name for an expression sequence and that there are no operands in the expression sequence. The NULL  expression sequence comes up fairly often, but usually in a pretty invisible way. For example, the command

>    solve( cos(ln(x))=tan(x)^2, x );

did not seem to return any result. But it did return a result. It returned NULL .

>    whattype( solve(cos(ln(x))=tan(x)^2, x) );

exprseq

>    evalb( solve( cos(ln(x))=tan(x)^2, x ) = NULL );

true

Whenever a Maple command seems to do its work "silently", without any output, the command is really returning the NULL  expression sequence.

>   

Maple has two very important and common uses for expression sequences. First, many Maple commands, when they want to express several outputs, put the output items in an expression sequence. The most common example of this is the solve  command.

>    x:='x':

>    solve( x^3-4*x^2-5*x=0, x );

0, 5, -1

There are three solutions to the equation in the solve  command and solve  puts the three answers in an expression sequence. We can ask Maple to verify this by using the whattype  command again.

>    whattype( % );

exprseq

If we modify the solve  command a little bit and put braces around the last x  in the command, then we get the solutions in a different form.

>    solve( x^3-4*x^2-5*x=0, {x} );

{x = 0}, {x = 5}, {x = -1}

The output is still an expression sequence, but now each item in the sequence is an equation with braces around it.

>    whattype( % );

exprseq

Let us give the expression sequence a name.

>    solutions := %%;

solutions := {x = 0}, {x = 5}, {x = -1}

Now we can access individual solutions using the notations we gave above.

>    op( 1, [solutions] );

{x = 0}

>    solutions[2];

{x = 5}

>    solutions[2..3];

{x = 5}, {x = -1}

>    assign( solutions[3] );

>    x;

-1

>    x:='x';

x := 'x'

>   

We just saw that Maple uses expression sequences to represent multiple outputs from a command. Maple's other common use for expression sequences is to represent multiple inputs to a command (or function). We want to demonstrate that the inputs to a Maple function are always contained in an expression sequence. Here is an example. The next command defines and names an expression sequence.

>    test_sequence := x^2, x=-2..2, color=blue, axes=box;

test_sequence := x^2, x = -2 .. 2, color = blue, axes = box

This sequence has four items in it.

>    nops( [test_sequence] );

4

Notice that test_sequence  looks like the inputs to a plot  command. And we can use it exactly that way.

>    plot( test_sequence );

[Maple Plot]

In the next command, the evaluation of plot  is delayed but test_sequence  is evaluated so that we can see how the input to plot  really is an expression sequence.

>    'plot'( test_sequence );

plot(x^2,x = -2 .. 2,color = blue,axes = box)

Now evaluate plot .

>    %;

[Maple Plot]

Here is another example. First, let us define our own multivariate function.

>    f := (x,y,z,w) -> x+y+z+w;

f := proc (x, y, z, w) options operator, arrow; x+y+z+w end proc

Here is an expression sequence.

>    es := b, c, d;

es := b, c, d

Now evaluate the function with what looks like (but is not) two inputs.

>    f(a,es);

a+b+c+d

Let us look at what the function really saw as its inputs.

>    'f'(a,es);

f(a,b,c,d)

Suppose we delay the evaluation of es . What do you think will be the result of the following function call?

>    f(a,'es');

Error, (in f) f uses a 3rd argument, z, which is missing

>   

The last several examples have shown that expression sequences are basic for representing both the input and output of Maple commands and functions.

>   

Maple has a special command, seq , for creating expression sequences.  Here are some examples of its use.

>    seq( x^i, i=-2..5 );

1/(x^2), 1/x, 1, x, x^2, x^3, x^4, x^5

>    seq( Pi, i=-2..2 );

Pi, Pi, Pi, Pi, Pi

>    seq( 1/n, n=1..10 );

1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10

>    seq( evalf(1/n), n=1..10 );

1., .5000000000, .3333333333, .2500000000, .2000000000, .1666666667, .1428571429, .1250000000, .1111111111, .1000000000

>   

>   

3.2.2. Lists

The next most basic data type in Maple is a list . A list is an expression sequence with square brackets around it.

Recall that stuff  is our expression sequence from the last section. We redefine it here for convenience.

>    stuff := 1, 2, abc, x^2+1, `hi world`, Pi, x -> x^2, 1/2, 1;

stuff := 1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

An expression sequence with brackets around it gives us a list.

>    [stuff];

[1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1]

Let us give this list a name so that we can work with it.

>    liststuff := %;

liststuff := [1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1]

Let us check the data type of our data structure, and also how many elements are in it.

>    whattype( liststuff );

list

>    nops( liststuff );

9

The op  command with only one argument returns all the elements in the data structure.

>    op( liststuff );

1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

Notice that the op  command returned an expression sequence. So the op  command can be used to convert a list into an expression sequence.

>   

We can access an individual element from a list or a range of elements.

>    op( 5, liststuff );

`hi world`

>    op( 5..7, liststuff );

`hi world`, Pi, proc (x) options operator, arrow; x^2 end proc

Now compare the previous two commands with the next two.

>    liststuff[5];

`hi world`

>    liststuff[5..7];

[`hi world`, Pi, proc (x) options operator, arrow; x^2 end proc]

Notice that liststuff[5]  is an alternate notation for op(5, liststuff) , but liststuff[5..7]  is not quite the same as op(5..7, liststuff) . How are they different? Should liststuff[5]  really have been the same as op(5, liststuff) ? To make things even a bit more confusing, look at what the next command does. What is it an alternative to?

>    liststuff[];

1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

>   

Surprisingly enough, we can even use negative numbers to access items from a list. The index -1  means the last item in a list and as the negative index decreases we access items from right to left through the list.

>    op( -1, [a, b, c, d, e] );

e

>    op( -2, [a, b, c, d, e] );

d

>    op( -3, [a, b, c, d, e] );

c

But negative indexes do not always work the way you might think they would. Based on the last three commands, what would you expect the next command to output?

>    op( -1..-3, [a, b, c, d, e] );

Error, improper op or subscript selector

What about this command?

>    op( -3..-1, [a, b, c, d, e] );

c, d, e

Using negative indexes can lead to very non intuitive results. Consider the next two examples.

>    op( -4..4, [a, b, c, d, e] );

b, c, d

>    op( -3..3, [a, b, c, d, e] );

c

You might think that in any range m..n  you must have m  less than n . But things are not that simple.

>    op( 4..-4, [a, b, c, d, e] );

Error, improper op or subscript selector

>    op( 3..-3, [a, b, c, d, e] );

c

In fact, one way to list all the data items in a list is to use the range 1..-1 , i.e., from first to last.

>    op( 1..-1, [a, b, c, d, e] );

a, b, c, d, e

On the other hand, the range -1..1  (from last to first?) causes an error.

>    op( -1..1, [a, b, c, d, e] );

Error, improper op or subscript selector

We can use negative indexes with the bracket selection notation also.

>    [a, b, c, d, e][-3..-1];

[c, d, e]

>   

Exercise : Come up with a simple rule for what is allowed in a range m..n  when it is used for accessing items in a list and either m , n  or both is negative.

>   

We did not get the op  command to produce a range of elements from a list in reverse order, but we can do this if we use the seq  command in combination with op .

>    list1 := [a, b, c, d, e];

list1 := [a, b, c, d, e]

>    [ seq( op(-i, list1), i=3..5 ) ];

[c, b, a]

>    [ seq( op(-i, list1), i=1..nops(list1) ) ];

[e, d, c, b, a]

We can abbreviate the above commands by using index notation.

>    [ seq( list1[-i], i=3..5 ) ];

[c, b, a]

Notice that the following command does not work.

>    [ seq( list1[i], i=-3..-5 ) ];

[]

>   

Exercise : Let list1  be defined as in the last example.

>    list1 := [a, b, c, d, e];

list1 := [a, b, c, d, e]

For each of the following two commands, rewrite the command so that it produces the same result but is easier to read.

>    [ seq( op(-i, list1), i=-5..-3 ) ];

[e, d, c]

>    [ seq( op(i, list1) , i=-5..-3 ) ];

[a, b, c]

>   

A special case of the op  command is op(0,  data_structure )  which, instead of accessing a piece of data from the data structure, (usually) returns the data type of the data structure.

>    op( 0, liststuff );

list

For most data structures, op(0,   data_structure )  is the same as whattype( data_structure ) . But we will see later that for some data structures, op(0,  data_structure )  returns something other than the data type. Also, notice that the following syntax does not do what you think it might.

>    liststuff[0];

Error, invalid subscript selector

>   

There is no special interpretation associated to the data in a list. The only real organization that Maple gives to a list is that Maple remembers the order of the data items in the list. So the following two lists are not considered the same, even though they contain the exact same data items.

>    list1 := [1, 2, 3, 4];

list1 := [1, 2, 3, 4]

>    list2 := [2, 1, 3, 4];

list2 := [2, 1, 3, 4]

>    evalb( list1=list2 );

false

As with the example with expression sequences, we would say that list1  and list2  have the same data type ( list ), and they contain the same data items, but they are not the same data structure.

>   

Exercise : Suppose we have two lists.

>    list1 := [a, b, c, d];

list1 := [a, b, c, d]

>    list2 := [u, v, w, x];

list2 := [u, v, w, x]

Find a command that will combine all the data from the two lists into one list.

>    list3 := ???

Error, character `?` unexpected

>   

Exercise : Given the following two expression sequences

>    es1 := a, b, c, d, e;

>    es2 := u, v, w, x, y;

es1 := a, b, c, d, e

es2 := u, v, w, x, y

use a single seq  command to create a third expression sequence es3  that is made by alternating elements from es1  with elements from es2 .

>    es3 := ???

Error, character `?` unexpected

>   

If L  is the name of a list, then Maple will use full evaluation when it is asked the find the value of L .

>    L := [a, b, c, d];

L := [a, b, c, d]

>    a := 'b'; b := 2; c := 'b'+1; d := 4;

a := b

b := 2

c := b+1

d := 4

>    L;

[2, 2, 3, 4]

Notice that several levels of evaluation were needed to fully evaluate L . The next three commands show the levels of evaluation.

>    eval( L, 1 );

>    eval( L, 2 );

>    eval( L, 3 );

[a, b, c, d]

[b, 2, b+1, 4]

[2, 2, 3, 4]

Recall that in the section on expression sequences we had to put brackets around an expression sequence before we could use the nops  command to find out the number of operands in the expression sequence.

>    nops( stuff );

Error, wrong number (or type) of parameters in function nops

>    nops( [stuff] );

9

By now we know that the brackets convert the expression sequence into a list. Why do we need the brackets? Because the nops  command is defined to accept only one input, the data structure that we are interested in. But when that data structure is an expression sequence, nops  thinks that it has multiple inputs, which is a mistake, so nops  returns an error message. By putting square brackets around stuff  and converting it into a list we do not change the number of operands in the data structure ( stuff  and [stuff]  have the same number of operands) but now nops  thinks it only has one input, the list. Here is a way to see this. In the following command, nops  is prevented from being evaluated by the right quotes, but stuff  is evaluated.

>    'nops'( stuff );

nops(1,2,abc,x^2+1,`hi world`,Pi,proc (x) options operator, arrow; x^2 end proc,1/2,1)

So the nops  command thinks it has nine inputs, but it was designed to only have one input.

>    %;

Error, wrong number (or type) of parameters in function nops

On the other and, when we put the brackets around stuff , it then appears to nops  as a single input which is a list.

>    'nops'( [stuff] );

nops([1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1])

>    %;

9

>   

Exercise : Can the op(0,   data_structure )  form of the op  command  be used somehow on expression sequences to get the data type?

>   

>   

3.2.3. Sets

Our third basic data type in Maple is called a set . A set looks like an expression sequence with curly braces around it, but we will see that sets are a little more subtle than that. A set data structure is usually used to represent the idea of a set from mathematics. So set data structures in Maple act a lot like sets in mathematics. Here is an example. Let us make a set out of our original expression sequence stuff  by putting braces around stuff  and then giving the resulting set a name. First, let us redefine the expression sequence stuff .

>    stuff := 1, 2, abc, x^2+1, `hi world`, Pi, x -> x^2, 1/2, 1;

stuff := 1, 2, abc, x^2+1, `hi world`, Pi, proc (x) options operator, arrow; x^2 end proc, 1/2, 1

Now create a set by putting a pair of braces around stuff .

>    {stuff};

{1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`}

Now give this set a name.

>    setstuff := %;

setstuff := {1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`}

Let us check the data type and number of operands for setstuff .

>    whattype( setstuff );

set

>    nops( setstuff );

8

>    nops( [stuff] );

9

Right away we should notice that something is different. First of all, for a set the order of the data items is not important so Maple chooses its own order to put them in. Second, sets cannot have repeated items in them, so there is only one 1  item in setstuff , but there were two 1  items in stuff  (and also liststuff , the list version of stuff ).

The op  command still works like it did with lists.

>    op( 5, setstuff );

x^2+1

>    op( 5..7, setstuff );

x^2+1, proc (x) options operator, arrow; x^2 end proc, abc

>    op( 5..-1, setstuff );

x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`

We can also use this alternate notation.

>    setstuff[5];

x^2+1

>    setstuff[5..7];

{x^2+1, proc (x) options operator, arrow; x^2 end proc, abc}

>    setstuff[5..-1];

{x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`}

Notice that, as with lists, setstuff[5]  is the same as op(5, setstuff)  but setstuff[5..7]  and op(5..7,setstuff)  are different. And we can use the following alternative to whattype .

>    op( 0, setstuff );

set

>   

As we stated just above, the elements of a set data structure are interpreted as the elements of a mathematical set, so the following two sets are the same as data structures.

>    set1 := {1,2,3,4,4};

set1 := {1, 2, 3, 4}

>    set2 := {2,1,3,4};

set2 := {1, 2, 3, 4}

>    evalb( set1=set2 );

true

>   

We can convert a set into an expression sequence by using the op  command.

>    op( setstuff );

1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`

Or we can use index notation.

>    setstuff[];

1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`

We can convert a set into a list by using op  and a pair of brackets.

>    [op( setstuff )];

[1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`]

Notice that this last list is not the same as liststuff  (why?). The following command uses a lot of brackets to convert a set into a list.

>    [setstuff[]];

[1, 2, Pi, 1/2, x^2+1, proc (x) options operator, arrow; x^2 end proc, abc, `hi world`]

>   

Exercise : How would you convert a list into a set?

>   

Maple has commands for doing common mathematical operations with sets. Here are two sets.

>    set1 := {a, b, c, d};

set1 := {2, 3, 4}

>    set2 := {c, d, e, f};

set2 := {3, 4, f, e}

We can form their union and intersection, and also find one set minus the other.

>    set1 union set2;

{2, 3, 4, f, e}

>    set1 intersect set2;

{3, 4}

>    set1 minus set2;

{2}

>   

Here is a simple example of how the difference between a list and a set can be important in Maple. In the following plot  command there is a list of functions and a list of colors. Since the lists are ordered, the functions and colors can be associated in an obvious way.

>    plot( [cos(x), sin(x)], x=-2*Pi..2*Pi, color=[blue, green] );

[Maple Plot]

In the next command we have a set of functions and a list of colors. Since the set is not ordered, there is no obvious way to associate a color with a function. In my Maple session, the cosine ends up green and the sine ends up blue, the opposite of what was expected, but this coloring can change in the next Maple session. Orderings for sets are session dependent and can change from one Maple session to another. If your session seems to be coloring the graphs the "correct" way, try switching the order of the functions in the set and re-executing the plot  command; the coloring of the graphs should end up the "wrong" way.

>    plot( {cos(x), sin(x)}, x=-2*Pi..2*Pi, color=[blue, green] );

[Maple Plot]

>   

Exercise : Explain why the empty expression sequence needs a special name, NULL , but the empty set and the empty list do not need special names.

>   

>   

3.2.4. Some numeric data types

Every kind of number that Maple can work with is actually a data structure with some kind of numeric  data type. Here are some examples.

>    whattype( 5 );

integer

>    whattype( 1/3 );

fraction

>    whattype( 1.0 );

float

Let us look at these numeric data types a bit more carefully, in particular the fraction  and float  data types.

A fractional number is represented in Maple by a data structure of type fraction . A fraction  is stored as two integers, the numerator  and the denominator . Let us look at an example, 22/7 .

>    whattype( 22/7 );

fraction

What are the pieces of data in this data structure?

>    op( 22/7 );

22, 7

>    op( 1, 22/7 );

22

>    op( 2, 22/7 );

7

What are the types of these data items?

>    whattype( op(1, 22/7) );

integer

>    whattype( op(2, 22/7) );

integer

To Maple, 22/7  is a data structure with data type fraction  and it contains the two data items 22  and 7  in that order. On the other hand, 7/22  is also a fraction  type data structure that contains the two data items 22  and 7 , but in a different order.

>    op( 7/22 );

7, 22

>    op( 1, 7/22 );

7

>    op( 2, 7/22 );

22

So 22/7  and 7/22  are data structures with the same data type and they contain the same data items, but they are not equal data structures. Notice that this is very analogous to the lists [22,7]  and [7,22] , which are two data structures with the same data type and contain the same data items, but [22,7]  and [7,22]  are not equal data structures.

>   

Exercise : Why are 22/7  and [22,7]  not equal data structures? They contain the same data items in the same order. What distinguishes them?

>    op( 22/7 );

>    op( [22,7] );

22, 7

22, 7

>   

If a fraction is negative, Maple puts the minus sign with the numerator data item.

>    op( -1/2 );

>    op( 1/(-2) );

-1, 2

-1, 2

So -1/2  and 1/(-2)  are stored as the same data structure since they have the same data type ( fraction ) and the same data elements, -1  and 2 , in the same order.

>   

Now we shall turn to decimal numbers. A decimal number is represented in Maple by a data structure of type float . Like a fraction , a float  is stored as two integers, the mantissa  and the exponent .  A decimal number like .33  is thought of by Maple as 33*10^(-2) .  The 33  is called the mantissa and is stored as the first item in the float  data structure, and -2  is called the exponent and is stored as the second item of the float  data structure.

>    whattype( .33 );

float

>    op( .33 );

33, -2

>    whattype( op(1, .33) );

integer

>    whattype( op(2, .33) );

integer

>   

The number 3.3  is thought of by Maple as 33*10^(-1) , and the number 33.  is considered 33*10^0 .  

>    op( 3.3 );

33, -1

>    op( 33. );

33, 0

This gives you an idea why decimal numbers in Maple are called "floats", or "floating point numbers". All three of the decimal numbers .33 , 3.3 , and 33.  have the same mantissa and they are distinguished by their different exponents. The exponent causes the decimal point to  "float around" the mantissa to give different decimal numbers. The term "floating point numbers" is not unique to Maple. It is used throughout engineering and computer science to mean the way that computers represent decimal numbers.

>   

Do not make the mistake of thinking that Maple floats are just Maple's version of real numbers. Maple floats are more subtle than that. For example the fraction 1/4 is equivalent as a real number to the decimal number .25 which is also equivalent to the decimal numbers .250 and .2500 since the trailing zeros do not change anything as far as real number are concerned. But not in Maple. Let us see how the contents of the .25 , .250 , and .2500  data structures compare.

>    op( .25 );

>    op( .250 );

>    op( .2500 );

25, -2

250, -3

2500, -4

Notice that the three data structures do not contain the same data items, so they are not the same data structure. Not too surprisingly though, the evalb  command says that these data structures are equal and that they are equal to 1/4 .

>    evalb( 1/4 = .25 );

>    evalb( .25 = .250 );

true

true

Here is an interesting way to see how the numbers 1/4 , .25 , .250 , and .2500  are related in Maple. Recall that the evalf  command is used to approximate an exact number with a decimal number and the evalf  command can take a second input that specifies the number of decimal digits to use in the approximation. Here are three different decimal approximations of 1/4 .

>    a := evalf( 1/4, 2 );

>    b := evalf( 1/4, 3 );

>    c := evalf( 1/4, 4 );

a := .25

b := .250

c := .2500

The previous three and the next three commands show that .25 , .250 , and .2500  are considered by Maple as three different approximations of 1/4  using different numbers of decimal digits.

>    op( a );

>    op( b );

>    op( c );

25, -2

250, -3

2500, -4

The last example and the next one show that the number of decimal digits in a floating point number is just the number of digits in the integer that is the mantissa part of the float data structure. The next four commands compute four different decimal approximations, using different numbers of decimal digits, of an integer.

>    a := evalf( 1451, 1 );

>    b := evalf( 1451, 2 );

>    c := evalf( 1451, 3 );

>    d := evalf( 1451, 4 );

a := .1e4

b := .15e4

c := .145e4

d := 1451.

>    op( a );

>    op( b );

>    op( c );

>    op( d );

1, 3

15, 2

145, 1

1451, 0

Here is another example.

>    op( 1. );

>    op( 1.0 );

>    op( 1.00 );

1, 0

10, -1

100, -2

These examples show that the numbers 1. , 1.0 , and 1.00  are three different numbers to Maple, since they are stored with different data in their data structures. Why should we make a distinction between 1. , 1.0 , and 1.00 ? In engineering and physics applications, these numbers have different meanings when they are interpreted as the results of making measurements. The number 1.  means a measurement that was not very precise while the numbers 1.0  and 1.00  represent more precise measurements. An engineer, when told that the result of a measurement was 1. , would know that there was some error in the measurement and the actual value was somewhere between .5  and 1.5 . Told that the result of a measurement was 1.0 , the engineer would know that the actual value was between 0.95  and 1.05 . When told that the result of a measurement was 1.00 , the engineer would know that the actual value was between 0.995  and 1.005 .

>   

We can represent floating point numbers in several different ways. Any number with a decimal point in it is considered a floating point number.

>    22./7;

3.142857143

>    whattype( % );

>    op( %% );

float

3142857143, -9

We can enter floating point numbers using a kind of scientific notation.

>    .123e4;

.123e4

>    123e4;

.123e7

>    12.3e-1;

1.23

The letter e  in this notation is an abbreviation of " e xponent", but the exponent in this notation need not be the same as the exponent in the float data structure.

>    3.4e6;

>    op( % );

.34e7

34, 5

We can also create float data structures directly by using the following notation.

>    Float(234,5);

>    op( % );

.234e8

234, 5

We can mix up these notations in any expression.

>    22./7 + 2e1 - Float(-3,-2);

23.17285714

Maple will display floating point numbers in several different ways. If a decimal number is not too big or too small, Maple displays it in the usual way.

>    evalf( Pi^Pi );

>    evalf( Pi^(-Pi) );

36.46215964

.2742569310e-1

If a number gets kind of big (or small) then Maple switches to scientific notation.

>    evalf( Pi^(Pi^Pi) );

>    evalf( Pi^(-Pi^Pi) );

.1340164240e19

.7461772001e-18

If a number gets really, really big, then the regular float data structure cannot hold a representation for the number and so Maple displays a special version of the float data structure.

>    evalf( Pi^(Pi^(Pi^Pi)) );

Float(infinity)

Here is what is in this special float data structure.

>    op( % );

1, infinity

The exponent is a special quantity. Here is what Maple tells us it is.

>    %[2];

>    whattype( % );

infinity

extended_numeric

Maple also has a way of representing negative numbers that are too large to be represented by a regular float data structure.

>    evalf( -Pi^(Pi^(Pi^Pi)) );

>    op( % );

Float(-infinity)

-1, infinity

If a number gets really, really small, then the regular float data structure cannot hold a representation for the number and so Maple displays it as a floating point zero (notice the decimal point next to the zero).

>    evalf( Pi^(-Pi^(Pi^Pi)) );

>    op( % );

0.

0, 0

Maple has two  kinds of floating point zeros. There is a negative floating point zero that represents negative numbers too small to be represented by a regular float data structure.

>    evalf( -Pi^(-Pi^(Pi^Pi)) );

>    op( % );

-0.

0, 0

>   

Exercise : Why does the following Float  data structure not create a negative zero?

>    Float(-0, 0);

0.

>   

>   

3.2.5. Names (or symbols)

The names that we use for assigned and unassigned variables are themselves simple data structures with the data type symbol . Here are some examples.

>    whattype( x );

symbol

>    whattype( xyz );

symbol

Here is a name that needs left quotes.

>    whattype( `hello there` );

symbol

>   

The only piece of data in a data structure of type symbol  is the name itself.

>    op( xyz );

xyz

>    nops( xyz );

1

Notice that the individual letters in the name are not considered the data items. It is the whole name that is the (single) data item.

>    op( `hello there` );

`hello there`

>    nops( `hello there` );

1

Notice that the words in the name are not themselves data items. Again, it is the whole name which is the data item.

Here is an example that shows how evaluation rules can help explain what might otherwise be pretty confusing results. First, define a list and a function.

>    f := [1,2,3];   # A list.

f := [1, 2, 3]

>    g := x -> x^2;  # A function.

g := proc (x) options operator, arrow; x^2 end proc

In the next command, whattype  uses full evaluation of f .

>    whattype( f );

list

In the next command   g  points to a function so whattype  uses last name evaluation.

>    whattype( g );

symbol

Here is the way to see what it is that whattype  is checking.

>    'whattype'( f );

whattype([1, 2, 3])

>    'whattype'( g );

whattype(g)

Last name evaluation can sometimes make a name act as if it were unassigned. Here is how we find out the type of what g  points to. We need to force the full evaluation of the name g .

>    whattype( eval(g) );

procedure

As we will see in a later worksheet, functions are data structures with the data type procedure .

>   

Exercise : Explain the results of the following four whattype  commands.

>    abc := 123;

abc := 123

>    whattype( abc );

integer

>    whattype( 'abc' );

symbol

>    whattype( `abc` );

integer

>    whattype( `123` );

symbol

>   

Exercise : Explain the result of the second whattype  command.

>    whattype( 0 );

integer

>    whattype( % );

symbol

Hint: What does %  refer to in the last command?

>   

>   

3.2.6. Strings

Strings are a data structure made up of characters, just like the symbol data structure described in the last subsection. However, strings are defined in Maple using the double quote key rather than the left quote key used for symbols. Here are some examples of strings.

>    "xyz";

>    "a string can contain any characters, like these; &, @ ! *** =?";

>    "0123456789";

>    "There is not a lot that you can do with strings.";

Strings and symbols may seem more similar than they really are. The symbol `hello world`  and the string "hello world"  are not considered equal by Maple.

>    evalb( `hello world`="hello world" );

false

They are two data structures with different data types.

>    whattype( `hello world` );

symbol

>    whattype( "hello world" );

string

Both data structures contain only one piece of data.

>    nops( `hello world` );

1

>    nops( "hello world" );

1

But notice in the next two commands that Maple does not quite consider them as containing the same thing. Also, notice the subtle difference in the fonts used in the next two outputs.

>    op( `hello world` );

`hello world`

>    op( "hello world" );

The convert  command can be used to convert a name into a string and a string into a name.

>    convert( `hello world`, string );

>    convert( "hello world", name );

`hello world`

We just mentioned that a string  data structure contains only one piece of data, and gave as evidence the nops  command. But in fact, it is not really clear just what Maple considers as the data in a string  data structure. For example, let s  be a name for the string "hello world" .

>    s := "hello world";

s :=

>    whattype( s );

string

The nops  command implies that there is only one piece of data in s .

>    nops( s );

1

But consider the following commands.

>    s[1];

>    s[2];

>    s[3];

>    s[11];

>    s[-1];

>    s[-2];

These commands would seem to imply, by analogy with the index notation for the list  and set  data types, that s  contains 11 pieces of data, i.e., each of the letters in the string. The length  command also backs up this claim.

>    length( s );

11

Whether or not a string has one or many data items in it turns out not to be important. What is more important is that we can use the index notation to access individual letters from a string, which is something that we cannot do with the letters in a name.

>    "hello world"[3..-3];

>    `hello world`[3..-3];

`hello world`[3 .. -3]

The most important difference between strings and symbols is that strings cannot be used as variable names. Trying to use a string as a variable is an error.

>    "hello world" := 0;

Error, invalid left hand side of assignment

Of course the following is allowed.

>    `hello world` := 0;

`hello world` := 0

>   

Exercise : Why do you think that Maple does not allow index notation with names to refer to the individual letters of the name as it does with strings?

>   

So what are strings used for? Mostly as labels for graphs and as messages to be printed out by the print  command (which we will make use of in later worksheets). Also, Maple's error messages are strings.

>    plot( x^2, x=-10..10, title="A graph of x squared.",

>         titlefont=[COURIER, BOLDOBLIQUE, 14] );

[Maple Plot]

>    print( "This is a message from Maple." );

>    plot();  # Cause an error message.

Error, (in plot) see ?plot for argument information

>   

It is worth noting that early releases of Maple made no distinction made between symbols and strings. In fact, the string data type did not exist and there was only the symbol data type. So symbols were used for two kinds of purposes, as variable names and as "strings", i.e., labels for graphs and messages to be printed out (e.g., error messages). It was finally decided that it was not very elegant to blur the distinction between these two uses of strings of characters, so the string data type was defined. The double quote key was chosen to define strings since it is commonly used for this purpose in other programming languages. But the double quote key had been the last result variable!

>   

3.2.7. Equations and inequalities

Let us restart Maple, to avoid any confusion from previous assignments.

>    restart;

Earlier we defined an equation as an equals sign with an expression on either side of it. It turns out that Maple considers an equation to be a data structure with data type equation . An equation data structure always has two operands, the left and right hand sides of the equation. Here are some examples.

>    whattype( y = x^2 );

`=`

>    op( y = x^2 );

y, x^2

>    op( 1, y = x^2 );

y

>    op( 2, y = x^2 );

x^2

Maple has special commands for accessing the operands of an equation data structure, lhs  and rhs .

>    lhs( y = x^2 );

y

>    rhs( y = x^2 );

x^2

Now we can be very specific about the meanings of the two kinds of "equals signs" in a Maple command like the following.

>    eqn := y = x^2;

eqn := y = x^2

This command gave a name to a data structure. The name given to the data structure is eqn , and the data structure being named is the equation data structure y=x^2 . As far as Maple is concerned, the following two commands are doing the same kind of thing, they are giving names to data structures.

>    ds1 := 1 = x^2 + y^2;

ds1 := 1 = x^2+y^2

>    ds2 := [1, `=` , x, `^`, 2, `+`,  y, `^`, 2];

ds2 := [1, `=`, x, `^`, 2, `+`, y, `^`, 2]

>    whattype( ds1 );

`=`

>    whattype( ds2 );

list

(What are all the left-quotes in ds2  for? Describe in detail the contents of ds2 .)

>   

There are three other data structures in Maple that are closely related to the equation data structure. These are the inequality data structures , <> , <= , < . Below are some examples of inequality data structures.

>    x <> y;

x <> y

>    whattype( x<>y );

`<>`

>    op( x<>y );

x, y

>    u+v <= 5;

u+v <= 5

>    whattype( u+v<=5 );

`<=`

>    op( u+v<=5 );

u+v, 5

>    5 < 0;

5 < 0

>    whattype( 5<0 );

`<`

>    op( 5<0 );

5, 0

Should there be a >=  and a >  data structure? The answer is no, because they are not needed. Maple automatically converts any "greater than" inequality into a "less than" data structure.

>    5 > 0;

0 < 5

>    whattype( 5>0 );

`<`

>    op( 5>0 );

0, 5

Notice how the order of the data items in the data structure are not what you would expect.

>    op( 1, 5>0 );

0

>    op( 2, 5>0 );

5

Unfortunately, this can get to be a bit confusing.

>    lhs( 5>0 );

0

>    rhs( 5>0 );

5

Here is another example.

>    x-y >= 0;

0 <= x-y

>    whattype( x-y>=0 );

`<=`

>    op( x-y>=0 );

0, x-y

>   

Equations and inequalities in Maple are not entirely equivalent to equations and inequalities in standard mathematical notation. For example, the mathematical equation x  = y  = z  means that x , y , and z  all have the same value. But if we translate this directly into Maple, we get an error message.

>    x = y = z;

Error, `=` unexpected

Equations and inequalities in Maple are not transitive. So we need to put parentheses into the last equation in order for Maple to accept it. But neither

>    (x = y) = z;

(x = y) = z

nor

>    x = (y = z);

x = (y = z)

means the same thing in Maple that x  = y  = z  means in mathematics (we will see why shortly). Similarly, we would want the following inequality to mean that x  is less than y   and   y  is less than z . But instead it gives us an error message.

>    x <= y <= z;

Error, unexpected relational operator

The following two inequalities do not cause an error, but neither one has the meaning that we want either.

>    x <= (y <= z);

>    (x <= y) <= z;

x <= (y <= z)

(x <= y) <= z

We will see later what is the proper way to fix x<=y<=z .

>   

We have said before that equations (and also inequalities) are used to ask questions. An equation or inequality data structure can be interpreted as being either true or false. The Maple command evalb  allows us to evaluate an equation or inequality data structure to see if it is true of false. Here are some simple examples.

>    evalb( 0>=5 );

false

Here are two true inequalities.

>    evalb( 0<1 );

true

>    evalb( 0<>1 );

true

Here is an equation.

>    x := 5:

>    y := 1:

>    evalb( x=5*y );

true

What do you think should be the result of the next command?

>    evalb( (x=5*y)=(2*x-5=5*y) );

true

Let us go over this result in detail. Each of x=5*y  and 2*x-5=5*y  is an equation data structure, and so (x=5*y)=(2*x-5=5*y)  is an equation data structure where each of the left and right hand sides are themselves equations. It might seem that we are asking if these are the same two equations. But they are definitely not the same equation, so that is not why the last command returned true. The last equation is true because Maple uses full evaluation before the evalb  command is evaluated. Here is what the evalb  command sees as its input just before it is evaluated.

>    'evalb'( (x=5*y)=(2*x-5=5*y) );

evalb((5 = 5) = (5 = 5))

If we delay the evaluation of the inner equations, then we can verify that they are not the same equation.

>    evalb( ('x=5*y')=('2*x-5=5*y') );

false

>   

As we mentioned earlier, the following equation is syntactically incorrect.

>    evalb( 1=1=1 );

Error, `=` unexpected

Putting in parentheses corrects the syntax but does not give us what we really intended. Why do you think the following two equations are false?

>    evalb( (1=1)=1 );

false

>    evalb( 1=(1=1) );

false

Hint: Which equal sign is evalb  evaluating? What is on either side of it?

Mathematically, the inequality 0<1<2 is true. But 0<1<2  is not correct Maple syntax so we cannot even ask if it is true.

>    evalb( 0<1<2 );

Error, `<` unexpected

If we put parentheses in 0<1<2, then we can correct the syntax.

>    (0<1) < 2;

>    0 < (1<2);

(0 < 1) < 2

0 < (1 < 2)

But if we put one of these in the evalb  command to see if it might be true, we get one of Maple's most inscrutable error messages.

>    evalb( (0<1)<2 );

Error, (in simpl/relopsum) invalid terms in sum

Just what sum is it that this message is referring to? Here is a hint.

>    a:='a': b:='b':

>    evalb( a<b );

a-b < 0

It seems that in the process of trying to determine if an inequality is true or not, Maple at some point converts the inequality into one involving zero. In the case of a<b , since a  and b  are unassigned, Maple cannot determine if this inequality is true or false so it just returns the inequality, but in the form a-b<0 . (Maple could have chosen to use alphabetical ordering of names to evaluate this inequality, but it did not.) Now back to (0<1)<2 . Maple probably converted this to (0<1)-2<0 .

>    (0<1)-2<0;

Error, (in simpl/relopsum) invalid terms in sum

Now we see what sum Maple means and where it came from.

>    (0<1)-2;

Error, (in simpl/relopsum) invalid terms in sum

>   

So how does one express in Maple the fact that 0<1<2. The answer comes from reading this aloud, "zero is less than 1 and 1 is less than 2". In Maple we translate this as 0<1 and 1<2 .

>    evalb( 0<1 and 1<2 );

true

Similarly, we would express the mathematical notation x  = y  = z  as x=y and y=z .

>    x := 3: y := x: z:= y:

>    evalb( x=y and y=z );

true

When we evaluate an equation (or inequality) data structure as either true or false, we are evaluating the equation (or inequality) as a boolean expression . The command evalb  is an abbreviation for " eval uate b oolean". In general, a boolean expression is any expression whose value is either true or false (as opposed to, say, a number). Any two boolean expressions can be combined using and  or or . For example 1 < abs(x)  is equivalent to x<-1 or x>1 . We will examine boolean expressions in more detail later.

>   

While we are discussing inequalities and the evalb  command, consider the following command.

>    evalb( Pi<4 );

Pi < 4

Maple has no problem with the next two commands.

>    evalb( 3.14<4 );

true

>    evalb( evalf(Pi)<4 );

true

I have no idea why Maple cannot make the comparison in the inequality Pi<4 .

>   

Finally, notice that the equation data structure is a lot like an ordered pair. In fact, Maple often uses equation data structures as a way to hold ordered pairs. One example of this that we will see later is the way Maple stores entries in a table data structure (in particular, the remember table stored in a procedure data structure).

>   

>   

3.2.8. Ranges

We use ranges in many different situations in Maple. Here are few examples.

>    x||(0..4);

x0, x1, x2, x3, x4

>    seq( x^2, x=0..4 );

0, 1, 4, 9, 16

>    plot( x->x^2, 0..4 ):

In this subsection we show that the "dot dot" operator ( .. ) is really used by Maple to define a data structure, with the data type range , that holds exactly two pieces of data (somewhat like the equation and inequality data structures).  As we will see, a range  data structure is often interpreted in Maple to mean some kind of range of numbers, but this interpretation is not universal, and the two pieces of data in a range data structure can actually be used for almost any purpose.

>   

Here is a simple example of a range data structure.

>    p..p^2;

p .. p^2

We can give it a name.

>    r := %;

r := p .. p^2

We can ask what its data type is and what are its pieces of data.

>    whattype( r );

`..`

>    op( r );

p, p^2

We can try to use it.

>    seq( i, i=r );

Error, unable to execute seq

>    w||(r);

w || (p .. p^2)

Since the data items in our range do not yet evaluate to numbers, the range has limited use right now. We can give p  a value, and then try using the range again.

>    p := 2;

p := 2

>    w||(r);

w2, w3, w4

>    seq( i, i=r );

2, 3, 4

Here is what the seq  command saw as its input before it was evaluated but after r  and its two data items were evaluated.

>    'seq'( i, i=r );

seq(i,i = 2 .. 4)

A range data structure can hold any two pieces of data, but if the data items of the range do not evaluate to numbers, then the range will not work in most Maple commands.

>   

Notice that two levels of evaluation are needed before r  evaluates to a "real" range. The next two commands try to show these levels of evaluation.

>    eval( r, 1 );

p .. p^2

>    eval( r, 2 );

p .. p^2

>    eval( r );

2 .. 4

Notice that the eval  command did not evaluate the names inside the range when we asked for levels of evaluation. When we used eval  with a list data structure, eval  was able to show the levels of evaluation of the names inside the list. For some kinds of data structures the eval  command can show the levels of evaluation inside the data structure, but for some other data structures eval  cannot.

>   

Here is another example of using a range that contains expressions instead of numbers. The following seq  command causes an error since the data items in the range do not evaluate to numbers yet.

>    x:='x':

>    seq( i, i=x..x^2 );

Error, unable to execute seq

Here is an interesting example of how we can give the expressions in the range a value. We can take this seq  command and nest it inside of another seq  command. The outer seq  command gives values to the range in the inner seq .

>    seq( seq(i, i=x..x^2), x=1..5 );

1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25

The last command created an expression sequence of expression sequences. It can be a bit hard to see where the sub expression sequences begin and end in the output. Here is a slight modification of the last command that creates an expression sequence of lists.

>    seq( [seq(i, i=x..x^2)], x=1..5 );

[1], [2, 3, 4], [3, 4, 5, 6, 7, 8, 9], [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
[1], [2, 3, 4], [3, 4, 5, 6, 7, 8, 9], [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Exercise : Write a single command that will generate an expression sequence of lists where each list contains the first n  odd integers.

>   

Exercise : Write a single command that will generate a list of lists where each list contains the first n  integers each raised to the n th power.

>   

Now let us look at the interpretation that Maple gives to a range data structure. The meaning of a range a..b  need not  be "all the numbers from a  to b ". The meaning of a range depends a great deal on the context in which it is used. For example in the following command

>    seq( i, i=-2..2 );

-2, -1, 0, 1, 2

the range -2..2  means all integers  from -2 to 2. But in the command

>    plot( i, i=-2..2 );

[Maple Plot]

the range -2..2  means all real numbers  from -2 to 2. And in the command

>    op( -2..2, [a, b, c, d, e, f] );

Error, improper op or subscript selector

the range -2..2  does not have a meaning, it caused an error. On the other hand the range 2..-2  works fine in the next op  command.

>    op( 2..-2, [a, b, c, d, e, f] );

b, c, d, e

The range 2..-2  does not cause an error in the following seq  command, but it results in no output (because the range is interpreted here as an empty range).

>    seq( i, i=2..-2 );

And in the following plot  command, 2..-2  seems to be interpreted just like -2..2 .

>    plot( i, i=2..-2 );

[Maple Plot]

So the meaning of a range data structure is very  command dependent!

>   

>   

3.2.9. Function calls

The last of Maple's basic data structures that we describe in this section is a function call  (also referred to as an unevaluated function call ). This is anything of the form

  name(exprseq)

that is, a name followed by a left parenthesis followed by an expression sequence followed by a right parenthesis, and where name  may be either an assigned or an unassigned variable. Here is an example of a function call.

>    f(x, y, z);

f(x,3,3)

>    whattype( % );

function

>    op( %% );

x, 3, 3

Notice that Maple calls the data type function , which is confusing since f  (the name part of this function call) need not be the name of any Maple function. The operands of the function call data structure are the operands of the expression sequence between the parentheses. Here is another example.

>    a_funny_name( z^2, [a,b,c], x, 2/3 );

a_funny_name(9,[a, b, c],x,2/3)

>    whattype( % );

function

>    op( %% );

9, [a, b, c], x, 2/3

>   

Notice that the following two data structures, called fc1  and fc2 , have the same data type and contain the same data items in the same order, but they are not the same data structure. So what distinguishes them?

>    fc1 := h(a, b, c);

>    fc2 := k(a, b, c);

fc1 := h(a,b,c)

fc2 := k(a,b,c)

>    whattype( fc1 );

>    whattype( fc2 );

function

function

>    op( fc1 );

>    op( fc2 );

a, b, c

a, b, c

>    evalb( fc1 = fc2 );

false

A function  data structure has a feature that most other data structures do not have, a zero'th data item. The zero'th data item in a function  data structure is the name  that appears in front of the parentheses as part of the function call.

>    op( 0, fc1 );

>    op( 0, fc2 );

h

k

So this is how Maple distinguishes fc1  from fc2 . If it were not for the function  data structure's zero'th data item, fc1  and fc2  would be indistinguishable. (Recall that for most data types, the " zero'th data item" as returned by the op  command is the data type of the data structure.)

>   

The unevaluated function call data structure has two main interpretations in Maple depending on whether the name in the function call is an assigned or unassigned name. The first is, not surprisingly, to represent function calls in the usual sense when the name in the function call is assigned to a function definition. Here are a few examples.

>    whattype( exp(x) );

function

>    whattype( 'sin(Pi)' );

function

(Why were right-quotes needed in the last example? What would be the type if they were removed?)

>    whattype( '(z -> z^2)(w)' );

function

>    f := z -> z;

>    whattype( 'f(u)' );

f := proc (z) options operator, arrow; z end proc

function

Notice the difference between the last whattype  command and the next three.

>    whattype( f );

symbol

>    whattype( eval(f) );

procedure

>    whattype( f(u) );

symbol

Since f  points to a function definition, by last name evaluation f  evaluates to f , so whattype(f)  returns symbol . If we force full evaluation of f , then whattype(eval(f))  returns procedure , which is the data type of a Maple function definition that uses the arrow notation.  And by the full evaluation rule and the definition of f , f(u)  evaluates to u , which is a name, so whattype(f(u))  returns symbol . This can get a bit confusing. Remember that a function definition is stored in a data structure with data type procedure  (that we will look at in a different worksheet) and that function  is the data type of a function call data structure that represents just the form  of a function call.

>   

Maple's other interpretation of a function call data structure is as a kind of tagged, or labeled, expression sequence. This is the way Maple interprets a function call in the case where the name at the front of the call is an unassigned name. The name at the front of the function call is the tag (or label) for the expression sequence inside the parentheses.

>    my_so_far_undefined_function(12, -2, 102);

my_so_far_undefined_function(12,-2,102)

>    whattype( % );

function

>    op( %% );

12, -2, 102

Maple makes use of a lot of these kinds of tagged expression sequences. Here is an example of Maple returning an unevaluated function call data structure as the result of a Maple command.

>    x := 'x':

>    solve( x^5-x+1 = 0 );

RootOf(_Z^5-_Z+1,index = 1), RootOf(_Z^5-_Z+1,index = 2), RootOf(_Z^5-_Z+1,index = 3), RootOf(_Z^5-_Z+1,index = 4), RootOf(_Z^5-_Z+1,index = 5)
RootOf(_Z^5-_Z+1,index = 1), RootOf(_Z^5-_Z+1,index = 2), RootOf(_Z^5-_Z+1,index = 3), RootOf(_Z^5-_Z+1,index = 4), RootOf(_Z^5-_Z+1,index = 5)

The solve  command returned an expression sequence containing five items. Each item is an unevaluated function call data structure and each of these unevaluated function call data structures holds two items.

>    %[1];

RootOf(_Z^5-_Z+1,index = 1)

>    whattype( % );

function

>    op( 0, %% );

RootOf

>    op( %%% );

_Z^5-_Z+1, index = 1

The information that Maple wanted to pass on as the result of the solve  command was placed in unevaluated function call data structures.

Here is another example of solve  using unevaluated function call data structures to represent its result.

>    solve( x^3+1 > 0 );

RealRange(Open(-1),infinity)

This result is made up of nested unevaluated function call data structures.

>    whattype( % );

function

>    op( 0, %% );

RealRange

>    op( %%% );

Open(-1), infinity

>    %[1];

Open(-1)

>    whattype( % );

function

Here is another example of how Maple can use an unevaluated function call. Let us make an assumption about the variable x .

>    assume( x>0, x<=5 );

Now we ask Maple about x .

>    about( x );

Originally x, renamed x~:

  is assumed to be: RealRange(Open(0),5)

We see that Maple stores the information about the assumptions on x  in a couple of nested unevaluated function calls, RealRange(Open(0),5) . Try changing the assumption on x  and seeing how Maple stores the new assumption.  To erase all assumptions, unassign x .

>    x := 'x';

x := 'x'

Here is a rather subtle, but very important, example of Maple using unevaluated function calls. Let us create a simple plot and give it a name rather than displaying it.

>    p := plot( [ [0,0], [1,1] ] );

p := INTERFACE_PLOT(CURVES([[0., 0.], [1., 1.]],COLOUR(RGB,1.0,0.,0.)),AXESLABELS(

From the last output we see that Maple puts all of its information for describing a plot in a bunch of nested unevaluated function calls.

>    whattype( p );

function

>    nops( p );

3

>    op( 0, p );

>    op( 1, p );

>    op( 2, p );

>    op( 3, p );

PLOT

CURVES([[0., 0.], [1., 1.]],COLOUR(RGB,1.0,0.,0.))

AXESLABELS(

VIEW(DEFAULT,DEFAULT)

These unevaluated function calls hold, as their "arguments", all of the data that Maple needs to draw the graph.

>    p;

[Maple Plot]

Maple makes extensive use of unevaluated function call data structures. Many of Maple's predefined internal data structures are unevaluated function call data structures that often contain other unevaluated function call data structures as operands. A good example of this internal use of unevaluated function call data structures, as we have just seen, is the PLOT data structure used to describe Maple's graphs.

>   

The official definition  of the unevaluated function call data type in the Maple help pages says that it is of the form name ( exprseq ). But in reality, Maple has a much broader idea of what an unevaluated function call is. The official definition  of an unevaluated function call data structure more accurately describes an unevaluated function call as being of the form expression ( exprseq  ). We have already sneaked into this section one example of this broader definition.

>    whattype( '(z -> z^2)(w)' );

function

>    op( 0, '(z->z^2)(w)' );

proc (z) options operator, arrow; z^2 end proc

>    whattype( % );

procedure

So we just saw a function  data structure of the form procedure ( exprseq ) and not name ( exprseq ). Here is another example.

>    whattype( '5(-2)' );

function

The next two commands also verify that Maple interprets 5(-2)  as a function call data structure.

>    type( '5(-2)', function );

true

>    op( 0, '5(-2)' );

5

5  is not a name.

>    whattype( % );

integer

Notice what 5(-2)  evaluates to.

>    5(-2);

5

>   

Exercise : What function does the function call 5(-2)  refer to?

>   

Here is another example of a function call that is not of the form name ( exprseq ).

>    f(x)(y,z);

x(3,3)

Let us check that this really is an unevaluated function call.

>    whattype( f(x)(y,z) );

function

What are the operands?

>    op( f(x)(y,z) );

3, 3

>    op( 0, f(x)(y,z) );

x

So f(x)(y,z)  is a function call of the form function ( exprseq ). In particular, the function being called is f(x) . Notice that in f(x)(y,z) , the f(x)  part represents both the value of one function call and the function of another function call. To put it another way, for the expression f(x)(y,z)  to make sense, it must be that f  represents a function whose value is another function (in particular, a function of two variables). In an optional section of the worksheet about functions we looked at examples of functions that return functions. Here is an example that works with the expression f(x)(y,z) .

>    f := x -> (u,v)->u^x+v^x;

f := proc (x) options operator, arrow; proc (u, v) options operator, arrow; u^x+v^x end proc end proc

Notice that f  is not  a function of three variables. It is a function of one variable that returns a function of two variables. Here is what f(x)  evaluates to.

>    f(x);

proc (u, v) options operator, arrow; u^x+v^x end proc

Here is what f(4)  looks like.

>    f(4);

proc (u, v) options operator, arrow; u^4+v^4 end proc

Notice how the value of f(4)  is a function of two variables. Here is what f(4)(y,z)  evaluates to.

>    f(4)(y,z);

162

>   

Exercise : What do you think Maple is doing when it evaluates the following expression?

>    (a,b)(c,d);

a(c,d), b(c,d)

>   

Exercise : Let us define an expression named f .

>    x:='x':

>    f := x^2+x+3;

f := x^2+x+3

Recall that we evaluate an expression at a point using the subs  (or the eval ) command.

>    subs( x=1, f );

5

Recall that we pointed out earlier that it is a mistake to use functional notation to try and evaluate at a point a function represented as an expression.

>    f(1);

x(1)^2+x(1)+3

Try to make sense out this last output. What did Maple do to get it? In particular, in the next output, why are the x's displayed using two different typefaces?

>    f(x);

x(x)^2+x(x)+3

(Here is a hint.)

>    (h+k)(x);

h(x)+k(x)

>   

Exercise : Suppose that you mean to enter the expression (5+w)*(3-w)  into Maple and so you type the following.

>    w:='w':

>    (5+w)(3-w);

5+w(3-w)

You forgot the multiplication symbol * . Explain, with as much detail as you can, how Maple parsed the input (5+w)(3-w) .

>   

Exercise : Suppose you want to represent the mathematical function g(x) = (x^2-3)*(x^2-2)  as an expression and then evaluate it at x = 2 . So you make the following two mistakes.

>    x:='x':

>    g := (x^2-3)(x^2-2); # Mistake 1.

g := x(x^2-2)^2-3

>    g(2);                # Mistake 2.

x(x^2-2)(2)^2-3

Explain the last output as best you can.

>   

Exercise : Suppose you want to represent the mathematical function g(x) = (x^2-3)*(x^2-2)  as a Maple function and then evaluate it at x = 2 . So you make the following mistake.

>    g := x -> (x^2-3)(x^2-2);

g := proc (x) options operator, arrow; (x^2-3)(x^2-2) end proc

Now evaluate g  at 2.

>    g(2);

1

Notice how subtle  the mistake is! Explain the last output as best you can.

>   

If you start to use Maple a lot, believe me, you will make the mistakes that the last four exercises demonstrate. And these can be hard  mistakes to track down in long, complicated calculations, especially the last one! After years of doing mathematics, we are so used to seeing (x^2-3)(x^2-2)  as correct that it is easy to pass over it when double checking a large expression.

>   

>   

>