14 April 2014 by Remco Bouckaert

If you want to log say a simple function of a parameter or set of parameters, programming a logger in Java is often overkill. A much simpler way is to use some of the scripting functionality that in BEAST. There are a number of options;

`RPNCalculator`which takes expressions in reverse polish notation

`ExpParser`in the

`MASTER?`package, you can use which takes arithmetic expressions

`Script`in the

`BEASTLabs`package, you can use complex arithmetic expressions as well as functions

## RPNCalculator

`RPNCalculator` is the simplest and most primitive of the lot. It takes as input a set of `Function`s and an expression in reverse Polish notation (RPN). RPN is stack based, and takes arguments first, and whenever an operator is pushed on the stack, it uses the top most positions to execute the operator. So “2 3 +” returns 5, “2 2 2 / /” return 0.5 as does “2 2 2 * /”. Variable names are resolved by the IDs of the arguments. Below, a complete XML fragment

## ExpCalculator

`ExpCalculator` can be found in the `feast` package and allows simple expressions to used as a `Function`. For example, to calculate the Eucledian distance to the point (20,50), you could use the following:

20 50

There is also a `ExpCalculatorDistribution` that you can use as a distribution where you can specify an expression to represent to log-density of the distribution. For example — ignoring constants — a normal distribtion could be specified like so:

which can be used in for example the prior. For more information, see the `feast` package.

## Script

To use `Script` you need to install the `BEASTLab` package (see the BEAST website for how to install packages).

With `beast.util.Script` you can now run complex mathematical expressions like

3 * sin(a[0]) + log(a[1]) * b

where `a` is a `Function` with 2 dimensions and `b` a single values `Function`. Parameters and Distributions are `Function`s, so you can use these for your expressions. Since `Script` is also a `Function` you can use the result of a `Script` in another `Script`.

Script has an input named `x`, and every `Function` and the variable names in the expression must match the ID of the input-value. A complete XML fragment for logging the above expression with two parameters `a` and `b` could look something like this:

1.0 2.0 3.0

With `Script`, you can define complex and recursive functions, for example factorial, like so:

function fac(x) { if (x <= 1) {return 1;} return x * fac(x-1); } function f(a) {return fac(a);}

Note that if you specify a scripts instead of an expression, the engine always

calls function `f` with arguments of the inputs `x` in order of appearance. The function specification goes as text inside the element, unlike an expression, which goes inside the `expression` attribute. An XML fragment logging the factorial of parameter `a` could look something like this:

5.0 function fac(x) { if (x <= 1) {return 1;} return x * fac(x-1); } function f(a) {return fac(a);}

Note that because the text is XML, any XML character (especially '<' and '&') need to be escaped. The <= in the above script must replaced by <=. To prevent this, you can wrap the text in a CDATA block, of which the content is not interpreted as XML but taken as is.

5.0

### Script syntax

By default, the `Script` uses `JavaScript` syntax for coding expressions and functions. For expressions, the `Math` scope is used, so any Math-function is available, so the following functions are available: `abs(), acos(), asin(), atan(), atan2(), ceil(), cos(), exp(), floor(), log(), max(), min(), pow(), random(), round(), sin(), sqrt(), tan()`. A disadvantage is that debugging is awkward to put it mildly. If it does not compile, the ScriptEngine does not offer much clues to where things go wrong.

You can specify other script engines by setting the `engine` attribute to one of `JavaScript, python, jruby,` or `groovy` and provided the script engine is available in your class path, you can use other syntax for specifying a script (though not for expressions). For example, to use python, you need to include jython in the class path, and set `engine='python'` on the Script element. A factorial logger could be done like this in python:

So far, these scripts are rather simple, and can effectively only useable for logging of advanced information. In a later blog, we will look how to use scripts in other situations. But for now happy scripting!