namespace reps { TD struct mvector { array values; typename D::Number& operator [] (int i) { return values[i]; } const typename D::Number& operator [] (int i) const { return values[i]; } mvector operator + (const mvector& M) const { mvector result; for(int i=0; i, D::Dim> values; array& operator [] (int i) { return values[i]; } const array& operator [] (int i) const { return values[i]; } matrix operator * (const matrix& M) const { matrix result; for(int i=0; i operator * (const mvector& V) const { mvector result; for(int i=0; i zero_vector() { mvector result; for(int i=0; i unit_vector(int id) { mvector result; for(int i=0; i>; TD std::string nz(const multivector& a) { constexpr int mdim = 1< Number(1e-10)) { if(str.s != "") print(str, " "); if(a[i] > Number(0)) print(str, "+"); print(str, a[i]); for(int u=0; u unit(const typename D::Number& a) { auto res = zero_vector>(); res[0] = a; return res; } TD constexpr multivector embed(const mvector& a) { auto res = zero_vector>(); for(int i=0; i unembed(const multivector& a) { mvector res; for(int i=0; i multimul(const multivector& a, const multivector& b) { constexpr int mdim = 1<>(); for(mvindex i=0; i(i, j); } return res; } template multivector chkmul(const multivector& a, const multivector& b) { constexpr int mdim = 1<>(); /* we initialize with 0s and then add stuff, so one add per component is not necessary */ for(mvindex i=0; i(i, j); else if(B::isflat(j)) res[i^j] += a[i] * mul_sign(i, j); else res[i^j] += a[i] * b[j] * mul_sign(i, j); } return res; } TD multivector conjugate(const multivector& a) { constexpr int mdim = 1<(i); return res; } TD multivector transpose(const multivector& a) { constexpr int mdim = 1<(i); return res; } template multivector apply_nm(multivector a); TD using poincare_rotation = std::pair, multivector>; /** decompose o into the poincare part and the rotational component */ TD poincare_rotation despin2(const multivector& a) { auto p = a; for(int i=(1<<(D::Dim-1)); i<(1<<(D::Dim)); i++) p[i] = typename D::Number(0); p = p * pow(chkmul,rotational,units>(p, conjugate(p))[0], -0.5); auto p1 = chkmul,rotational,poincare>(a, conjugate(p)); return {apply_nm, D>(p1), p}; } /** remove the rotational component of a, leaving only the poincare part */ TD multivector despin(const multivector& a) { auto p = a; for(int i=(1<<(D::Dim-1)); i<(1<<(D::Dim)); i++) p[i] = typename D::Number(0); auto p1 = chkmul,rotational,poincare>(a, conjugate(p)); if(nm == nmInvariant) return p1 * pow(chkmul,rotational,units>(p, conjugate(p))[0], -0.5); return apply_nm, D>(p1); } TD std::string nzv(const mvector& a) { return "vector(" + nz(embed(a)) + ")"; } TD std::string nzv(const matrix& a) { return ""; } template typename D::Number sqnorm(multivector a) { using N = typename D::Number; auto res = chkmul>(a, conjugate(a))[0]; if(res <= N(0) || isinf(res) || isnan(res)) res = N(1); return res; } TD typename D::Number sqnorm(mvector a) { using N = typename D::Number; N res(0); for(int i=0; i multivector flatten(multivector a) { using N = typename D::Number; auto divby = a[0]; a[0] = N(1); for(int i=1; i<(1< multivector apply_nm(multivector a) { if(nm == nmFlatten) return flatten(a); if(nm == nmForced || nm == nmWeak) return a * pow(sqnorm(a), -0.5); if(nm == nmBinary) { while(a[0] >= 2) { a = a / 2; } while(a[0] > 0 && a[0] < 0.5) { a = a * 2; } } return a; } TD mvector apply_nm(mvector a) { if(nm == nmFlatten) { cbc[cbcDiv]--; return a / a[D::Dim-1]; } if(nm == nmForced || nm == nmWeak) return a * pow(sqnorm(a), -0.5); if(nm == nmBinary) { while(a[D::Dim-1] >= 2) { a = a / 2; } while(a[D::Dim-1] > 0 && a[D::Dim-1] < 0.5) { a = a * 2; } } return a; } /** get b which is a coordinate of a, but in normalized form. That is, if a is normalized simply return b, otherwise, multiply b appropriately */ template E get_normalized(multivector a, E b) { if(nm != nmInvariant && nm != nmForced) return b * pow(sqnorm(a), -0.5); return b; } template E get_normalized(mvector a, E b) { if(nm != nmInvariant && nm != nmForced) return b * pow(sqnorm(a), -0.5); return b; } }