Vanishing zeroes for geometric algebra in Rust
fanf.dreamwidth.org
fanf.dreamwidth.org
Did you actually test whether this happens? If I understand correctly, you want to rely on the optimizer constant-folding multiplications with zero to zero. But strict IEEE floating point conformance notoriously does not allow collapsing multiplication with zero to zero (consider NaNs and infinities), or addition of zero to be a no-op (consider signed zeros).
Example:
That also affects the overall goal, seeing as the type-level optimizations do assume the above properties. This means that you will get different results in certain edge cases than a "naive" implementation that always stores 16 floating point values for each multivector (and that's before getting to things like non-associativity of floating point operations).
Yes I need to investigate that in more detail.
Edited to add: one option for making my assumption true might be to use fmul_fast and friends https://doc.rust-lang.org/core/intrinsics/fn.fmul_fast.html
Another idea is to rely on Rust-specific optimizations: make the concrete type used by the result expressions into
enum ZeroNum {
Zero,
Num(f64),
}
Operator overloading on this type works like it does on the separate Zero and Num types, but the cases are tested at run time instead of compile time. But this type is only used in a small context where the optimizer should be able to eliminate the checks in the same way I naively thought it would do for ops with 0.0.Instead it's "yes it's my fault that I forgot about the nonsensical concepts of positive and negative zero, and that the associative operation of addition isn't actually associative, and that addition's identity isn't actually and identity..."
Scheme has Numerical towers that automatically abstract over exact numeric representations, but instead this clearly smart engine is forced to spend mental cycles remembering and debugging this arbitrary special case logic.
Nulls, floating point, ... we really have some huge programming mistakes that have cost so much time over the years.
An no this isn't a rant on 'everybody should use scheme or Lisp, because that completely misses the point. It's that 'Worse Is Better' really is worse in the long run.
Maybe the problem isn't with GA but with the fact that few people know about it?
I think that people use GA and Clifford algebra interchangeably.
Grassmannians, Flag Manifolds, and Clifford Algebra were all introduced in my undergrad math degree. I think it's just CS people who are hyping GA up.
But geometric algebra, a.k.a. real Clifford algebra (“geometric algebra” was Clifford’s own name for it), can easily be taught to high school students in a very simple concrete way, and then used throughout science/engineering/computing courses aimed at non-math-majors. It can unify and simplify the wide variety of other mathematical formalisms that are used throughout undergraduate technical curricula. It is straight-forward to implement in a computer, and it makes calculations much easier to write down.
Most implementations I have seen do much more than quaternions. How hard did you look?
Here’s an example you can play with in a browser, https://enkimute.github.io/ganja.js/
But what is implemented in computers is not 1:1 with the algebraic tools that can be profitably employed to solve geometry problems symbolically. GA is a rich language full of useful tools which can describe/model many kinds of problems.
Coming from a math background, let me recommend you start with https://arxiv.org/abs/1205.5935
That's hardly the only definition of usefulness. I haven't used it yet but based on what I've read GA will be extremely useful in 3D graphics coding by unifying representations for previously distinct concepts and by providing formulas for common tasks with fewer special cases.
Check out a demo https://observablehq.com/@enkimute/animated-orbits
Join the discord https://discord.gg/vGY6pPk.
Enki (the guy behind bivector) also gave a talk on GA at SIGGRAPH 2019 https://www.youtube.com/watch?v=tX4H_ctggYo
Not sure if I should be impressed or horrified. ;-)
I don't yet know how well this will work in practice :-)
That's the point of geometric algebra!
The concept is that you can think of a line as a circle with infinite radius. Similarly, a plane is a sphere with an infinite radius. A rotation is can be represented using two reflections along lines or planes. Etc...
This makes some algorithms much more elegant, by removing conditional "if" statements. This matters when interpolating, which is the most common practical application of GA: game engines and robotic control often have problems with interpolating arbitrary rotations. With GA, there's no problem.
That's a different thing though. "Thinking of something as" is not the same as "is" in terms of types. The OP is right that in terms of programming ergonomics, it would be better to have distinct types that share the same operations, so you can _treat_ them in similar ways.
Generally speaking, a multi-vector can be broken down by which "grades" it contains. There are subspaces like "all even grades" that are closures under all basic operations.
If I remember correctly, the "even subset" of a 3D GA multi-vector is isomorphic to the Quarternions, which is why they turn up so often in 3D graphics libraries.
But think about how messy this is! These 3D libraries are blending together subsets of vaguely related algebras that are not "compatible" from a type theory perspective and so they're forced to convert back-and-forth. It's like mixing Unicode UTF-8 with Latin-1 byte strings. If you squint, it looks like one is the subset of the other... but not really.
With a pure GA-base library, the "rotation interpolation" functions would use the "even multivector subset" type, and be totally compatible with the rest of the library. It's the same type definitions, just with different parameters. This would be like using UTF-8 Unicode throughout the program, but having the ability to define a string-based type that only allows the "Basic Multilingual Plane".
The wording is important here. These "type definitions" you are talking about are not types. We usually call them "type constructors". So we mean the same thing, but please don't call multivector out to be a type without specifying the "grade" (then it becomes a type).
Yes, exactly. And making that not happen is the point of using distinct types `int` vs `float` vs `char* ` vs `struct foo* ` rather than stuffing everything into a `register_t`, or worse, `object`. (Or, as the case may be, `scalar` vs `vector` vs `bivector` etc, rather than stuffing everything into `multivector`.)