Message Boards Message Boards

MathCompile - my implementation of code compilation

Posted 4 years ago

The first release (version 0.1.0) of the package is available now. You can access the releases here, and the guide here.


MathCompile is a package I am working on as a different approach to code compilation than Compile and FunctionCompile. MathCompile is focused on improving the availability of functional programming and covering the functionalities provided by the built-in compiler. It also brings performance improvements due to its architecture.

MathCompile is still at its early stage where a lot of features are to be added and bugs are expected. Any feedback and comments are welcome.

The package can be accessed here https://github.com/njpipeorgan/MathCompile with Documentations.


Installation

To install the package:

  1. clone the repository to local machine;
  2. open Mathematica and and choose File | Install...;
  3. Select Application for the type of item to install, and select From Directory... for the source, then open the directory you cloned named MathCompile.

A C++ compiler supporting C++17 standard is required; see this wiki page for more information. If you are working on a recent Linux or macOS platform, a compatible version of GCC or Clang may have been installed. On Windows platforms, you may follow §Windows on the page to install and configure the compiler (Mingw-w64 is recommeded).

In a nutshell

After installing the package, load it by executing

<<MathCompile`

Here is a Wolfram Language function that calculates the product of the elements in a list of integers:

f = Function[{Typed[x, {Integer, 1}]}, Times @@ x];

Compile this function using CompileToBinary.

cf = CompileToBinary[f];

The compiled function can be called just like a normal function.

cf[{1,2,3,4}]    (* gives 24 *)

How is its performace

Functions compiled by MathCompile are intended to perform as if they were written in native C++. They typically have equal or higher performance than those by the built-in compiler. Here I show the example of accelerating Mandelbrot set computation from version 12 code compilation introduction page.

The implementation of the function is the same.

f0=Function[{Typed[p0, "ComplexReal64"]},
  Module[{iters = 1, max = 1000, p = p0},
    While[iters < max && Abs[p] < 2, p = p^2 + p0; iters++]; iters
  ]
]

It is compiled by both the built-in compiler and MathCompile.

f1 = FunctionCompile[f0];
f2 = CompileToBinary[f0];

Measure how long it takes to apply each of these functions to a grid.

AbsoluteTiming[Table[f0[x + I y], {y, -1.5, 1.5, .025}, {x, -2., 1., .025}];]
AbsoluteTiming[Table[f1[x + I y], {y, -1.5, 1.5, .025}, {x, -2., 1., .025}];]
AbsoluteTiming[Table[f2[x + I y], {y, -1.5, 1.5, .025}, {x, -2., 1., .025}];]

The performance are shown in the table below. Measurements are made on Mathematica 12.0, Ubuntu 18.04, Intel Coffe Lake, GCC 7.4.

              Time (sec)  Speedup
Uncompiled    2.695       /
Built-in      0.060       45x
MathCompile   0.016       168x

MathCompile achieved a factor of ~170 speedup compared to the uncompiled version and a factor of ~4 speedup compared to the built-in compiler.

Which functions are compilable

Currently, over 180 functions are compilable, see this wiki page Compilable Functions for the full list. MathCompile covers most of the functions compilable by the built-in compiler and add a few more, and many more functions will be supported with the development of the package.

How does it work

MathCompile compiles a Wolfram Language function similar to the native Compile function with CompilationTarget as "C". During the compilation process, the function is first translated into C++ code; then the C++ compiler is called to compile the C++ code into a dynamic library that can be loaded into the kernel as a library function.

MathCompile package comes with a header-only library in C++ that implements all supported functions. Therefore, the generated C++ code can be called by external programs without any dependency on the Wolfram kernel or the runtime library.

You may wonder—but why C++? A short answer is that C++ is expressive enough so that the C++ compiler is able to do many things for developers (me in this case).

Consider the function f = #+2&, which can be called later by a variety of arguments: we expect f[2] to give 4 and f[3.14] to give 5.14, or f[1, 2, 3] to give 3 and f[{1, 2, 3}] to give {3, 4, 5}. If we want the function to compile in C, we have to trace every call to the function and implement that version of the function ourselves when necessary, like these:

int f_i(int x) { return x + 2; }
double f_d(double x) { return x + 2; }
double f_ddd(double x, double y, double z) { return x + 2; }
......

But in C++, this function is naturally expressed as a generic lambda

auto f = [](auto x, auto...) { return x + 2; };

where C++ compiler will instantiate the function for us automatically whenever it is called.

More information

The Guide on MathCompile wiki introduces how to use the package. It also shows how to generate the intermediate C++ code which can be used with external programs.

Performance Tests page shows the performance of MathCompile on some interesting problems.

Check out What to expect for what is going to be implemented potentially in the near future.

POSTED BY: Brian Lu
5 Replies

enter image description here -- you have earned Featured Contributor Badge enter image description here

Your exceptional post has been selected for our editorial column Staff Picks http://wolfr.am/StaffPicks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: Moderation Team

This looks really impressive! Thank you for sharing this with the WL user community, Brian. I hope to explore its functionality over the upcoming Christmas break.

I have to admit to being a bit curious as to your motivation(s) for building such a package. Are there WL projects that you really need more speed than the current internal compiler implementations can provide?

POSTED BY: Todd Allen

My motivation of working on this project is not performance but to make the process of compilation more user-friendly. For example, when I tried this in v12.0

FunctionCompile@Function[{},Range[0.0,5.0,1.5]]

I found the error message very confusing, where I assumed that it should be compilable without problem. I don't know about the progress of development on these issues, but I guess it may have been improved in v12.1.

I typically do not care too much about the performance of Mathematica, otherwise it would be easier for me write LibraryLink functions in C/C++, which almost always happens in my research actually. But it's good to see performance improvements. I feel like it is important to those who are not very familiar with lower-level languages.

POSTED BY: Brian Lu

This looks cool! Thanks for sharing!

Also saw the wll-interface project from your GitHub page. Very nice if you would take some time talk about it!

POSTED BY: Silvia Hao

Thanks, Silvia. Will do.

POSTED BY: Brian Lu
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract