quakeforge/ruamoko/gatest/multivector.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

282 lines
6.3 KiB
R

#include <string.h>
#include "algebra.h"
#include "basisblade.h"
#include "basislayout.h"
#include "multivector.h"
#include "util.h"
@implementation MultiVector
static MultiVector *new_mv (Algebra *algebra, BasisLayout *layout)
{
MultiVector *mv = [[[MultiVector alloc] init] autorelease];
mv.algebra = [algebra retain];
layout = layout ? layout : [algebra layout];
mv.layout = [layout retain];
mv.num_components = [layout num_components];
mv.components = obj_malloc (mv.num_components * sizeof (double));
return mv;
}
+(MultiVector *) new:(Algebra *) algebra
{
MultiVector *mv = new_mv (algebra, nil);
for (int i = 0; i < mv.num_components; i++) {
mv.components[i] = 0;
}
return mv;
}
+(MultiVector *) new:(Algebra *) algebra values:(double *) values
{
MultiVector *mv = new_mv (algebra, nil);
for (int i = 0; i < mv.num_components; i++) {
mv.components[i] = values[i];
}
return mv;
}
+(MultiVector *) new:(Algebra *) algebra group:(BasisGroup *) group
{
BasisLayout *layout = [BasisLayout new:1 groups:&group];
MultiVector *mv = new_mv (algebra, layout);
for (int i = 0; i < mv.num_components; i++) {
mv.components[i] = 0;
}
return mv;
}
+(MultiVector *) new:(Algebra *) algebra group:(BasisGroup *) group values:(double *) values
{
BasisLayout *layout = [BasisLayout new:1 groups:&group];
MultiVector *mv = new_mv (algebra, layout);
for (int i = 0; i < mv.num_components; i++) {
mv.components[i] = values[i];
}
return mv;
}
+(MultiVector *) copy:(MultiVector *) src
{
MultiVector *mv = new_mv (src.algebra, src.layout);
for (int i = 0; i < mv.num_components; i++) {
mv.components[i] = src.components[i];
}
return mv;
}
-(void)dealloc
{
[algebra release];
[layout release];
obj_free (components);
[super dealloc];
}
-(string)describe
{
string str = nil;
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
BasisBlade *b = [layout bladeAt:i];
str = sprintf ("%s%s%g%s", str, str ? " + " : "", components[i], [b name]);
}
if (!str) {
str = "0";
}
return str;
}
-(double *) components
{
return components;
}
-(int)indexFor:(unsigned)mask
{
return [layout bladeIndex:mask];
}
-(double *) componentFor:(BasisBlade *) blade
{
return &components[[layout bladeIndex:[blade mask]]];
}
-(MultiVector *) product:(MultiVector *) rhs
{
MultiVector *prod = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
double lc = components[i];
BasisBlade *lb = [layout bladeAt:i];
for (int j = 0; j < rhs.num_components; j++) {
if (!rhs.components[j]) {
continue;
}
double rc = rhs.components[j];
BasisBlade *rb = [rhs.layout bladeAt:j];
BasisBlade *b = [lb geometricProduct:rb metric:[algebra metric]];
double s = [b scale];
if (!s) {
continue;
}
int ind = [prod.layout bladeIndex:[b mask]];
prod.components[ind] += s * lc * rc;
}
}
return prod;
}
-(MultiVector *) wedge:(MultiVector *) rhs
{
MultiVector *prod = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
double lc = components[i];
BasisBlade *lb = [layout bladeAt:i];
for (int j = 0; j < rhs.num_components; j++) {
if (!rhs.components[j]) {
continue;
}
double rc = rhs.components[j];
BasisBlade *rb = [rhs.layout bladeAt:j];
BasisBlade *b = [lb outerProduct:rb];
double s = [b scale];
if (!s) {
continue;
}
int ind = [prod.layout bladeIndex:[b mask]];
prod.components[ind] += s * lc * rc;
}
}
return prod;
}
-(MultiVector *) dot:(MultiVector *) rhs
{
MultiVector *prod = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
double lc = components[i];
BasisBlade *lb = [layout bladeAt:i];
int lg = [lb grade];
for (int j = 0; j < rhs.num_components; j++) {
if (!rhs.components[j]) {
continue;
}
double rc = rhs.components[j];
BasisBlade *rb = [rhs.layout bladeAt:j];
int rg = [rb grade];
BasisBlade *b = [lb geometricProduct:rb metric:[algebra metric]];
int g = [b grade];
if ((lg <= rg) && (g != rg - lg)) {
continue;
}
if ((lg > rg) && (g != lg - rg)) {
continue;
}
double s = [b scale];
if (!s) {
continue;
}
int ind = [prod.layout bladeIndex:[b mask]];
prod.components[ind] += s * lc * rc;
}
}
return prod;
}
-(MultiVector *) plus:(MultiVector *) rhs
{
MultiVector *plus = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
double c = components[i];
if (!c) {
continue;
}
BasisBlade *b = [layout bladeAt:i];
int ind = [plus.layout bladeIndex:[b mask]];
plus.components[ind] += c;
}
for (int i = 0; i < rhs.num_components; i++) {
double c = rhs.components[i];
if (!c) {
continue;
}
BasisBlade *b = [rhs.layout bladeAt:i];
int ind = [plus.layout bladeIndex:[b mask]];
plus.components[ind] += c;
}
return plus;
}
-(MultiVector *) minus:(MultiVector *) rhs
{
MultiVector *minus = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
double c = components[i];
if (!c) {
continue;
}
BasisBlade *b = [layout bladeAt:i];
int ind = [minus.layout bladeIndex:[b mask]];
minus.components[ind] += c;
}
for (int i = 0; i < rhs.num_components; i++) {
double c = rhs.components[i];
if (!c) {
continue;
}
BasisBlade *b = [rhs.layout bladeAt:i];
int ind = [minus.layout bladeIndex:[b mask]];
minus.components[ind] -= c;
}
return minus;
}
-(MultiVector *) dual
{
MultiVector *dual = new_mv (algebra, nil);
unsigned dual_mask = (1 << [algebra dimension]) - 1;
printf ("dual: %x %d\n", dual_mask, [algebra dimension]);
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
double lc = components[i];
BasisBlade *lb = [layout bladeAt:i];
unsigned mask = [lb mask] ^ dual_mask;
double s = 1;
int ind = [layout bladeIndex:mask];
printf (" : %x %d\n", mask, ind);
dual.components[ind] += s * lc;
}
return dual;
}
-(MultiVector *) reverse
{
MultiVector *reverse = new_mv (algebra, nil);
for (int i = 0; i < num_components; i++) {
if (!components[i]) {
continue;
}
double c = components[i];
BasisBlade *b = [layout bladeAt:i];
int g = [b grade];
unsigned mask = [b mask];
double s = g & 2 ? -1 : 1;//FIXME do in BasisBlade?
int ind = [layout bladeIndex:mask];
reverse.components[ind] += s * c;
}
return reverse;
}
@end