Contents Previous Next Index
3 Maple Expressions
This chapter introduces Maple expressions associated with scalar data structures.
3.1 In This Chapter
Introduction: automatic simplification and evaluation; syntax and constructors
Using names, strings, and numbers in expressions
Unevaluated expressions
Expression types: arithmetic, Boolean, relational, and set-theoretic expressions; expressions for data structures; indexed expressions; function and member selection expressions
Assigning attributes
Classifying, examining, and manipulating expressions
3.2 Introduction
Expressions and Statements
Maple language elements can be classified as either expressions or statements. An expression is a first-class data element in the Maple language. In other words, expressions can be stored in data structures, passed as arguments to procedures, and manipulated in various ways; they are often used to represent mathematical objects. Statements, on the other hand, are not first-class data elements; they generally describe non-mathematical programming constructs and are used to affect the state of Maple.
This chapter describes expressions associated with scalar data structures. For information about non-scalar data structures, see Basic Data Structures.
For more information about Maple statements, see Maple Statements.
Automatic Simplification and Evaluation
Maple uses two processes to compute expressions: automatic simplification and evaluation. Automatic simplification is a process that Maple applies to the input immediately; this process cannot be controlled. Expression evaluation occurs after an initial round of automatic simplification; this process can be controlled in certain ways. For each kind of expression described in this chapter, the rules for both automatic simplification and expression evaluation are described.
Syntax and Constructors
You can create most expressions by entering the appropriate syntax. However, some expressions, such as expressions that include tables or a series, can only be created by calling a constructor. A constructor is a command that can be used as an alternative method of creating certain expressions.
For example, a sum that would normally be entered using the syntax for addition
a + b + c + d;
a+b+c+d
can also be entered using the constructor `+`.
`+`( a, b, c, d );
With some exceptions (for example, series, lists, sets, and procedures), the name of the constructor for an expression can be displayed by using the op command with its first argument equal to 0.
op( 0, a + b + c + d );
`+`
The example above shows that the constructor for the expression a + b + c + d is the command assigned to the name `+`.
3.3 Names
Names have several purposes in Maple. They can be used to reference algebraic indeterminates, symbols, and variables in your code.
Names provided a basic introduction to Maple names. The following section describes concepts related to names in more detail.
A Maple name can be either global or local, depending on its scope. In this chapter, only global names are used. A global name is created either by referring to it at the top level of your program or by declaring it to be global in either a procedure or module definition. For more information about scope, see Variables in Procedures.
Two names are the same if they have the same spelling and scope. Maple keeps only one copy of any name in memory, so in a large expression that includes an indeterminate x, only one copy of the name x is kept in memory. Each occurrence of x in the expression refers to the same name x.
The polynomial
x^3 - 3*x^2 + 3*x - 1;
x3−3⁢x2+3⁢x−1
contains three occurrences of the name x, but all three point to the same location in memory.
Maple is unique in that names can represent themselves. As a result, you can use names as algebraic indeterminates, for example, to construct polynomials or other algebraic expressions.
Names can also be used to represent variables in your code. When a name is assigned a value, that name is associated with another expression and evaluating the name results in its assigned value being returned. When a name is unassigned, evaluating the name results in the name itself.
In this example, the name a is assigned to the value 2.
a := 2;
a≔2
Before using a name on the left side of an assignment, the name has no assigned value.
b;
b
When a value is assigned to a name, subsequent evaluation of the name results in its assigned value.
a;
2
For more information about assigning values, see Assignments.
Creating Names: Lexical Conventions
When creating names in Maple, you must be aware of certain lexical conventions.
Environment Variables
Names beginning with an underscore character (_) are reserved for use by the Maple library. You should not create names that begin with an underscore.
As a special case, any name beginning with the four character sequence "_Env" is treated as an environment variable.
Environment variables are a special kind of variable in that an assignment to one within a procedure is automatically unassigned when the procedure has finished running. Therefore, environment variables only affect subprocedures called from that procedure, unless they are superseded locally.
The following predefined environment variables do not begin with _Env: Testzero, UseHardwareFloats, Rounding, %, %%, %%%, Digits, _ans, index/newtable, mod, Order, printlevel, Normalizer, NumericEventHandlers.
Environmental Variables Scope
Unlike a local variable, whose scope is restricted to the procedure containing the local variable itself, an environment variable can be referenced globally by all sub-procedures called by or deeper than the current procedure, but the environment variable cannot be referenced by procedures above the current procedure.
For more information about environment variables, refer to the envvar help page. For more information about procedures, see Procedures or refer to the procedure help page.
Constants
In addition to keywords, as described in Reserved Words, Maple has several predefined constants.
You can display a sequence of all the names that represent symbolic constants in Maple by using the global variable constants.
constants;
false,γ,∞,true,Catalan,FAIL,π
seq(i=evalf(i), i in constants);
false=false,γ=0.5772156649,∞=Float⁡∞,true=true,Catalan=0.9159655942,FAIL=FAIL,π=3.141592654
Maple also has several other special constants. Table 3.1 lists some of them. For more information, refer to the initialconstants help page.
Name
Meaning
lasterror
the most recent error
constants
initially known symbolic constants
libname
path of the Maple libraries
Digits
number of digits in floating-point computations
NULL
empty expression sequence
FAIL
cannot determine value
Order
truncation order for series
printlevel
control display of information
I
complex number
undefined
undefined numeric quantity
For more information about constants in Maple, refer to the type/constant help page.
Protected Names
A protected name has a predefined meaning; you cannot directly assign a value to a protected name. For example, the names of built-in commands such as sin; utility operations such as degree; commands such as diff; and type names such as integer and list, are protected names. An error occurs if you attempt to assign a value to any of these names.
list := [1,2];
Error, attempting to assign to `list` which is protected. Try declaring `local list`; see ?protect for details.
The Maple system prevents these names from re-assignment. However, even though it is not recommended, it is possible to reassign values to these names by first unprotecting them as illustrated by the following statements.
Note: You can unassign values to Maple system names by entering a restart command or by ending your Maple session. In general, using the unprotect command to modify Maple system names is not recommended.
unprotect(sin);
sin := "a sin indeed";
sin≔a sin indeed
As a result, Maple components that rely on the sine function may not work as expected.
plot( sin, 0..2*Pi, coords=polar );
Error, (in plot) unexpected options: ["a sin indeed", 0 .. 2*Pi]
To check whether a name is protected, use the type command.
type(sin, protected);
false
type(sine, protected);
To prevent values from being assigned to a name, use the protect command.
mysqr := x -> x^2;
mysqr≔x↦x2
type(mysqr, protected);
protect( mysqr );
mysqr := 9;
Error, attempting to assign to `mysqr` which is protected. Try declaring `local mysqr`; see ?protect for details.
3.4 Unevaluated Expressions
In general, Maple evaluates all expressions immediately. In some situations, it is necessary to delay the evaluation of an expression. An expression enclosed in right single quotes is called an unevaluated expression. It takes the general form
'expr'
where expr is an arbitrary expression. All of the expressions contained within the right single quotes are not evaluated.
For example, the sin command normally performs the following computations.
sin( 0.5 );
0.4794255386
sin( Pi / 2 );
1
To prevent the evaluation of these computations, you can enclose the expressions in right single quotes (also called unevaluation quotes) as follows.
'sin( 0.5 )';
sin⁡0.5
'sin( Pi / 2 )';
sin⁡π2
You can enclose expressions of any length or complexity in unevaluation quotes.
'sin( 0.5 )^2 + cos( 0.5 )^2';
sin⁡0.52+cos⁡0.52
Also, you can enclose subexpressions in unevaluation quotes to prevent certain parts of an expression from evaluating.
'sin( 0.5 )'^2 + cos( 0.5 )^2;
sin⁡0.52+0.7701511530
The sections below describe cases in which you may want to delay evaluation.
Protecting Names and Options
Unevaluation quotes can be used to prevent the evaluation of names.
a := x^2 + x + 1;
a≔x2+x+1
x2+x+1
'a';
a
This is important when you want to use a variable as a name, regardless of whether it has an assigned value.
Also, unevaluation quotes can be used to protect options. Names are often used as options to control the behavior of a command. If the name of that option has been used as a variable, the command that has been called uses the value of the variable and not the option name as expected. Unevaluation quotes can be used around option names to protect against this.
symbolic := 4;
symbolic≔4
sqrt( -9*x^2*y, 'symbolic' );
3⁢x⁢−y
In the next example, an exception is raised because the name of a command option is not enclosed in unevaluation quotes.
output := 2:
CodeGeneration:-C( x^2, output = string );
Error, (in Translate) options [2 = string] not recognized
In this example, the best way to use the output option is to quote the name, thus preventing its evaluation in case the name output has an assigned value.
CodeGeneration:-C( x^2, 'output' = 'string' );
cg = x * x;
Tip: It is also recommended that you also use unevaluation quotes for the names of types and conversions. For more information, see Structured Types.
For more information on types and conversions, refer to the type and convert help pages.
Generic Expressions
Expressions sometimes describe the operation to take place in a generic sense. For example, B[i] can be used in certain contexts with unevaluation quotes to denote a generic index into B. If unevaluation quotes are not used, Maple will try to look up the specific ith element of B.
B := <1,2,3,4>;
B≔
sum(B[i], i = 1..4);
Error, bad index into Vector
sum('B[i]', i = 1..4);
10
Pass by Reference
Some commands accept a name as an argument, with the intent that it will be used to store a result. Unevaluation quotes ensure that the variable name (and not the value assigned to the variable) is used in the procedure.
remainder := irem(45,3,'quotient'); quotient;
remainder≔0
15
remainder := irem(44,3,'quotient'); quotient;
remainder≔2
14
If quotient is not enclosed in unevaluation quotes, the second call in the above example raises an exception because 15, the value of quotient, is not a valid third argument to the irem command.
Displaying the Original Command
For display purposes, it is sometimes useful to show the original command before a solution is computed.
v := 'int(x*y^2, [x=0..1, y=0..1] )';
v≔∫01∫01x⁢y2ⅆxⅆy
v;
16
Unassigning Names
To reset the value of a name, assign the unevaluated name (its initial value) to the name. For example,
x := 2+3;
x≔5
x := 'x';
x≔x
Now, the value of x is reset to x.
Evaluation and Automatic Simplification
It is important to note the differences between computations that occur during the evaluation process and those that occur during the automatic simplification process. Unevaluation quotes do not prevent automatic simplifications from occurring. For example, basic numeric arithmetic is one form of automatic simplification. In the following expression, the unevaluation quotes do not prevent the numeric addition from occurring.
'2 +3';
5
In this example, Maple first simplifies the unevaluated sum '2 + 3' to the expression '5'. During the evaluation process, Maple "removes" the right single quotes and produces the numeric result 5.
All unevaluated expressions are of the type uneval. You can use the type command to check whether an expression is an unevaluated expression.
type( ''x'', 'uneval' );
true
In the example above, the first argument to the call to the type command is the name x, which is enclosed in two sets of unevaluation quotes. The result of evaluating the first argument is the unevaluated expression 'x' because the evaluation process removes one set of unevaluation quotes. The resulting expression is therefore of type uneval.
On the other hand, if you enclose the first argument to type in only one set of unevaluation quotes, the evaluation process removes the only set of unevaluation quotes, leaving the result as the name x, which is not an unevaluated expression.
type( 'x', 'uneval' );
In other words, the type command accesses the name x, rather than the unevaluated expression 'x', since the type command accesses the result of its arguments that have been evaluated.
In the example above quotes were also used around the type name uneval. This provides a measure of protection just in case the variable name, uneval has an assigned value (which is unlikely because uneval is protected). During normal function evaluation, each argument, x and uneval is evaluated. With quotes, 'x' becomes x, and 'uneval' becomes uneval as seen by the type procedure. Without quotes, x would become the value of x (which may be the symbol x itself), and uneval would become the value of uneval, which is usually the symbol uneval itself. Unevaluation quotes make the displayed call robust against cases where the variable you are using unexpectedly has a value. It is rarely necessary to use this level of caution in interactive use, but when you write programs, it is a good practice to include unevaluation quotes to make your code as robust as possible.
Another special case of unevaluation arises in function calls.
'f'(a)
Suppose f is not assigned to anything. Since evaluating f does not call a procedure, Maple returns the unevaluated function call f(a).
f(a);
f⁡x2+x+1
Similarly, using uneval quotes around a function evaluation will cause Maple to behave as if the named function had no value.
''sin''(Pi);
sin⁡π
(39);
(40);
0
You will find this facility useful when writing procedures that need to act on the whole original expression, not the evaluated result.
For more examples and information on unevaluated expressions, refer to the uneval help page.
Example: Defining a Procedure That Is Returned Unevaluated
You may need to use unevaluation quotes when you are defining a procedure that is returned unevaluated. This is necessary, for example, when you are defining a procedure that evaluates a numeric result for numeric inputs, but does not produce a numeric result otherwise. (The procedure may perform normalizations and apply symmetries, if appropriate.) It is important to write procedures using this method so that they can be plotted, optimized, or numerically integrated, for example.
Consider the following procedure.
f := proc( x ) if x > 2 then x else 2 end if end proc:
Using the wrong calling sequence in a call to plot results in an error.
plot( f( x ), x = -10 .. 10 );
Error, (in f) cannot determine if this expression is true or false: 2 < x
The correct calling sequence would be either plot( 'f'(x), x=-10..10), which puts uneval quotes around f, or plot( f, -10..10), which avoids computing f(x) by omitting the variable altogether. Remember that arguments in a function call are evaluated first before the called procedure sees them.
Here, the precursor evaluation of f(x) tries to apply f to the unassigned symbol, x.
f( x );
The procedure could be rewritten so that it returns unevaluated whenever it encounters arguments that cannot be processed. This trick causes f(x) to evaluate to itself when non-numeric input is passed in.
f := proc( x ) if type( x, 'numeric' ) then if x > 0 then x else 2 end if else 'procname( _passed )' end if end proc:
The unevaluated expression 'procname( _passed )' returns the full calling sequence unevaluated.
f⁡x
The expression procname( _passed ) must be enclosed in unevaluation quotes to prevent an infinite loop.
3.5 Numbers
Maple supports computation with exact numerical quantities, as well as approximate computation to arbitrarily high accuracy with floating-point numbers.
Integers
A natural integer is any sequence of one or more decimal digits.
12345;
12345
The maximum number of digits is system-dependent. To determine the maximum number of digits, use the following command.
kernelopts( 'maxdigits' );
38654705646
A signed integer is formed by appending + or - before any natural integer.
-42;
−42
+42;
42
An integer is either a natural integer or a signed integer.
You can use the length command to determine the number of digits in an integer.
2^42;
4398046511104
length( 2^42 );
13
Fractions
A rational number (fraction) is the quotient of two integers, where the denominator is always positive.
Use the division operator (forward slash) / to enter a fraction.
integer / natural
For example,
2 / 3;
23
You can enter a fraction in which the numerator and denominator have a common (integer) factor, but Maple automatically simplifies this to the lowest terms.
4 / 6;
In addition, Maple automatically moves a negative sign to the numerator.
2/(-3);
−23
Fractions are automatically simplified to an integer if the denominator is a divisor of the numerator.
6/3;
You can use the numer and denom commands to extract the numerator and denominator, respectively, of a fraction.
numer( 2/3 );
denom( 2/3 );
3
Fractions can also be created by using the Fraction constructor with the numerator and denominator as arguments.
Fraction( 2, 3 );
Floats
Maple supports computation with floating-point numbers to arbitrary precision.
A float can be input using a period for the decimal.
2.3;
2.3
2.;
2.
.7;
0.7
-.567;
−0.567
Or, using exponent form using a suffix containing the letter "e" or "E" followed by an integer with no spaces between.
4e3;
4000.
2.3e6;
2.3×106
.2E3;
200.
Observe that spaces are significant. The first example is a difference rather than a float in exponent form.
.2e -3;
−2.8
.2e-3;
0.0002
Also, the following is invalid.
3.e4;
30000.
Floats represent numbers of the form s*10^e, where the number s is called the significand or mantissa of the float, and the number e is called the exponent. The significand is a Maple integer. Therefore, it is restricted to values that have, at most, the number of digits indicated by the kernelopts( 'maxdigits') command.
The maximum value of the exponent is a platform-dependent quantity whose value may be queried by using the Maple_floats command.
Maple_floats( 'MAX_EXP' );
9223372036854775806
Similarly, the minimum value of the exponent is given by the value
Maple_floats( 'MIN_EXP' );
−9223372036854775806
returned by the Maple_floats command. For more information, refer to the Maple_floats help page.
You can also create software floats by using the constructor SFloat. This constructor accepts the significand and exponent as arguments, and has the general form
SFloat( m, e )
SFloat( 23, -1 );
To extract the significand and exponent of a software float, use the SFloatMantissa and SFloatExponent commands.
SFloatMantissa( 2.3 );
SFloatExponent( 2.3 );
−1
The significand and exponent are also the operands of a software float.
op( 2.3 );
23,−1
Two software floats are equal if they represent the same number. However, equal floats by themselves do not need to be the same object in memory.
evalb( 2.3 = 2.30 );
addressof( 2.3 ); addressof( 2.30 );
36893628422764247132
36893628422603906236
Observe that the significands (and therefore, also, the exponents) differ in this example.
SFloatMantissa( 2.30 );
230
Note that equal floats with different significands inside of two otherwise identical objects will require something stronger than evalb for comparison. evalb is the implicit comparison used when evaluating conditionals in if statements.
evalb( 2.3 + x = 2.30 + x );
evalb(<2.3,4.5> = <2.30,4.50>);
Testing the difference of the two expressions, or calling a command to do a deeper comparison may be necessary.
evalb( (2.3 + x) - (2.30 + x) = 0 );
EqualEntries(<2.3,4.5>, <2.30,4.50>);
The names of the constructor SFloat and accessors SFloatMantissa and SFloatExponent all begin with the letter S. The S stands for "software" because these floating-point numbers are implemented in software. Maple also supports the floating-point numbers supported by the underlying hardware, called hardware floats or hfloats. You can create a hardware float by using the hardware float constructor HFloat.
HFloat( 24375, -3 );
24.3750000000000
h := HFloat( 24.375 );
h≔24.3750000000000
op( h );
243750000000000000,−16
Note, however, that hfloats are binary floating-point numbers, rather than decimal floating-point numbers. That means that unlike the example above, there is often round-off error when decimal numbers are converted into hfloats. For more information, see Hardware Floating-Point Numbers.
op( HFloat(2.3) );
229999999999999982,−17
The SFloatMantissa and SFloatExponent commands also accept hardware floats as input.
SFloatMantissa( h );
243750000000000000
SFloatExponent( h );
−16
For more information on floating-point numbers, see Floating-Point Numbers.
Complex Numbers
Maple supports arithmetic with complex numbers of the form a+bi, where i=−1 is the imaginary unit. In Maple, the imaginary unit is normally denoted by I; that is, the uppercase letter "I" is used rather than the lowercase "i". Therefore, the complex number with the real part equal to 2 and imaginary part equal to 3 is entered, naturally, as follows.
2 + 3*I;
2+3⁢I
In general, a complex number has the form
re + im * I
where re and im are the real and imaginary parts of the complex number, respectively. If the expressions re and im are of type extended_numeric; the resulting complex number will be of type complex( extended_numeric ). (It is not necessary that re and im are reals; they may be arbitrary algebraic expressions. However, in this case, the result of the syntax above will generally be an algebraic expression that will not be a complex numeric constant.)
You can also create complex numbers using the Complex constructor. It can be called using either one or two arguments. The single-argument form has the following syntax.
Complex( expr )
If the argument expr is of type complex, the Complex constructor returns the value of expr. Otherwise, if expr is of type extended_numeric, the Complex constructor returns expr * I.
Complex( 2 ), Complex( 0 ), Complex( 0.0 );
2⁢I,0,0.⁢I
Complex( 2 + 3*I ), Complex( infinity ), Complex( undefined );
2+3⁢I,∞⁢I,undefined⁢I
The two-argument form has the following syntax.
Complex( re, im )
The first argument is interpreted as the real part and the second argument is interpreted as the imaginary part, of the complex number constructed.
Complex( 2, 3 ), Complex( 2.1, 3 ), Complex( 0, 0 );
2+3⁢I,2.1+3.⁢I,0
Note that if either of the arguments is a float, the real and imaginary parts of the complex number created are both of type float.
A complex zero with floating-point real and imaginary components can have four sign combinations.
z1 := 0.0 + 0.0*I; z2 := 0.0 - 0.0*I; z3 := -0.0 - 0.0*I; z4 := -0.0 + 0.0*I;
z1≔0.+0.⁢I
z2≔0.−0.⁢I
z3≔−0.−0.⁢I
z4≔−0.+0.⁢I
Similar to 0.0 = -0.0, numerically, these four complex zeros are numerically equivalent.
evalb( z1 = z2 and z2 = z3 and z3 = z4 );
If the arguments re and im are not of type extended_numeric, the Complex constructor is returned unevaluated.
Complex( u, v );
Complex⁡u,v
Except if one of the arguments is complex, in which case, an exception is raised.
Complex( 2 + 3*I, 1 );
Error, invalid arguments for Complex constructor
It is important to understand that there is a single complex infinity, which is a point on the Riemann sphere. It can be denoted in different ways:
inf1 := infinity + infinity * I; inf2 := infinity - infinity * I; inf3 := -infinity - infinity * I; inf4 := -infinity + infinity * I;
inf1≔∞+∞⁢I
inf2≔∞−∞⁢I
inf3≔−∞−∞⁢I
inf4≔−∞+∞⁢I
However, all of these forms are numerically equivalent.
evalb( inf1 = inf2 and inf2 = inf3 and inf3 = inf4 );
They are all treated as distinct from the positive and negative real infinities.
To select the real or imaginary part of a complex number, use the Re and Im commands, respectively.
Re( 2.3 + sqrt(2)*I );
Im( 2.3 + sqrt(2)*I );
Note that, for a symbolic expression of the form a + b*I, it is not assumed that a is the real part and b is the imaginary part. Therefore, the Re and Im commands are not unevaluated on such input.
Re( a + b*I );
ℜ⁡a−ℑ⁡b
Im( a + b*I );
ℑ⁡a+ℜ⁡b
However, the evalc command uses special rules for processing complex expressions, in which any unknown symbol is assumed to be real. Therefore, when the evalc is used, these expressions are returned as follows.
evalc( Re( a + b*I ) );
evalc( Im( a + b*I ) );
For more information, refer to the evalc help page.
You can change the default name used to input and display the imaginary unit by using the interface command.
interface( 'imaginaryunit' = i );
(The previous value is returned.) After calling the command above, the name i is used to represent the imaginary unit.
Complex( 2, 3 );
2+3⁢ⅈ
When this command is used, the name i can no longer be used as a program variable. As an example, the following statements display error messages.
i := 2;
Error, illegal use of an object as a name
add( i^2, i = 1 .. 5 );
To restore the default imaginary unit, use the following command.
interface( 'imaginaryunit' = I );
i
3.6 Indexed Expressions
Indexed expressions represent selection operations. The general form of an indexed expression is
expr [ index ]
where expr is an arbitrary expression and index represents a sequence of expressions. The following are examples of indexed expressions.
2[ 3, 4 ];
23,4
a[];
a[ 1 ];
a1
a[ b ];
ab
a[ b, c ];
ab,c
map[ 2 ];
map2
[ 1, 2, 3 ][ 2 ..3 ][ 1 ];
Note that the last example above contains a nested (or iterated) indexed expression.
The constructor for indexed expressions is the name ?[].
`?[]`( S, [ a, b, c ] );
Sa,b,c
Note that the indices must be enclosed with square brackets in a list.
All or some of the elements of an index sequence can be extracted by using the op command. The nops command will tell you how many elements are in the index sequence.
nops( a[ b, c, d ] );
op( a[ b, c, d] );
b,c,d
op( 2, a[ b, c, d ] );
c
op( 2..3, a[ b, c, d ] );
c,d
Indexed expressions are often used to perform selection operations. The behavior of a selection operation depends on the type of expression, expr, and the index sequence given.
If expr is itself a sequence of expressions, the index sequence must evaluate to a positive integer, an integral range, or the empty sequence. The following are all examples of valid ways to index a sequence.
expr := (1,2,3,4);
expr≔1,2,3,4
expr[ 3 ];
expr[ 1 .. 3 ];
1,2,3
expr[];
1,2,3,4
expr[ 2 .. 1 ];
The result of evaluating an indexed sequence is a selection of the components of the sequence. The indexing sequence must represent a valid index or range of indices. Attempting to select an entry beyond the length of the sequence and will raise an error.
expr[ 88 ];
Error, invalid subscript selector
Similarly, components of lists, sets, arrays, matrices, and vectors can be selected
L := [1,2,3,4];
L≔1,2,3,4
L[ 3 ];
L[ 1 .. 3 ];
L[];
M := <1,2,3;4,5,6>;
M≔
M[2,3];
6
M[1..2,1..2];
S := { red, blue, green, orange };
S≔blue,green,orange,red
S[ 3 ];
orange
Note that, because sets are sorted data structures, the order at construction time may not match the order stored internally. It is not predictable what color will be returned by the index used to specify the third entry above. (It may not be green.)
A negative number may be used as an index, which selects elements starting from the end of the list. Positive and negative indices mixed in a range return an empty selection.
L[ -1 ];
4
L[ -3 .. -2 ];
2,3
L[ -3 .. 1 ];
Lists can be used as an index to pick out specific entries, such as the first and third entries of a list, or the four corners of a matrix.
L[ [1,3] ];
1,3
M[[1,2],[1,3]];
Indexing on arrays, matrices and vectors is very flexible. In the case of these data structures, round-brackets can also be used to index in a way that is useful to programming. For example, where M[1] will return the first row of the matrix, M(1) will return the first entry (regardless of the number of dimensions).
M[1];
M(1);
This class of data structures are known as rectangular tables, or "rtables" for short. For more information on what ways they can be indexed, refer to the rtable_indexing help page.
If expr is a name with no assigned value, the result of evaluating the indexed expression is an indexed name. In this case, the index can be any sequence of expressions, and if desired, it is up to your program to define the meaning of the expression.
aName[ x^2 - 3*x, "a string", anotherName[ 2, b ] ];
aNamex2−3⁢x,a string,anotherName2,b
A string may be indexed by a positive integer, a positive integral range, or a general sequence. The indexed string expression evaluates to itself, unless the indexing sequence is an integer or integral range, in which case, the result is a substring of the indexed string.
"abcde"[ 3 ];
"abcde"[ 2 .. 4 ];
bcd
"abcde"[ u, v^2 - s*t ];
abcdeu,−s⁢t+v2
"abcde"[];
abcde
If expr evaluates to a table, and if the index given is found in the table the expression evaluates to the corresponding entry. Otherwise, the indexed expression evaluates to itself.
t := table( [ a = 1, b = 2, (c,d) = 3 ] );
t≔table⁡c,d=3,a=1,b=2
t[ a ];
t[ c, d ];
t[ u, v ];
tu,v
If expr evaluates to a module, the index must evaluate to the name of an export of the module, and then the entire indexed expression evaluates to the value of expr:-index.
m := module() export e, f := 2; end module:
m[ e ];
e
evalb( e = m[ e ] );
m[ f ];
For more information about modules, see Programming with Modules.
3.7 Member Selection
The member selection operator :- is used to select exports of a module, and also to designate a symbol as a global symbol. Member selection expressions have one of the following general forms.
modexpr :- expname
:- name
The first form above is used to select a member of a module.
m := module() export e, f:= 2; end module:
m:-e;
evalb( e = m:-e );
m:-f;
The first operand, modexpr, must evaluate to a module. The second operand, expname, must be a literal name; it is not evaluated. If expname is not a name, or is not the name of an export of the module modexpr, an exception is raised. The syntax m:-e is similar to m[e], in that they both evaluate module m's export e. The difference is that the index selection form will evaluate e before resolving the export.
In the second form, the operand name must be a literal name. The expression :-name then evaluates to the global instance of the name name.
The following example defines, and then immediately calls, a procedure which declares a local variable t. Since this local variable is never assigned, it evaluates to itself. The call to the evalb command then compares, on the left-hand side of the equation, the local name t to the global name t resulting from applying the member selection operator to t. The result is false because the global name t and the name t local to the procedure are different expressions.
proc() local t; evalb( t = :-t ) end proc();
For more information on modules and member selection, see Programming with Modules.
3.8 Functions
A function expression is a Maple expression of the form
expr( sequence )
that contains zero or more expressions in the sequence within the parentheses. It represents a function call.
F();
F⁡
F( x );
F⁡x
F( x, y );
F⁡x,y
sin( x + y );
sin⁡x+y
Typically, expr is the name of a procedure or mathematical function. It can be a general expression.
The zeroth operand of a function expression is expr.
op( 0, F( x, y, z ) );
F
The other operands are the arguments,
op( F( x, y, z ) );
x,y,z
and the number of operands is the number of arguments.
nops( F( x, y, z ) );
nops( F() );
Maple supports an algebra of operators, so that complicated expressions such as
(f^2 + g@h - 2)( x );
f⁡x2+g⁡h⁡x−2
can be formed. Note that Maple applies such "operator expressions" to the arguments. @ is the composition operator. For more information on composition of functions, see Composition.
It is important to know that Maple computes numeric quantities as applicable operators with constant values. Therefore, for example, the expression
2( x );
is computed as an application of the constant operator 2 to the argument x, which evaluates to 2. In fact, numeric "operators" can accept any number of arguments.
2( x, y, 3 );
Note that an expression such as
'2( 3 )';
2⁡3
(in which unevaluation quotes are used to delay the evaluation process) appears to be a product. However, this expression is, in fact, a function expression. When permitted to evaluate fully, the result is the constant value of the operator.
2( 3 );
Calls to Procedures
The most important kind of function expression to understand is the case in which the zeroth operands is a procedure or, more commonly, an expression (typically, as a name) that evaluates to a procedure.
p( arg1, arg2, ..., argN )
In this case, p is a procedure or an expression, such as a name, that evaluates to a procedure, and arg1, arg2, ..., argN are zero or more argument expressions.
For example, the name sin evaluates to a procedure that computes the mathematical sin function. A function expression of the form
sin( expr )
computes the sin of its argument expr. This is performed as follows: Maple evaluates the name sin and finds that it is assigned a procedure. The argument expr is evaluated to produce a result. That result is then passed to the procedure assigned to the name sin and the result computed by that procedure for the specific input is returned as the overall value of the function call sin( expr ).
For information on defining functions and procedures, see Functional Operators and Procedures.
3.9 Arithmetic Expressions
Arithmetic Operators
The arithmetic operators in Maple include + (addition), - (subtraction), * (multiplication), / (division), and ^ (exponentiation). These operators are used to create rational expressions, such as polynomials.
x^2 - 3*x + 1;
x2−3⁢x+1
Addition and Subtraction
The addition operator `+` and the subtraction operator `-` are typically used as binary infix operators, but may also be used as unary prefix operators to indicate a signed expression.
a + b + 3;
a+b+3
u - v;
u−v
+7;
7
A sum resulting from the evaluation of either an addition or subtraction operation is an expression of type `+`.
type( u - v, '`+`' );
The expression u-v has the operands u and -v; that is, it is a sum of the summands u and -v.
op( u - v );
u,−v
Note that subtraction is not an associative operator.
( 1 - 2 ) - 3 <> 1 - ( 2 - 3 );
−4≠2
However, addition is both associative and commutative:
b + a + c = a + b + c;
b+a+c=b+a+c
Although sums are formed by using the binary operator `+`, they are actually expressions of arbitrarily large arity (greater than unity). Since addition is associative, Maple "flattens" all sums of more than two summands during the automatic simplification process. Therefore, an expression of type `+` can have many operands.
nops( a + b + c + d + e );
You can use the name `+` as a constructor to form a sum.
`+`( a, b, c );
b+a+c
Since Maple performs automatic simplification, the number of operands of a sum may not be apparent from the input.
nops( a + 2 + b + 3 + c + 4 );
In this example, Maple combines the integer terms in the sum.
a + 2 + b + 3 + c + 4;
a+9+b+c
To see that this occurs during the automatic simplification process, enclose the input in unevaluation quotes to delay evaluation.
'a + 2 + b + 3 + c + 4';
In a sum such as
'2 + 3';
the addition is performed, as indicated, during the automatic simplification process. The same sum can be computed in another way:
u := 3:
'2 + u';
2+u
In this example, the arithmetic is not performed because the value of the variable u does not replace the name u during the automatic simplification process. If the unevaluation quotes are removed to allow the full evaluation of the expression, numeric addition is performed.
2 + u;
Since addition is commutative, the order of summands in an expression of type `+` is arbitrary. It is fixed within a Maple session, but may vary from one session to another. Therefore, you must not rely on the operands of a sum occurring in any specific order.
Operands of a sum are automatically simplified, recursively.
'2/3 + sin( 5*Pi/6 - 2*Pi/3 )';
23+sin⁡π6
Since procedures are not called during the automatic simplification process, the example above does not fully simplify to the result
2/3 + sin( 5*Pi/6 - 2*Pi/3 );
76
during the automatic simplification process. However, the argument to the sin command is computed to the simpler form 16⁢π, just as it would if it had been entered by itself.
'5*Pi/6 - 2*Pi/3';
π6
If any numeric literal in a sum is a float, all the numeric operands are converted to floats and their sum is computed as a float. For more information, see Floating-Point Contagion.
'a + 2 + b + 3.7 + c + Pi';
a+8.841592654+b+c
Arithmetic computed during the automatic simplification process includes arithmetic with values of infinity, undefined values, and signed (floating-point) zeroes.
'2.3 + undefined';
Float⁡undefined
'2.3 + infinity';
Float⁡∞
'-0.0 + 0';
−0.
'infinity - infinity';
'infinity - Float(infinity)';
Sums of non-algebraic summands can be formed. A sum of lists of the same length returns the corresponding list of sums. This occurs during the automatic simplification process.
'[ a, b, c ] + [ x, y, z ]';
x+a,y+b,z+c
Sums of arrays, matrices, and vectors occur during the regular evaluation process.
<1,2;3,4> + <5,6;7,8>;
Attempting to add lists or matrices of different sizes results in an error.
[ 1, 2 ] + [ 1, 2, 3 ];
Error, adding lists of different length
<1,2;3,4> + <1,2>;
Error, (in rtable/Sum) invalid input: dimensions do not match: Matrix(1 .. 2,1 .. 2) cannot be added to Vector[column](1 .. 2)
Since the addition of sets (which are not ordered) is not well-defined, a sum formed with a set is returned unevaluated.
{ 1, 2 } + { 3, 4 }; { 1, 2 } + [ 3, 4 ];
1,2+3,4
Multiplication and Division
Products are formed by using the `*` and `/` operators. The result of evaluating either a multiplication or division operation is an expression of type `*`.
type( a * b, '`*`' ); type( a / b, '`*`' );
You can use the dismantle command to print a representation of the internal structure of any Maple expression.
dismantle( a / b );
PROD(5) NAME(4): a INTPOS(2): 1 NAME(4): b INTNEG(2): -1
The output shows that the quotient is actually stored as a product of two factors: one consisting of the expression a with a power of 1 and the other consisting of the expression b with a power of −1: a⁡1⁢b⁡−1.
Similar to sums, products are commutative and associative. Also, products are flattened due to associativity, even though the `*` operator is binary. Automatic simplification is applied to products, so as with sums, numeric factors are automatically combined.
'2 * 3 * x * y';
6⁢x⁢y
Also like sums, the order of factors in an expression of type `*` is arbitrary, and may vary between Maple sessions.
'y * x * 3 * 2';
The number of operands reflects the number of factors remaining after automatic simplification has taken place.
nops( 2 * 3 * x * y );
op( 2 * 3 * x * y );
6,x,y
The name `*` can be used as a constructor to form products.
`*`( a, b, c );
a⁢b⁢c
If any numeric constant in a product is a float, the result of gathering all of the constants into a single factor is a float.
'3.1 * a / 2 / b * 4';
6.200000000⁢ab
'2.3 * ( 5*Pi/6 - 2*Pi/3 )';
1.204277184
This effect does not extend into function calls.
'2.3 * sin( 5*Pi/6 - 2*Pi/3 )';
2.3⁢sin⁡π6
You can multiply a list by a number and the product is applied to all of the list elements during the automatic simplification process.
'2 * [ 2, 3 ]';
4,6
Matrix multiplication is done with the `.` operator rather than `*`. Division is not defined for matrices.
<1,2;3,4> . <5,6;7,8>;
<1,2;3,4> . LinearAlgebra:-MatrixInverse( <5,6;7,8>);
Multiplying or dividing two arrays of the same size will perform paired element-wise operations on the individual entries. The element-wise operators *~ and /~ can be used on both arrays and matrices to achieve the same result.
Array([[1,2],[3,4]]) * Array([[5,6],[7,8]]);
Array([[1,2],[3,4]]) / Array([[5,6],[7,8]]);
<1,2;3,4> /~ <5,6;7,8>;
<1,2;3,4> *~ <5,6;7,8>;
For more information on element-wise operators, see Programming-Language Operators.
Exponentiation
Powers are formed by using the `^` operator.
a^b;
It is strictly a binary operator; nested powers must be written with parentheses.
(a^b)^c;
abc
a^(b^c);
The following input results in a syntax error.
a^b^c;
Error, ambiguous use of `^`, please use parentheses
Rational number powers are used to represent roots. Exact roots are left uncomputed, while floating-point roots are computed during the automatic simplification process.
4^(1/2);
'(2.1)^(1/3)';
1.280579165
Expressions to a power of 0 are reduced to unity during the automatic simplification process. The type of the resulting 1 depends on the type of the zero power, unless the base of the expression is a float, in which case the result is a float.
'a ^ 0';
'a ^ 0.0';
1.0
'(x^2 - 1 + 3)^0';
There are some exceptions when infinity and undefined values are raised to a float zero power.
'Float( undefined ) ^ 0.0';
'Float( infinity ) ^ 0.0';
'Float( -infinity ) ^ (-0.0)';
Note the distinction between Float( -infinity ) ^ (-0.0) and -Float( infinity ) ^ (-0.0): the latter is first automatically simplified to - Float(undefined) and then to Float(undefined).
In Maple, the indeterminate form 0^0 with an exact base is interpreted as 1.
0^0;
0.0 ^ 0;
1.
0 ^ 0.0;
Although a complex floating-point zero does not automatically simplify to a real zero, expressions raised to a complex zero are simplified automatically to an exact or floating-point unity.
a^(0.0 + 0.0*I);
Powering of matrices is done in the mathematical sense achieving repeated matrix products. Powering of arrays is done element-wise.
<1,2;3,4> ^3;
Array([[1,2],[3,4]]) ^3;
Rational Expressions
Using sums and products, more complicated expressions can be formed.
expr := ( a + a*b ) / ( a*b - b );
expr≔a⁢b+aa⁢b−b
Conceptually, Maple creates the following structure.
Figure 3.1: expr DAG
Here, expr is a product of two operands
nops( expr );
op( expr );
a⁢b+a,1a⁢b−b
and each operand is itself an expression with two operands.
e1, e2 := op( expr );
e1,e2≔a⁢b+a,1a⁢b−b
nops( e1 ); nops( e2 );
Maple does not automatically simplify the following expression. To perform such simplifications, use the normal command.
expr := (x - 1)/(x^2 - 1);
expr≔x−1x2−1
normal( expr );
1x+1
The normal command only performs normalization of rational expressions with rational coefficients.
expr := ( (sin(t)^2 + cos(t)^2)*(x - 1)/(x^2 - 1));
expr≔sin⁡t2+cos⁡t2⁢x−1x2−1
sin⁡t2+cos⁡t2x+1
Note: Use the simplify command to apply more powerful simplifications.
Maple also does not automatically expand the products of sums.
(a + b) * (c + d);
a+b⁢c+d
Use the expand command (or the normal command, with the expanded option) to perform such expansions.
expr := (a + b) * (c + d);
expr≔a+b⁢c+d
expand( expr );
a⁢c+a⁢d+b⁢c+b⁢d
normal( expr, 'expanded' );
Similarly, you must use the normal command to simplify the following rational expression.
expr2 := expand( expr ) / (a + b);
expr2≔a⁢c+a⁢d+b⁢c+b⁢da+b
normal( expr2 );
c+d
Noncommutative Multiplication
Noncommutative multiplication is represented by the dot operator (.), which is used mainly in linear algebra computations for multiplication of matrices and vectors. It may also be used to represent the noncommutative product of other types of mathematical expressions.
A . B;
If A and B are of type constant, then A . B = A * B during the evaluation process (but not during the automatic simplification process). However, if one of A and B is a Matrix or a Vector, and the other is a Matrix, Vector, or constant, the product is interpreted as a matrix or vector product. If A or B is an Array (and the other is not a Matrix or Vector), then A . B is interpreted as element-wise multiplication. For arguments that are not of type Matrix, Vector, or constant, A . B remains unevaluated, but more importantly, it is not automatically simplified to or interpreted as being equal to B . A.
7 . 6;
'7 . 6';
7·6
A.B <> B.A;
A·B≠B·A
M:=<<1,0,2>|<0,1,2>|<0,0,2>>;
V:=<10,0,0>;
V≔
M . V;
lambda . M . V;
λ·
A := Array([[1,2],[3,4]]);
A≔
B := Array([[a,b,c],[d,e,f]]);
3 . B;
The dot character has three meanings in Maple:
as a decimal point in a floating-point number (for example, 2.3),
as part of a range (for example, x..y), or
as the noncommutative multiplication operator. To distinguish between these three cases, Maple uses the following rule: any dot with spaces before and/or after it that is not part of a number is interpreted as the noncommutative multiplication operator.
For example, 2.3 is a number, 2 . 3 and 2 .3 return 6, and 2. 3 displays an error.
2.3, 2 . 3, 2 .3;
2.3,6,6
2. 3;
Factorials
The unary, postfix factorial operator ! is used to represent the mathematical factorial operation.
5!;
120
Maple can compute large factorials quickly.
length( 1000000! );
5565709
If the argument of the ! operator is symbolic, it is returned unevaluated.
(a + b)!;
a+b!
The argument of the ! operator is subject to automatic simplification, but factorials are not computed during the automatic simplification process.
'(2+3)!';
5!
If the argument of the ! operator is a float, the expression is computed using the GAMMA function.
2.3! = GAMMA( 3.3 );
2.683437382=2.683437382
If the argument is a non-negative integer, Maple computes the factorial. If the argument is a negative integer, a numeric event is triggered.
(-3)!;
Error, numeric exception: division by zero
However, if the argument is a negative integer float, the complex number Float(-infinity) - Float(infinity)*I is returned.
(-3.0)!;
Float⁡-∞−Float⁡∞⁢I
For other arguments, the factorial operator is returned unevaluated after first evaluating its argument.
sin( Pi / 6 )!;
12!
The command factorial is the same as the ! operator.
factorial( 5 );
Forming Sums and Products
Since creating structures within loops may be inefficient, Maple provides commands for creating sums and products efficiently.
add( expression, i=m .. n);
mul( expression, i=m .. n);
where i is a name, m and n are numeric values, and expression is an expression that depends on i.
The add command is semantically equivalent to the following loop:
S := 0; old := i; for i from m to n do S := S+expression; end do; i := old; S; # the result
The add command is more efficient since it does not build each of the many intermediate sums. The semantics of mul are similar with the exception that if n<m, the result is 1, rather than 0.
mul(a+i, i=1..4);
a+1⁢a+2⁢a+3⁢a+4
add(a||i, i=0..3);
a0+a1+a2+a3
In the loop example shown above, each of the expressions a0, a0+a1, and a0+a1+a2 are constructed, stored in memory, and then removed by the garbage collector. That overhead is part of what makes the loop less efficient than the add command in this case.
For more information on the add and mul commands, refer to the add help page. For more information on the concatenation operator, ||, see The Concatenation Operator.
Note: The add and mul commands differ from sum and product in that the former are straightforward construction commands while the latter are commands for computing closed forms for symbolic sums and products.
3.10 Boolean and Relational Expressions
Boolean Constants
The Boolean constants in Maple are the names true, false and FAIL. These are otherwise ordinary names, but have a special meaning in a Boolean context.
When you call the Boolean evaluator evalb, the expression passed as its argument is interpreted as a Boolean-valued expression if possible, and evaluated as such.
FAIL is used to mean an unknown or undetermined value. For more information on the constant FAIL, refer to the FAIL help page.
Boolean Operators
Maple supports several operators for the Boolean combination of expressions: not, and, or, xor, and implies.
The not Operator
The not operator represents logical negation. It has the following general syntax.
not expr
When applied to a Boolean-valued expression, it returns a value according to the following table.
expr
not true;
not false;
not FAIL;
The and Operator
The and operator represents logical conjunction. It is a binary operator of the form
expr1 and expr2
If both operands evaluate to a truth value, the entire expression is evaluated according to the following truth table.
expr1
expr2
If a truth value cannot be determined, the expression is returned unevaluated.
x and y;
xandy
However, some automatic simplifications are applied to and expressions.
true and x;
x
The or Operator
The or operator represents logical disjunction. It is a binary operator of the form
expr1 or expr2
x or y;
xory
However, some automatic simplifications are applied to or expressions.
false or x;
The xor Operator
The xor operator represents logical exclusive disjunction. It is a binary operator of the form
expr1 xor expr2
If both of its operands evaluate to truth values, the entire expression is evaluated according to the following truth table.
The implies Operator
The implies operator represents logical implication. It is a binary operator of the form
expr1 implies expr2
x implies y;
x⇒y
Some automatic simplifications are applied to implies expressions.
false implies x;
x implies true;
Relational Operators
Relational operators are used to form comparisons to be evaluated in a Boolean context. The relational operators in Maple are =, <>, <, <=, and in. Each is a binary operator that accepts two operands. When evaluated in a Boolean context, each of these operators determines whether its two operands have a certain relationship.
An equation is formed by using the = operator.
x = y;
x=y
This has the general form
expr1 = expr2
It represents an equation with expr1 as the left-hand side and expr2 as the right-hand side. When evaluated in a Boolean context, it returns a value of true if its operands are equal, and returns a value of false otherwise.
evalb( 1 = 2 );
evalb( 2 = 2 );
Note that comparing distinct unassigned names returns a value of false.
evalb( x = y );
The names x and y are distinct and unequal names in Maple and, when they are unassigned, they are considered different expressions in a Boolean comparison. If the names x and y have assigned values, those values are first substituted into the comparison, and the equality computation is performed on the assigned values, rather than the names themselves.
In general, expressions are compared for equality according to their memory address. That is, two expressions are considered equal in a Boolean context if they have the same address in memory. However, for certain expressions, a more mathematical test for equality is used. For example, the floating-point numbers 2.0000 and 2.0 are considered numerically equal, even though they are distinct objects in memory.
evalb( 2.0000 = 2.0 );
addressof( 2.0000 );
36893628422603897532
addressof( 2.0 );
36893628422603897564
In fact, when the floating-point number 2.0 is compared to the integer 2, they are considered equal.
evalb( 2.0 = 2 );
Determining whether two procedures are semantically equivalent is an undecidable problem in Computer Science. However, procedures which are detectably equivalent by simple transformations are considered to be equal. For example, it is clear that the name of a procedure parameter is not normally important, so the following two simple procedures are considered equal, although they are distinct expressions in memory.
evalb( proc(x) 2*x end proc = proc(y) 2*y end proc );
An inequation can be formed by using the <> operator. The general form is
expr1 <> expr2
This expression represents non-equality and returns a value of true if its operands are unequal, and false if its operands are equal.
x <> y;
x≠y
evalb( 1 <> 2 );
evalb( 2 <> 2 );
Testing for inequality is performed similarly to testing for equality. Comparing two distinct unassigned names using the <> operator computes the equality of the names. The expression
evalb( x <> y );
returns a value of true because the names x and y are distinct as names.
A strict inequality is created by using the < operator. This has the general form
expr1 < expr2
and can also be constructed using the form
expr1 > expr2
x < y;
x<y
You can also use the > operator.
y > x;
Maple automatically converts this to the same expression as results from the first form.
When evaluated in a Boolean context, Maple performs the indicated mathematical comparison, or returns the inequality as unevaluated if the operands do not evaluate to comparable expressions. If the operands are comparable, the inequality evaluates to the value true if the first operand is less than, but not equal to, the second operand, and evaluates to false otherwise. If the operands are not comparable, the inequality evaluates to itself.
A non-strict inequality is formed using the <= operator. This has the general form
expr1 <= expr2
It can also be constructed using the form
expr1 >= expr2
x <= y;
x≤y
When evaluated in a Boolean context, and when the operands are comparable, it returns a value of either true or false according to whether the first operand is less than, or equal to, the second operand.
Membership is represented by the in operator. It is used in the general form
expr1 in expr2
When evaluated in a Boolean context, it evaluates to the value true if its first operand expr1 is a member of its second operand expr2. If expr1 does not belong to expr2, the expression evaluates to false. Maple can determine a truth value if the second operand expr2 is a container object; that is, either a set or list, or an unevaluated function call of the form SetOf( T ), where T is a Maple type. An expression of the form
expr in SetOf( T )
where T is a Maple type is equivalent to the expression type( expr, T ).
evalb( 1 in { 1, 2, 3 } );
evalb( 5 in { 1, 2, 3 } );
evalb( x in X );
x∈X
evalb( 2 in SetOf( integer ) );
evalb( 2/3 in SetOf( integer ) );
Note the simplification applied to the statement with the evalb command in the following example.
x in A union B;
x∈A∪B
evalb( x in A union B );
x∈Aorx∈B
If the second operand is not an explicit container object, the expression remains an unevaluated in expression. However, some automatic simplifications may be applied.
Efficient Boolean Iteration
In the same way the commands add and mul can be used to efficiently form + and * expressions, conjunctions and disjunctions can be evaluated efficiently using the andmap and ormap commands, which are similar to the map command described in Maple Statements.
andmap( procedure, expression, ... )
ormap( procedure, expression, ... )
The following example considers type(element,name) for each element of the list. ormap determines whether this statement is true for at least one element of the list. andmap determines whether this statement is true for all the elements of the list.
ormap(type, [1, "a", `a`, a()], name);
andmap(type, [1, "a", `a`, a()], name);
The main difference between these commands and map is that andmap and ormap have short-circuit ("McCarthy") semantics, which means that an answer is returned as soon as it can be determined.
andmap(proc(x) print(x); x<2 end proc, [1,2,3,4]);
3.11 Expressions for Data Structures
This section describes basic concepts related to data structure expressions. For more information on programming with data structures, see Basic Data Structures.
Sequences
The most basic aggregate expression type in Maple is the sequence. Sequences are formed by using the `,` (comma) operator.
a, 2/3, sin( x ), 5.1;
a,23,sin⁡x,5.1
A sequence consists of zero or more other expressions, called elements or members. A sequence with exactly one member is automatically simplified to its unique member. The empty sequence, containing zero members, is the value of the name NULL, and may be written as ().
evalb( () = NULL );
Sequences occur in many other data structures as a (principal) component, within which they acquire additional semantics. Some examples include lists, sets, and function calls.
Automatic simplification of sequences is affected by recursively simplifying the component expressions.
'2 + 3, 1 - 7, 0^0, sin( Pi / 6 )';
5,−6,1,sin⁡π6
Nested sequences are also flattened during the automatic simplification process.
'( 1, 2 ), 3, ( 4, 5 )';
1,2,3,4,5
Because sequences are used to pass multiple arguments to procedures, it is not normally possible to operate on a sequence as such (the list type described below is designed for exactly for that reason). For example, you cannot pass a (nontrivial) sequence to the type command to check its type. Therefore, there is no Maple type for sequences. However, the whattype command returns the name exprseq when it is passed either zero or more than one argument.
whattype();
exprseq
whattype( 1, 2 );
Note that the name exprseq is not the name of any valid type in Maple.
Similarly, you cannot query the zeroth operand of a sequence. For example, the following results in an error.
op( 0, ( 1, 2, 3 ) );
Error, invalid input: op expects 1 or 2 arguments, but received 4
This is because the sequence 0, ( 1, 2, 3 ) is flattened to the sequence 0, 1, 2, 3 during automatic simplification of the function call before the op command is actually called. Therefore, the op command is passed four arguments instead of only the two that are apparently intended.
There is no constructor for sequences, but there is a built-in command for creating sequences, called seq. The basic syntax of seq is below. It accepts many other types of arguments as well.
seq(expression, i = integer1..integer2)
seq( i^2, i = 1 .. 5 );
1,4,9,16,25
seq( 2 .. 14 );
2,3,4,5,6,7,8,9,10,11,12,13,14
seq( i, i = 0.4 .. 1.1, 0.3 );
0.4,0.7,1.0
For more information on the seq command, refer to the seq help page.
Another way to create sequences is to use the dollar sign ($) operator.
expression $ i = integer1 .. integer2
i^2 $ i = 1 .. 5;
The dollar sign operator is a binary operator that performs a similar function to the seq command, but behaves slightly differently: the $ operator evaluates the expression argument once before any substitutions, while the command does not evaluate until after each substitution of i.
cat(a,x) $ x= 1..2;
ax,ax
seq(cat(a,x), x= 1..2);
a1,a2
In general, it is recommended that you use the seq command instead of the dollar sign operator.
Lists
Lists are created by enclosing a sequence of expressions between square brackets. Lists are essentially sequences, which are designated as a single unit for other operations.
[ sequence ]
[ 1, 2, 3 ];
Unlike sequences, lists can form properly nested structures.
[ 1, 2, [ 3, 4 ] ];
Use the numelems command to determine the number of members in the enclosed sequence. Note that lists can contain sublists. These are still counted as a single entry.
numelems( [ 1, 2, 3 ] );
numelems( [ 1, 2, [ 3, 4 ] ] );
To access the i-th operand of a list, use an index to the list expression.
L := [ a, b, c, d ];
L≔a,b,c,d
To access the sequence of all elements in a list, use the op command. Converting back and forth between lists and sequences can be a common operation, and is very efficient.
Lseq := op(L);
Lseq≔a,b,c,d
L2 := [ op(L), op(L) ];
L2≔a,b,c,d,a,b,c,d
It is common to create a list by using the seq command to create the enclosed sequence.
[ seq( i^2, i = 1 .. 5 ) ];
Lists are ordered; two lists with the same members in a different order are distinct.
evalb( [ 1, 2, 3 ] = [ 2, 1, 3 ] );
Lists are immutable; you cannot change the elements of a list once it has been created. You can, however, create a new list using members of an existing list or lists.
In the next example, we create a new list with second entry d.
L := [ a, b, c ];
L≔a,b,c
L2 := [ L[ 1 ], d, L[ 3 ] ];
L2≔a,d,c
You can also use the subsop command for this purpose.
L3 := subsop( 2 = d, L );
L3≔a,d,c
evalb( L2 = L3 );
The example above creates a new list using the original list L by substituting its second operand for the expression d. If you need to change elements frequently it is usually better to use an array. Arrays can be changed in-place avoiding the need for a copy. For more information on the subsop command, refer to the subsop help page.
For more information about lists, see Lists.
Sets
Sets, similar to lists, are created from a sequence of expressions. However, sets use braces ({}) to enclose the sequence.
{ sequence }
{3, 2, 1};
In addition to the syntactical differences, sets differ from lists in that they are unordered and do not have duplicate entries. These two properties are enforced during the automatic simplification process.
'{3, -1, 0}';
−1,0,3
'{1, 1, 1, 1}';
Note that the sets' ordering in the output may not match the input sets' ordering.
In Maple 11 and earlier, the ordering of sets was unpredictable as it was based on the positions of the elements in memory. In Maple 12 and later, set ordering is deterministic, session independent, and based on properties of the contents. This just means that the same set will now appear in the same order even after restarting Maple. For more information on the ordering of sets, refer to the set help page.
For more information on how to use sets in programming, see Sets. More information on Maple expressions related to sets will be described later in this chapter.
Tables
Tables are mutable data structures that associate an index with an entry. Both the index and entry can be arbitrary expressions. The underlying structure is sparse (a hash table), and expands as more entries are inserted.
T := table();
T≔table⁡
T[color] := "red";
Tcolor≔red
T[color];
red
T[1,2,3] := x^2+4;
T1,2,3≔x2+4
Assigning values to indexed names is further described in Indexed Expressions.
Tables can be initially populated by providing a list of equations as an argument to the table constructor.
T := table([a=1, b=2, c=3, d=4]);
T≔table⁡d=4,a=1,b=2,c=3
T[a] + T[c];
For names with tables assigned to them, last name evaluation rules apply. Last name evaluation is explained in more detail in Evaluation Rules for Tables. The most visible effect of last name evaluation is that the name of the table is displayed by default rather than all of its entries.
T;
T
eval(T);
table⁡d=4,a=1,b=2,c=3
Rectangular Tables
Rectangular tables, or rtables, are mutable data structures that associate a numeric index sequence with an arbitrary entry. The bounds of the index are predefined and directly correspond to the amount of memory reserved to hold entries.
The same rtable data structure is used to implement arrays, matrices, and vectors.
A := Array(0..5,i->2*i);
A[0];
A[5];
V := Vector([1,2,3]);
V[1];
M := Matrix(3,3,shape=identity);
M[2,2];
Rectangular tables are very flexible and offer a rich set of features. For a more in-depth discussion of them, see Arrays.
3.12 Set-Theoretic Expressions
Maple includes a full set of set-theoretic operators for membership relation, set inclusion, and other operations.
Membership
In Maple, the set membership relation is expressed by using the in operator. It has the following syntax.
a in b
where a and b can be arbitrary expressions.
Normally, a membership expression is returned unevaluated.
a in b;
a∈b
1 in { 1, 2, 3 };
1∈1,2,3
However, when evaluated in a Boolean context, one of the values true and false is returned if the expression b evaluates to a set or list and Maple can determine whether the expression a belongs to the expression b. For more information on Boolean evaluation of membership expressions, see Boolean and Relational Expressions.
Use the rhs and lhs commands to extract the right or left hand side of the an in operator.
lhs( a in b );
rhs( a in b );
Set Inclusion
Set inclusion (the subset relation) is represented in Maple by the binary subset operator. It has the following syntax.
a subset b
where a and b are arbitrary expressions that can evaluate to sets.
a subset b;
a⊆b
{ 1, 2 } subset {2, 3, 5 };
{} subset T;
T subset {};
T⊆∅
If Maple can determine whether the expressed relation is true or false, the expression evaluates to true or false. Otherwise, the expression is returned unevaluated.
An unevaluated set inclusion expression has two operands a and b.
nops( a subset b );
op( a subset b );
a,b
The individual operands can be accessed by using the lhs and rhs commands.
lhs( a subset b );
rhs( a subset b );
Other Binary Operators for Sets
You can create new sets from existing sets by using any of the binary set-theoretic operators.
The union of two sets is created by using the union operator, which has the following syntax.
a union b
where a and b are expressions that can evaluate to a set.
a union b;
a∪b
{ 1, 2 } union { 2, 3, 4 };
{ 1, 2 } union T;
T∪1,2
The following expression displays an error message, since the second operand cannot evaluate to a set.
{ a, b, c } union "a string";
Error, invalid input: union received a string, which is not valid for its 2nd argument
A union expression may be returned unevaluated, and the operands of an unevaluated union expression a union b are the expressions a and b.
nops( a union b );
op( a union b );
Note that the union operation is commutative.
b union a;
The union operation is also associative. A union of three or more operands returns an unevaluated function call.
a union b union c;
a∪b∪c
The union operation performs certain normalizations.
a union a;
{} union a;
Intersections of sets are represented using the intersect operator, which has the general syntax.
a intersect b
The operands a and b are expressions that can evaluate to a set.
a intersect b;
a∩b
{ 1, 2, 3 } intersect { 3, 4, 5 };
{} intersect T;
∅
Note that although union and intersection are mutually distributive, neither distributes automatically over the other in a symbolic expression. However, the expand command can distribute intersections over unions.
expand( a intersect (b union c) );
a∩b∪a∩c
Maple takes the canonical form of a set-theoretic expression to be a union of intersections, so the expand command does not distribute symbolic unions over intersections.
expand( a union (b intersect c) );
a∪b∩c
3.13 Other Expressions
Functional Operators
The operator -> (arrow) can be used as a short-hand form to create procedures inline in commands which take procedures as arguments such as Array constructors and the map command.
( vars ) -> result
The following two procedures are identical except in how they are displayed:
x -> x^2;
x↦x2
proc(x) x^2 end proc;
procxx^2end proc
as are these two:
(x,y,z) -> sqrt(x^2+y^2+z^2);
x,y,z↦x2+y2+z2
proc(x,y,z) sqrt(x^2+y^2+z^2) end proc;
procx,y,zsqrt⁡x^2+y^2+z^2end proc
For more information on the arrow operator, refer to the operators/functional help page. For more information on procedures, see Procedures.
Composition
Use the operators @ and @@ to represent the composition (of functions). The operator @ denotes the composition of functions and takes the general form
f @ g
where each of f and g can be an arbitrary expression.
(f@g)(x);
f⁡g⁡x
Note that @ has lower precedence than function application, so that the parentheses surrounding f@g above are necessary:
f@g(x);
f@g⁡x
The @ operator performs numerous simplifications and normalizations, and is (left) associative.
(exp @ ln)( s );
s
a @ b @ c @ d;
a@b@c@d
Repeated composition is represented by the operator @@. It has the general form
f @@ n
This denotes the n-fold composition of a function f.
expand( (f@@3)( x ) );
f⁡f⁡f⁡x
Note that the iterated composition is not automatically expanded in the example above. It is necessary to apply the expand command.
It is important to distinguish repeated composition of an expression from the arithmetic power. The former is represented in Maple using the @@ operator, while the latter is represented using the ^ operator.
expand( (f@@2)( x ) );
f⁡f⁡x
(f^2)( x );
f⁡x2
The first example above denotes the 2-fold composition of f with itself, while the second denotes the arithmetic square of f. In particular, although the inverses of the circular functions are commonly denoted by a power-like notation in written mathematics, in Maple, for example, sin^(-1) denotes the reciprocal of the sin function, while sin@@(-1) denotes the arcsine (arcsin).
sin@@(-1);
arcsin
(sin@arcsin)( x );
sin^(-1);
1sin
(sin^(-1))( x );
1sin⁡x
Neutral Operators
Neutral operators are constructions that are treated as operators by Maple, but that have no predefined meaning so that they can be customized.
A neutral operator symbol is formed by the ampersand character (&) followed either by a valid Maple name not containing ?, or by a sequence of one or more special characters. For more information, refer to the neutral help page.
a &name b
expr := a &your_operator_name_here b;
expr≔a&your_operator_name_hereb
A commonly used neutral operator is &* which is often used for representing a non-commutative multiplication. Unlike dot (.), it does not automatically combine scalar constants.
1 &* 2;
1&*2
1 . 2;
Ranges
The .. operator is used to construct ranges, and usually has the following syntax.
a .. b
in which the endpoints a and b can be arbitrary expressions.
It is important to distinguish between a range expression, such as 3 .. 7, with explicit numeric endpoints, and the corresponding sequence 3, 4, 5, 6, 7. The seq command can be used to produce the latter from the former.
Often, a range is used in an expression of the form i = a .. b, as an argument to a command (such as add), and denotes the range over which an index such as i is to vary.
55
A consecutive sequence of two or more dots (.) is parsed as a range operator. For example,
2 ......... 7;
2..7
If the left-hand endpoint of a range is a float ending with a decimal point, or if the right-hand endpoint is a float beginning with a decimal point, it is therefore necessary to separate the endpoint from the range operator with one or more space characters.
2....3;
2..3
2. .. .3;
2...0.3
The number of operands of a range expression is equal to 2.
nops( a .. b );
The operands are the left and right-hand endpoints.
op( a .. b );
Use the lhs and rhs commands to extract the individual operands of a range expression.
lhs( a .. b );
rhs( a .. b );
The type of a range expression is range or the equivalent form `..`.
type( a .. b, 'range' );
type( a .. b, '`..`' );
Ranges can be used to index complex data structures as well as strings and sequences.
[ 1, 2, 3, 4, 5 ][ 2 .. 3 ];
{ 1, 2, 3, 4, 5 }[ 2 .. 3 ];
"abcde"[ 2 .. 3 ];
bc
( 1, 2, 3, 4, 5 )[ 2 .. 3 ];
There is a special form of input syntax for ranges in which one or both endpoints is missing.
..;
..
In the example above, each endpoint is the empty sequence () (or NULL). It is valid to omit just one of the endpoints.
a ..;
a..
.. b;
..b
When used in this way to index a data structure, a missing endpoint denotes the end of the valid range of indices.
[ 1, 2, 3, 4, 5 ][ 3 .. ];
3,4,5
[ 1, 2, 3, 4, 5 ][ .. 4 ];
[ 1, 2, 3, 4, 5 ][ .. ];
Note the distinction between the third example above and the following example
[ 1, 2, 3, 4, 5 ][];
in which the index is empty.
The Concatenation Operator
The operator || denotes the concatenation of names and strings. It takes the general form
a || b
in which the first operand a can be either a name or a string, and the second operand b can be a name, a string, an integer, an integral range, a character range, or an expression sequence of names, strings, and integers. If the second operand b is another kind of expression, an unevaluated || expression is returned.
"foo" || "bar";
foobar
foo || bar;
foo || "bar";
"foo" || bar;
x || 1;
x1
x || (1..3);
x1,x2,x3
"x" || (1,2,3);
x || ("a" .. "f");
xa,xb,xc,xd,xe,xf
x || ("s", "t", "w" );
xs,xt,xw
f( y ) || t;
f⁡y‖t
The type of the result, if not an unevaluated || expression, is determined by the type of the first operand. If the first operand a is a string, the type of the result (or results, in the case of a sequence) is a string. If the first operand is a name, the type of the result, or results, is a name.
The first operand of the || operator is not evaluated, but the second operand is.
u := 2: v := 3:
u || v;
u3
The symbol `||`, which must be enclosed in left single quotes when not used as an infix operator, is a type name.
type( f( y ) || t, '`||`' );
If a concatenation expression is returned unevaluated, it has two operands.
nops( f( s ) || t );
op( f( s ) || t );
f⁡s,t
For most applications, the cat command is more appropriate, as it evaluates all of its arguments. For more information, refer to the cat help page.
The Double Colon Operator
The :: (double colon) operator is used to represent a type test, and takes two operands in the following form.
expr :: t
where expr is an arbitrary expression, and t is a type expression. When evaluated in a Boolean context, it is equivalent to type( expr, t ).
evalb( [ 1, 2, 3 ] :: list );
[ 1, 2 ] :: list and 2 > 3;
In addition to its use as a general Boolean expression, it is used to introduce type annotations on parameters and type assertions for local variables and procedure return types. For more information, see Procedures.
Outside of a Boolean context, the :: operator is essentially inert, and returns an expression of type :: with two operands.
type( a :: b, '`::`' );
nops( a :: b );
op( a :: b );
You can use the lhs and rhs commands to access the operands of a :: expression.
lhs( a :: b );
rhs( a :: b );
Series
Maple supports generalized power series expansions using a series data structure. This is a basic symbolic data structure that is used in many fundamental algorithms, such as the computation of symbolic limits and symbolic integration. There is no syntax for the input of series; a series structure is created by calling the series constructor, which has the general forms
series( expr, eqn, ord )
series( expr, name, ord )
where expr is an algebraic expression, eqn is an equation of the form
name = pt
where name is a name and pt is the point of series expansion. The optional argument ord specifies the order of truncation of the series. This is, by default, equal to the value of the environment variable Order, whose default value is 6. If the second form using name is used, the expansion point is taken to be 0.
series( exp( x ), x );
1+x+12⁢x2+16⁢x3+124⁢x4+1120⁢x5+O⁡x6
series( exp( x ), x, 10 );
1+x+12⁢x2+16⁢x3+124⁢x4+1120⁢x5+1720⁢x6+15040⁢x7+140320⁢x8+1362880⁢x9+O⁡x10
series( exp( x ), x = 0 );
series( exp( x ), x = 1 );
ⅇ+ⅇ⁢x−1+12⁢ⅇ⁢x−12+16⁢ⅇ⁢x−13+124⁢ⅇ⁢x−14+1120⁢ⅇ⁢x−15+O⁡x−16
In general, a truncated power series expansion to order ord of expr, about the point pt is computed. If the expansion point pt is infinity, then an asymptotic expansion is computed.
In general, the series expansion is not exact, so there will be an order term of the form
O( pt^ord )
present as the last term in the series. This is not always present, however. For example, a series expansion of a low-degree polynomial is exact.
series( x^2 + x + 1, x );
1+x+x2
The presence of an order term depends also on the truncation order.
series( x^20 + x + 1, x );
1+x+O⁡x20
series( x^20 + x + 1, x, 30 );
1+x+x20
A series data structure prints very much like a polynomial, but it is a distinct data structure. In certain cases, a polynomial (sum of product) data structure is returned. This happens when the generalized series expansion requires fractional exponents.
s := series( sqrt( sin( x ) ), x );
s≔x−x5212+x921440+O⁡x132
type( s, 'series' );
The operands of a series expression are as follows.
The 0th operand is an expression of the form x−a, where x is the variable of expansion, and a is the expansion point. Odd operands are the coefficients of the series, while positive even operands are the exponents. In general, for a series expression s, op(2*i-1,s) evaluates to the ith coefficient of s, while op(2*i,s) evaluates to the ith exponent.
op( 0, series( F( x ), x = a ) );
x−a
op( series( exp( x^2 ), x ) );
1,0,1,2,12,4,O⁡1,6
Note that the series data structure is sparse in the sense that terms with 0 coefficient are not part of the data structure.
A series structure can be converted to a polynomial by using the convert command with the name polynom as the second argument.
s := series( exp( x ), x );
s≔1+x+12⁢x2+16⁢x3+124⁢x4+1120⁢x5+O⁡x6
p := convert( s, 'polynom' );
p≔1+x+12⁢x2+16⁢x3+124⁢x4+1120⁢x5
type( p, 'polynom' );
3.14 Attributes
In addition to their operands, certain types of expressions can have other information associated with them in the form of attributes. As described earlier in this chapter, protected names are a type of attribute. If an expression has attributes, they can be examined by using the attributes command.
attributes(sin);
protected,_syslib
Attributes can be assigned to expressions of the following types: name, string, list, set, Array, Matrix, Vector, equation, procedure, unevaluated function call, or float using the setattribute command.
setattribute(expression, attributes)
The setattribute command returns a copy of the expression with the attributes assigned. If the expression is a symbol or string, it is modified in-place. For other data types, the original expression is left unchanged.
x := 1.0;
x≔1.0
setattribute('x', "blue");
attributes('x');
blue
myname := "Johanessphere":
setattribute(myname, "Great Name", "Not a Real Name");
Johanessphere
attributes("Johanessphere");
Great Name,Not a Real Name
y := setattribute('f(z)',"common");
y≔f⁡z
attributes(y);
common
attributes('f(z)');
All Maple expressions are valid attributes, including expression sequences.
You can check whether an expression has attributes by using the attributed type. For more information, refer to the type,attributed help page.
type(`just a name`, 'attributed');
type(sin, 'attributed');
3.15 Using Expressions
Evaluating and Simplifying Expressions
Example 1
To understand how Maple evaluates and simplifies expressions, consider the following example.
x := Pi/6:
sin(x) + 2*cos(x)^2*sin(x) + 3;
174
Maple first reads and parses the input. As the input is parsed, Maple builds an expression tree to represent the value.
sin⁡x+2⁢cos⁡x2⁢sin⁡x+3
Maple simplifies the expression tree and then evaluates the result. The evaluation process substitutes values for variables and invokes any commands or procedures. In this case, x evaluates to 16⁢π. Therefore, with these substitutions, the expression is
sin⁡Pi6+2⁢cos⁢Pi62⁢sin⁡Pi6+3
When the sin and cos commands are called, Maple obtains a new "expression tree,"
12+2⁢12⁢32⁢12+3
Maple simplifies this result to obtain the fraction 17/4.
Example 2
Alternatively, consider the next example: evaluation occurs, but no simplification is possible.
x := 1;
x≔1
sin⁡1+2⁢cos⁡12⁢sin⁡1+3
Substituting Subexpressions
The simplest method of substitution in Maple is to use the subsop command. This is an operation on the expression tree. It creates a new expression by replacing an operand in the original expression with the given value.
subsop( n=value, expr);
subsop( list=value, expr);
L := [a, b, [c,d,e]]:
M := subsop(1=A, L):
L, M;
a,b,c,d,e,A,b,c,d,e
subsop([3,1]=C, L);
a,b,C,d,e
Note that most operations in Maple do not alter expressions in-place but, in fact, create new expressions from old ones. For a list of exceptions, see Mutable Data Structures.
Also, note that the subsop command acts on the expression tree by changing an arrow in the DAG, and not by changing the value of a node which would change all identical instances. That is, in the following example only one instance of a is changed, not all. See Figure 3.2.
expr := (a+a*b)/(a*b-b);
subsop([1,1]=2*c, expr);
2⁢c+aa⁢b−b
Figure 3.2: subsop Example DAGs
The subsop command is powerful, but generally useful only in very specific programming applications. The most generally useful command for substitution is the two-argument version of the eval command.
The eval command has the following syntax, where s is an equation, list, or set of equations.
eval( expr, s );
expr := x^3 + 3*x + 1;
expr≔x3+3⁢x+1
eval( expr, x=y );
y3+3⁢y+1
eval( expr, x=2 );
eval( sin(x) + x^2, x=0 );
The eval command performs substitution on the expression considered as a DAG rather than a tree, so it can be quite efficient for large expressions with many repeated subexpressions.
An alternative to the eval command is the subs command, which performs syntactic substitution. It computes the expression as a tree and replaces subexpressions in an expression with a new value. The subexpressions must be operands, as identified by the op command. Using the subs command is equivalent to performing a subsop operation for each occurrence of the subexpressions to be replaced.
The subs command has the following syntax, where s is an equation, list, or set of equations.
subs( s, expr );
f := x*y^2;
f≔x⁢y2
subs( {y=z, x=y, z=w}, f );
y⁢z2
The other difference between the eval and subs commands is demonstrated in the following example.
subs( x=0, cos(x) + x^2 );
cos⁡0
eval( cos(x) + x^2, x=0 );
In the preceding subs command, Maple substitutes 0 (zero) for x and simplifies the result. Maple simplifies cos(0) + 0^2 to cos(0). By using the eval command, Maple evaluates cos(0) to 1 (one).
During the substitution process, operands are compared in the expression tree of expr with the left-hand side of an equation.
eval( a*b*c, a*b=d );
The substitution does not result in d*c because the operands of the product a*b*c are a, b, c. That is, the products a*b, b*c, and a*c do not appear specifically as operands in the expression a*b*c. The easiest way to make such substitutions is to solve the equation for one unknown and substitute for that unknown.
eval( a*b*c, a=d/b );
d⁢c
You cannot always use this method; for certain expressions, it may not produce the expected results. The algsubs command provides a more powerful substitution facility.
algsubs( a*b=d, a*b*c );
Two more useful substitution commands are subsindets and evalindets. These commands perform substitution on all subexpressions of a given type; the former uses the subs functionality and the latter uses the eval functionality.
subsindets( expr, atype, transformer, rest )
evalindets( expr, atype, transformer, rest )
evalindets([1,2,3,4,5], prime, x->(x+1)^2);
1,9,16,4,36
evalindets((x+1)^2+x^4-1, {`*`,`^`}, expand);
x4+x2+2⁢x
Structured Types
A simple type check may not always provide sufficient information. For example, the command
type( x^2, `^` );
verifies that x^2 is an exponentiation, but does not indicate whether the exponent is, for example, an integer. To do so, you must use structured types. Consider the following example.
type( x^2, 'name^integer' );
Because x is a name and 2 is an integer, the command returns a value of true.
To learn more about structured types, study the following examples. The square root of x does not have the structured type name^integer.
type( x^(1/2), 'name^integer' );
The expression (x+1)^2 does not have type name^integer, because x+1 is not a name.
type( (x+1)^2, 'name^integer' );
The type anything matches any expression.
type( (x+1)^2, 'anything^integer' );
An expression matches a set of types if the expression matches one of the types in the set.
type( 1, '{integer, name}' );
type( x, '{integer, name}' );
The type set(type) matches a set of elements of type type.
type( {1,2,3,4}, 'set(integer)' );
type( {x,2,3,y}, 'set({integer, name})' );
Similarly, the type list(type) matches a list of elements of type type.
type( [ 2..3, 5..7 ], 'list(range)' );
Note that ⅇ2 is not of type anything^2.
exp(2);
ⅇ2
type( (487), 'anything^2' );
Because ⅇ2 is the typeset version of exp(2), it does not match the type anything^2.
type( exp(2), 'exp'(integer) );
The next example illustrates why you should use unevaluation quotes (') to delay evaluation when including Maple commands in type expressions.
type( int(f(x), x), int(anything, anything) );
Error, testing against an invalid type
An error occurs because Maple evaluates int(anything, anything).
int(anything, anything);
anything22
This is not a valid type. If you enclose the int command in unevaluation quotes, the type checking works as intended.
type( int(f(x), x), 'int'(anything, anything) );
The type specfunc(type, f) matches the function f with zero or more arguments of type type.
type( exp(x), 'specfunc(name, exp)' );
type( f(), 'specfunc(name, f)' );
The type function(type) matches any function with zero or more arguments of type type.
type( f(1,2,3), 'function(integer)' );
type( f(1,x,Pi), 'function( {integer, name} )' );
In addition to testing the type of arguments, you can test the number of arguments. The type anyfunc(t1, ..., tn) matches any function with n arguments of the listed types in the correct order.
type( f(1,x), 'anyfunc(integer, name)' );
type( f(x,1), 'anyfunc(integer, name)' );
type( f(x), 'anyfunc(integer, name)' );
Another useful variation is to use the And, Or, and Not type constructors to create Boolean combinations of types. Note that these are different from the and, or, and not logical operators.
type(Pi, 'And( constant, numeric)');
Pi is of type symbol, not of type numeric.
type(Pi, 'And( constant, Not(numeric))');
For more information on structured types, refer to the type,structured help page. For more information on how to define your own types, refer to the type,defn help page.
The indets command is useful for extracting a set of all the subexpressions of a given type.
indets( expr, atype)
indets(z-exp(x^2-1)+1, 'name');
x,z
indets(Pi+3^(1/2)+4.1, 'integer');
indets(Pi+3^(1/2)+4.1, 'numeric');
3,12,7.241592654
indets(Pi+3^(1/2)+4.1, 'constant');
3,12,7.241592654,3,7.241592654+3
Note that the indets command analyzes the entire expression so that the base of the exponent 3 is recognized as an integer. If you want to select only subexpressions from the top level, use the command select described in The select, remove, and selectremove Commands.
If you want to test whether that an expression has a subexpression of a given type, use the hastype command rather than the indets command since it avoids building a potentially large set of expressions.
hastype([1,2,3.,5.,6.,7.], 'float');
3.16 Exercises
Find the numerator and denominator of the irreducible form of 4057114691 divided by 4404825097799.
Construct floating-point numbers using the floating-point number constructor. Construct the number 917.3366 using a positive exponent, and then using a negative exponent. Construct a floating-point approximation of 1/3.
Without using the Digits environmental variable, find the difference between π estimated to 20 digits and 10 digits.
Calculate the negative complex root of -1369, and then sum 3 and the root. Find the inverse of this complex sum. Find the inverse of (a*b)/c+((a-d)/(b*e))*I) in standard form, where a, b, c, d, and e are real.
The Fibonacci numbers are a sequence of numbers. The first two numbers in the sequence are zero (0) and one (1). For n greater than two, the nth number in the sequence is the sum of the two preceding numbers. Assign values to indexed names representing the first, second, and general Fibonacci numbers.
Using the time command, determine the time required to multiply two ten-by-ten matrices.
Use Maple to verify de Morgan's laws.
Contrast the behavior of functions and expressions by performing the following commands.
Define a function f equal to x3. Define an expression g equal to x3.
Evaluate f and g at 2.
Evaluate f and g at y.
Assign the value 2 to x. Evaluate f and g.
Swap the values of two variables using one statement.
Sum the smallest 100 prime integers.
Hint: Use the ithprime or nextprime function.
Download Help Document