MbLan expression language

MbLan syntax

MbLan is the app's embedded expression language used for defining custom fractal types and paint modes.

For a simple fractal type or paint mode definition, you use only MbLan expressions. If you have any experience with programming, or even with spreadsheet formulas, you shoud find it easy.

For an advanced definition you use MbLan programs. MbLan syntax is based on C/Java. Do not forget to end each instruction with a semicolon ;

In addition to C/Java syntax, MbLan introduces some extensions making it easier to enter formulas using an Android keyboard.

MbLan compiler is powered by JavaCC. Those who are really interested may take a look at MbLan syntax definition file: mblan.jj.

Data types

MbLan uses the following data types:

int integer number (standard C/Java int)
double floating-point number (standard C/Java double)
complex complex number

You may refer to real and imaginary parts of a complex variable z or a complex expression (eg. z + c) as follows:

real
part
z.x
z.re
re(z)
(z + c).x
(z + c).re
re(z + c)
imaginary
part
z.y
z.im
im(z)
(z + c).y
(z + c).im
im(z + c)

You may construct complex values using complex function or complex literals as in the following examples:

complex(z.x - 1, z.y + 1)
complex(1, 0)
1.2 + 2.3e-2i
-5i

Declaring variables

You may declare helper variables at the very beginning of the Initialization code section of an advanced custom fractal type or paint mode definition. Follow the example below:

double sum, tmp4me;
int count;
complex a, a_c;
int k;

Helper variables are by default initialized to 0.

Because of the shortcut power syntax extension, variable names must not end with a digit.

MbLan expression syntax

You may use the following C/Java based syntax:

Arithmethic operators:

+ - * / %

MbLan supports arithmetic operations on complex or mixed-type arguments (except for % operator). The implicit type conversion from int to double and from double to complex is also supported. For explicit type conversion see the function reference.

Integer division by zero will give the result of 0 instead of crashing the app.

Comparison operators:

== != < <= > >=

The result of comparison is int value 0 (false) or 1 (true). When comparing complex numbers the result is 1 if both parts fulfill the condition.

No support for chaining like a == b == c.

Logical operators:

&& ||

Logical operators take int arguments (0 means false, non-zero value means true) and give int result of 0 or 1.

Unary arithmetic negation:

-

Unary logical negation:

!

Conditional expression:

cond ? true_expr : false_expr

Function call:

sin(z)
pow(z, 2.5)

Comments:

// single-line comment
/* multi-line
comment */

MbLan syntax extensions

MbLan introduces the following syntax extensions to make formulas more readable and easier to type on a mobile device.

Implicit multiplication

You may express multiplication by writing arguments with no * operator between. You may even write no space between arguments (of course not if both are variables).

Warning: implicit multiplication binds stronger than explicit one (see the last example below). More details in Operators precedence section.

example use equivalent to
a b c a * b * c
3.5zc 3.5 * zc
2z + z2 2 * z + z^2
2z + 2(z - c) 2 * z + 2 * (z - c)
(k + 1)(z - 2) (k + 1) * (z - 2)
z (-2) z * -2
a b / c d (a * b) / (c * d)

Exponentiation operator ^

Warning: exponentiation binds stronger than implicit multiplication (see the last example below). More details in Operators precedence section.

example use equivalent to
z^3 pow(z, 3)
c^0.7 pow(c, 0.7)
(a + b)^3^(k + 1) pow(a + b, pow(3, k + 1))
z^2c pow(z, 2) * c

Shortcut power

You may express exponentiation by following a base (variable only) with an exponent (positive integer literal only) with no space between. Typing ^ on a mobile device is not so easy.

This is the reason that variable names must not end with a digit.

example use equivalent to
z2 pow(z, 2)
a4 pow(a, 4)
z 4 z * 4
z-2 z - 2
(z + 1)5 (z + 1) * 5

No parenthesis unary function call

You may call unary functions without using parenthesis. This can be especially useful for chaining function calls like writing:

abs log rad z

instead of:

abs(log(rad(z)))

Warning: unary function call binds stronger than any other operation but shortcut power (see examples below). More details in Operators precedence section.

example use equivalent to
abs z abs(z)
abs sin z^2 (abs(sin(z)))^2
sin(z)^2 (sin(z))^2
log abs x y log(abs(x)) * y
sin z.x (sin(z)).x
sin 2z cos z2 sin(2) * z * cos(z^2)

Operators precedence

MbLan operators precedence in descending order (just like in C or Java plus MbLan extensions).

shortcut power z2
unary function call sin z
sin(z)
complex postfix z.x z.y z.re z.im
exponentiation ^
implicit multiplication 2z
unary operators - !
multiplicative operators * / %
additive operators + -
relational operators < <= => >
comparison operators == !=
logical AND &&
logical OR ||
conditional expression ? :

The operators associativity is like in C or Java. Exponentiation operator ^ binds right-to-left.

In case of any doubts, you may use parenthesis.

Instructions and programs

MbLan program is a sequence of instructions. Each instruction must be followed by a semicolon ;

You may also use instruction blocks { } like in C or Java.

The list of available instructions is quite short:

assignment

variable = expression;

iteration break

break;

conditional instruction

if(cond) instr else instr
if(cond) instr

The following example is iteration code for a hybrid Mandelbrot / Burning ship fractal with a custom escape condition:

if (abs(z.x) >= bailout) break;
if (n % 2) {
/* two steps of Burning ship without adding c */
    z = (abs z)^2;
    z = (abs z)^2;
}
else
/* one step of Mandelbrot */
    z = z2 + c;


The result of the above example using Stings paint mode (no smoothing defined).

Built-in variables

You may use the built-in variables listed below. Any change of value affects only the calculation for the current point.

c complex
the current point
read-only
z complex
the current orbit element value,
read-only in a paint mode definition
limit int
the iteration limit
read-only
accessible in a fractal definition
the value may vary between points when using the Detail level control as the app may adjust the iteration limit while rendering the image
i int
the current orbit element index
read-only
accessible in iteration code of a paint mode or a paint mode formula
n int
the last computed orbit element number in the fractal iteration code section
the orbit length in a paint mode definition or in the fractal finalize code section
can be written only in fractal finalize code
smooth double
the value of the smooth factor
can be written only in the finalize code section of an advanced fractal definition
always equal 1 when computing a custom paint mode for the fractal interior
exponent double
the value of the exponent used for smoothing when using the DIVERGENCE escape
accessible only in fractal definition
bailout double
the value of bailout used for the DIVERGENCE escape or the CONVERGENCE escape
accessible only in fractal definition
value double
the paint value to be mapped to the color from the palette
accessible only in the iteration and the finalize code sections of an advanced paint mode definition
start int
the index of starting element for orbit processing when computing a paint value (see Orbit based coloring section)
accessible only in a paint mode definition
can be written only in the initialization code section
pi double, read-only
Pi value
e double, read-only
natural logarithm base

Accessing orbit elements

You may refer to the orbit elements indexing built-in z variable like an array. Follow the examples listed below.

z[0] the first element
z[expr] an arbitrary element where expr is an int expression
z[n] the previous element in a fractal formula or iteration code where this is equivalent to z
z[n - 1] the element preceding a previous one in fractal formula or iteration code;
the last element in a paint mode definition or fractal finalize code
z[i] the current element in a paint mode definition where this is equivalent to z
z[i - 1] a previous element in a paint mode definition

You do not need to worry about exceeding the orbit range. You will just get 0 value in such a case (even in you use a negative index).

Function reference

The following sections describe all the functions available in MbLan with their supported arguments data types and the result data type.

MbLan supports implicit data type conversion so you may pass an int instead of a double or a double instead of a complex.

Most of the functions work like their C/Java equivalents so they are not explained in detail.

WARNING: Due to RenderScript limitations, exponentiation, logarithm and trigonometric functions work on single-precision floating-point numbers. This may cause image quality loss at a zoom of about 1e+5 or greater.

Rounding, type conversion, miscellaneous

int int(double) : int
type conversion
double double(int) : double
type conversion
complex complex(double, double) : complex
complex(x, y) = x + i y
round round(double) : double
floor floor(double) : double
ceil ceil(double) : double
abs abs(int) : int
abs(double) : double
abs(x) = |x|
sgn sgn(int) : int
sgn(double) : double
sgn(x) = (x == 0 ? 0 : (x > 0 ? 1 : -1))
min min(int, int) : int
min(double, double) : double
max max(int, int) : int
max(double, double) : double
undef undef(double) : int
undef(complex) : int
returns 1 if an argument is undefined (NaN or infinity) and 0 otherwise
for complex argument returns 1 if any of parts is undefined

Complex operations

abs abs(complex) : complex
abs(x + i y) = |x| + i |y|
rabs rabs(complex) : complex
rabs(x + i y) = |x| + i y
iabs iabs(complex) : complex
rabs(x + i y) = x + i |y|
rad rad(complex) : double
rad(z) = |z| = sqrt(z.x^2 + z.y^2)
rad2 rad2(complex) : double
rad2(z) = |z|^2 = z.x^2 + z.y^2
arg arg(complex) : double
complex number argument (value in the range of (-pi, pi])
conj conj(complex) : complex
conj(x + i y) = x - i y
flip flip(complex) : complex
flip(x + i y) = -x + i y
swap swap(complex) : complex
swap(x + i y) = y + i x
dot dot(complex, complex) : double
dot(a, b) = a.x b.x + a.y b.y
min min(complex, complex) : complex
min(a, b) = min(a.x, b.x) + i min(a.y, b.y)
max max(complex, complex) : complex
max(a, b) = max(a.x, b.x) + i max(a.y, b.y)

Exponentiation and logarithms

sqr sqr(int) : int
sqr(double) : double
sqr(complex) : complex
sqr(x) = x^2
sqrt sqrt(double) : double
sqrt(complex) : complex
square root, sqr(x) = x^0.5
pow pow(double, int) : double
pow(double, double) : double
pow(complex, int) : complex
pow(complex, double) : complex
pow(complex, complex) : complex
log log(double) : double
log(complex) : complex
natural logarithm
exp exp(double) : double
exp(complex) : complex
exp(x) = e^x

Trigonometric functions

sin sin(double) : double
sin(complex) : complex
cos cos(double) : double
cos(complex) : complex
tan tan(double) : double
tan(complex) : complex
sinh sinh(double) : double
sinh(complex) : complex
cosh cosh(double) : double
cosh(complex) : complex
tanh tanh(double) : double
tanh(complex) : complex
asin asin(double) : double
acos acos(double) : double
asin asin(double) : double
atan atan(double) : double
asinh asinh(double) : double
acosh acosh(double) : double
atanh atanh(double) : double

Special lyapstep function

lyapstep lyapstep(AB_sequence, complex, complex) : complex

The special lyapstep function is a shortcut for computing Lyapunov fractals.

Its first argument should be a sequence of A and B characters, eg.:

lyapstep(AAABB, z, c)

The following pseudo-code describes how the function works.

lyapstep(seq, z, c) {
  double r;
  if (seq[n % len(seq)] == 'B')
    r = -c.y;
  else
    r = c.x;
  double a = abs(r * (1 - 2 * z.x));
  z.y = (a > 0 ? -log(a) : 0);
  z.x = r * z.x * (1 - z.x);
  return z;
}

An example of use can be found in built-in Lyapunov fractals definitions.

Tips

Undefined values

You may get undefined (NaN or infinity) variable values (eg. as a result of double division by zero or computing a square root for a negative argument). In such a case the computing will not crash but you may get further undefined values.

When an orbit element value is undefined the escape condition will never be met and iteration will continue until iteration count limit is reached.

If a paint value is undefined it is skipped by a built-in aggregation. When using CUSTOM aggregation, a final paint value is changed to zero if it is undefined.

Warning: for simplicity, handling undefined values is not shown in a visible fixed program part of an advanced paint mode definition.

You may handle undefined values by yourself using the built-in undef function.

Optimization

MbLan compiler does not perform any code optimization. You may do it yourself by using helper variables for common intermediate results. Do not expect too much unless you have really big common expressions in your fractal definition.

Let's consider the following iteration code of root finding fractal:

z = z - (z4 + z3 - 1) / (4z3 + 3z2);

It will compute a little bit faster if you rewrite it like this:

zb = z2;
zc = zb z;
z = z - (zb2 + zc - 1) / (3zc + 3zb);

You may also use initialization code to compute intermediate values that do not depend on previous orbit value. This may give noticeable effects if there are many such calculations. An example may be found in the built-in Magnet 2 fractal definition.