Language and Programming - New Features in Maple 2019 - Maplesoft

What's New in Maple 2019

Language and Programming

Maple 2019 includes the following enhancements to the Maple language and programming facilities. 



Maple Language 

Two Variable for-in Loops 

Maple's for-in loop iterates over a container (list, Array, etc.), setting the loop's control variable to the value of each element in turn: 

> for i in [a,b,c] do
   print(i)
end do;
 

 

 

a
b
c
 

Usually, having just the element's value is sufficient, but sometimes its index into the container is also needed. The new two-variable form of the for-in loop makes this straightforward: 

> R:= LinearAlgebra:-RandomMatrix(3,4);
 

rtable(1 .. 3, 1 .. 4, [[-32, 27, 99, 92], [-74, 8, 29, -31], [-4, 69, 44, 67]], subtype = Matrix)
 

> for ind, val in R do
  if val < 0 then R[ind] := -val end if
end do:
 

> R;
 

rtable(1 .. 3, 1 .. 4, [[32, 27, 99, 92], [74, 8, 29, 31], [4, 69, 44, 67]], subtype = Matrix)
 

Using Assignments, if- statements, try- statements, and Loops in Expressions 

It is now possible to use statements within expressions. The supported statements are: assignments, if-statements, try-statements, and all forms of loop-statements. 

An assignment can be written within an expression by enclosing it in parentheses. The value of an assignment expression is the value that was assigned (that is, the evaluated right-hand side of the assignment). 

> x:=2:
 

> if x<>0 and (invx :=1/x) <1 then print(invx) end if:
 

`/`(1, 2)
 

> i:=2:
 

> do i until (i:=nextprime(i)) > 15;
 

 

 

 

 

 

2
3
5
7
11
13
 

The if- and try- expressions can be written anywhere within an expression: 

> x:=-3;
 

Typesetting:-mprintslash([x := -3], [-3])
 

> signedSqr := x* if x<0 then -x else x end if;
 

Typesetting:-mprintslash([signedSqr := -9], [-9])
 

The value of such an expression is the value of the last expression computed in a statement sequence within it (i.e. the value that % would have if the expression were evaluated as a statement). 

Loop expressions must generally be enclosed in parentheses, except in a few unambiguous cases: as the sole entry in a list or set, or the entire right-hand side of an assignment or return statement. 

 

> N :=5;
 

Typesetting:-mprintslash([N := 5], [5])
 

> [for i to N do i end do];
 

[1, 2, 3, 4, 5]
 

> sqrSeq := for i to N do i^2 end do;
 

Typesetting:-mprintslash([sqrSeq := 1, 4, 9, 16, 25], [1, 4, 9, 16, 25])
 

Unlike a loop-statement, the value of a loop expression is a sequence of the last values computed in each iteration of the loop. 

Storage for the result of loop-expressions is allocated efficiently. In most cases, the amount of storage required can be determined in advance, so it is all pre-allocated. When it cannot be determined in advanced, it is grown in a way that is still O(N) in the number of iterations, instead of the O(N^2) cost when appending one element at a time. 

Loop expressions make it easy to generate sequences whose length cannot be readily predetermined. For example, this generates a list of all primes less than some upper bound. 

 

> N:=100;
 

Typesetting:-mprintslash([N := 100], [100])
 

> [(i:=2), (while (i:= nextprime(i)) <N do i end do)]
 

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
 

Note that input of these expression-statements is currently not supported by 2-D input in the Standard interface. 

Increment, Decrement, and Assignment Operators 

Maple now supports C-style increment, decrement, and assignment operators. Rather than having to write, 

> N := N+1;
 

Typesetting:-mprintslash([N := 101], [101])
 

one can write, 

> N+=1;
 

Typesetting:-mprintslash([N := 102], [102])
 

or: 

> ++N;
 

Typesetting:-mprintslash([N := 103], [103])
 

Besides being shorter to type, in cases where N is expensive to compute, this is more efficient. Consider, 

A[expensiveOperation()] := A[expensiveOperation()] + 3; 

 

compared to: 

A[expensiveOperation()] += 3; 

In the latter, expensiveOperation() is called only once. 

The increment and decrement operators, ++ and --, can be applied either before or after the value to be incremented or decremented. If applied before, then the result of expression is the new value. If applied after, the result is the previous value: 

> N := 1;
 

Typesetting:-mprintslash([N := 1], [1])
 

> a := ++N;
 

 

Typesetting:-mprintslash([N := 2], [2])
Typesetting:-mprintslash([a := 2], [2])
 

> b := N++;
 

 

Typesetting:-mprintslash([N := 3], [3])
Typesetting:-mprintslash([b := 2], [2])
 

> N;
 

 

3
 

The assignment operators, like ordinary := assignments, can be used within an expression by enclosing the entire assignment in parentheses. 

The complete set of assignment operators is: 

+=, -=, *=, /=, mod=, ^=, .=, and=, or=, xor=, implies=,
   union=, intersect=, minus=, and ,=
 

The last one, the `,=` operator, is special. In most cases, it constructs an expression sequence of the left and right-hand sides, assigning it to the left-hand side: 

 

> s := 1;
 

Typesetting:-mprintslash([s := 1], [1])
 

> s ,= 2, 3;
 

Typesetting:-mprintslash([s := 1, 2, 3], [1, 2, 3])
 

> s;
 

1, 2, 3
 

However, when it is applied to one-dimensional Arrays or any object implementing a `,=` method, the right-hand side is appended to the container in-place: 

> A := Array([a,b,c]);
 

rtable(1 .. 3, [2, 2, c], subtype = Vector[row])
 

> refA := A;
 

rtable(1 .. 3, [2, 2, c], subtype = Vector[row])
 

> A ,= d:
 

> A, refA;
 

rtable(1 .. 4, [2, 2, c, d], subtype = Vector[row]), rtable(1 .. 4, [2, 2, c, d], subtype = Vector[row])
 

Note that input of these assignment operators is currently not supported by 2-D input in the Standard interface. 

Efficient Mutable Strings and the String Function 

Strings in Maple are immutable. This makes them very efficient to use as values, but less efficient to manipulate. 

> a := "Hello"; b:= "world";
 

 

Typesetting:-mprintslash([a :=
Typesetting:-mprintslash([b :=
 

> a := cat(a," ",b);
 

Typesetting:-mprintslash([a :=
 

After the above has executed, `a` has the value "Hello world", but the string "Hello" still exists in memory until the garbage collector dispose of it. Thus, the following is inefficient: 

> s := "";
 

Typesetting:-mprintslash([s :=
 

> for c from "a" to "z" do s := cat(s,c) end do:
 

> s;
 

abcdefghijklmnopqrstuvwxyz
 

This successively produces the strings "a", "ab", "abc", etc., leaving each previous result to be cleaned up later.

Maple 2019 allows mutable strings to be represented as one-dimensional Arrays of 1-byte integers. Such an Array can be constructed explicitly,
 

> s := Array([], datatype=integer[1]);
 

s := rtable(1 .. 0, [], subtype = Vector[row])
 

or using the new notation: 

> s:= Array("");
 

s := rtable(1 .. 0, [], subtype = Vector[row])
 

The Array can also be constructed and initialized in a single call: 

> s := Array("Hello");
 

rtable(1 .. 5, [72, 101, 108, 108, 111], subtype = Vector[row])
 

The `,=` assignment operator can be used to append to the Array, in-place: 

> s ,= " ";
 

rtable(1 .. 6, [72, 101, 108, 108, 111, 32], subtype = Vector[row])
 

> s ,= "world";
 

More than one item can be appended at once, including other such arrays: 

rtable(1 .. 11, [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100], subtype = Vector[row])
 

> question := Array("How are you?");
 

rtable(1 .. 12, [72, 111, 119, 32, 97, 114, 101, 32, 121, 111, 117, 63], subtype = Vector[row])
 

> s ,= "! ", question, "\n";
 

The printf "%s" format understands these Arrays: 

rtable(1 .. 26, [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 32, 72, 111, 119, 32, 97, 114, 101, 32, 121, 111, 117, 63, 10], subtype = Vector[row])
rtable(1 .. 26, [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 32, 72, 111, 119, 32, 97, 114, 101, 32, 121, 111, 117, 63, 10], subtype = Vector[row])
rtable(1 .. 26, [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 32, 72, 111, 119, 32, 97, 114, 101, 32, 121, 111, 117, 63, 10], subtype = Vector[row])
 

> printf("The string: %s",s);
 

The string: Hello world! How are you?
 

The new String function can convert this back to a regular immutable string: 

> t := String(s);
 

Typesetting:-mprintslash([t :=
 

The String function can also convert and concatenate multiple arguments into a string: 

> s := Array("Hello");
 

rtable(1 .. 5, [72, 101, 108, 108, 111], subtype = Vector[row])
 

> String(s, " world! The answer is ", 7!/5!);
 

Hello world! The answer is 42
 

Neutral Operators 

The set of valid characters for symbolic neutral operators has been expanded. Previously, the allowable symbols after the initial "&" character were: 

! " $ * + , - . / < = > ? @ \ ^ ~ 

Now, the first character after the "&" can also be one of these: 

% & ' ( ) : ; [ ] ` { | } 

The second and subsequent characters after the "&" can be from the original set, or these additional characters: 

) ] | } 

Neutral operators are usually left-associative: 

> a &x  b &y c;
 

`&y`(`&x`(
 

If a neutral operator starts with "&&" and has at least one additional character, then it is right associative: 

> a &&x  b &&y c;
 

`&&x`(
 

Note that input of the new neutral operators is currently not supported by 2-D input in the Standard interface. 

Local Scoping 

Maple 2019 removes the requirement that all procedure and module local and global variables, and module exported variables, be declared at the beginning of the procedure or module before any executable statement.

Declarations of exported variables can appear anywhere within the top-level statement sequence of a module, and global declarations can appear in any statement sequence within a procedure or module. Local variable declarations are even more flexible, and can appear as statements, within assignment expressions, and in the control variable specification of
for-loops.

Variable declarations have a defined scope, and the same variable can be declared in more than one scope as long as the declarations are compatible, and one scope is not contained within the other.

This feature is not supported in 2-D input.
 

Miscellaneous 

Operator procedures, defined using the arrow notation, may now have local variable declarations: 

> iota := n -> local i; (for i to n do i od):
 

> iota(5);
 

1, 2, 3, 4, 5
 

Note that input of local variable declarations for operator procedures is currently not supported by 2-D input in the Standard interface. 

The `in` membership test operator now works even if the member being tested evaluates to NULL: 

> n := 3;
 

Typesetting:-mprintslash([n := 3], [3])
 

> evalb(n in {1,2,3});
 

true
 

> n := NULL;
 

Typesetting:-mprintslash([n := ], [])
 

> evalb(n in {1,2,3});
 

false
 

Previously, cases where the candidate might be NULL had to be protected like this: 

> evalb(n <> NULL and n in {1,2,3});
 

false
 

The `lprint` command can now be invoked with an optional index argument, [2], which will cause it to line-break any procedures that it prints. Unlike the output produced by the pretty-printer, which will attempt to pack several statements onto one line if an entire statement sequence fits, `lprint[2]` will line-break and indent in a completely consistent manner, and will not center the result on the screen: 

> f := proc(x,y) local a; if x < y then y-x else a := x-y; a^2 end if end proc;
 

Typesetting:-mprintslash([f := proc (x, y) local a; if `<`(x, y) then `+`(y, `-`(x)) else a := `+`(x, `-`(y)); `*`(`^`(a, 2)) end if end proc], [proc (x, y) local a; if `<`(x, y) then `+`(y, `-`(x)) e...
 

> lprint[2](eval(f));
 

proc( x, y )
   local a;
   if x < y then
       y-x;
   else
 

       a := x-y;
       a^2;
   end if;
end proc
 

The "%a" and "%A" formats of the printf, sprintf, and fprintf functions can now be modified by the "Z" modifier, which instructs them to produce output equivalent to the `lprint[2]` output above. In conjunction with sprintf, this effectively allows lprinting to a string: 

> s := sprintf("%Za",eval(f));
 

 

 

New Commands 

ArrayTools 

> with(ArrayTools):
 

Partition 

The Partition command partially sorts a data structure around a given order statistic. 

 

> v := [5, 2, 5, 2, 3, 4, 4, 5, 3, 1, 5, 2, 3, 2, 2, 4, 3, 3, 1, 2]:
 

Partition can be used to find the third-smallest entry of v. 

> w := Partition(v, 3)
 

Typesetting:-mprintslash([w := [1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]], [[1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]])
 

> w[3]
 

2
 

We see that w__3 = 2, so the third-smallest entry of v is 2. 

Remove 

The Remove command removes entries and shrinks an Array. 

 

> A := Array([11, 22, 33, 44, 55]):
 

Remove A[3] and shrink: 

> Remove(A, 3)
 

rtable(1 .. 4, [11, 22, 44, 55], subtype = Vector[row])
 

Reverse 

The Reverse command reverses the entries of a Matrix, Vector, or Array. 

> A := Array([1, 2, 3, 4]):
 

> Reverse(A)
 

rtable(1 .. 4, [4, 3, 2, 1], subtype = Vector[row])
 

convert/english 

The convert/english command is not new, but it now allows for round-tripping of integer to english conversions.
 

> en := convert(-1234567890, 'english');
 

 

> n := convert( en, 'english');
 

Typesetting:-mprintslash([n := -1234567890], [-1234567890])
 

Download 

The Download command now makes it possible to download data from a URL to a local file. 

tablereverse 

The tablereverse function takes a table and returns a new table that is a reversal of the initial table. 

> T := table(["apple" = "fruit", "orange" = "fruit", "zucchini" = "vegetable", "milk" = "dairy"])
 

Typesetting:-mprintslash([T := TABLE([
 

> tablereverse(T)
 

Typesetting:-mprintslash([TABLE([
 

Kernel Options 

The kernelopts command has several new options:traceshowspecassign: boolean; If true, causes some assignments shown during tracing to appear in a distinctive way. The default is false. 

  • tracesplitmulassign: boolean; If true, causes multiple assignments shown during tracing to appear individually. The default is false.
 

Command Line Interface 

New Interface Options 

Several new options to the interface command have been introduced. These primarily affect the command-line interface:

The
trailingsemicolon option, which is false by default, causes a semicolon to be printed after the last statement in each statement sequence when a procedure is printed (by lprint, print, or the "%a" printf format).

The
compactdisplay option, which is true by default, tells the pretty-printer to pack multiple statements onto one line when they fit. If set to false, then multiple statements are usually printed on separate lines, the exception being when the entire single statement (e.g. an if-statement) containing the multiple statements fits on one line.

The existing
errorbreak option, which controls what happens when Maple is reading a script of commands from a file, has a new allowed value of 3. This is equivalent to interface(errorbreak=2), meaning that reading should stop on any error, but has the additional effect of issuing a stack trace, as if the user had typed the tracelast command after the error occurred. This option can also be set by passing -e3 when invoking Maple from the system command line.

The
echofile option tells Maple to echo all input and output of a session to a log file. The value of this option should be a string, specifying the name of the file. If the specified file name ends in ".html" or ".htm", the session is logged in HTML format, with syntax highlighting, otherwise it is logged as plain text. If an empty string or the string "none" is specified, echoing to a file is terminated. This option can be invoked from the very beginning of a session by using the --echofile=filename option when invoking Maple from the system command line. 

Color Output 

When used with a compatible terminal, Maple can now do color syntax highlighting for both output and user input. This new capability is controlled by the following interface options: 

Option 

Description 

ansi=true or ansi=false 

Controls whether any form of highlighting is used at all. 

ansicolor=list, ansicolor=integer, ansicolor=[] 

Controls the choice of colors used. If set to a list, the list specifies the colors for different categories of output. An integer in the range of 0 to 6 selects one of several predefined color palettes. An empty list produces output that uses bold, italic, and underline
attributes, but no colors.
 

ansilprint=true or ansilprint=false 

Controls whether lprinted output is syntax highlighted. 

ansiedit=true or ansiedit=false 

Controls whether command-line input is syntax highlighted. 

showcolors 

Illustrates the current syntax highlight color palette. 

showtermcolors 

Shows what colors the terminal is capable of displaying. 

 

Color support is enabled by default if the current terminal is known to support it. It can be manually controlled using the interface options described above, or these can be put in the user's Maple initialization file.

Color support has also been extended to the character plot driver, which can be selected using interface(plotdevice=colorchar). See plot/device.

Likewise, the ImageTools:-Preview command can now produce color character output (color "ASCII art"), which is much more representative of the actual image than a monochrome character preview was.
 

Command History Manipulation 

The command-line interface adds several new facilities for interactively manipulating, replaying, saving, and restoring the history of commands entered into Maple. Typing "!!?" at the Maple prompt will display a brief summary. 

Debugger 

The output of the showstat command has been improved with respect to the display of long lines, especially in-line procedures and statements that would previously display as one long unbroken line.

A new debugger command,
edit, will open the source file containing the currently stopped procedure, at the line corresponding to the current statement. A corresponding Maple command, editsource(), will do the same for a specified procedure and statement number. Both require that the source code is available, and that kernelopts(keepdebuginfo) was set to true or Maple was started with the --keep-debug-info option on the system command line.

The
help command in the debugger now displays a summarized version of the information on the debugger help page. An optional argument to the help command will display help for only those debugger commands for which the argument is a prefix (e.g. "help stop" will display help for stopat, stopwhen, etc.). 

Mint 

A new option for the stand-alone mint utility (normally used to find potential issues in Maple programs) now has an option to generate a "ctags" format file. This is a file that can be used by many text editors to find the implementation of a given procedure when a special key is pressed (or menu item invoked) on a call to that procedure. It was originally designed for the "C" programming language, but works equally well with other languages so long as there exists a tool to generate the tag file. The "-c" option to Mint, which should be followed by the desired name of the tag file, will do that for all the files it processes during one call. Typically, one would call mint on the top level module of a package, resulting in a tag file for the entire package.

In keeping with the theme of coloring command line output, mint can now also produce color output if the system environment variable MINT_COLORS is set appropriately. This is analogous to similar schemes used by Linux command line utilities such as grep (GREP_COLORS) or gcc (GCC_COLORS).