Skip to content
dustin2711 edited this page Aug 3, 2024 · 9 revisions

Starting a line with //#pragma or #pragma allows executing compiler directives that can control various aspects of code generation and optimization.

Code generator pragmas

Pragma output

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.

Syntax

//#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).

Example

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);

Pragma onlyEvaluate

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.

Syntax

//#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.

Example

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.

Keep in mind

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.

Pragma in2out

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.

Syntax

//#pragma in2out {in 1} {in 2} {in m} -> {out 1} {out 2} {out n}

Example

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
}

Graphical output pragmas

Pragma Range

Defines the range of a input scalar variable. This range is used to set the slider interval in Ganja.js visualization.

Syntax

//#pragma range {min} <= {t} <= {max}

This defines, that the scalar variable t lives in interval [min,max].

Example

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

Note

This pragma only works when using Ganja Code Generator.

Pragma segments

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.

Syntax

//#pragma segments A1 B1, A2 B2, ... , An Bn

Example

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

Notes

This pragma only works when using Ganja Code Generator.

Pragma triangles

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.

Syntax

//#pragma triangles A1 B1 C1, A2 B2 C2, ... , An Bn Cn

Example

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

Notes

This pragma only works when using Ganja Code Generator.

Pragma normalize

This pragma will normalize the next output vector, i.e. the length of the vector will be one.

Example

#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.

Pragma return

This pragma allows the generated function to return an object of the given class instead of an array or tuple.

Syntax

#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>.

Example

#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);

Note

This pragma currently only works in C# and Python code generator. Additionally, the Checkbox "useArrays" must be disabled in language configuration.

Pragma insert

This pragma will insert the text afterwards at the beginning of the generated code file. This can be very useful together with pragma return.

Example

#pragma insert from line import Line

This will add the following text at the code file beginning.

from line import Line