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:
|
||||
matrix:
|
||||
algebra:
|
||||
- name: complex
|
||||
descriptor: "complex:-1;Scalar:1;MultiVector:1,e0"
|
||||
- name: epga1d
|
||||
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
|
||||
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
|
||||
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:
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
[](https://crates.io/crates/geometric_algebra)
|
||||
|
||||
## 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
|
||||
- [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();
|
||||
assert_eq!(generator_indices.next().unwrap(), 'e');
|
||||
for generator_index in generator_indices {
|
||||
let generator = Self::from_index(1 << (generator_index.to_digit(16).unwrap()));
|
||||
result = BasisElement::product(&result, &generator, algebra);
|
||||
let generator_index = generator_index.to_digit(16).unwrap();
|
||||
assert!((generator_index as usize) < algebra.generator_squares.len());
|
||||
result = BasisElement::product(&result, &Self::from_index(1 << generator_index), algebra);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
@ -95,12 +96,18 @@ impl BasisElement {
|
|||
|
||||
impl std::fmt::Display for BasisElement {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
if self.index == 0 {
|
||||
formatter.pad_integral(self.scalar >= 0, "", &self.scalar.abs().to_string())
|
||||
let name = format!("e{}", self.component_bits().map(|index| format!("{:X}", index)).collect::<String>());
|
||||
formatter.pad_integral(
|
||||
self.scalar >= 0,
|
||||
"",
|
||||
if self.scalar == 0 {
|
||||
"0"
|
||||
} else if self.index == 0 {
|
||||
"1"
|
||||
} else {
|
||||
let string = format!("e{}", self.component_bits().map(|index| format!("{:X}", index)).collect::<String>());
|
||||
formatter.pad_integral(self.scalar >= 0, "", string.as_str())
|
||||
}
|
||||
name.as_str()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,9 +178,9 @@ impl Involution {
|
|||
let involution = Self::identity(algebra);
|
||||
vec![
|
||||
("Neg", involution.negated(|_grade| true)),
|
||||
("Automorph", involution.negated(|grade| grade % 2 == 1)),
|
||||
("Transpose", involution.negated(|grade| grade % 4 >= 2)),
|
||||
("Conjugate", involution.negated(|grade| (grade + 3) % 4 < 2)),
|
||||
("Automorphism", involution.negated(|grade| grade % 2 == 1)),
|
||||
("Reversal", involution.negated(|grade| grade % 4 >= 2)),
|
||||
("Conjugation", involution.negated(|grade| (grade + 3) % 4 < 2)),
|
||||
("Dual", involution.dual(algebra)),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1179,9 +1179,7 @@ impl MultiVectorClass {
|
|||
DataType::MultiVector(involution_result.multi_vector_class()),
|
||||
Expression {
|
||||
size: 1,
|
||||
content: match name {
|
||||
"Reflection" => ExpressionContent::Variable(parameter_a.name),
|
||||
"Transformation" => ExpressionContent::InvokeInstanceMethod(
|
||||
content: ExpressionContent::InvokeInstanceMethod(
|
||||
parameter_a.data_type.clone(),
|
||||
Box::new(Expression {
|
||||
size: 1,
|
||||
|
|
@ -1190,8 +1188,6 @@ impl MultiVectorClass {
|
|||
involution_result.name,
|
||||
vec![],
|
||||
),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
},
|
||||
)],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ fn main() {
|
|||
for class in registry.classes.iter() {
|
||||
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();
|
||||
for class_a in registry.classes.iter() {
|
||||
let parameter_a = Parameter {
|
||||
|
|
@ -118,10 +117,10 @@ fn main() {
|
|||
}
|
||||
for (parameter_b, pair_trait_implementations) in pair_trait_implementations.values() {
|
||||
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() {
|
||||
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();
|
||||
let magnitude = MultiVectorClass::derive_magnitude("Magnitude", &squared_magnitude, ¶meter_a);
|
||||
emitter.emit(&magnitude).unwrap();
|
||||
|
|
@ -140,9 +139,9 @@ fn main() {
|
|||
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(involution) = single_trait_implementations.get(involution_name) {
|
||||
if let Some(reversal) = single_trait_implementations.get("Reversal") {
|
||||
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();
|
||||
single_trait_implementations.insert(result_of_trait!(inverse).name.to_string(), inverse);
|
||||
}
|
||||
|
|
@ -187,7 +186,7 @@ fn main() {
|
|||
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_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") {
|
||||
|
|
@ -198,12 +197,11 @@ fn main() {
|
|||
if let Some(c_pair_trait_implementations) =
|
||||
c_trait_implementations.2.get(¶meter_b.multi_vector_class().class_name)
|
||||
{
|
||||
for name in &["Reflection", "Transformation"] {
|
||||
let transformation = MultiVectorClass::derive_sandwich_product(
|
||||
name,
|
||||
"Transformation",
|
||||
&geometric_product,
|
||||
&geometric_product_2,
|
||||
&involution,
|
||||
&reversal,
|
||||
c_pair_trait_implementations.1.get("Into"),
|
||||
¶meter_a,
|
||||
¶meter_b,
|
||||
|
|
@ -219,4 +217,3 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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(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 hpga2d;
|
||||
pub mod epga3d;
|
||||
pub mod ppga3d;
|
||||
pub mod hpga3d;
|
||||
pub mod simd;
|
||||
|
||||
impl complex::Scalar {
|
||||
impl epga1d::Scalar {
|
||||
pub const fn new(real: f32) -> Self {
|
||||
Self { g0: real }
|
||||
}
|
||||
|
|
@ -15,16 +21,16 @@ impl complex::Scalar {
|
|||
self.g0
|
||||
}
|
||||
|
||||
pub fn sqrt(self) -> complex::MultiVector {
|
||||
pub fn sqrt(self) -> epga1d::ComplexNumber {
|
||||
if self.g0 < 0.0 {
|
||||
complex::MultiVector::new(0.0, (-self.g0).sqrt())
|
||||
epga1d::ComplexNumber::new(0.0, (-self.g0).sqrt())
|
||||
} 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 {
|
||||
Self {
|
||||
g0: simd::Simd32x2 {
|
||||
|
|
@ -73,23 +79,23 @@ pub trait Dual {
|
|||
/// Negates elements with `grade % 2 == 1`
|
||||
///
|
||||
/// Also called main involution
|
||||
pub trait Automorph {
|
||||
pub trait Automorphism {
|
||||
type Output;
|
||||
fn automorph(self) -> Self::Output;
|
||||
fn automorphism(self) -> Self::Output;
|
||||
}
|
||||
|
||||
/// Negates elements with `grade % 4 >= 2`
|
||||
///
|
||||
/// Also called reversion
|
||||
pub trait Transpose {
|
||||
/// Also called transpose
|
||||
pub trait Reversal {
|
||||
type Output;
|
||||
fn transpose(self) -> Self::Output;
|
||||
fn reversal(self) -> Self::Output;
|
||||
}
|
||||
|
||||
/// Negates elements with `(grade + 3) % 4 < 2`
|
||||
pub trait Conjugate {
|
||||
pub trait Conjugation {
|
||||
type Output;
|
||||
fn conjugate(self) -> Self::Output;
|
||||
fn conjugation(self) -> Self::Output;
|
||||
}
|
||||
|
||||
/// General multi vector multiplication
|
||||
|
|
@ -140,15 +146,7 @@ pub trait ScalarProduct<T> {
|
|||
fn scalar_product(self, other: T) -> Self::Output;
|
||||
}
|
||||
|
||||
/// `self * other * self`
|
||||
///
|
||||
/// Basically a sandwich product without an involution
|
||||
pub trait Reflection<T> {
|
||||
type Output;
|
||||
fn reflection(self, other: T) -> Self::Output;
|
||||
}
|
||||
|
||||
/// `self * other * self.transpose()`
|
||||
/// `self * other * self.reversion()`
|
||||
///
|
||||
/// Also called sandwich product
|
||||
pub trait Transformation<T> {
|
||||
|
|
@ -170,7 +168,7 @@ pub trait Magnitude {
|
|||
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
|
||||
pub trait Signum {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue