-
Notifications
You must be signed in to change notification settings - Fork 27
Pragmas
Starting a line with //#pragma or #pragma allows executing compiler directives that can control various aspects of code generation and optimization.
This pragma defines the set of multivector components, that should be computed in output. Restricting the components of an output multivector may lead to good optimizations because of the fact, that computations can be omitted.
//#pragma output {m} {blade 1} {blade 2} ... {blade n}
This states, that from output multivector m, only the blades {blade 1}, ... ,{blade n} will be computed, the other blades are omitted (in some programming language they are 0).
Following example will restrict output of p to the blades e1 and e2^e0. Although there are other components of p that are non-zero, they are not computed because the user is only interested in multivector components e1 and e2^e0.
//#pragma output {p} e1 e2^e0
?p = createPoint(1,2,3);
This pragma defines a variable as an intermediate variable, which is not in the output set. Therefore only those multivector components are computed, which are required for further computations. In contrast, question mark "?" computes all multivector components (because the multivector is in the output set).
The pragma can also be abbreviated with the exclamation mark "!" before destination variable in an assignment instead of using the pragma onlyEvaluate.
The purpose of this pragma is to enhance optimization of generated code.
//#pragma onlyEvaluate {c}
c = a + b;
or more simple and shorter
!c = a + b
This states the multivector c as an intermediate variable, for which only those multivector components are computed that are required for further computations.
Let us compute in algebra cra the centre of a circle, which is given by three points:
P1 = createPoint(x1,y1);
P2 = createPoint(x2,y2);
P3 = createPoint(x3,y3);
?c = *(P1^P2^P3);
?m = c*einf*c;
Optimizing this code using GAALOP with Maxima yields (Code is abbreviated):
void CircleOfThreePoints(float x1, float x2, float x3, float y1, float y2, float y3, float c[16], float m[16]) {
c[1] = ...; // e1
c[2] = ...; // e2
c[3] = (x1 / 2.0 * y2 - x2 / 2.0 * y1) * y3 * y3 + ((-(x1 / 2.0 * y2 * y2)) + x2 / 2.0 * y1 * y1 - x1 / 2.0 * x2 * x2 + (x1 * x1) / 2.0 * x2) * y3 + x3 / 2.0 * y1 * y2 * y2 + ((-(x3 / 2.0 * y1 * y1)) + x1 / 2.0 * x3 * x3 - (x1 * x1) / 2.0 * x3) * y2 + ((x2 * x2) / 2.0 * x3 - x2 / 2.0 * x3 * x3) * y1; // einf
c[4] = ...; // e0
m[1] = (-(2.0 * c[1] * c[4])); // e1
m[2] = (-(2.0 * c[2] * c[4])); // e2
m[3] = (-(c[2] * c[2])) - c[1] * c[1]; // einf
m[4] = (-(2.0 * c[4] * c[4])); // e0
}
We can see that 4 components of c and 4 components of m are computed. But we also see, that c[3] is not used to compute m, our main interesting centre point. c[3] is a relatively long equation, and we compute it, but we do not need it.
We now exchange the question marks on line 4 with an exclamation mark:
P1 = createPoint(x1,y1);
P2 = createPoint(x2,y2);
P3 = createPoint(x3,y3);
!c = *(P1^P2^P3);
?m = c*einf*c;
Optimizing this code using GAALOP with Maxima yields (Code is abbreviated again):
void CircleOfThreePoints(float x1, float x2, float x3, float y1, float y2, float y3, float m[16]) {
float c[16] = { 0.0 };
c[1] = ...; // e1
c[2] = ...; // e2
c[4] = ...; // e0
m[1] = (-(2.0 * c[1] * c[4])); // e1
m[2] = (-(2.0 * c[2] * c[4])); // e2
m[3] = (-(c[2] * c[2])) - c[1] * c[1]; // einf
m[4] = (-(2.0 * c[4] * c[4])); // e0
}
The c[3] component disappears and the code is optimized, by simply exchanging a question mark with an exclamation mark. This minimalistic example already shows the big potential of the exclamation marks in order to get performant code.
While choosing the right multivectors to be marked with question marks "?" is relatively simple (all multivectors that should be in the output set, must be marked with a question mark, and vice versa), choosing the right amount and positions of the exclamation marks "!" is non-trivial and will result in more or less optimized code.
Setting an exclamation mark on each line makes the right-hand sides of the assignments shorter and avoids duplicate computations, but also will avoid summarizing and precomputing mathematical expressions by optimization. In contrast, setting no exclamation marks allows summarizing and precomputing mathematical expressions by optimization, but will make the right-hand sides of the assignments longer. Remove for example the exclamation mark from last code example and you will see the long expressions.
In order to generate highly-optimized code, the user must develop an experience for choosing the right positions of exclamation marks "!". A good place to set the first exclamation marks are variables, which are used multiple times later in the GAALOPScript.
This pragma allows the fixation of the order of the input variables and output variables. GAALOP's default ordering of the input and output variables is the lexicographical order.
//#pragma in2out {in 1} {in 2} {in m} -> {out 1} {out 2} {out n}
Consider the following code to compute a circle from a centre point and radius in algebra cga:
?P = createPoint(x,y,z);
?S = P - 0.5*r*r*einf;
Optimized C/C++ Code by GAALOP:
void order(float r, float x, float y, float z, float P[32], float S[32]) {
P[1] = x; // e1
P[2] = y; // e2
P[3] = z; // e3
P[4] = (z * z) / 2.0 + (y * y) / 2.0 + (x * x) / 2.0; // einf
P[5] = 1.0; // e0
S[1] = P[1]; // e1
S[2] = P[2]; // e2
S[3] = P[3]; // e3
S[4] = P[4] - (r * r) / 2.0; // einf
S[5] = 1.0; // e0
}
Now we want to define the centre point coordinates before radius in calling the function. Also we want to have the output array S before P. We use the pragma in2out:
//#pragma in2out x,y,z,r -> S,P
?P = createPoint(x,y,z);
?S = P - 0.5*r*r*einf;
Now the optimized C/C++ Code by GAALOP is:
void order(float x, float y, float z, float r, float S[32], float P[32]) {
P[1] = x; // e1
P[2] = y; // e2
P[3] = z; // e3
P[4] = (z * z) / 2.0 + (y * y) / 2.0 + (x * x) / 2.0; // einf
P[5] = 1.0; // e0
S[1] = P[1]; // e1
S[2] = P[2]; // e2
S[3] = P[3]; // e3
S[4] = P[4] - (r * r) / 2.0; // einf
S[5] = 1.0; // e0
}
Defines the range of a input scalar variable. This range is used to set the slider interval in Ganja.js visualization.
//#pragma range {min} <= {t} <= {max}
This defines, that the scalar variable t lives in interval [min,max].
Following code example in cga algebra draws a blue point p1, which can be moved three units in x-direction, and 1 unit in y-direction.
?p1 = createPoint(x,y,0);
:Blue;
:p1;
//#pragma range 0 <= x <= 3
//#pragma range 1 <= y <= 2
This pragma only works when using Ganja Code Generator.
Draws line segments from 2 points given as multivectors. The colour of each segment (spanned by the 2 multivectors Ax Bx) is equal to its first point, respectively.
//#pragma segments A1 B1, A2 B2, ... , An Bn
Following code example in cga algebra draws two line segments: p1-p2 and p2-p3
?p1 = createPoint(0,0,0);
?p2 = createPoint(1,1,0);
?p3 = createPoint(0.5,0.5,1.5);
:Blue;
:p1;
:p2;
:Green;
:p3;
//#pragma segments p1 p2, p2 p3
This pragma only works when using Ganja Code Generator.
Draws triangles from 3 points given as multivectors. The colour of each triangle (spanned by the 3 multivectors Ax Bx Cx) is equal to its first point, respectively.
//#pragma triangles A1 B1 C1, A2 B2 C2, ... , An Bn Cn
Following code example in cga algebra draws a tetrahedron.
?p1 = createPoint(0,0,0);
?p2 = createPoint(1,0,0);
?p3 = createPoint(0.5,1,0);
?p4 = createPoint(0.5,0.5,1.5);
:Blue;
:p1;
:p2;
:p3;
:Green;
:p4;
//#pragma triangles p1 p2 p3, p4 p1 p2, p4 p1 p3, p4 p2 p3
This pragma only works when using Ganja Code Generator.
This pragma will normalize the next output vector, i.e. the length of the vector will be one.
#pragma normalize
?output = 1.0 * e1 + 1.0 * e2
With normalize, the output vector will be approximately 0.7071 * e1 + 0.7071 * e2 instead of 1.0 * e1 + 1.0 * e2.
This pragma allows the generated function to return an object of the given class instead of an array or tuple.
#pragma return VARIABLE typed RETURNTYPE as RETURNOBJECT
- VARIABLE: The name(s) of the Gaalop variable(s) that shall be returned as object. In case of multiple variables, separate them with commas (... return line1, line2 typed ...)
- RETURNTYPE: The return type in the method declaration. This must be stated although untyped languages do not require it.
- RETURNOBJECT: This text will be inserted at the method's return. Components can be stated in the format <component>, e.g. <e1> or <e1e2>.
#pragma return line typed Line as Line(<e1>, <e2>)
?line = e1 + e2
This will generate the following code:
from typing import Tuple
def return_line_test() -> Tuple[Line]:
line_e1 = 1.0
line_e2 = 1.0
return Line(line_e1, line_e2);
This pragma currently only works in C# and Python code generator. Additionally, the Checkbox "useArrays" must be disabled in language configuration.
This pragma will insert the text afterwards at the beginning of the generated code file. This can be very useful together with pragma return.
#pragma insert from line import Line
This will add the following text at the code file beginning.
from line import Line