Difference between revisions of "User Reference:Expression Syntax"

From BCI2000 Wiki
Jump to: navigation, search
(Built-in Functions)
Line 42: Line 42:
 
:asin, acos, atan, atan2
 
:asin, acos, atan, atan2
 
:sinh, cosh, tanh
 
:sinh, cosh, tanh
 +
Arguments and behavior of those functions agree with their implementations in the standard C library.
 +
In addition, the following functions are provided which are not present the standard C library:
 +
:<tt>bits(value, position, count)</tt> converts <tt>value</tt> to a 64 bit unsigned integer, and extracts <tt>count</tt> bits starting at bit <tt>position</tt>. Bits are counted from least to most significant, starting at zero.
 +
:<tt>bit(value, position)</tt> computes the result of <tt>bits(value, position, 1)</tt> in a slightly more efficient way.
 +
 
By deriving from the <tt>Expression</tt> class, a programmer may support additional functions from his own code.
 
By deriving from the <tt>Expression</tt> class, a programmer may support additional functions from his own code.
  

Revision as of 16:12, 18 March 2016

BCI2000 contains an expression parser that evaluates user-defined arithmetic expressions at run-time. Expression syntax tries to be intuitive and is based on C and Matlab notation.

Syntax

Empty Expression

The empty expression is a valid expression, and evaluates to 0.

"Real" Numbers

Numbers may be given as literals in decimal or scientific notation: 100, 1e2, 100.0, (1000/10) all refer to the same number. Complex numbers are not supported.

Operators

Arithmetic operators
 ^ unary- * / + -
Unlike C but consistent with Matlab, a^b evaluates to the b-th power of a.
Comparison operators
 < > <= >= == != ~=
Note that a single equals sign is not a valid operator. For the "not equal" operator, the C version (!=) is supported along with the Matlab version (~=).
Logical operators
 ! ~ && ||
Again, ! and ~ are synonymous to match both C and Matlab conventions. When mixing boolean and numerical expressions, values need to be converted back and forth between numbers and logical values. As usual, zero is treated as false, and nonzero values are treated as true. Reversely, false is converted into the number 0, and true is converted into 1. There are no literals for true and false; use 0 and 1 instead.
Condition operator
 <condition>?<if-expr>:<else-expr>
As in C, the ternary condition operator ?: allows for if-then-else-like constructs. If condition is true, the condition operator evaluates to the value of if-expr, and to the value of else-expr otherwise.
Precedence
Operator precedence follows the order of appearance in the above list. As usual, parentheses ( ) may be used to override operator precedence.

Built-in Functions

By default, expressions know a number of mathematical functions by name. These are:

sqrt
fabs, abs (alias to fabs)
fmod, mod (alias to fmod)
floor, ceil
exp, log, log10
pow
sin, cos, tan
asin, acos, atan, atan2
sinh, cosh, tanh

Arguments and behavior of those functions agree with their implementations in the standard C library. In addition, the following functions are provided which are not present the standard C library:

bits(value, position, count) converts value to a 64 bit unsigned integer, and extracts count bits starting at bit position. Bits are counted from least to most significant, starting at zero.
bit(value, position) computes the result of bits(value, position, 1) in a slightly more efficient way.

By deriving from the Expression class, a programmer may support additional functions from his own code.

Variables

Expressions support the creation of variables, and may contain statements that perform assignment, as in

MyVariable:=MyOtherVariable+10;

On the right hand side of the assignment, only existing variables may occur. On the left side, when a non-existing variable is referenced, it is created.

The scope of variables depends on the expression's evaluation context. When calling Expression::Evaluate(), a pointer to an Expression::VariableContainer may be specified by the programmer. When no such container is specified, variables cannot be used. When the container is cleared each time before an expression is evaluated, variables are local to the expression. When the same container is specified across expression evaluation, variables keep their values across multiple evaluations. When the same container is specified when evaluating multiple expressions, variables and values are shared amongst these expressions.

States

Expressions may involve state variables. These are referred to by name as in

TargetCode==ResultCode

or

(TargetCode-1)*ResultCode

When a variable exists with the same name as a state, the state takes precedence. To address states unambiguously, use

State(TargetCode)==State(ResultCode)

When assigning to state variables, always use

State(ResultCode):=3

Signal Values

Depending on context, expressions may involve signal values:

10*Signal(1,3)

Here, "Signal" refers to a filter's input signal. Consistently with configuration parameters (e.g., indices specified inside the LinearClassifier matrix), indices are one-based. Similarly, labels and physical units may be used when defined for the signal in question, e.g.

Signal( "CPz", 10ms )

will address a channel labeled "CPz", and a physical sample position 10ms from the epoch begin when defined for the signal in question. (Note: In previous versions of BCI2000 (previous to the Apr 2008 build, up to source revision 1914), expressions used zero-based indices; you may have to update your configuration accordingly when using expressions that involve signals.)

Semicolon

The semicolon may be used to concatenate multiple statements and expressions into a single expression. The expression will then evaluate to the value of the last statement or expression. Examples: The expression "4;5" evaluates to 5; the expression "x:=4; y:=3;" evaluates to 3; the expression ";" evaluates to 0; the expression "1;" evaluates to 1.

Comments

Expressions support C++-style comments. Beginning with two slashes, a comment extends to the end of a line:

Result:=PreviousTargetCode-State(TargetCode); // Compute the return value
PreviousTargetCode:=State(TargetCode); // Store the target code
Result; // Return the result

Examples

  • An expression that evaluates to the ResultCode state only if that equals the TargetCode state (i.e., in case of a successful trial):
(ResultCode==TargetCode)?ResultCode:0
  • A mapping of TargetCode values to arbitrary numbers:
(TargetCode==0)?3:(TargetCode==1)?-4:(TargetCode==2)?18:0

Caveats

  • There is no integer arithmetic. All evaluation is done in floating point, even if only integers are involved. As a result, comparisons may fail unexpectedly, or boolean conversion may always yield true:
 x^2-(3/7+4/5)*x+(4/5)*(3/7)==(x-4/5)*(x-3/7)
should be true independently of x but will always evaluate to false due to roundoff errors.
In most cases, a numerically robust reformulation of the expression should resolve the problem.
  • Sometimes, operator precedence or behavior may not match your intuition. When in doubt, use brackets:
(TargetCode^(-3))/5
rather than
TargetCode^-3/5
which is equivalent to the previous line but may be misunderstood as
TargetCode^(-3/5)