1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// ============================================================================
// VERSORC-MATH: BASIS BLADES & CAYLEY MULTIPLICATION SIGN CALCULATOR
// License: Apache-2.0
// ============================================================================
use crate::signature::MetricSignature;
/// Basis blade represented as a bitmask of generator vectors.
/// E.g., scalar = 0b0000, e_1 = 0b0001, e_2 = 0b0010, e_12 = 0b0011, e_123 = 0b0111.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Blade(pub u32);
impl Blade {
pub const SCALAR: Self = Self(0);
#[inline(always)]
pub const fn new(mask: u32) -> Self {
Self(mask)
}
#[inline(always)]
pub const fn generator(i: usize) -> Self {
Self(1 << i)
}
/// Grade of the blade (number of basis vectors spanning it).
#[inline(always)]
pub const fn grade(self) -> usize {
self.0.count_ones() as usize
}
/// Reverse sign of the blade: (-1)^{k(k-1)/2}.
#[inline(always)]
pub const fn reverse_sign(self) -> i8 {
let k = self.grade();
if k < 2 {
1
} else if (k * (k - 1) / 2) % 2 == 0 {
1
} else {
-1
}
}
/// Grade involution sign of the blade: (-1)^k.
#[inline(always)]
pub const fn involution_sign(self) -> i8 {
if self.grade() % 2 == 0 {
1
} else {
-1
}
}
/// Clifford conjugation sign of the blade: (-1)^{k(k+1)/2}.
#[inline(always)]
pub const fn conjugation_sign(self) -> i8 {
let k = self.grade();
if (k * (k + 1) / 2) % 2 == 0 {
1
} else {
-1
}
}
/// Computes the geometric product of two basis blades e_I * e_J under metric Cl(p, q, r).
/// Returns Some((resulting_blade, sign)) or None if the result is zero (due to degenerate r-generators).
#[inline]
pub fn geometric_product<const P: usize, const Q: usize, const R: usize>(
self,
rhs: Self,
) -> Option<(Self, i8)> {
let mask_a = self.0;
let mask_b = rhs.0;
// 1. Calculate permutation transpositions (swaps) to order generators
let mut swaps = 0u32;
let mut temp_b = mask_b;
while temp_b != 0 {
let j = temp_b.trailing_zeros();
// Count generators in A that are strictly greater than generator j
swaps += (mask_a >> (j + 1)).count_ones();
temp_b &= temp_b - 1; // Clear lowest set bit
}
let mut sign: i8 = if swaps % 2 == 0 { 1 } else { -1 };
// 2. Evaluate metric contraction for common generators: e_k * e_k = eta_kk
let common = mask_a & mask_b;
if common != 0 {
let mut temp_common = common;
while temp_common != 0 {
let k = temp_common.trailing_zeros() as usize;
let metric_sq = MetricSignature::<P, Q, R>::basis_square(k);
if metric_sq == 0 {
return None; // Degenerate generator squared to zero
}
sign *= metric_sq;
temp_common &= temp_common - 1;
}
}
let resulting_mask = mask_a ^ mask_b;
Some((Self(resulting_mask), sign))
}
/// Computes the exterior wedge product e_I ^ e_J.
/// Nonzero if and only if blades share no common generators (I & J == 0).
#[inline]
pub fn wedge_product(self, rhs: Self) -> Option<(Self, i8)> {
if (self.0 & rhs.0) != 0 {
return None; // Linearly dependent generators wedge to zero
}
// Swaps identical to geometric product when common == 0
let mut swaps = 0u32;
let mut temp_b = rhs.0;
while temp_b != 0 {
let j = temp_b.trailing_zeros();
swaps += (self.0 >> (j + 1)).count_ones();
temp_b &= temp_b - 1;
}
let sign: i8 = if swaps % 2 == 0 { 1 } else { -1 };
Some((Self(self.0 | rhs.0), sign))
}
/// Computes the left contraction e_I _| e_J under metric Cl(p, q, r).
/// Nonzero only if grade(result) == grade(J) - grade(I).
#[inline]
pub fn left_contraction<const P: usize, const Q: usize, const R: usize>(
self,
rhs: Self,
) -> Option<(Self, i8)> {
let r = self.grade();
let s = rhs.grade();
if r > s {
return None;
}
let (prod_blade, sign) = self.geometric_product::<P, Q, R>(rhs)?;
if prod_blade.grade() == s - r {
Some((prod_blade, sign))
} else {
None
}
}
/// Computes the right contraction e_I |_ e_J under metric Cl(p, q, r).
/// Nonzero only if grade(result) == grade(I) - grade(J).
#[inline]
pub fn right_contraction<const P: usize, const Q: usize, const R: usize>(
self,
rhs: Self,
) -> Option<(Self, i8)> {
let r = self.grade();
let s = rhs.grade();
if r < s {
return None;
}
let (prod_blade, sign) = self.geometric_product::<P, Q, R>(rhs)?;
if prod_blade.grade() == r - s {
Some((prod_blade, sign))
} else {
None
}
}
}