This repository contains code to work with multivector expressions of geometric algebra. The idea is to realise a complete toolchain with a geometric algebra specific domain specific language based on truffle/graal with state of the art smart editing features, debugging functionality and a fast implementation based on JCasADi.
The project is in an early state of development, so it is not yet advised to use it in real world applications. If you have feedback or feature suggestions, please create a new GitHub Issue.
Download the GraalVM 22.3.2 (Linux (amd64), Java17).
Extract the downloaded archive to an arbitrary location.
Add a new java platform with the name "GraalVM".
Within the Netbeans 17 IDE you can do this if you follow these steps:
- open project properties via right-click on the project
- navigate to Build / Compile
- click "Manage Java Platforms..."
or navigate to this point via the Tools main menu.
- click "Add Platform..."
- In the poping-up wizard:
- select platform type "Java Standard Edition"
- choose the platform folder within the extracted archive.
- name it "GraalVM"
- open project properties via right-click on the project
- navigate to Build / Compile
- in the drop-down list labeled "Java Platform" choose "GraalVM"
To update the GraalVM, navigate into the parent directory of your GraalVM installation and execute the following (customized) command:
./<foldername of your GraalVM installation>/bin/gu upgrade
A separate directory for the new installation will be created.
Next, you need to redo the Netbeans configuration.
If you are the first collaborator updating to a new version, you also need to
- update the
graalvm.version
property in the pom.xml of the DSL4GA_Impl_Truffle subproject. - update the download link in this documentation.
The project depends on the vecmath library in the refactored version of the JogAmp Community. Your can find this library here. Unfortunately there is no maven repository available. That is why you need to download the jar file manually and add it as a local depency of the project. To do this in the nebeans ide: Right-click on the depencies of the project and add the dependency manually. The group id is "org.jogamp.java3d", the artifactId is "vecmath" and the type is "jar".
Alternatively clone it from GitHub, update the compiler version in it's pom.xml and build it.
Clone and checkout
and build those projects to have them available in your local Maven cache. SparseMatrix is a simple Java sparse matrix implementation used primarily as interface between the annotation based Java API and the DSL. So it allows to write code independend from GA-specific objects. CGACasADi is a fast symbolic implementation of CGA based on CasADI. A Java-Wrapper for CasADI based on Swig is used for Java integration.
In order to run the example invokation in the package 'de.dhbw.rahmlab.geomalgelang.App' make sure you successfully executed the steps GraalVM Setup and Dependencies Setup beforehand.
If you use an IDE other than Netbeans and execute the generated .class files directly rather than the generated .jar file, it might be necessary to configure the Maven execution in your IDE with the same properties set in the nbactions.xml file.
An annotation based API useful espcially for testing is available.
A Syntax-Highlighting plugin for the Netbeans-IDE can be found here.
A Netbeans-IDE plugin which adds a submenu into the context-menu of the editor to insert CGA-specific symbols and operators can be found here.
CGA multivectors and objecs of its subtypes are completely hidden - not visible outside the DSL. Input data to and output data from the DSL is transfered by objects of the classes listed in the following table:
Name | implementation class | hints |
---|---|---|
double | Double | |
Tuple3d | org.jogamp.vecmath.Tuple3d | |
Quat4d | org.jogamp.vecmath.Quat4d | |
DualQuat4d | de.orat.math.vecmath.ext.DualQuat4d | |
DualNumber | de.orat.math.vecmath.ext.DualNumber | |
ComplexNumber | de.orat.math.vecmath.ext.ComplexNumber |
Inside the DSL all of these types are automatically casted into CGA multivectors. No other operations are possible based on these types inside the DSL.
- Numeric literals like "0.5" and scalar constants like "π" are in OPNS representation.
- There needs to be at least one function defined with the name
main
. Invokations of the program will call this one first. - Currently, callees need to be defined above the callers.
- In consequence,
main
needs to be the last function defined. - A function will return only the list in the last line of its definition.
- The return value of a call needs to be assigned to a variable.
- An assignment to multiple variables in the same line is possible if the right side consists only of a call.
- The count of the assigned variables must match the count of the result values of a call.
- With an assignment to "_", a return value can be discarded. This is only possible for calls which return at least two values.
- If the right side of an assignment is not only a call but a composed expression, within it are only calls allowed which return exactly one value.
Custom functions can be defined like in the following example:
fn test(a) {
a, 5
}
fn main(a, b) {
_, c := test(b)
a, b, c
}
Variables can be visualized after assignment with a preceding colon. For correct visualization, make sure that the variable is in IPNS representation.
In the following example, the variable b will be visualized:
fn main(a) {
:b := a
}
Hint: Operator precedence determines how operators are parsed concerning each other. A higher precedence number results in a higher binding strength. Thus operators with higher precedence become the operands of operators with lower precedence.
Exceptions from the precedence rules:
- Expressions like
a-b
evaluate tosubtraction(a, b)
instead ofgeometric_product(a, negate(b))
.
Hint: The Unicode and Latex name for the symbol used for left contraction is "RIGHT FLOOR" and for right contraction is "LEFT FLOOR". Please be cautious to this detail when writing Latex or programming tools which work with the language.
precedence | symbol | latex | unicode | name | implementation | hints |
---|---|---|---|---|---|---|
4 | \u0020 | geometric product | multivector1.gp(multivector2) | Zero or more space characters are interpreted as the operator. | ||
3 | ∧ | \wedge | \u2227 | outer product (join, span for no common subspace) | multivector1.op(multivector2), not used for double, for tuple3d it makes sense but actually no implementation is available | joining linearily independend vectors/two disjoint subspaces |
1 | + | + | \u002B | addition | multivector1.add(multivector2) | |
1 | - | - | \u002D | subtraction | multivector1.sub(multivector2) | |
3 | ⌋ | \rfloor | \u230B | left contraction | multivetor1.ip(multivector2, LEFT_CONTRACTION) | |
3 | ⌊ | \lfloor | \u230A | right contraction | multivector1.ip(multivector1, RIGHT_CONTRACTION); where the grade operator for negative grades is zero. This implies that something of higher grade cannot be contracted onto something of lower grade . |
|
3 | ∨ | \vee | \u2228 | regressive product (meet if intersected) | multivector1.vee(multivector2) or (multivector1* ∧ multivector2*)* | |
2 | / | / | \u002F | division (inverse geometric product) | multivector1.div(multivector2) |
precedence | symbol | latex | unicode | description | implementation | CLUscript |
---|---|---|---|---|---|---|
3 | ⋅ | \cdot | \u22C5 | inner product | multivector1.ip(multivector2, RIGHT_CONTRACTION) | Decreasing dimensions or contracting a subspace. In the default configuration equal to left contraction (corresponding to Ganja.js). But this looks to be incompatible with some formulas in [Kleppe], which work only with the usage of right contraction. In CLUscript this corresponds to ".". |
3 | ∩ | \cap | \u2229 | meet (intersection) = largest common subspace | multivector1.meet(multivector2) | & |
3 | ∪ | \cup | \u222A | join (union) of two subspaces is there smallest superspace = smallest space containing them both | multivector1.join(multivector2) or multivector2* ⋅ multivector1 or (multivector2* ∧ multivector1*)* | | |
All 1-ary operators have higher precedence than 2-ary ones.
All 1-ary operators are right-sides except from the negate operator '-'.
Except dual/undual the operators cancel itself so if your write X˜˜ no reverse is executed.
precedence | symbol | latex | unicode | description | implementation | CLUscript |
---|---|---|---|---|---|---|
5 | - | - | \u002D | negate | (-1 cast to multivector).gp(multivector) | - |
6 | ⁻¹ | \textsuperscript{-1} | \u207B\u00B9 | general inverse | multivector.generalInverse() | ! |
6 | * | \textsuperscript{*} | \u002A | dual | multivector.dual() | |
6 | ˜ | \textsuperscript{$\tilde$} | \u02DC | reverse/adjoint: reverse all multiplications (a sign change operation) | multivector.reverse() | ˜ |
6 | † | \textsuperscript{\textdagger} | \u2020 | clifford conjugate (a sign change operation) | multivector.conjugate() |
There exist three types of involution operations: Space inversion, reversion and the combination of both the clifford conjugation.
precedence | symbol | latex | unicode | description | implementation |
---|---|---|---|---|---|
6 | ⁻* | \textsuperscript{-*} | \u207B\u002A | undual | multivector.undual() or -multivector.dual() |
6 | ² | \textsuperscript{2} | \u00B2 | square | multivector.gp(multivector), sqr(double) |
6 | ^ | \textsuperscript{$\wedge$} | \u005E | grade involution/inversion (a sign change operation) | multivector.gradeInversion(multivector) |
symbol | latex | unicode | description | implementation |
---|---|---|---|---|
<multivector>ₚ (with ₚ ∈ {₀, ₁, ₂, ₃, ₄, ₅}) | < = \u003C, > = \u003E, ₀ = \u2080, ₁ = \u2081, ₂ = \u2082, ₃ = \u2083, ₄ = \u2084, ₅ = \u2085 | grade extraction, grade p=0-5 as subscript | multivector.extractGrade(int grade) |
symbol | description | implementation |
---|---|---|
exp() | exponential | MultivectorSymbolic.exp() |
normalize() | normalize by squared norm | MultivectorSymbolic.normalize() |
squaredNorm() | squared norm of a mulitvector | MultivectorSymbolic.squaredNorm() |
scp() | scalar product | not yet implemented |
dot() | dot product | not yet implemented |
abs() | absolute value of a scalar only | Math.abs(CGAScalar) |
sqrt() | square root of a scalar only | new CGAScalar(Math.sqrt(CGAScalar)) |
atan2(x,y) | arcus tansgens 2 (Converts the coordinates (x,y) to coordinates (r, theta) and returns the angle theta as the couterclockwise angle in radians between -pi and pi of the point (x,y) to the positive x-axis.) | new CGAScalar(Math.atan2(CGAScalar, CGAScalar)) |
negate14() | negate the signs of the vector- and 4-vector parts of an multivector. Usable to implement gerneral inverse. | MultivectorSymbolic.negate14() |
symbol | description | implementation |
---|---|---|
translator(tuple3d) | creates a translation from an 3d-tuple | createTranslation(tuple3d) |
rotator(tuple3d, double) | creates a rotation from an 3d-tuple representing the rotation axis and a double representing the angle in radian | createTranslation(tuple3d) |
symbol | latex | Unicode | description | implementation |
---|---|---|---|---|
ε₀ | \epsilon_0 | \u03B5\u2080 | base vector representing the origin | createOrigin(1d) |
εᵢ | \epsilon_i | \u03B5\u1D62 | base vector representing the infinity | createInf(1d) |
ε₁ | \epsilon_1 | \u03B5\u2081 | base vector representing x direction | createEx(1d) |
ε₂ | \epsilon_2 | \u03B5\u2082 | base vector representing y direction | createEy(1d) |
ε₃ | \epsilon_3 | \u03B5\u2083 | base vector representing z direction | createEz(1d) |
symbol | latex | Unicode | description | implementation |
---|---|---|---|---|
ε₊ | \epsilon_+ | \u03B5\u208A | ε₀ + 0.5εᵢ | |
ε₋ | \epsilon_- | \u03B5\u208B | 0.5εᵢ - ε₀ | |
π | \pi | \u03C0 | Ludolphs- or circle constant | Math.PI |
∞ | \infty | \u221E | corresponding to infinity vector in Dorst, Fontijne & Mann 2007 | 2ε₀ |
o | o | \u006F | corresponding to origin vector in Dorst, Fontijne & Mann 2007 | 0.5εᵢ |
n | n | \u006E | corresponding to infinity vector in Doran & Lasenby | εᵢ |
ñ | \tilde{n} | \u00F1 | corresponding to origin vector in Doran & Lasenby | -2ε₀ |
E₀ | E_0 | \u0045\u2080 | Minkovsky bi-vector (is its own inverse) | ε₀ ∧ εᵢ |
E₃ | E_3 | \u0045\u2083 | Euclidean pseudoscalar | ε₁ ∧ ε₂ ∧ ε₃ |
E | E | \u0045 | Pseudoscalar | ε₀ ∧ ε₁ ∧ ε₂ ∧ ε₃ ∧ εᵢ |
ε₀E₀=-ε₀, E₀ε₀=ε₀, εᵢE₀=εᵢ, E₀εᵢ=-εᵢ, E₀²=1, ε₀²=εᵢ²=0, ε₊²=1, ε₋²=-1, ε₊⋅ε₋=0
description | formula | grade | class |
---|---|---|---|
Point pair from two conformal points (p1, p2) | p1∧p2 | 2 | round |
(Flat) Finite-infinite point pair or Flat point from one conformal point (p) | p∧εᵢ | 2 | flat |
Circle from three ipns Points (p1, p2, p3) | p1∧p2∧p3 | 3 | round |
Line from two conformal planes (p1, p2) | p1∧p2∧εᵢ | 3 | flat |
Sphere from four ipns points (p1, p2, p3, p4) | p1∧p2∧p3∧p4 | 4 | round |
Plane from three ipns points (p1, p2, p3) | p1∧p2∧p3∧εᵢ | 4 | flat |
Plane between two ipns points (p1, p2) | $ (\vec{p}_1\wedge\vec{p}2)*\wedge\epsilon\infinity $ | 4 | flat |
The conformal points in the table above have to be given in inner product null space represenation.
description | formula | grade |
---|---|---|
Point from euclidian vector (x) | x+0.5x²εᵢ+ε₀ | 1 |
Sphere from conformal point (P) and radius (r) | P-0.5r²εᵢ | 1 |
Plane from euclidian normal vector (n) and distance to origin (d) | n+dεᵢ | 1 |
Circle from two conformal spheres (s1, s2) | s1∧s2 | 2 |
Line from two conformal planes (p1, p2) | p1∧p2 | 2 |
Point pair from three conformal spheres (s1, s2, s3) | s1∧s2∧s3 | 3 |
description | formula |
---|---|
Backprojection of a conformal point (P) into an euclidian vector. The formula in the first bracket normalizes the point. Then this normalized point is rejected from the minkowski plane. | (P/(P⋅εᵢ))∧E₀E₀⁻¹ |
Location of a round (X) or a tangent (X) represented in 3d coordinates | -0.5(XεᵢX)/(εᵢ⋅X)² |
Direction vector (attitude) of a dual line (L*) represented as 3d coordinates of (ε₁, ε₂, ε₃). | (L*⋅ε₀)⋅εᵢ |
Radius (r) of a conformal sphere (S) | r² = (S*)² = S*⋅S* |
Distance (d) between the the center of a conformal sphere (S) and a conformal point (P) | d² = S⋅S-2S⋅P |
description | formula |
---|---|
Matrix free implementation of the inverse | x⁻¹ = (x† x^ x˜ negate14(x)(x x† x^ x˜))/(x x† x^ x˜ negate14(x) (x x† x^ x˜)) |
name | equation | description |
---|---|---|
anticommutivity | u ∧ v = - (v ∧ u) | |
distributivity | u ∧ (v + w) = u ∧ v + u ∧ w | |
associativity | u ∧ (v ∧ w) = (u ∧ v) ∧ w | |
(A ⌊ B)˜ = B˜ C∧ A˜ | ||
A ∧ B * C = A * (B ⌋ C) | ||
C * (B ∧ A) = (C ⌊ B) * A | ||
intersection | (A ∨ B)* = B* ∧ A* | Intersection = outer product in the ipns representation; B* ∧ A* means computing the union of everything which is not B and everything that is not A. The dual of that must be what have A and B in common. |
projection | (A ⌋ B) B⁻¹ | Projection of A onto B |
rejection | (A ∧ B) B⁻¹ | Rejection of A from B |
duality | (A ⌋ B)* = A ∧ B* | |
A ⌋ (B ⌋ C) = (A ∧ B) ⌋ C | ||
(A ⌋ B) ⌋ C = A ∧ (B ⌋ C) | if C contains A | |
down projection | (εᵢ ∧ ε₀) ⌋ (X ∧ (εᵢ ∧ ε₀)) | extracts the pure euclidean part of the given multivector |
Determines an arbitrary point |