Geometric algebra
Geometric algebra is an other name for Clifford algebras and it's basically an algebra containing a vector space and obeying the following axioms:
The purpose of this task is to implement such an algebra with vectors of arbitrary size, or up to 32 dimensions if that's easier to implement in your language.
To demonstrate your solution, you will use it to implement quaternions. From an orthonormal basis , create the three elements:
and show that .
J
Using the implementation from the Quaternion type task:
<lang J> i=: 0 1 0 0
j=: 0 0 1 0 k=: 0 0 0 1 i mul j mul k
_1 0 0 0
i mul i
_1 0 0 0
j mul j
_1 0 0 0
k mul k
_1 0 0 0</lang>
Perl 6
<lang perl6>unit class MultiVector; has Real %.blades{UInt}; method clean { for %!blades { %!blades{.key} :delete unless .value; } } method narrow {
for %!blades { return self if .key > 0 && .value !== 0; } return %!blades{0} // 0;
}
sub e(UInt $n?) returns MultiVector is export {
$n.defined ?? MultiVector.new(:blades(my Real %{UInt} = (1 +< $n) => 1)) !! MultiVector.new
}
my sub grade(UInt $n) is cached { [+] $n.base(2).comb } my sub order(UInt:D $i is copy, UInt:D $j) is cached {
my $n = 0; repeat {
$i +>= 1; $n += [+] ($i +& $j).base(2).comb;
} until $i == 0; return $n +& 1 ?? -1 !! 1;
}
multi infix:<+>(MultiVector $A, MultiVector $B) returns MultiVector is export {
my Real %blades{UInt} = $A.blades.clone; for $B.blades {
%blades{.key} += .value; %blades{.key} :delete unless %blades{.key};
} return MultiVector.new: :%blades;
} multi infix:<+>(Real $s, MultiVector $A) returns MultiVector is export {
my Real %blades{UInt} = $A.blades.clone; %blades{0} += $s; %blades{0} :delete unless %blades{0}; return MultiVector.new: :%blades;
} multi infix:<+>(MultiVector $A, Real $s) returns MultiVector is export { $s + $A } multi infix:<*>(MultiVector $A, MultiVector $B) returns MultiVector is export {
my Real %blades{UInt}; for $A.blades -> $a {
for $B.blades -> $b { my $c = $a.key +^ $b.key; %blades{$c} += $a.value * $b.value * order($a.key, $b.key); %blades{$c} :delete unless %blades{$c}; }
} return MultiVector.new: :%blades;
} multi infix:<**>(MultiVector $ , 0) returns MultiVector is export { MultiVector.new } multi infix:<**>(MultiVector $A, 1) returns MultiVector is export { $A } multi infix:<**>(MultiVector $A, 2) returns MultiVector is export { $A * $A } multi infix:<**>(MultiVector $A, UInt $n where $n %% 2) returns MultiVector is export { ($A ** ($n div 2)) ** 2 } multi infix:<**>(MultiVector $A, UInt $n) returns MultiVector is export { $A * ($A ** ($n div 2)) ** 2 }
multi infix:<*>(MultiVector $, 0) returns MultiVector is export { MultiVector.new } multi infix:<*>(MultiVector $A, 1) returns MultiVector is export { $A } multi infix:<*>(MultiVector $A, Real $s) returns MultiVector is export {
return MultiVector.new: :blades(my Real %{UInt} = map { .key => $s * .value }, $A.blades);
} multi infix:<*>(Real $s, MultiVector $A) returns MultiVector is export { $A * $s } multi infix:</>(MultiVector $A, Real $s) returns MultiVector is export { $A * (1/$s) } multi prefix:<->(MultiVector $A) returns MultiVector is export { return -1 * $A } multi infix:<->(MultiVector $A, MultiVector $B) returns MultiVector is export { $A + -$B } multi infix:<->(MultiVector $A, Real $s) returns MultiVector is export { $A + -$s } multi infix:<->(Real $s, MultiVector $A) returns MultiVector is export { $s + -$A }
multi infix:<==>(MultiVector $A, MultiVector $B) returns Bool is export { $A - $B == 0 } multi infix:<==>(Real $x, MultiVector $A) returns Bool is export { $A == $x } multi infix:<==>(MultiVector $A, Real $x) returns Bool is export {
my $narrowed = $A.narrow; $narrowed ~~ Real and $narrowed == $x;
}</lang>
And here is the code implementing and verifying quaternions:
<lang perl6>use MultiVector; use Test;
plan 1;
my constant i = e(1)*e(2); my constant j = e(2)*e(3); my constant k = e(1)*e(3);
ok i**2 == j**2 == k**2 == i*j*k == -1;</lang>
- Output:
1..1 ok 1 -