quakeforge/ruamoko/gatest/algebra.r
Bill Currie 4e441d359a [gatest] Write a simple parser for playing with GA
Currently only PGA(3) is supported, but that's because the parser is
rather simple (recursive descent with a lame lexer), but it works well
enough for playing with geometric algebra without having to recompile
every time.
2023-05-27 12:47:33 +09:00

156 lines
3.4 KiB
R

#include <stdlib.h>
#include "algebra.h"
#include "metric.h"
#include "basisblade.h"
#include "basisgroup.h"
#include "basislayout.h"
#include "multivector.h"
#include "util.h"
@implementation Algebra
+(Algebra *) R:(int)p, int m, int z
{
Algebra *a = [[[Algebra alloc] init] autorelease];
a.metric = [[Metric R:p, m, z] retain];
int d = p + m + z;
a.dimension = d;
a.num_components = 1 << d;
BasisBlade **blades = obj_malloc (a.num_components * sizeof (BasisBlade *));
int *counts = binomial (d);
int *indices = obj_malloc ((d + 1) * sizeof (int));
indices[0] = 0;
for (int i = 0; i < d; i++) {
indices[i + 1] = counts[i];
}
prefixsum (indices, d + 1);
for (int i = 0; i < a.num_components; i++) {
int grade = count_bits (i);
int ind = indices[grade]++;
blades[ind] = [BasisBlade basis:i];
}
a.grades = obj_malloc ((d + 1) * sizeof (BasisGroup *));
for (int i = 0; i < d + 1; i++) {
int c = counts[i];
int ind = indices[i];
a.grades[i] = [[BasisGroup new:c basis:blades + ind - c] retain];
}
if (p == 3 && m == 0 && z == 1) {
// 3d PGA (w squares to 0, x y z square to +1):
// : x y z w
// : yz zx xy 1
// : xw yw zw xyzw
// : zyw xzw yxw xyz
BasisBlade *pga_blades[16] = {
blades[1], blades[2], blades[3], blades[4],
blades[7], blades[6], blades[5], blades[0],
blades[8], blades[9], blades[10], blades[15],
blades[14], blades[13], blades[12], blades[11],
};
BasisGroup *pga_groups[4] = {
[BasisGroup new:4 basis:pga_blades + 0],
[BasisGroup new:4 basis:pga_blades + 4],
[BasisGroup new:4 basis:pga_blades + 8],
[BasisGroup new:4 basis:pga_blades + 12],
};
a.layout = [[BasisLayout new:4 groups: pga_groups] retain];
} else if (p == 2 && m == 0 && z == 1) {
// 2d PGA (w squares to 0, x y square to +1):
// : x y w 1
// : yw wx xy xyw
BasisBlade *pga_blades[8] = {
blades[1], blades[2], blades[3], blades[0],
blades[6], blades[5], blades[4], blades[7],
};
BasisGroup *pga_groups[2] = {
[BasisGroup new:4 basis:pga_blades + 0],
[BasisGroup new:4 basis:pga_blades + 4],
};
a.layout = [[BasisLayout new:2 groups: pga_groups] retain];
} else {
// just use the grades as the default layout
a.layout = [[BasisLayout new:d + 1 groups: a.grades] retain];
}
obj_free (indices);
obj_free (counts);
obj_free (blades);
return a;
}
+(Algebra *) PGA:(int)n
{
return [Algebra R:n, 0, 1];
}
-(void)dealloc
{
obj_free (grades);
[metric release];
[layout release];
[super dealloc];
}
-(BasisGroup *)grade:(int)k
{
return grades[k];
}
-(BasisLayout *)layout
{
return layout;
}
-(Metric *) metric
{
return metric;
}
-(int)count
{
return num_components;
}
-(int)dimension
{
return dimension;
}
-(MultiVector *) group:(int)group
{
return [MultiVector new:self group:[layout group:group]];
}
-(MultiVector *) group:(int)group values:(double *)values
{
return [MultiVector new:self group:[layout group:group] values:values];
}
-(MultiVector *) ofGrade:(int)grade
{
return [MultiVector new:self group:grades[grade]];
}
-(MultiVector *) ofGrade:(int)grade values:(double *)values
{
return [MultiVector new:self group:grades[grade] values:values];
}
-(void) print
{
int count = [layout count];
for (int i = 0; i < count; i++) {
BasisGroup *g = [layout group:i];
int c = [g count];
printf ("%d %d %@\n", i, c, [g set]);
for (int j = 0; j < c; j++) {
printf (" %@\n", [g bladeAt:j]);
}
}
}
@end