quakeforge/tools/qfcc/test/pga3d.r
Bill Currie a91595ad6b [qfcc] Make the GA tests a little easier to "use"
All errors are printed now, and the line numbers of the error message
are given, making finding the offending test much easier.
2024-12-07 02:52:10 +09:00

588 lines
14 KiB
R

#include "test-harness.h"
#pragma warn no-vararg-integer
#define error(fmt, ...) \
do { \
printf ("%s:%d: in %s: " fmt, __FILE__, __LINE__, __FUNCTION__ \
__VA_OPT__(,) __VA_ARGS__); \
ret = 1; \
} while (false)
typedef @algebra(float(3,0,1)) PGA;
typedef PGA.group_mask(0x04) scalar_t;
typedef PGA.group_mask(0x01) vector_t;
typedef PGA.group_mask(0x20) trivector_t;
typedef PGA.group_mask(0x10) quadvector_t;
typedef union {
PGA.group_mask(0x0a) bvec;
struct {
PGA.group_mask(0x02) dir;
PGA.group_mask(0x08) mom;
};
} bivector_t;
typedef union {
PGA.group_mask(0x1e) mvec;
bivector_t bvec;
struct {
PGA.group_mask(0x02) dir;
scalar_t scalar;
PGA.group_mask(0x08) mom;
quadvector_t qvec;
};
} evengrades_t;
typedef union {
PGA.group_mask(0x21) mvec;
struct {
vector_t vec;
trivector_t tvec;
};
} oddgrades_t;
static int
test_wedge (void)
{
int ret = 0;
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
quadvector_t qvec, qvecb;
@algebra (PGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3 + e0;
bvec.bvec = -3*e01 + 5*e02 + 7*e03 + 11*e23 - 4*e31 + 2*e12;
tvec = 1*e032 + 4*e013 + 7*e021 - 2*e123;
qvec = 8*e0123;
vecb = 5*e1 + 12*e2 - 13*e0;
bvecb.bvec = 6*e20 + 4*e01 + 1*e12;
tvecb = 3*e032;
qvecb = 1*e0123;
vecc = 5*e1 + 4*e2 - 3*e3 + 4*e0;
vecd = e1 + e2 + e3 + e0;
}
if (scalar != 42) {
error ("scalar != 42: %g\n", scalar);
}
if ((vec4)vec != '3 -2 4 1') {
error ("vec != '3 -2 4 1': %q\n", vec);
}
if ((vec3)bvec.dir != '11 -4 2' || (vec3)bvec.mom != '-3 5 7') {
error ("bvec != '11 -4 2' '-3 5 7': %v %v\n", bvec.dir, bvec.mom);
}
if ((vec4)tvec != '1 4 7 -2') {
error ("tvec != '1 4 7 -2': %g\n", tvec);
}
if ((scalar_t)qvec != 8) {
error ("tvec != 8: %g\n", qvec);
}
bivector_t a = { .bvec = vecvecb };
if ((vec3)a.dir != '-48 20 46' || (vec3)a.mom != '44 -14 52') {
error ("vec ∧ vecb != '-48 20 46' '44 -14 52': %v %v\n", a.dir, a.mom);
}
auto b = a.bvecvecc;
if ((vec4)b != '358 -472 -430 -298') {
error ("a ∧ vecc != '358 -472 -430 -298': %v\n", b);
}
auto c = bvecd;
if ((scalar_t)c != 842) {
error ("b ∧ vecd != 842': %g\n", c);
}
a.bvec = vecbvec;
if ((vec3)a.dir != '48 -20 -46' || (vec3)a.mom != '-44 14 -52') {
error ("vecb ∧ vec != '48 -20 -46' '-44 14 -52': %v %v\n",
a.dir, a.mom);
}
b = vecca.bvec;
if ((vec4)b != '-358 472 430 298') {
error ("vecc ∧ a != '-358 472 430 298': %v\n", b);
}
c = vecdb;
if ((scalar_t)c != 842) {
error ("vecd ^ b != 842': %g\n", c);
}
c = a.bvec(veccvecd);
if ((scalar_t)c != -842) {
error ("a ∧ (vecc ∧ vecd) != -842': %g\n", c);
}
c = (vecdvecc)a.bvec;
if ((scalar_t)c != 842) {
error ("(vecd ∧ vecc) ∧ a != 842': %g\n", c);
}
return ret;
}
static int
test_dot (void)
{
int ret = 0;
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
quadvector_t qvec, qvecb;
@algebra (PGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3 + e0;
bvec.bvec = -3*e01 + 5*e02 + 7*e03 + 11*e23 - 4*e31 + 2*e12;
tvec = 1*e032 + 4*e013 + 7*e021 - 2*e123;
qvec = 8*e0123;
vecb = 5*e1 + 12*e2 - 13*e0;
bvecb.bvec = 6*e20 + 4*e01 + 1*e12;
tvecb = 3*e032;
qvecb = 1*e0123;
vecc = 5*e1 + 4*e2 - 3*e3 + 4*e0;
vecd = e1 + e2 + e3 + e0;
}
if (qvecqvecb != 0) {
error ("(qvec • qvecb) != 0': %g\n", qvecqvecb);
}
auto a = tvecqvec;
if ((vec4)a != '0 0 0 -16') {
error ("vec • vecb != '0 0 0 -16': %v\n", a);
}
bivector_t b = { .mom = bvec.bvecqvec };
if ((vec3)b.dir != '0 0 0' || (vec3)b.mom != '-88 32 -16') {
error ("bvec • qvec != '0 0 0' '-88 32 -16': %v %v\n", b.dir, b.mom);
}
auto c = vecqvec;
if ((vec4)c != '24 -16 32 0') {
error ("vec • qvec != '24 -16 32 0': %v\n", c);
}
a = bvec.bvectvec;
if ((vec4)a != '22 -8 4 9') {
error ("bvec • tvec != '22 -8 4 9': %v\n", a);
}
b.bvec = vectvec;
if ((vec3)b.dir != '-6 4 -8' || (vec3)b.mom != '30 17 -14') {
error ("vec • tvec != '-6 4 -8' '30 17 -14': %v %v\n", b.dir, b.mom);
}
if (bvec.bvecbvec.bvec != -141) {
error ("(bvec • bvec) != -141': %g\n", bvec.bvecbvec.bvec);
}
a = vecbvec.bvec;
if ((vec4)a != '-12 -38 -10 -9') {
error ("vec • bvec != '-12 -38 -10 -9': %v\n", a);
}
if (vecvecb != -9) {
error ("(vec • vecb) != -9': %g\n", vecvecb);
}
a = qvectvec;
if ((vec4)a != '0 0 0 16') {
error ("vec • vecb != '0 0 0 16': %v\n", a);
}
b.bvec = qvecbvec.bvec;
if ((vec3)b.dir != '0 0 0' || (vec3)b.mom != '-88 32 -16') {
error ("qvec • bvec != '0 0 0' '-88 32 -16': %v %v\n", b.dir, b.mom);
}
c = qvecvec;
if ((vec4)c != '-24 16 -32 0') {
error ("vec • qvec != '-24 16 -32 0': %v\n", c);
}
a = tvecbvec.bvec;
if ((vec4)a != '22 -8 4 9') {
error ("tvec • vec != '22 -8 4 9': %v\n", a);
}
b.bvec = tvecvec;
if ((vec3)b.dir != '-6 4 -8' || (vec3)b.mom != '30 17 -14') {
error ("tvec • vec != '-6 4 -8' '30 17 -14': %v %v\n", b.dir, b.mom);
}
a = bvec.bvecvec;
if ((vec4)a != '12 38 10 9') {
error ("bvec • vec != '12 38 10 9': %q\n", a);
}
return ret;
}
static int
test_geom (void)
{
int ret = 0;
scalar_t scalar;
vector_t vec, vecb, vecc, vecd;
bivector_t bvec, bvecb;
trivector_t tvec, tvecb;
quadvector_t qvec, qvecb;
@algebra (PGA) {
scalar = 42;
vec = 3*e1 - 2*e2 + 4*e3 + e0;
bvec.bvec = -3*e01 + 5*e02 + 7*e03 + 11*e23 - 4*e31 + 2*e12;
tvec = 1*e032 + 4*e013 + 7*e021 - 2*e123;
qvec = 8*e0123;
vecb = 5*e1 + 12*e2 - 13*e0;
bvecb.bvec = 6*e20 + 4*e01 + 1*e12;
tvecb = 3*e032;
qvecb = 1*e0123;
vecc = 5*e1 + 4*e2 - 3*e3 + 4*e0;
vecd = e1 + e2 + e3 + e0;
}
if (qvec * qvecb != 0) {
error ("(qvec * qvecb) != 0': %g\n", qvec * qvecb);
}
auto a = tvec * qvec;
if ((vec4)a != '0 0 0 -16') {
error ("vec * vecb != '0 0 0 -16': %v\n", a);
}
bivector_t b = { .mom = bvec.bvec * qvec };
if ((vec3)b.dir != '0 0 0' || (vec3)b.mom != '-88 32 -16') {
error ("bvec * qvec != '0 0 0' '-88 32 -16': %v %v\n", b.dir, b.mom);
}
auto c = vec * qvec;
if ((vec4)c != '24 -16 32 0') {
error ("vec * qvec != '24 -16 32 0': %v\n", c);
}
oddgrades_t d = { .mvec = bvec.bvec * tvec };
if ((vec4)d.vec != '22 -8 4 9' || (vec4)d.tvec != '30 85 -34 0') {
error ("bvec * tvec != '22 -8 4 9' '30 85 -34 0': %q %q\n",
d.vec, d.tvec);
}
evengrades_t e = { .mvec = vec * tvec };
if ((vec3)e.dir != '-6 4 -8' || (vec3)e.mom != '30 17 -14'
|| e.scalar || (scalar_t)e.qvec != 21) {
error ("vec * tvec != 0 '-6 4 -8' '30 17 -14' 21: %g %v %v %g\n",
e.scalar, e.bvec.dir, e.bvec.mom, e.qvec);
}
e.mvec = bvec.bvec * bvec.bvec;
if (e.scalar != -141 || (vec3)e.bvec.dir || (vec3)e.bvec.mom
|| (scalar_t)e.qvec != -78) {
error ("bvec * bvec != -141 '0 0 0' '0 0 0' -78: %g %v %v %g\n",
e.scalar, e.bvec.dir, e.bvec.mom, e.qvec);
}
d = { .mvec = vec * bvec.bvec };
if ((vec4)d.vec != '-12 -38 -10 -9' || (vec4)d.tvec != '-45 -29 7 49') {
error ("vec * bvec != '-12 -38 -10 -9' '-45 -29 7 49': %v %v\n",
d.vec, d.tvec);
}
e.mvec = vec * vecb;
if (e.scalar != -9 || (scalar_t)e.qvec
|| (vec3)e.bvec.dir != '-48 20 46' || (vec3)e.bvec.mom != '44 -14 52') {
error ("(vec * vecb) != -9 '-48 20 46' '44 -14 52' 0': %g %v %v %g\n",
e.scalar, e.bvec.dir, e.bvec.mom, e.qvec);
}
a = qvec * tvec;
if ((vec4)a != '0 0 0 16') {
error ("vec * vecb != '0 0 0 16': %v\n", a);
}
e.mvec = qvec * bvec.bvec;
if (e.scalar || (scalar_t)e.qvec
|| (vec3)e.bvec.dir || (vec3)e.bvec.mom != '-88 32 -16') {
error ("(vec * vecb) != 0 '0 0 0' '-88 32 -16' 0': %g %v %v %g\n",
e.scalar, e.bvec.dir, e.bvec.mom, e.qvec);
}
c = qvec * vec;
if ((vec4)c != '-24 16 -32 0') {
error ("qvec * vec != '-24 16 -32 0': %q\n", c);
}
d = { .mvec = tvec * bvec.bvec };
if ((vec4)d.vec != '22 -8 4 9' || (vec4)d.tvec != '-30 -85 34 0') {
error ("tvec * bvec != '22 -8 4 9' '-30 -85 34 0': %q %q\n",
d.vec, d.tvec);
}
e.mvec = tvec * vec;
if (e.scalar || (scalar_t)e.qvec != -21
|| (vec3)e.bvec.dir != '-6 4 -8' || (vec3)e.bvec.mom != '30 17 -14') {
error ("tvec * vec != 0 '-6 4 -8' '30 17 -14' -21: %g %v %v %g\n",
e.scalar, e.bvec.dir, e.bvec.mom, e.qvec);
}
d.mvec = bvec.bvec * vec;
if ((vec4)d.vec != '12 38 10 9' || (vec4)d.tvec != '-45 -29 7 49') {
error ("vec * bvec != '12 38 10 9' '-45 -29 7 49': %q %q\n",
d.vec, d.tvec);
}
return ret;
}
static int
test_dual (void)
{
int ret = 0;
@algebra (PGA) {
auto a = 1f;
auto a0 = e0;
auto a1 = e1;
auto a2 = e2;
auto a3 = e3;
auto a23 = e23;
auto a31 = e31;
auto a12 = e12;
auto a01 = e01;
auto a02 = e02;
auto a03 = e03;
auto a032 = e032;
auto a013 = e013;
auto a021 = e021;
auto a123 = e123;
auto a0123 = e0123;
#define TEST_DUAL(x, y) \
if (x != y) { \
error ("⋆" #x " != " #y "\n"); \
}
TEST_DUAL (a, e0123);
TEST_DUAL (a0, e123);
TEST_DUAL (a1, e032);
TEST_DUAL (a2, e013);
TEST_DUAL (a3, e021);
TEST_DUAL (a23, e01);
TEST_DUAL (a31, e02);
TEST_DUAL (a12, e03);
TEST_DUAL (a01, e23);
TEST_DUAL (a02, e31);
TEST_DUAL (a03, e12);
TEST_DUAL (a032, -e1);
TEST_DUAL (a013, -e2);
TEST_DUAL (a021, -e3);
TEST_DUAL (a123, -e0);
TEST_DUAL (a0123, 1);
#undef TEST_DUAL
#define TEST_DUAL(x) \
if (x *x != e0123) { \
error (#x " * ⋆" #x " != e0123\n"); \
}
TEST_DUAL (a);
TEST_DUAL (a0);
TEST_DUAL (a1);
TEST_DUAL (a2);
TEST_DUAL (a3);
TEST_DUAL (a23);
TEST_DUAL (a31);
TEST_DUAL (a12);
TEST_DUAL (a01);
TEST_DUAL (a02);
TEST_DUAL (a03);
TEST_DUAL (a032);
TEST_DUAL (a013);
TEST_DUAL (a021);
TEST_DUAL (a123);
TEST_DUAL (a0123);
#undef TEST_DUAL
}
return ret;
}
static int
test_undual (void)
{
int ret = 0;
@algebra (PGA) {
auto a = 1f;
auto a0 = e0;
auto a1 = e1;
auto a2 = e2;
auto a3 = e3;
auto a23 = e23;
auto a31 = e31;
auto a12 = e12;
auto a01 = e01;
auto a02 = e02;
auto a03 = e03;
auto a032 = e032;
auto a013 = e013;
auto a021 = e021;
auto a123 = e123;
auto a0123 = e0123;
#define TEST_UNDUAL(x, y) \
if (@undual x != y) { \
error ("@undual" #x " != " #y "\n"); \
}
TEST_UNDUAL (a, e0123);
TEST_UNDUAL (a0, -e123);
TEST_UNDUAL (a1, -e032);
TEST_UNDUAL (a2, -e013);
TEST_UNDUAL (a3, -e021);
TEST_UNDUAL (a23, e01);
TEST_UNDUAL (a31, e02);
TEST_UNDUAL (a12, e03);
TEST_UNDUAL (a01, e23);
TEST_UNDUAL (a02, e31);
TEST_UNDUAL (a03, e12);
TEST_UNDUAL (a032, e1);
TEST_UNDUAL (a013, e2);
TEST_UNDUAL (a021, e3);
TEST_UNDUAL (a123, e0);
TEST_UNDUAL (a0123, 1);
#undef TEST_UNDUAL
#define TEST_UNDUAL(x) \
if (@undual x * x != e0123) { \
error ("@undual " #x " * " #x " != e0123\n"); \
}
TEST_UNDUAL (a);
TEST_UNDUAL (a0);
TEST_UNDUAL (a1);
TEST_UNDUAL (a2);
TEST_UNDUAL (a3);
TEST_UNDUAL (a23);
TEST_UNDUAL (a31);
TEST_UNDUAL (a12);
TEST_UNDUAL (a01);
TEST_UNDUAL (a02);
TEST_UNDUAL (a03);
TEST_UNDUAL (a032);
TEST_UNDUAL (a013);
TEST_UNDUAL (a021);
TEST_UNDUAL (a123);
TEST_UNDUAL (a0123);
#undef TEST_UNDUAL
}
return ret;
}
static int
test_basics (void)
{
int ret = 0;
@algebra (PGA) {
auto plane1 = e1 + 8*e0;
auto plane2 = e2 + 8*e0;
auto line = plane1 @wedge plane2;
auto p = -3*e021 + e123;
auto point = line @dot p * ~line;
auto rot = line * p * ~line;
auto p1 = 12*e032 + 4*e013 + e123;
auto p2 = 4*e032 + 12*e013 + e123;
auto x = point @regressive rot;
if ((vec4)plane1 != '1 0 0 8' || (vec4)plane2 != '0 1 0 8') {
error ("plane1 or plane2 wrong: %q %q\n", plane1, plane2);
}
if ((vec4)p != '0 0 -3 1' || (vec4)p1 != '12 4 0 1'
|| (vec4)p2 != '4 12 0 1') {
error ("p or p1 or p2 wrong: %q %q %q\n", p, p1, p2);
}
bivector_t b = { .bvec = line };
if ((vec3)b.dir != '0 0 1' || (vec3)b.mom != '-8 8 0') {
error ("line is wrong: %v %v\n", b.dir, b.mom);
}
oddgrades_t o = { .mvec = point };
if ((vec4)o.vec || (vec4)o.tvec != '-8 -8 -3 1') {
error ("point is wrong: %q\n", point);
}
o.mvec = rot;
if ((vec4)o.vec || (vec4)o.tvec != '-16 -16 -3 1') {
error ("rot is wrong: %q %q\n", o.vec, o.tvec);
}
evengrades_t e = { .mvec = x };
if (e.scalar || (scalar_t)e.qvec
|| (vec3)e.dir != '-8 -8 0' || (vec3)e.mom != '-24 24 0') {
error ("x is wrong: %g %v %v %g\n", e.scalar, e.dir, e.mom, e.qvec);
}
}
return ret;
}
int
main (void)
{
int ret = 0;
if (sizeof (scalar_t) != sizeof (float)) {
error ("scalar has wrong size: %d\n", sizeof (scalar_t));
}
if (sizeof (vector_t) != 4 * sizeof (scalar_t)) {
error ("bivector has wrong size: %d\n", sizeof (vector_t));
}
// the pair of vec3s in a bivector have an alignment of 4
if (sizeof (bivector_t) != 8 * sizeof (scalar_t)) {
error ("bivector has wrong size: %d\n", sizeof (bivector_t));
}
if (sizeof (bivector_t) != sizeof (PGA.group_mask(0x0a))) {
error ("bivector group has wrong size: %d\n",
sizeof (PGA.group_mask(0x0a)));
}
if (sizeof (trivector_t) != 4 * sizeof (scalar_t)) {
error ("trivector has wrong size: %d\n", sizeof (trivector_t));
}
if (sizeof (quadvector_t) != sizeof (scalar_t)) {
error ("quadvector has wrong size: %d\n", sizeof (quadvector_t));
}
if (sizeof (evengrades_t) != sizeof (bivector_t)) {
evengrades_t e;
#define offsetof(s,f) ((int)(&((s*)0).f))
printf ("evengrades has wrong size: %d\n", sizeof (evengrades_t));
printf ("mvec: %d, bvec: %d, scalar: %d, qvec: %d\n",
sizeof (e.mvec), sizeof (e.bvec),
sizeof (e.scalar), sizeof (e.qvec));
printf ("mvec: %d, bvec: %d, scalar: %d, qvec: %d\n",
offsetof (evengrades_t, mvec), offsetof (evengrades_t, bvec),
offsetof (evengrades_t, scalar), offsetof (evengrades_t, qvec));
ret = 1;
}
if (test_wedge ()) {
printf ("wedge products failed\n");
ret = 1;
}
if (test_dot ()) {
printf ("dot products failed\n");
ret = 1;
}
if (test_geom ()) {
printf ("geometric products failed\n");
ret = 1;
}
if (test_dual ()) {
printf ("dual failed\n");
ret = 1;
}
if (test_undual ()) {
printf ("dual failed\n");
ret = 1;
}
if (test_basics ()) {
printf ("basics failed\n");
ret = 1;
}
return ret;
}