Adds more prebuilt projective geometric algebras.
Renames Automorph => Automorphism. Renames Transpose => Reversal. Renames Conjugate => Conjugation. Removes Reflection (as that is covered by Transformation). Fixes std::fmt::Display for BasisElement again (not only -1 but also 0).
This commit is contained in:
parent
8c025b5dc2
commit
53e514d861
6 changed files with 78 additions and 68 deletions
16
.github/workflows/actions.yaml
vendored
16
.github/workflows/actions.yaml
vendored
|
|
@ -21,12 +21,24 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
algebra:
|
algebra:
|
||||||
- name: complex
|
- name: epga1d
|
||||||
descriptor: "complex:-1;Scalar:1;MultiVector:1,e0"
|
descriptor: "epga1d:1,1;Scalar:1;ComplexNumber:1,e01"
|
||||||
|
- name: ppga1d
|
||||||
|
descriptor: "ppga1d:0,1;Scalar:1;DualNumber:1,e01"
|
||||||
|
- name: hpga1d
|
||||||
|
descriptor: "hpga1d:-1,1;Scalar:1;SplitComplexNumber:1,e01"
|
||||||
|
- name: epga2d
|
||||||
|
descriptor: "epga2d:1,1,1;Scalar:1;MultiVector:1,e12,e1,e2|e0,e012,e01,-e02;Rotor:1,e12;Point:e12,e01,-e02;Plane:e0,e2,e1;Translator:1,e01,-e02;Motor:1,e12,e01,-e02;MotorDual:e012,e0,e2,e1"
|
||||||
- name: ppga2d
|
- name: ppga2d
|
||||||
descriptor: "ppga2d:0,1,1;Scalar:1;MultiVector:1,e12,e1,e2|e0,e012,e01,-e02;Rotor:1,e12;Point:e12,e01,-e02;Plane:e0,e2,e1;Translator:1,e01,-e02;Motor:1,e12,e01,-e02;MotorDual:e012,e0,e2,e1"
|
descriptor: "ppga2d:0,1,1;Scalar:1;MultiVector:1,e12,e1,e2|e0,e012,e01,-e02;Rotor:1,e12;Point:e12,e01,-e02;Plane:e0,e2,e1;Translator:1,e01,-e02;Motor:1,e12,e01,-e02;MotorDual:e012,e0,e2,e1"
|
||||||
|
- name: hpga2d
|
||||||
|
descriptor: "hpga2d:-1,1,1;Scalar:1;MultiVector:1,e12,e1,e2|e0,e012,e01,-e02;Rotor:1,e12;Point:e12,e01,-e02;Plane:e0,e2,e1;Translator:1,e01,-e02;Motor:1,e12,e01,-e02;MotorDual:e012,e0,e2,e1"
|
||||||
|
- name: epga3d
|
||||||
|
descriptor: "epga3d:1,1,1,1;Scalar:1;MultiVector:1,e23,-e13,e12|e0,-e023,e013,-e012|e123,e1,e2,e3|e0123,e01,e02,e03;Rotor:1,e23,-e13,e12;Point:e123,-e023,e013,-e012;Plane:e0,e1,e2,e3;Line:e01,e02,e03|e23,-e13,e12;Translator:1,e01,e02,e03;Motor:1,e23,-e13,e12|e0123,e01,e02,e03;PointAndPlane:e123,-e023,e013,-e012|e0,e1,e2,e3"
|
||||||
- name: ppga3d
|
- name: ppga3d
|
||||||
descriptor: "ppga3d:0,1,1,1;Scalar:1;MultiVector:1,e23,-e13,e12|e0,-e023,e013,-e012|e123,e1,e2,e3|e0123,e01,e02,e03;Rotor:1,e23,-e13,e12;Point:e123,-e023,e013,-e012;Plane:e0,e1,e2,e3;Line:e01,e02,e03|e23,-e13,e12;Translator:1,e01,e02,e03;Motor:1,e23,-e13,e12|e0123,e01,e02,e03;PointAndPlane:e123,-e023,e013,-e012|e0,e1,e2,e3"
|
descriptor: "ppga3d:0,1,1,1;Scalar:1;MultiVector:1,e23,-e13,e12|e0,-e023,e013,-e012|e123,e1,e2,e3|e0123,e01,e02,e03;Rotor:1,e23,-e13,e12;Point:e123,-e023,e013,-e012;Plane:e0,e1,e2,e3;Line:e01,e02,e03|e23,-e13,e12;Translator:1,e01,e02,e03;Motor:1,e23,-e13,e12|e0123,e01,e02,e03;PointAndPlane:e123,-e023,e013,-e012|e0,e1,e2,e3"
|
||||||
|
- name: hpga3d
|
||||||
|
descriptor: "hpga3d:-1,1,1,1;Scalar:1;MultiVector:1,e23,-e13,e12|e0,-e023,e013,-e012|e123,e1,e2,e3|e0123,e01,e02,e03;Rotor:1,e23,-e13,e12;Point:e123,-e023,e013,-e012;Plane:e0,e1,e2,e3;Line:e01,e02,e03|e23,-e13,e12;Translator:1,e01,e02,e03;Motor:1,e23,-e13,e12|e0123,e01,e02,e03;PointAndPlane:e123,-e023,e013,-e012|e0,e1,e2,e3"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
[](https://crates.io/crates/geometric_algebra)
|
[](https://crates.io/crates/geometric_algebra)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
This repository allows you to describe [geometric algebras](https://en.wikipedia.org/wiki/Geometric_algebra) with 1 to 16 generator elements and generate SIMD-ready, dependency-less libraries for them.
|
This repository allows you to describe [geometric algebras](https://en.wikipedia.org/wiki/Geometric_algebra) with 1 to 16 generator elements and generate SIMD-ready, dependency-less libraries for them. It also comes with a set of prebuilt projective geometric algebras in 1D, 2D and 3D which are elliptic, parabolic (euclidian) or hyperbolic.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
- [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) Parser: See [examples](.github/workflows/actions.yaml)
|
- [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) Parser: See [examples](.github/workflows/actions.yaml)
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,9 @@ impl BasisElement {
|
||||||
let mut generator_indices = name.chars();
|
let mut generator_indices = name.chars();
|
||||||
assert_eq!(generator_indices.next().unwrap(), 'e');
|
assert_eq!(generator_indices.next().unwrap(), 'e');
|
||||||
for generator_index in generator_indices {
|
for generator_index in generator_indices {
|
||||||
let generator = Self::from_index(1 << (generator_index.to_digit(16).unwrap()));
|
let generator_index = generator_index.to_digit(16).unwrap();
|
||||||
result = BasisElement::product(&result, &generator, algebra);
|
assert!((generator_index as usize) < algebra.generator_squares.len());
|
||||||
|
result = BasisElement::product(&result, &Self::from_index(1 << generator_index), algebra);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
@ -95,12 +96,18 @@ impl BasisElement {
|
||||||
|
|
||||||
impl std::fmt::Display for BasisElement {
|
impl std::fmt::Display for BasisElement {
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
if self.index == 0 {
|
let name = format!("e{}", self.component_bits().map(|index| format!("{:X}", index)).collect::<String>());
|
||||||
formatter.pad_integral(self.scalar >= 0, "", &self.scalar.abs().to_string())
|
formatter.pad_integral(
|
||||||
} else {
|
self.scalar >= 0,
|
||||||
let string = format!("e{}", self.component_bits().map(|index| format!("{:X}", index)).collect::<String>());
|
"",
|
||||||
formatter.pad_integral(self.scalar >= 0, "", string.as_str())
|
if self.scalar == 0 {
|
||||||
}
|
"0"
|
||||||
|
} else if self.index == 0 {
|
||||||
|
"1"
|
||||||
|
} else {
|
||||||
|
name.as_str()
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,9 +178,9 @@ impl Involution {
|
||||||
let involution = Self::identity(algebra);
|
let involution = Self::identity(algebra);
|
||||||
vec![
|
vec![
|
||||||
("Neg", involution.negated(|_grade| true)),
|
("Neg", involution.negated(|_grade| true)),
|
||||||
("Automorph", involution.negated(|grade| grade % 2 == 1)),
|
("Automorphism", involution.negated(|grade| grade % 2 == 1)),
|
||||||
("Transpose", involution.negated(|grade| grade % 4 >= 2)),
|
("Reversal", involution.negated(|grade| grade % 4 >= 2)),
|
||||||
("Conjugate", involution.negated(|grade| (grade + 3) % 4 < 2)),
|
("Conjugation", involution.negated(|grade| (grade + 3) % 4 < 2)),
|
||||||
("Dual", involution.dual(algebra)),
|
("Dual", involution.dual(algebra)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1179,19 +1179,15 @@ impl MultiVectorClass {
|
||||||
DataType::MultiVector(involution_result.multi_vector_class()),
|
DataType::MultiVector(involution_result.multi_vector_class()),
|
||||||
Expression {
|
Expression {
|
||||||
size: 1,
|
size: 1,
|
||||||
content: match name {
|
content: ExpressionContent::InvokeInstanceMethod(
|
||||||
"Reflection" => ExpressionContent::Variable(parameter_a.name),
|
parameter_a.data_type.clone(),
|
||||||
"Transformation" => ExpressionContent::InvokeInstanceMethod(
|
Box::new(Expression {
|
||||||
parameter_a.data_type.clone(),
|
size: 1,
|
||||||
Box::new(Expression {
|
content: ExpressionContent::Variable(parameter_a.name),
|
||||||
size: 1,
|
}),
|
||||||
content: ExpressionContent::Variable(parameter_a.name),
|
involution_result.name,
|
||||||
}),
|
vec![],
|
||||||
involution_result.name,
|
),
|
||||||
vec![],
|
|
||||||
),
|
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)],
|
)],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ fn main() {
|
||||||
for class in registry.classes.iter() {
|
for class in registry.classes.iter() {
|
||||||
emitter.emit(&AstNode::ClassDefinition { class }).unwrap();
|
emitter.emit(&AstNode::ClassDefinition { class }).unwrap();
|
||||||
}
|
}
|
||||||
let involution_name = if generator_squares == vec![-1] { "Conjugate" } else { "Transpose" };
|
|
||||||
let mut trait_implementations = std::collections::BTreeMap::new();
|
let mut trait_implementations = std::collections::BTreeMap::new();
|
||||||
for class_a in registry.classes.iter() {
|
for class_a in registry.classes.iter() {
|
||||||
let parameter_a = Parameter {
|
let parameter_a = Parameter {
|
||||||
|
|
@ -118,10 +117,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
for (parameter_b, pair_trait_implementations) in pair_trait_implementations.values() {
|
for (parameter_b, pair_trait_implementations) in pair_trait_implementations.values() {
|
||||||
if let Some(scalar_product) = pair_trait_implementations.get("ScalarProduct") {
|
if let Some(scalar_product) = pair_trait_implementations.get("ScalarProduct") {
|
||||||
if let Some(involution) = single_trait_implementations.get(involution_name) {
|
if let Some(reversal) = single_trait_implementations.get("Reversal") {
|
||||||
if parameter_a.multi_vector_class() == parameter_b.multi_vector_class() {
|
if parameter_a.multi_vector_class() == parameter_b.multi_vector_class() {
|
||||||
let squared_magnitude =
|
let squared_magnitude =
|
||||||
MultiVectorClass::derive_squared_magnitude("SquaredMagnitude", &scalar_product, &involution, ¶meter_a);
|
MultiVectorClass::derive_squared_magnitude("SquaredMagnitude", &scalar_product, &reversal, ¶meter_a);
|
||||||
emitter.emit(&squared_magnitude).unwrap();
|
emitter.emit(&squared_magnitude).unwrap();
|
||||||
let magnitude = MultiVectorClass::derive_magnitude("Magnitude", &squared_magnitude, ¶meter_a);
|
let magnitude = MultiVectorClass::derive_magnitude("Magnitude", &squared_magnitude, ¶meter_a);
|
||||||
emitter.emit(&magnitude).unwrap();
|
emitter.emit(&magnitude).unwrap();
|
||||||
|
|
@ -140,9 +139,9 @@ fn main() {
|
||||||
single_trait_implementations.insert(result_of_trait!(signum).name.to_string(), signum);
|
single_trait_implementations.insert(result_of_trait!(signum).name.to_string(), signum);
|
||||||
}
|
}
|
||||||
if let Some(squared_magnitude) = single_trait_implementations.get("SquaredMagnitude") {
|
if let Some(squared_magnitude) = single_trait_implementations.get("SquaredMagnitude") {
|
||||||
if let Some(involution) = single_trait_implementations.get(involution_name) {
|
if let Some(reversal) = single_trait_implementations.get("Reversal") {
|
||||||
let inverse =
|
let inverse =
|
||||||
MultiVectorClass::derive_inverse("Inverse", &geometric_product, &squared_magnitude, &involution, ¶meter_a);
|
MultiVectorClass::derive_inverse("Inverse", &geometric_product, &squared_magnitude, &reversal, ¶meter_a);
|
||||||
emitter.emit(&inverse).unwrap();
|
emitter.emit(&inverse).unwrap();
|
||||||
single_trait_implementations.insert(result_of_trait!(inverse).name.to_string(), inverse);
|
single_trait_implementations.insert(result_of_trait!(inverse).name.to_string(), inverse);
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +186,7 @@ fn main() {
|
||||||
emitter.emit(&division).unwrap();
|
emitter.emit(&division).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(involution) = single_trait_implementations.get(involution_name) {
|
if let Some(reversal) = single_trait_implementations.get("Reversal") {
|
||||||
if let Some(b_trait_implementations) = trait_implementations.get(&geometric_product_result.multi_vector_class().class_name) {
|
if let Some(b_trait_implementations) = trait_implementations.get(&geometric_product_result.multi_vector_class().class_name) {
|
||||||
if let Some(b_pair_trait_implementations) = b_trait_implementations.2.get(¶meter_a.multi_vector_class().class_name) {
|
if let Some(b_pair_trait_implementations) = b_trait_implementations.2.get(¶meter_a.multi_vector_class().class_name) {
|
||||||
if let Some(geometric_product_2) = b_pair_trait_implementations.1.get("GeometricProduct") {
|
if let Some(geometric_product_2) = b_pair_trait_implementations.1.get("GeometricProduct") {
|
||||||
|
|
@ -198,18 +197,16 @@ fn main() {
|
||||||
if let Some(c_pair_trait_implementations) =
|
if let Some(c_pair_trait_implementations) =
|
||||||
c_trait_implementations.2.get(¶meter_b.multi_vector_class().class_name)
|
c_trait_implementations.2.get(¶meter_b.multi_vector_class().class_name)
|
||||||
{
|
{
|
||||||
for name in &["Reflection", "Transformation"] {
|
let transformation = MultiVectorClass::derive_sandwich_product(
|
||||||
let transformation = MultiVectorClass::derive_sandwich_product(
|
"Transformation",
|
||||||
name,
|
&geometric_product,
|
||||||
&geometric_product,
|
&geometric_product_2,
|
||||||
&geometric_product_2,
|
&reversal,
|
||||||
&involution,
|
c_pair_trait_implementations.1.get("Into"),
|
||||||
c_pair_trait_implementations.1.get("Into"),
|
¶meter_a,
|
||||||
¶meter_a,
|
¶meter_b,
|
||||||
¶meter_b,
|
);
|
||||||
);
|
emitter.emit(&transformation).unwrap();
|
||||||
emitter.emit(&transformation).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
src/lib.rs
44
src/lib.rs
|
|
@ -1,12 +1,18 @@
|
||||||
#![cfg_attr(all(target_arch = "wasm32", target_feature = "simd128"), feature(wasm_simd))]
|
#![cfg_attr(all(target_arch = "wasm32", target_feature = "simd128"), feature(wasm_simd))]
|
||||||
#![cfg_attr(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "neon"), feature(stdsimd))]
|
#![cfg_attr(all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "neon"), feature(stdsimd))]
|
||||||
|
|
||||||
pub mod complex;
|
pub mod epga1d;
|
||||||
|
pub mod ppga1d;
|
||||||
|
pub mod hpga1d;
|
||||||
|
pub mod epga2d;
|
||||||
pub mod ppga2d;
|
pub mod ppga2d;
|
||||||
|
pub mod hpga2d;
|
||||||
|
pub mod epga3d;
|
||||||
pub mod ppga3d;
|
pub mod ppga3d;
|
||||||
|
pub mod hpga3d;
|
||||||
pub mod simd;
|
pub mod simd;
|
||||||
|
|
||||||
impl complex::Scalar {
|
impl epga1d::Scalar {
|
||||||
pub const fn new(real: f32) -> Self {
|
pub const fn new(real: f32) -> Self {
|
||||||
Self { g0: real }
|
Self { g0: real }
|
||||||
}
|
}
|
||||||
|
|
@ -15,16 +21,16 @@ impl complex::Scalar {
|
||||||
self.g0
|
self.g0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sqrt(self) -> complex::MultiVector {
|
pub fn sqrt(self) -> epga1d::ComplexNumber {
|
||||||
if self.g0 < 0.0 {
|
if self.g0 < 0.0 {
|
||||||
complex::MultiVector::new(0.0, (-self.g0).sqrt())
|
epga1d::ComplexNumber::new(0.0, (-self.g0).sqrt())
|
||||||
} else {
|
} else {
|
||||||
complex::MultiVector::new(self.g0.sqrt(), 0.0)
|
epga1d::ComplexNumber::new(self.g0.sqrt(), 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl complex::MultiVector {
|
impl epga1d::ComplexNumber {
|
||||||
pub const fn new(real: f32, imaginary: f32) -> Self {
|
pub const fn new(real: f32, imaginary: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
g0: simd::Simd32x2 {
|
g0: simd::Simd32x2 {
|
||||||
|
|
@ -73,23 +79,23 @@ pub trait Dual {
|
||||||
/// Negates elements with `grade % 2 == 1`
|
/// Negates elements with `grade % 2 == 1`
|
||||||
///
|
///
|
||||||
/// Also called main involution
|
/// Also called main involution
|
||||||
pub trait Automorph {
|
pub trait Automorphism {
|
||||||
type Output;
|
type Output;
|
||||||
fn automorph(self) -> Self::Output;
|
fn automorphism(self) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Negates elements with `grade % 4 >= 2`
|
/// Negates elements with `grade % 4 >= 2`
|
||||||
///
|
///
|
||||||
/// Also called reversion
|
/// Also called transpose
|
||||||
pub trait Transpose {
|
pub trait Reversal {
|
||||||
type Output;
|
type Output;
|
||||||
fn transpose(self) -> Self::Output;
|
fn reversal(self) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Negates elements with `(grade + 3) % 4 < 2`
|
/// Negates elements with `(grade + 3) % 4 < 2`
|
||||||
pub trait Conjugate {
|
pub trait Conjugation {
|
||||||
type Output;
|
type Output;
|
||||||
fn conjugate(self) -> Self::Output;
|
fn conjugation(self) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// General multi vector multiplication
|
/// General multi vector multiplication
|
||||||
|
|
@ -140,15 +146,7 @@ pub trait ScalarProduct<T> {
|
||||||
fn scalar_product(self, other: T) -> Self::Output;
|
fn scalar_product(self, other: T) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `self * other * self`
|
/// `self * other * self.reversion()`
|
||||||
///
|
|
||||||
/// Basically a sandwich product without an involution
|
|
||||||
pub trait Reflection<T> {
|
|
||||||
type Output;
|
|
||||||
fn reflection(self, other: T) -> Self::Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `self * other * self.transpose()`
|
|
||||||
///
|
///
|
||||||
/// Also called sandwich product
|
/// Also called sandwich product
|
||||||
pub trait Transformation<T> {
|
pub trait Transformation<T> {
|
||||||
|
|
@ -170,7 +168,7 @@ pub trait Magnitude {
|
||||||
fn magnitude(self) -> Self::Output;
|
fn magnitude(self) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direction without magnitude (set to scalar `1.0`)
|
/// Direction without magnitude (set to scalar `-1.0` or `1.0`)
|
||||||
///
|
///
|
||||||
/// Also called sign or normalize
|
/// Also called sign or normalize
|
||||||
pub trait Signum {
|
pub trait Signum {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue