Cellular automata, WinCA application III
In this article, third of the series, I continue to explain the operation of the WinCA application, devoted to the construction and execution of cellular automata. This time I will show the language used to define the transitions between the different states of the automaton cells.
Here you can find the first article of the series about WinCA application.
In this link you can download the WinCA application executables, and in this other one you can download the source code of the WinCA solution, written in CSharp with Visual Studio 2015.
In cellular automata, cells can change from one state to another, depending on different conditions, usually related to the properties of the current cell and neighboring cells. WinCA application uses a language with which you can define the expressions that determine the change from a state to any other.
Language definition
Numbers and text strings
You can use numbers, which can have decimals, separated by the decimal point character (.). You can use also strings of constant text, enclosing them between double quotation marks ("). To use a double quote character within the text constant, you must precede it with the escape character (\).
Property and variable references
The expression language is designed to use state properties and variables defined with the property editor. To refer to a property of the state of the current cell, you have to use its name preceded by the backslash character (\), and, to refer to a variable, you have to use also its name preceded by the underscore character (_). If you want to get the result with a certain type of data, you can add, after the name, the colon character (:) followed by the type name (int, double, bool, string), for example:
\Alive:bool
Indicates the value of the Alive property of the current state of the cell with the type forced to Boolean.
The properties that are most interesting are those of the cells neighboring the current one. To refer to one of the neighbor cells in particular, you have to use the index of it (which is indicated in the automata editor), enclosed in square brackets ([]), separated from the name of the property by a period (.), for example:
[1].\Alive
It refers to the Alive property of the neighbor with the index 1. Instead of the number one you can also use an arithmetic expression, as we will see later.
Some functions perform an aggregate of the properties of all neighbor cells, a counting, for example. In these functions you must use the name of the property preceded by the semicolon character (;), for example:
;\Alive
Be careful not forgetting to use the semicolon character (;) since in an aggregate function it is also allowed to use the reference to the properties of the current cell, which must be referenced without using this character.
Boolean expressions
The expression to change from one state to another must be a Boolean expression. If this expression evaluates to true, the transition between states is fired, otherwise the cell remains in its current state. Each expression defines the conditions of the transition from a given state to another single one. For each state, there may be as many expressions as remaining states, although it is not mandatory to define transitions between all states.
Boolean expressions of state change can use the operators | (or), & (and) and ! (not) to bind subexpressions. The precedence of operators is: first !, then & and, lastly |. You can modify the precedence by enclosing a subexpression between braces ({ and }).
The operands must also have a Boolean value. The simplest are the constants $t (true) and $f (false).
You can use the ist() and isf() functions to evaluate whether the value of a property or variable is true or false, respectively. These functions should be used instead of the property directly, for example:
ist(\Alive)
Checks whether the value of the Alive property of the current cell is true. If the property is not of Boolean type, a conversion is automatically performed (numeric values other than zero are true, and non-empty text strings are also true).
There are functions that work with text strings, returning Boolean values that can also be used as operands in a Boolean expression. All of them use two arguments, arg1 and arg2, which must be text strings and can be constant strings, expressions that return a text string, which we will see later, or references to properties or variables. They are the following:
- cont(arg1, arg2): Returns true if arg1 contains the text string arg2.
- stw(arg1, arg2): Returns true if arg1 starts with the text string arg2.
- endw(arg1, arg2): Returns true if arg1 ends with the text string arg2.
- match(arg1, arg2): Returns true if arg1 matches to the regular expression passed in arg2.
- streq(arg1, arg2): Returns true if arg1 and arg2 are equal. It is not case-sensitive.
- streqcs(arg1, arg2): Returns true if arg1 and arg2 are equal. Case sensitive.
There are also two Boolean functions to perform operations with all neighbor cells of the current one. They are band() and bor(), which evaluate the Boolean expression passed as argument in all neighboring cells and return the result of applying the Boolean operations and or or to the results. For example:
band(;\Alive)
Returns a Boolean AND operation of the value of the Alive property of all neighbor cells (do not forget the semicolon (;), or the function will only process the current cell).
Finally, you can use also relational expressions as operands.
Relational expressions
There are expressions that compare two arithmetic expressions, using the operators << (less), <= (less than or equal), == (equal), >= (greater than or equal), >> (greater) and <> (different). For example:
icount(;\Alive) >> 3
Returns true if there are more than three neighbors of the current cell with value true in the Alive property.
Arithmetic expressions
The operands of the arithmetic expressions are numerical values of type int or double. If references to properties or variables are used, the corresponding conversion is performed. The operators that can be used are, from least to highest precedence order: - (difference), + (sum), @ (binary or), # (binary xor), * (product), / (quotient), % (integer module), ? (binary and), ^ (exponentiation) and - (unary minus).
You can use parentheses to enclose subexpressions and change the precedence of operators.
In addition to the numbers, there are the following constants that can be used as operands: $e (the number e), $pi (the number pi), and the pseudo-constants $runi (a random value between 0 and 1, with uniform distribution) and $rnorm (a random value, with normal distribution, with mean 0 and standard deviation 1).
There are functions that return an integer value and accept as a parameter an arithmetic expression. They are the following:
- int(arg): Converts the value of the argument to an integer.
- isign(arg): Returns the sign of the argument, -1 for negative values and 1 for positive values.
- ifloor(arg): Returns the largest integer that is smaller than the argument.
- iceil(arg): Returns the smallest integer that is greater than the argument.
- iabs(arg): Returns the absolute value of the rounded argument to an integer.
- red(arg), green(arg), blue(arg): They return the red, green or blue component of the argument, which is converted to Color.
Other functions perform aggregates of the properties of neighboring cells and return an integer value. All, except icount, whose argument is a Boolean expression, accept an argument which is an arithmetic expression. They are the following:
- icount(arg): Returns the account of the neighbors in which the Boolean expression passed as parameter is true.
- isum(arg): Returns the sum of the expression values for all neighboring cells.
- iprod(arg): Returns the product of the expression values for all neighboring cells.
- imax(arg): Returns the maximum value of the expression for all neighboring cells.
- imin(arg): Returns the minimum expression value for all neighboring cells.
- iavg(arg): Returns the arithmetic mean of the expression for all neighboring cells.
Finally, there are two functions that operate with two arguments of type text string and return an integer, they are cmp(arg1, arg2), which compares the text string arg1 with arg2 and returns -1 if arg1 < arg2, 0 if they are equal and 1 if arg1 > arg2, and pos(arg1, arg2), which returns the position of the text string arg2 within arg1, or -1 if it does not contain it. 0 is the first position.
Regarding functions that return a result of type double, the following have a single argument that is an arithmetic expression:
- double(arg): Converts the argument to a value of type double.
- dsign(arg): Returns the sign of the argument, -1 or 1, as in the version for integers.
- ln(arg), log(arg), log2(arg): Natural, base 10 and base 2 logarithm of arg.
- sqrt(arg): Square root of arg.
- exp(arg): Returns the number e raised to arg.
- dfloor(arg): Greater integer that is less than arg.
- dceil(arg): The smaller integer greater than arg.
- sin(arg), sinh(arg): Sine and hyperbolic sine of arg.
- cos(arg), cosh(arg): Cosine and hyperbolic cosine of arg.
- tan(arg), tanh(arg): Tangent and hyperbolic tangent of arg.
- dabs(arg): Absolute value of arg.
- hue(arg), sat(arg), bri(arg): Force arg to type Color and return the hue, saturation and brightness respectively.
There are also aggregate functions with double return type that process all the neighbors of the current cell:
- dsum(arg): Add the results of applying arg to all neighboring cells.
- dprod(arg): Product of applying arg to all neighboring cells.
- dmax(arg), dmin(arg): Maximum and minimum values when applying arg to neighboring cells.
- var(arg), svar(arg): Variance and sample variance of the results of applying arg to all neighboring cells.
- sd(arg), ssd(arg): Standard deviation and sample standard deviation of the results of applying arg to all neighboring cells.
- davg(arg): Arithmetic mean of the results of applying arg to all neighboring cells.
The dcount(arg) function takes a Boolean expression as a parameter, and returns how many of the neighbors make it true, as a value of type double.
To work with text strings, returning as a result another text string, you can use the function strc(arg1, arg2), which returns the concatenation of arg1 and arg2, which must be expressions or constants of type text; subs(arg1, arg2, arg3) returns the substring of the text string arg1, starting at the position indicated with arg2 with length arg3, which are both arithmetic expressions. The repl(arg1, arg2, arg3) function returns the text string arg1 with the occurrences of the text string arg2 replaced by arg3.
Transitions editor
In order to view the transitions editor, you can open the Conway's game of life cellular automaton in the Life-game.cauto file, in the Examples directory. Click the last button on the upper toolbar to display the different editors, and select Transitions from the Window menu. You will see a form like this:
In the upper left corner is an array in which all possible combinations of two states are shown. The gray boxes are the combinations of a state with itself, which cannot have transitions between them, white boxes are undefined transitions between states, and boxes with two green arrows are defined transitions between states which have an expression. To select any transition between two states, double-click with the mouse on the corresponding box.
Below this matrix, there is the tree control that shows all the states in the first level and all their defined transitions in the second level. You can also edit a transition by selecting the final state in this list.
On the right is the expression editor. Once the expression is written, you can check the syntax by compiling it with the first button on the toolbar just above the text editor. If all is correct, the remaining two buttons will be activated. With the last button you can see the compilation messages, although I warn you that they are quite cryptic, as I use them to debug the expressions system.
The second button on this toolbar can be used to test the expression:
On the left side there is a toolbar where you must select a state for the current cell. In the toolbar below it, you can select states for neighbors. It is necessary to select the state of at least one neighbor. Each time you select a status for a neighbor, a new drop-down list is displayed so you can add another neighbor. You can delete the last neighbor with the delete button, at the end of the toolbar.
On the right side is the expression, which you can break down into its components by unfolding them in the tree. When selecting the element, you can see the result of the corresponding subexpression in the text box on the left. In this dialog you cannot modify the expression, you have to close, modify and recompile it to make changes.
And that's all for the moment. In the following article I will comment on the source code of the states properties.