Dynamic Multivectors¶
CDynamicMultivector<TValue, TBlade> is the workhorse representation for
high-dimensional and exploratory work. It stores only the non-zero blade
coefficients in a std::map, so memory and computation scale with the
number of populated blades rather than the full algebra dimension (2ⁿ).
Template Parameters¶
| Parameter | What it controls |
|---|---|
TValue |
Coefficient type: double, float, int64_t, … |
TBlade |
Algebra shape via CBlade<Dim, Sig> (see below) |
Defining the algebra with CBlade¶
#include "Tan.GA/Blade.h"
// CBlade<VectorSpaceDimension, VectorSpaceSignature>
// Signature is a bitmask: bit k = 1 means basis vector eₖ squares to -1
// 3D Euclidean (all positive)
using TBlade3 = GA::CBlade<3, 0>::TBlade; // 8 blades
// 4D Projective
using TBlade4 = GA::CBlade<4, 0>::TBlade; // 16 blades
// 5D Conformal (e5 squares to -1, bit 4 set → signature = 0b10000 = 16)
using TBlade5 = GA::CBlade<5, 16>::TBlade; // 32 blades
// Generic 10D (for crypto / ring experiments)
using TBlade10 = GA::CBlade<10, 0>::TBlade; // 1024 blades
Required Headers¶
#include "Tan.GA/DynamicMultivector.h"
#include "Tan.GA/MV_Operators.h"
#include "Tan.GA/Algo.h" // for Inverse
#include "Tan.GA/String.h" // for ToString
#include "Tan.Math/Congruence.h" // for CCongruence_Float / CCongruence_HMod
Construction and Population¶
using namespace Tan;
using TBlade = GA::CBlade<5, 0>::TBlade;
using TValue = double;
using TMV = GA::CDynamicMultivector<TValue, TBlade>;
// 1. Default (zero, no storage allocated)
TMV wA;
// 2. Add individual blades
// Blade ids are uint32_t bit patterns: e1=1, e2=2, e1∧e2=3, …
wA.AddValueBlade(2.0, 1u); // 2*e1
wA.AddValueBlade(3.0, 2u); // 3*e2
// identical blade ids are accumulated: AddValueBlade(x, id) adds x to existing coefficient
// 3. Zero and repopulate
wA.Zero();
// 4. Remove near-zero coefficients (uses ValuePrecision tolerance)
wA.Prune();
Useful Introspection¶
// Number of stored (non-zero after Prune) blades
unsigned n = wA.GetBladeCount();
// Retrieve the coefficient for a specific blade id
TValue coeff;
bool found = wA.GetValueBlade(coeff, TBlade(3u)); // e12
// Iterate over all stored blades
wA.ForEachBlade([](const TValue& val, const TBlade& blade) {
printf("blade %u: %g\n", blade.GetId(), val);
return true; // return false to stop early
});
// Check whether wA and wB are equal within precision
bool eq = GA::IsZero(wA - wB);
Products¶
All products write into the first argument (result). The operands can be any combination of multivector types (dynamic, fixed, subspace).
TMV wB, wC;
// Geometric product C = A * B
GA::GP(wC, wA, wB);
// Outer (wedge) product C = A ^ B
GA::OP(wC, wA, wB);
// Inner product C = A · B
GA::IP(wC, wA, wB);
// Geometric product with modular reduction of each coefficient
Tan::CCongruence_HMod<int64_t> xMod(97);
GA::GP_Congruence(wC, wA, wB, xMod);
Congruence Maps¶
A congruence object controls how coefficients are mapped after each arithmetic operation. Two built-in classes are available.
CCongruence_Float<T> — floating-point (identity)¶
Tan::CCongruence_Float<double> xCongruence;
// Map(x) = x (identity)
// InvMap(x) = 1/x (reciprocal for inverse)
CCongruence_HMod<T> — centred modular arithmetic¶
// All coefficients are reduced to the range (-mod/2, mod/2]
Tan::CCongruence_HMod<int64_t> xMod(97);
// Reduce a full multivector in-place
GA::Congruence(wA, xMod); // wA coefficients → (-49, 48]
// Product with immediate reduction
GA::GP_Congruence(wC, wA, wB, xMod);
Inversion¶
GA::Inverse solves wA * wInv = scalar_identity using Gaussian
elimination on a matrix derived from left-multiplication by wA.
Tan::CCongruence_Float<double> xCongruence;
TMV wInv;
GA::EResult eRes = GA::Inverse(wInv, wA, xCongruence);
if (eRes == GA::EResult::Success)
{
// Verify: A * A^{-1} ≈ scalar 1
TMV wTest;
GA::GP(wTest, wA, wInv);
wTest.Prune();
printf("A * A^{-1} = %s\n", GA::ToString(wTest).c_str());
}
else
{
printf("wA is not invertible in this algebra.\n");
}
For integer coefficient rings, use CCongruence_HMod:
Tan::CCongruence_HMod<int64_t> xMod(97);
TMV wInvMod;
GA::EResult eRes = GA::Inverse(wInvMod, wA, xMod);
// wInvMod satisfies (wA * wInvMod) ≡ 1 (mod 97)
Scalar Multiply and Linear Arithmetic¶
// Scale
TMV wScaled = wA * TValue(3);
// Add / subtract (coefficient-wise, matching blades)
TMV wSum = wA + wB;
TMV wDiff = wA - wB;
// Negate
TMV wNeg = wA * TValue(-1);
Example: 10-Dimensional Algebra¶
using TBlade10 = GA::CBlade<10, 0>::TBlade;
using TValue = int64_t;
using TMV10 = GA::CDynamicMultivector<TValue, TBlade10>;
// AlgebraDimension = 2^10 = 1024 possible blades
// But only populated ones consume memory
static_assert(TMV10::AlgebraDimension == 1024);
TMV10 wA, wB, wC;
// Add a handful of blades
wA.AddValueBlade(1, 1u); // e1
wA.AddValueBlade(2, 4u); // e3
wA.AddValueBlade(-1, 16u); // e5
wB.AddValueBlade(3, 2u); // e2
wB.AddValueBlade(1, 8u); // e4
GA::GP(wC, wA, wB);
wC.Prune();
printf("A*B = %s\n", GA::ToString(wC).c_str());
// Only the few resulting blades are stored, not all 1024