Gedae Idea Language Reference
Updated May 2012
Algebraic Expressions
Variables can be declared with an expression that sets their value.
- C = 2 * PI * R;
Data Types
The following data types are supported: float, double, complex, and dcomplex (double complex), char, short, int, INT (32 bit on 32 bit OS, 64 on 64), dint (64 bit), unsigned char, unsigned short, unsigned int, unsigned INT, unsigned dint.
When declaring a variable, the data type can be declared.
When declaring a variable, the data type can be left off and inferred from the expression that sets it.
If a variable is typed, the result of the expression is cast to the data type.
Ranges
Ranges are positive finite values.
- range i = 10;
All ranges can be used in expressions.
Dimensions
There are three dimension types:
- Families – preindices using square braces, for example, [f]x
- Arrays – postindices using square braces, for example, x[r][c]
- Time – postindices using parentheses, for example, x(t)
On the LHS of equations, dimensions can be expressed only as simple expressions (that is, single range variables).
If a variable is declared without the stream modifier or a time index and its expression does not include any streams, then it is a parameter. Parameters do not have a rate and cannot be dereferenced by a time index. Parameters can be declared without an expression to set their value.
- x = 1; // parameter
- int y; // unset parameter
- z = x + y; // parameter
If a variable is declared with the stream modifier or a time index, then it is a stream. If a variable’s expression includes a stream, then it is a stream. All streams are infinite. All streams must be declared with an expression to set their value.
- stream x = 1; // stream
- y = x; // stream
On the RHS of equations, dimensions can be any expression.
Operators
All C binary operators are supported.
The C unary operators ! and ~ are supported.
The C tertiary operator ?: is supported.
The # operator is a unary operator that returns the size of the range.
The ` operator is a binary operator for expressing powers.
A collapsing operator performs an operator across a dimension.
- Sum += M[i][j]; // matrix sum
- Dot += X[i] * Y[i]; // dot product
- Prod += M[i][j] * N[j][k]; // matrix multiply
- Dil[i][j] ||= Im[i+i1][j+j1]; // dilution image kernel
The dimension(s) of a collapsing operator are all ranges that appear in the RHS of the expression that do not appear on the LHS. If an index appears on the RHS and not the LHS, then the assignment operator must be a collapsing operator.
- range i = 10;
- a[i] = i;
- x = a[i]; // illegal
The following collapsing operators are provided.
Function | Description | Initialization |
---|---|---|
+= | Increment and assign | 0 |
-= | Decrement and assign | 0 |
*= | Multiply and assign | 1 |
/= | Divide and assign | 1 |
&= | Bitwise AND and assign | |
^= | Bitwise exclusive OR and assign | 0 |
|= | Bitwise inclusive OR and assign | 0 |
&&= | AND and assign | 1 |
||= | Inclusive OR and assign | 0 |
^^= | Exclusive OR and assign | 0 |
>?= | Maximum and assign | Lowest negative number |
<?= | Minimum and assign | Highest positive number |
Functions
Expressions can be grouped together into functions. Functions can have any number of outputs and any number of inputs, including zero. Function outputs are not typed. The type is determined from the expressions that set the output.
- Y foo(float X) {
- Y = (X+1)/2; // implicitly declared as float
- }
Invocation
Functions can be invoked in expressions.
- X = 2;
- Y = foo(1);
- Z = Y + foo(X);
All inputs from the function’s argument list must be specified in the invocation.
If a multiple output function with N outputs is used, then up to N variables can be listed on the LHS. If M<N variables are listed, then the first M return values are used. When a multiple output function is used in an expression, only the first output is used.
- Y,Z bar(float X) {
- Y = (X+1)/2;
- Z = (X-1)/2;
- }
- ...
- Y = bar(1)+1; // sets Y to 2
- Y2, Z2 = bar(Y); // sets Y2 to 1 and Z2 to 0
Overloading
Functions can be used for both parameters and streams.
- Y foo(float X) {
- Y = (X+1)/2;
- }
- ...
- int x = 2;
- p = foo(x); // parameter
- stream float y = x;
- s = foo(y); // stream
Implementation
Functions can be implemented by expressions or by kernels. Kernels use the Equation Field to define the expression or function that they implement. If a kernel equation defines a function, then the family and token dimensions of the outputs must be specified.
- Name: mf_qr
- Equation: q[i][j], r[j][k] = qr(in);
Data Structures
Data structures allow tokens to be organized into a single container and referenced by field name.
Definitions
The C struct syntax is used to define a structure.
- struct cart {
- float x;
- float y;
- float z;
- }
The data type of each element is defined in the structure definition. Fields cannot be arrays, but arrays of structures can be created.
Constructor
A data structure is constructed by providing an array of values.
- float x = 2.9;
- cart pnt = {x, 3.0, -1.3}; // parameter
Expressions can be used inside the constructor, but the constructor cannot be used inside expressions.
Structures can contain all streams or all parameters.
Reference
The C . (period) infix operator is used in expressions to reference the fields in a structure.
- out cartDistance(cart in) {
- out = sqrt(in.x`2 + in.y`2 + in.z`2);
- }
Data Flow
The introduction of time into a programming language offers a new method of program structure and introduces issues with data flow that must be considered.
Static Rates
The relationship between rates of different streams is determined by their use in expressions. Expressions can be written with relative time indices, stating the number of tokens relative to the current time. When using relative time indices, decreases in rate can be accomplished by referencing multiple tokens at or ahead of the 0 index. Delay and overlap can be accomplished by referencing negative time indices.
- range i = 10;
- a = a(-1)+1;
- b2 = (a + a(1))/2; // decimation by 2 by averaging
- c = b(-1); // delay by 1
- c2 = b + b(-1); // overlap of size 1
- d(i) = c; // hold for 10 samples
The combination of static rates must follow data flow rules. Multiple static rates on the same stream cannot be used in the same construct. The verification of static rates is done by the data flow graph (DFG) compiler.
Tiling
Relative time indices can also be used to specify tiling operations and the interpolation and decimation needed to perform this token decomposition. The interpolation from creating tiles from a matrix can be expressed using arithmetic on smaller ranges. The decimation from reconstituting a larger array from tiles can be expressed using the % and / operators on the ranges. Alternatively, the comma notation can be used.
- range t = inf;
- range i = 10; // matrix size
- range j = 10;
- range i1 = 5; // tile size
- range i2 = 2;
- a[i][j](t) = i+10*j;
- b[i2][j](i1) = a[i1*#i2+i2][j]; // create tiles
- c[i2][j] = foo(b[i2][j]);
- d[i][j] = c[i/#i1][j](i%#i1); // reform matrix
Dynamic Rates
Dynamic ranges can create dynamic rates. The combination of dynamic rates must follow data flow rules. Streams of different rates cannot be used in the same expression. The verification of dynamic rates is done by the DFG compiler.
- range r = 10;
- a[r] = r;
- b(r) = a[r];
- d[r] = b + a[r]; // illegal combination of rates
Conditionals
Conditionals can be used to set values based on a parameter or stream value. They can also be used to reduce data rate.
If Statement
The C syntax is used for an if statement.
An if statement can introduce a dynamic stream.
- Threshold = 0;
- if (a > Threshold)
- b = a; // b is a slower rate than a
An if statement with else if and/or else clauses can be used to perform a select.
- Threshold = 0;
- if (a > Threshold)
- b = a;
- else
- b = Threshold; // b is at the same rate as a
An if statement with else if and/or else clauses can be used to perform branching,
- if (c == 0)
- x = foo(a);
- else
- y = bar(a);
A complete branch and merge where for each input token, a token is produced on the output stream,
- if (c == 0)
- b = foo(a);
- else
- b = bar(a); // b is at the same rate as a
And an incomplete branch and merge where some branches do not produce tokens on the stream,
- if (c == 0)
- b = foo(a);
- else if (c == 1)
- b = bar(a); // b is not produced if c is not 0 or 1
Note a is consumed regardless of the condition. A token must be available on a regardless of the value of c, and that token is consumed regardless of the value of c.
Switch Statement
The C syntax for a switch statement is used with the change that each case statement is assumed to end in a break. Any overlap in case statements can be implemented by duplicating code in each case. As in C, the switch statement does not require a default clause, and thus it can introduce dynamic streams.
- switch (c) {
- case 0: e=c+1; d = a;
- case 1: e=c+1; d = b;
- default: d = 0;
- }
Iteration
Loops are used to iterate on tokens, i.e., all tokens are held during the duration of the loop. Loops must iterate on at least one token.
A for, while, or do-while loop specifies iteration. For for loops, the C syntax is used. For while and do-while loops, the syntax is very similar to the C syntax.
For Loop
Variables created by the for loop, called iteration variables, are initialized in the initialization section of the for construct. If these iteration variables are used on the RHS of expressions in the body of the loop, the variable refers to the current value of the token, not the new value computed during the current iteration.
- for (c=1.0, k=0; k k=k+1) {
- c = c * exp(-1); // iteration on held token
- }
The new value of the token can be reused inside the body of the loop by using an intermediate variable inside the loop. Intermediate variables are variables defined inside the body of the loop.
- for (c=1.0, d=1.0, k=0; k<10; k=k+1) {
- temp = c * exp(-1); // intermediate variable for “new” c
- c = temp;
- d = d + temp;
- }
While Loop
While loops and do-while loops are also supported, but their syntax differs from the C syntax by adding a section to initialize iteration variables. This initialization section makes the syntax very similar to for loops.
- while (c=1.0; c>0.1) {
- c = c * exp(-1); // iteration on held token
- }
- do (d=c) {
- d = d * exp(1);
- } while (d<1.0);
State Reset
Conditionals and loops all include the resetting of state. Iteration constructs reset state at the beginning of the loop. Conditional constructs reset state when the branch changes.
The following example implements a conditional low pass filter. The low pass filter uses a delay to store the previous tokens. This state is reset whenever valid(-1) == 0 and valid == 1.
- if (valid) {
- y = y(-1) + alpha * ( x – y(-1) );
- }
State variables can be used in the data flow graph language to retain information across conditional or loop boundaries.
Return to the LEARN main page.