{"id":13741909,"url":"https://github.com/jeremyong/gal","last_synced_at":"2026-02-26T20:52:02.525Z","repository":{"id":137383815,"uuid":"208496240","full_name":"jeremyong/gal","owner":"jeremyong","description":"Geometric Algebra Library","archived":false,"fork":false,"pushed_at":"2019-11-30T03:47:12.000Z","size":1502,"stargazers_count":96,"open_issues_count":1,"forks_count":8,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-11-15T12:37:09.095Z","etag":null,"topics":["clifford-algebras","computational-algebra","conformal-geometry","cplusplus-17","cplusplus-20","cpp","cpp17","cpp20","finite-fields","geometric-algebra","graphics","projective-geometry","quaternion-algebra"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeremyong.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-09-14T19:57:19.000Z","updated_at":"2024-11-13T02:06:49.000Z","dependencies_parsed_at":"2024-01-13T16:24:37.008Z","dependency_job_id":"e056e632-f115-4e1c-bcae-809ab2bdbbf8","html_url":"https://github.com/jeremyong/gal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremyong%2Fgal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremyong%2Fgal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremyong%2Fgal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeremyong%2Fgal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeremyong","download_url":"https://codeload.github.com/jeremyong/gal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253158507,"owners_count":21863313,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clifford-algebras","computational-algebra","conformal-geometry","cplusplus-17","cplusplus-20","cpp","cpp17","cpp20","finite-fields","geometric-algebra","graphics","projective-geometry","quaternion-algebra"],"created_at":"2024-08-03T04:01:03.978Z","updated_at":"2026-02-26T20:52:02.475Z","avatar_url":"https://github.com/jeremyong.png","language":"C++","funding_links":[],"categories":["Uncategorized","C++"],"sub_categories":["Uncategorized"],"readme":"# Geometric Algebra Library\n\n[![Build Status](https://travis-ci.org/jeremyong/gal.svg?branch=master)](https://travis-ci.org/jeremyong/gal)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\n[**GAL**](https://www.jeremyong.com/gal/) (project page link) is a C++17 expression compiler and engine for computing with geometric algebra. It focuses primarily on speed and customizability with the ambition for being suitable for use in production environments where real-time speed is a factor.\n\nSome things that make GAL unique are:\n\n- GAL deals with the intrinsically higher dimensionality of GA by reducing computation to a sparse subset at compile time.\n- Often, when dealing with GA constructions, many terms may eliminate but in ways that are not optimizable by the compiler. GAL uses compile-time techniques to ensure that term cancellation which is guaranteed to be correct can be elided.\n- GAL separates computation into three layers: data, algebraic expression evaluation, and computation. Each layer is customizable, and examples of why you might want to do so include supporting exotic metrics or number systems or generating shader ISA code (as opposed to CPU evaluation).\n- While GAL is template-heavy, fast compile times are a top priority for GAL, which leverages numerous modern C++17 techniques (C++2a soon) to improve compile times.\n\nFor the most complete and up-to-date documentation, please refer to the project page [here](https://www.jeremyong.com/gal/). If you wish to learn more about the internals of the library, feel free to continue reading.\n\n## Runtime and Compile-time performance\n\nGAL is slowly converging to hand-optimized code for computing with geometric entities in the various algebras.\nThe goal is, of course, perfect convergence (up to auto-vectorization at least).\n\nRuntime and compile time performance is achieved by using the following approach to expression evaluation.\n\n1. Expressions are encoded using flattened arrays of Reverse-Polish Notation nodes.\n2. Expression inputs are entities that are encoded with flat representations (e.g. an R3 point is just 3 floats and not tied to a multivector representation).\n3. Prior to evaluation, expression inputs are expressed in indeterminate multivector form (parameters of each input are expressed via integral tags, not floating-point values). This is encoded using 3 flat compile-time arrays per multivector (storing intederminates, monomials, and polynomials) for fast simplification and evaluation.\n4. Expressions are expanded in indeterminate form using polynomial coefficients so that term arithmetic can happen exactly over the field of rationals. A number of techniques are used to put strict upper bounds on compile time memory and CPU usage whever possible.\n5. The final indeterminate form is evaluated coefficient by coefficient. For CSE, the compiler is relied on at this time, although future work in doing compile time multivariate polynomial reduction is possible. For maximal throughput, this does not rely on features like `std::tuple` which are known to have poor compilation performance where possible.\n6. The results are optionally cast back into the flat entity form which extracts multivector components and applies scaling as appropriate. This operation is also a compile time operation which may cause additional computation to drop out trivially.\n\n## Rights and Attribution\n\nGAL is licensed permissively under the MIT license and free as in :beer:.\n\nAttribution is appreciated, but not required for use of the library. If you would like to cite this work in an academic setting, feel free to use the following BibTex snippet, produced here for your convenience:\n\n```latex\n@misc{jeremy_ong_2019,\n    author = {Ong, Jeremy},\n    title = {GAL},\n    year = {2019},\n    publisher = {GitHub},\n    journal = {GitHub repository},\n    howpublished = {\\url{https://github.com/jeremyong/gal}},\n    commit = {[insert commit used]}\n}\n```\n\nPlease adjust the snippet above per recommendations from the journal you wish to publish to.\n\n## Usage\n\nBeing a template-library, GAL is header-only and can be installed by either linking the `gal` interface target via cmake or by copying the files in `src` to a known include path.\n\nTo build the tests, you need a C++ compiler that supports C++17 or greater.\nOlder compilers that purport to support C++17 *may not work* due to invalid conformance.\n\n```sh\n# From the root directory of this project\nmkdir build\ncd build\n\n# Optionally supply release type, flags, etc and pick your favorite generator\ncmake .. -G Ninja\n\n# ... or whichever (ideally multicore-friendly) build system you choose\nninja\n\n# Run the tests\n./bin/gal_test\n```\n\nIt is recommend when using clang that `-fno-math-errno` be passed to your compiler's build settings as this was found to be an obstacle for clang to generate optimal code in many circumstances. Many platforms set this as the default, but depending on the math library that is linked on your system, your mileage may vary.\n\nA secondary recommendation is that usage should comfortably enable both `-ffast-math` and `-mfma`. The former\nis usually not used to retain finer control over numerical stability. However, using GA improves stability\nconsiderably over traditional linear algebra approaches. The second flag enables fused-multiply-add\ninstructions which both improves precision and is available on most hardware.\n\n## MSVC\n\nMSVC is not yet supported because this library relies on several techniques that break under MSVC due to a\nlack of standards conformance. Help is appreciated in this regard (especially if you're a VC++ dev!).\n\n## Motivation\n\nGeometric Algebra promises (and fulfills) a unified algebraic system for manipulating geometric objects\n(points, lines, planes, spheres, etc) in a way that is coordinate-free, consistent, and logical. A\ntypical computer graphics library is often the union of a number of disjoint algebras and algorithms.\nExamples include dual quaternions for skinning, quaternions for rotation, 1-up projective space for linear\nrotations and translations when interpolation is not needed, and special handling for objects that do not\ntransform covariantly with the metric (e.g. normal vectors).\n\nA (very) loose way of understanding how GA does this is by encoding operations in a way that loses less\nrelevant information. For example, consider the cross-product. Once computed, the information that it\noriginated from two vectors with some orientation relative to each other is lost. Indeed, given nothing\nbut the coordinates of a normal vector, it is impossible to describe the orientation of the vectors that\nproduced it. In GA, such information is encoded by higher ordered basis elements beyond the standard ones\nproferred in the typical R3 vector space. This is what makes GA a *graded* algebra. The second important\n(and necessary) piece that gives GA its power are the operations between elements of this algebra. Without\ngoing into much detail, the geometric product encodes both projections and rejections nicely within the\nframework supplies us with the *conjugate* (aka \"sandwich\") operator to elegantly supply interpolatable (read.\ndifferentiable) rotations and translations of any geometric object. All of this is to say, the state\nspace of the *code* needed to express a vast range of computation is compressed significantly.\n\nThere is a \"problem\" though, which is that, being a graded algebra, geometric algebras are necessarily\nhigher-dimensional than the spaces they represent. A 3D space typically requires 3 coordinates but in GA,\nthis would require 8 (2^3) coordinates to describe a fully general multivector. The 5D conformal space\n(conformal meaning that homomorphisms are angle-preserving) requires 32 coordinates! On top of that,\nthere are often a number of term cancellations as expressions are evaluated (as quantities contract one\none another in ways that are degenerate for example). This results in a higher operation count, all else\nbeing equal. Generally, actual computation is done in smaller embeddings within the full tensor algebra,\nand runtime compression of the data is unacceptable.\n\nTo combat this, GAL provides a fully compile time expression evaluation system and computational engine\nto fully simplify expressions. Perhaps the most egregious example is a CGA (Conformal Geometric Algebra)\npoint being contracted onto itself (the contraction operator resembles the dot product but is generalized\nto act on higher-order elements than just vectors). Under CGA, the contraction of a point to itself is\n*exactly* zero. However, if you implemented a contraction operator using standard floating point math,\nthe compiler would be unable to optimize this as such in general. GAL makes the following code possible:\n\n```c++\n#include \u003cgal/cga.hpp\u003e\n\nusing point  = gal::cga::point\u003cfloat\u003e;\n\nfloat point_norm(point p)\n{\n    return compute([](auto p)\n    {\n        // Contract a cga point back onto itself\n        // Note that p here contains no actual data! It is just the type that represents a CGA point\n        // with internal tags that refer to the values contained in the outer scope p (we locally\n        // shadow the variable name for brevity)\n        return p \u003e\u003e p;\n    }, p);\n}\n```\n\nThe assembly for the routine above looks like the following (compiled with -O1, not even -O2):\n\n```assembly\npoint_norm(gal::cga::point\u003cfloat\u003e):\n        pxor    xmm0, xmm0\n        ret\n```\n\nand it should go without saying that `xor` of a register to itself is assembly-shorthand for just zeroing\nthe register. In other words, all the multiplications of a 5-coordinate vector to itself got optimized away\ncompletely!\n\n## API\n\nThe library is still under flux, but for now, the snippet below should give you a decent idea of how to use GAL.\nFor more complete documentation, please refer to the [project page](https://jeremyong.com/gal).\n\nExample usage:\n\n```c++\n#include \u003cgal/vga.hpp\u003e\n#include \u003cgal/pga.hpp\u003e\n\n// Let's work with the projectivized dual space of R3\nusing gal::pga::compute;\n\n// We'll specify our points in R^3\nusing point = gal::vga::point\u003cfloat\u003e;\n\n// Let's construct a few random points.\n// Each of these points occupies no more than 12 bytes (+ alignment padding).\npoint p1{2.4f, 3.6f, 1.3f};\npoint p2{-1.1f, 2.7f, 5.0f};\npoint p3{-1.8f, -2.7f, -4.3f};\n\n// We issue a computation using the `compute` method which accepts a lambda.\n// Note that when we supply VGA points, the points become automatically dualized.\nplane\u003cfloat\u003e p = gal::pga::compute\u003cgal::pga::plane\u003cfloat\u003e\u003e([](auto p1, auto p2, auto p3)\n{\n    // The p1, p2, and p3 variables here are shadow types of the points residing\n    // \"in the engine\" and we operate with them using any of the operations:\n    // operator*        := Geometric product\n    // operator^        := Exterior (aka wedge) product\n    // operator~        := Reversion\n    // operator!        := (Poincare) Dual\n    // operator\u0026        := Regressive product (point meet, plane join)\n    // operator+        := Vector space addition\n    // operator-        := Vector space subtraction\n    // operator|        := Symmetric inner product\n    // operator\u003e\u003e       := Left contraction\n    // operator%        := Sandwich operator (rhs ^ lhs ^ ~rhs)\n\n    // Operations that are permitted are chosen because they respect associativity\n    // in the way you would expect.\n\n    // Here we just use the regressive product to construct a plane which passes through\n    // the three points.\n    return p1 \u0026 p2 \u0026 p3;\n}, p1, p2, p3);\n\n// The results have now been computed and placed into the constructed plane which\n// is parametered by the equation ax + by + cz + d = 0\n// Here, we check to ensure that the three points we used in the construction do\n// in fact lie on the plane.\nauto epsilon = /* a small float value */;\nCHECK_EQ(p1.x * p.x + p1.y * p.y + p1.z * p.z + p.d, epsilon);\nCHECK_EQ(p2.x * p.x + p2.y * p.y + p2.z * p.z + p.d, epsilon);\nCHECK_EQ(p3.x * p.x + p3.y * p.y + p3.z * p.z + p.d, epsilon);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeremyong%2Fgal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeremyong%2Fgal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeremyong%2Fgal/lists"}