Compile a numeric Maple procedure to native code
Calling Sequence
Parameters
Description
The External C++ Compiler
Options
Temporary File Storage
Run-time Support
Managing Large Procedures
Array Support
Support for Recursion
Operation in Secure Mode
The autocompile Procedure Option
Examples
Compiler:-Compile( p, opts )
p
-
{procedure,list(procedure)}; a Maple procedure or list of procedures
opts
options; one of trace=true/false, optimize=true/false, inmem=true/false and warnings=true/false
The Compiler:-Compile command compiles a limited subset of Maple procedures (described in more detail below) to native code and returns the compiled procedure. Note that the module Compiler is not a package.
Typically, the Compiler can provide improved performance for procedures that run long enough to justify the overhead of compilation, or which are called so frequently as to amortize this overhead.
Translation is effected by the use of a special purpose CodeGeneration backend. Maple procedures are translated to C++ language code, which is subsequently compiled by an external C++ compiler. The compiled code is then dynamically linked into Maple, using the external calling facility, to produce a Maple-callable procedure that, when called with appropriate inputs, will invoke the compiled code. Because the overhead of interpretation has been largely removed from the compiled code, in many cases, a compiled procedure will run faster even than it does when run under evalhf.
The set of procedures that can be successfully translated by the numeric code compiler is very limited. In general, procedures are limited to those that manipulate data types that have fairly direct representations as hardware integers, floats, and arrays containing these types of values. In part, procedures are limited to those that can be successfully translated to C by the CodeGeneration package. (See CodeGeneration/TranslationDetails for detailed information.)
There are additional restrictions imposed by the numeric code compiler on top of those imposed by the CodeGeneration package.
No nested procedures can be translated.
No modules can be translated.
Exception handling (other than merely raising an exception) cannot be translated.
Procedures that return arrays or allocate new arrays cannot be translated.
Procedures that call other procedures about which insufficient type information can be obtained at compile time cannot be translated.
Integer data are limited to word-sized integers on the current hardware. Computations that produce larger integers will raise an overflow exception.
Floating-point computations, including complex floating-point operations, are carried out entirely in hardware precision (like evalhf).
Since all supported hardware uses radix 2 floating-point arithmetic, while Maple's software floating-point system is a radix 10 system, computations that depend crucially on the radix will produce different results.
A single procedure or a list of procedures may be passed as the first argument to the Compiler:-Compile command. If the first argument is a list, then the Compiler:-Compile command automatically maps over this list, returning a list of the compiled procedures.
Since correct compilation is heavily dependent upon the Compiler determining the types of parameters and variables, it is advisable to annotate procedures submitted to the compiler with type information. While this is often not necessary, as the Compiler will usually deduce the correct types for variables, it may be needed in certain cases where the Compiler deduces the incorrect type.
A crucial component of the compilation tool chain is the external C++ compiler, which is used to compile the generated C++ code.
On Linux and macOS platforms, the default compiler is LLVM which is distributed and linked into Maple. LLVM will be used to compile code as long as the inmem=false option is not passed to the Compiler:-Compile command.
On all Linux platforms, the GNU C++ compiler can be used to compile the emitted C++ code. The GNU C++ compiler is not distributed with Maple, and must be installed separately, if it is not already present on the system. The numeric code compilation facility relies on the "g++" command being present in the program search path (the value of the "PATH" environment variable). To access "g++" the inmem=false option must be passed to the Compiler:-Compile command.
On all macOS platforms, the Clang compiler can be used to compile the emitted C++ code. The Clang compiler is not distributed with Maple, and must be installed separately using Command Line Tools for Xcode, if it is not already present on the system. The numeric code compilation facility relies on the "clang++" command being present in the program search path (the value of the "PATH" environment variable). To access "clang++" the inmem=false option must be passed to the Compiler:-Compile command.
On Windows platforms, the Clang compiler is used which is distributed with Maple.
You can set infolevel[Compiler] to a positive value (1 or 3) to obtain some information about what the compiler is doing.
The Compiler:-Compile command accepts several options that affect how code is generated.
Use the trace option to enable tracing of compiled procedure execution. This is similar to the trace option for ordinary Maple procedures. You can specify the trace option by writing trace = true (or just trace) or trace = false as an argument to the Compiler:-Compile command. By default, tracing is not enabled.
Enable extra warnings during translation by specifying warnings = true (or just warnings) as an option to the Compiler:-Compile command. To disable extra warnings (the default), specify warnings = false.
The inmem option can be used to select which external C++ compiler is used. On Linux and macOS platforms LLVM will be used unless the option inmem=false is passed. If inmem=false is passed in, the GNU C++ or Clang compilers will be used on the Linux and macOS platforms respectively. This option is currently disregarded on Windows.
Request that Maple attempt to optimize the input procedure by specifying the optimize option, in the form optimize = true (or just optimize) or optimize = false. At present, this causes the code to be optimized prior to translation by passing it through codegen[optimize]. Optimization is not performed by default.
The compiler generates a number of temporary files during execution. The shared library or DLL into which the code is compiled is stored in a temporary directory unique to each user and process. These files are meant to persist for the duration of the Maple session in which they were created. You can control the directory into which these temporary directories are placed by means of the system environment variable MAPLE_TEMPDIR, which must be set to a directory (or folder) to which you have write permissions.
If the system environment variable MAPLE_TEMPDIR is not defined, or if it cannot be used (for example, if it does not exist or is not writable), then a platform-dependent algorithm is used to try to find a suitable directory in which to store files. If no other directory can be found, then the current working directory is used. Note that, on Windows, the temporary directory used may not have spaces in its name, unless it is the current directory, in which case relative path names are passed to the OpenWatcom compiler.
Compiled code is able to access a run-time library of support functions. The run-time library contains a number of utilities that aid in the execution of compiled code, as well as a library of mathematical functions that is shared with the evalhf command. In addition, some hardware-integer versions of several Maple commands that operate on integers are provided, as are limited versions of print and type.
The built-in mathematical functions available in the run-time library are as follows.
arccos
arccosh
arccot
arccoth
arccsc
arccsch
arcsec
arcsech
arcsin
arcsinh
arctan
arctanh
argument
BesselI
BesselJ
BesselK
BesselY
ceil
conjugate
cos
cosh
cot
coth
csc
csch
csgn
Dirac
erf
erfc
exp
floor
frac
HankelH1
HankelH2
Heaviside
Im
ln
log
Re
round
sec
sech
signum
sin
sinh
tan
tanh
trunc
In addition, limited versions of the following Maple procedures are provided in the run-time library.
abs
fprint
igcd
iquo
irem
isqrt
lprint
max
min
modp
mods
print
type
The following types are recognized by the type run-time function.
even
finite
float
infinity
integer
neg_infinity
negative
negint
negzero
nonnegative
nonnegint
nonposint
nonpositive
numeric
odd
pos_infinity
posint
positive
poszero
real_infinity
realcons
undefined
Modular arithmetic is supported: addition, multiplication, division (by a unit), powers, and negation will not overflow. The mod environment variable is implemented in the runtime.
The run-time library contains only limited versions of the listed builtin procedures. These procedures are capable only of handling hardware datatypes (integer, floating-point or complex floating-point). Integer-valued run-time procedures can neither return nor accept infinity or -infinity. Integer computations that overflow the size of the machine word cause an exception indicating the overflow to be raised. This applies also to integer arithmetic. The run-time type procedure recognizes no types not listed above, and neither structured types nor user-defined types are supported.
When a compiled procedure returns a complex result equal to 0.+0.⁢I, the result is converted to 0. in all cases. However, an imaginary part equal to −0. is preserved.
In the Compiler run-time environment, non-default numeric event handling settings are not guaranteed to be respected.
Thread Safety
As of Maple 18, the run-time library for compiled procedures is thread-safe. This means that a thread-safe Maple procedure will result in one that remains thread-safe once compiled.
In order to take advantage of this in multithreaded code, you must include option threadsafe on procedures to be compiled. This will ensure that the kernel recognizes the compiled procedure as one that is thread-safe and allow it to be called from multiple threads.
Note, however, that the compiler itself is not thread-safe. This means that procedures with option autocompile cannot be used in multithreaded code, until after they have been compiled (by calling them at least once).
Compilation of procedures involving very large expressions may require significant overhead, both to generate the C++ code and to run the C++ compiler on the generated code. Consider using the optimize option if you encounter any of the following problems.
The Compiler is taking a very long time to generate C code.
The external C++ compiler takes a very long time to compile the generated C code.
The external C++ compiler runs out of memory when compiling the generated C code.
Arrays can only appear as parameters of a procedure that is to be compiled. Although there is some support for global and lexically scoped variables, these are limited to scalar-valued quantities, and sufficient type information must be present to determine their effective type during the execution of the compiled procedure.
Multidimensional Arrays (such as Matrices) are supported. Because it is normally inconvenient to provide dimensional information for Arrays in a parameter type description, the CodeGeneration package will determine the number of dimensions of an Array parameter from the way in which it is accessed in the body of the procedure being compiled. If an Array parameter is never accessed in the body of a procedure being compiled, and no dimensional information is provided in a parameter type description, then the Array parameter will be assumed to be one dimensional.
Recursive procedures are supported by the Compiler. For the compiled code to operate recursively, recursive calls must be made via the procname implicit parameter rather than the name the procedure is assigned to. (Strictly speaking, a recursive procedure in Maple must be coded this way to be guaranteed of operating recursively whether or not it is to be compiled.)
During compilation, tail-recursive calls are detected and transformed into iteration. This means that tail-recursive procedures compile to very fast code.
Because the Compiler creates temporary files and executes external processes, it is not available when Maple is started in secure mode, using the -z command line option, or when enhanced security has been enabled via the Options menu in the GUI.
A Maple procedure may be given the option autocompile. This causes the kernel to attempt to compile the procedure to native code on first execution. If the compilation succeeds, the name by which the procedure was invoked is re-assigned the value of the compiled procedure. In effect, the original procedure is replaced with the procedure that runs the compiled code.
p := proc( x :: float ) :: float; 2.3 * x end proc:
cp≔Compiler:-Compile⁡p:
cp⁡1.1
2.52999999999999980
p := proc( n :: posint, x :: float ) :: float; local i :: integer, s :: float; s := 0.0; for i from 1 to n do s := s + x / i end do; s end proc:
cp≔Compiler:-Compile⁡p
cp ≔ procoptioncall_external,define_external⁡maple_compiled_m0ac6a896a5a9f41c9517543d1c6e9edb,MAPLE,IN_MEM=140289142468736;call_external⁡0,140289142468736,true,false,false,argsend proc
time⁡p⁡100000,2.3
0.222
time⁡evalhf⁡p⁡100000,2.3
0.013
time⁡cp⁡100000,2.3
0.
p := proc( n :: posint, a :: Array( datatype = float[ 8 ] ) ) local i::integer, s::float; s := 0.0; for i from 1 to n do s := s + a[ i ] end do; s end proc:
a≔Array⁡1..5,u↦evalf⁡1u,datatype=float8
a≔1.0.5000000000000000.3333333333000000.2500000000000000.200000000000000
p⁡5,a
2.28333333330000
cp⁡5,a
2.28333333329999988
Compiled procedures retain array bounds checking:
cp⁡7,a
Error, (in cp) array index out of bounds
N≔100000:a≔Array⁡1..N,u↦evalf⁡1u,datatype=float8:
time⁡p⁡N,a;time⁡evalhf⁡p⁡N,a;time⁡cp⁡N,a
0.047
0.011
Recursive procedures can be handled, as in this implementation of the Towers of Hanoi problem.
HanoiMove := proc( a :: Array( 1 .. 4, datatype = integer[ 4 ] ), numdisks :: posint, frompeg :: posint, topeg :: posint ) local tmp; if numdisks = 1 then a[ frompeg ], a[ topeg ] := a[ frompeg ] - 1, 1 + a[ topeg ] else tmp := 6 - ( frompeg + topeg ); procname( a, numdisks - 1, frompeg, tmp ); procname( a, 1, frompeg, topeg ); procname( a, numdisks - 1, tmp, topeg ) end if end proc:
cHanoiMove≔Compiler:-Compile⁡HanoiMove:
st≔time⁡:HanoiMove⁡Array⁡1..4,datatype=integer4,17,1,3:time⁡−st
6.174
st≔time⁡:cHanoiMove⁡Array⁡1..4,datatype=integer4,17,1,3:time⁡−st
0.007
Complex floating-point data are supported.
p := proc( a :: Array( datatype = complex[8] ), n :: posint ) :: complex(extended_numeric); local s, i; s := 0.0 + 0.0*I; for i from 1 to n do s := s + arcsin( a[ i ] ) end do; s end proc:
a≔Array⁡I,−I,1,−1,:-datatype=:-complex8:
p,cp⁡a,4
0.+0.⁢I,0.+0.⁢I
Use the trace option to effect tracing of compiled procedures.
p := proc( n :: integer ) :: integer; if n < 1 then 0 else 1 + procname( n - 1 ) end if end proc:
cp≔Compiler:-Compile⁡p,trace:
cp⁡5
{--> enter p, args = 5
5
The autocompile option can be used to cause procedures to attempt compilation on their first invocation.
Sort := proc( a :: Array( datatype = integer[ 4 ] ), n :: posint ) local i, j, m, tmp; option autocompile; for i from 1 to n do m := i; for j from 1 + i to n do if a[ j ] < a[ m ] then m := j end if end do; a[ m ], a[ i ] := a[ i ], a[ m ] end do end proc:
a≔Array⁡1..10,i↦mods⁡RandomTools:−MersenneTwister:−GenerateInteger32⁡,2147483647,datatype=integer4
a≔−795755683581869301−404620561−708632710545404203−133711904−372047866949333984568478650−823916245
Sort⁡a,10
949333984
a
−823916245−795755683−708632710−404620561−372047866−133711904545404203568478650581869301949333984
The following example demonstrates support for modular arithmetic and lexically scoped parameters.
p := proc( m :: posint ) proc( a :: integer, b :: integer ) ( a + b ) mod m end end proc:
add111≔Compiler:-Compile⁡p⁡111:
add111⁡234,456
24
234+456mod111
add111⁡199,14
102
`mod`≔mods:
−9
mods⁡199+14,111
Overloaded procedures can be used to implement algorithms that run compiled code for suitable inputs, but fall back to interpreted Maple code for other inputs.
F := overload([ proc( s :: float, n :: integer[ 4 ] ) :: float; local i; option overload, autocompile; userinfo( 1, "F", "using native code" ); sin( s / n ) # for small n, use native code end proc, proc( s :: float, n :: integer ) :: float; local i; option overload; userinfo( 1, F, "using Maple software code" ); sin( s / n ) # for large n use Maple arithmetic end proc, proc( s :: algebraic, n :: algebraic ) 'F( args )' # return a symbolic result end proc, NULL]):
infolevelF≔2:
F⁡evalf⁡π,100
F: "using native code"
0.0314107590822283386
F⁡evalf⁡π,231
1.46291807945817713×10−9
F⁡π,100
Another example.
`mod`≔modp:
F := overload([ proc( a :: Array( datatype = integer[ 4 ] ), n :: posint, m :: integer[ 4 ] ) :: integer[ 4 ]; option overload, autocompile; local i, s; userinfo( 1, F, "using small modulus implementation" ); s := 0; for i from 1 to n do s := ( s + a[ i ] ) mod m end do; s end proc, proc( a :: Array, n :: posint, m :: integer ) :: integer; option overload; local i, s; userinfo( 1, F, "using large modulus implementation" ); s := 0; for i from 1 to n do s := ( s + a[ i ] ) mod m end do; s end proc, NULL]):
a≔Array⁡seq⁡2imod101,i=0..50,datatype=integer4:
F⁡a,51,101
F: "using small modulus implementation"
98
a≔Array⁡seq⁡2imod240+1,i=0..50:
F⁡a,51,240+1
F: "using large modulus implementation"
49
If Maple is started with the `-z' option, the Compiler is not available for use, and an exception like the following is raised. (The exception will not be raised if you execute this example in a session not started with the `-z' option.)
Compiler:-Compile⁡p⁡111
Error, (in Compiler) this command is not available in secure mode
See Also
Array
codegen[optimize]
CodeGeneration
CodeGeneration/TranslationDetails
define_external
evalhf
mod
option
procname
RandomTools
Download Help Document