78clifford::
clifford() : representation_label(0), metric(0), commutator_sign(-1)
96clifford::
clifford(const
ex & b,
unsigned char rl) : inherited(b), representation_label(rl), metric(0), commutator_sign(-1)
104clifford::clifford(
const ex & b,
const ex & mu,
const ex & metr,
unsigned char rl,
int comm_sign) : inherited(b, mu), representation_label(rl), metric(metr), commutator_sign(comm_sign)
128 inherited::read_archive(
n, sym_lst);
130 n.find_unsigned(
"label", rl);
132 n.find_ex(
"metric",
metric, sym_lst);
133 n.find_unsigned(
"commutator_sign+1", rl);
139 inherited::archive(
n);
156 if (is_a<indexed>(
metric)) {
157 if (symmetrised && !(ex_to<symmetry>(ex_to<indexed>(
metric).
get_symmetry()).has_symmetry())) {
180 if (is_a<clifford>(other))
181 metr = ex_to<clifford>(other).get_metric();
185 if (is_a<indexed>(metr))
189 return (indices.size() == 2)
216 return inherited::let_op(i);
222 if(is_a<clifford>(subsed)) {
223 ex prevmetric = ex_to<clifford>(subsed).metric;
227 c.metric = newmetric;
244 return inherited::compare_same_type(other);
257 return !is_a<diracgamma5>(seq0) && !is_a<diracgammaL>(seq0) &&
258 !is_a<diracgammaR>(seq0) && !is_a<cliffordunit>(seq0) &&
259 !is_a<diracone>(seq0);
270 this->print_dispatch<inherited>(
c, level);
291 c.s <<
"\\hspace{-1.0ex}/}";
294 this->print_dispatch<inherited>(
c, level);
300 c.s << std::string(level,
' ') << class_name() <<
" @" <<
this
301 << std::hex <<
", hash=0x" <<
hashvalue <<
", flags=0x" <<
flags << std::dec
302 <<
", " <<
seq.size()-1 <<
" indices"
303 <<
", symmetry=" <<
symtree << std::endl;
305 seq[0].print(
c, level +
c.delta_indent);
320DEFAULT_PRINT_LATEX(diracgammaL, "gammaL
", "{\\gamma_L}
")
321DEFAULT_PRINT_LATEX(diracgammaR, "gammaR
", "{\\gamma_R}
")
324static void base_and_index(const ex & c, ex & b, ex & i)
326 GINAC_ASSERT(is_a<clifford>(c));
327 GINAC_ASSERT(c.nops() == 2+1);
329 if (is_a<cliffordunit>(c.op(0))) { // proper dirac gamma object or clifford unit
332 } else if (is_a<diracgamma5>(c.op(0)) || is_a<diracgammaL>(c.op(0)) || is_a<diracgammaR>(c.op(0))) { // gamma5/L/R
335 } else { // slash object, generate new dummy index
336 varidx ix(dynallocate<symbol>(), ex_to<idx>(c.op(1)).get_dim());
337 b = indexed(c.op(0), ix.toggle_variance());
343struct is_not_a_clifford {
344 bool operator()(const ex & e)
346 return !is_a<clifford>(e);
351bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
353 GINAC_ASSERT(is_a<clifford>(*self));
354 GINAC_ASSERT(is_a<indexed>(*other));
355 GINAC_ASSERT(is_a<diracgamma>(self->op(0)));
356 unsigned char rl = ex_to<clifford>(*self).get_representation_label();
358 ex dim = ex_to<idx>(self->op(1)).get_dim();
359 if (other->nops() > 1)
360 dim = minimal_dim(dim, ex_to<idx>(other->op(1)).get_dim());
362 if (is_a<clifford>(*other)) {
364 // Contraction only makes sense if the representation labels are equal
365 if (ex_to<clifford>(*other).get_representation_label() != rl)
368 size_t num = other - self;
370 // gamma~mu gamma.mu = dim ONE
373 *other = dirac_ONE(rl);
376 // gamma~mu gamma~alpha gamma.mu = (2-dim) gamma~alpha
378 && is_a<clifford>(self[1])) {
383 // gamma~mu gamma~alpha gamma~beta gamma.mu = 4 g~alpha~beta + (dim-4) gamam~alpha gamma~beta
385 && is_a<clifford>(self[1])
386 && is_a<clifford>(self[2])) {
388 base_and_index(self[1], b1, i1);
389 base_and_index(self[2], b2, i2);
390 *self = 4 * lorentz_g(i1, i2) * b1 * b2 * dirac_ONE(rl) + (dim - 4) * self[1] * self[2];
396 // gamma~mu gamma~alpha gamma~beta gamma~delta gamma.mu = -2 gamma~delta gamma~beta gamma~alpha - (dim-4) gamam~alpha gamma~beta gamma~delta
398 && is_a<clifford>(self[1])
399 && is_a<clifford>(self[2])
400 && is_a<clifford>(self[3])) {
401 *self = -2 * self[3] * self[2] * self[1] - (dim - 4) * self[1] * self[2] * self[3];
408 // gamma~mu Sodd gamma.mu = -2 Sodd_R
409 // (Chisholm identity in 4 dimensions)
410 } else if (!((other - self) & 1) && dim.is_equal(4)) {
411 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
414 *self = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(other), std::reverse_iterator<exvector::const_iterator>(self + 1)));
415 std::fill(self + 1, other, _ex1);
419 // gamma~mu Sodd gamma~alpha gamma.mu = 2 gamma~alpha Sodd + 2 Sodd_R gamma~alpha
420 // (commutate contracted indices towards each other, then use
421 // Chisholm identity in 4 dimensions)
422 } else if (((other - self) & 1) && dim.is_equal(4)) {
423 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
426 auto next_to_last = other - 1;
427 ex S = ncmul(exvector(self + 1, next_to_last));
428 ex SR = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(next_to_last), std::reverse_iterator<exvector::const_iterator>(self + 1)));
430 *self = (*next_to_last) * S + SR * (*next_to_last);
431 std::fill(self + 1, other, _ex1);
435 // gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha
436 // (commutate contracted indices towards each other, simplify_indexed()
437 // will re-expand and re-run the simplification)
439 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
442 auto next_to_last = other - 1;
443 ex S = ncmul(exvector(self + 1, next_to_last));
445 *self = 2 * (*next_to_last) * S - (*self) * S * (*other) * (*next_to_last);
446 std::fill(self + 1, other + 1, _ex1);
450 } else if (is_a<symbol>(other->op(0)) && other->nops() == 2) {
452 // x.mu gamma~mu -> x-slash
453 *self = dirac_slash(other->op(0), dim, rl);
462bool cliffordunit::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
464 GINAC_ASSERT(is_a<clifford>(*self));
465 GINAC_ASSERT(is_a<indexed>(*other));
466 GINAC_ASSERT(is_a<cliffordunit>(self->op(0)));
467 clifford unit = ex_to<clifford>(*self);
468 unsigned char rl = unit.get_representation_label();
470 if (is_a<clifford>(*other)) {
471 // Contraction only makes sense if the representation labels are equal
472 // and the metrics are the same
473 if ((ex_to<clifford>(*other).get_representation_label() != rl)
474 && unit.same_metric(*other))
477 auto before_other = other - 1;
479 ex mu_toggle = other->op(1);
480 ex alpha = before_other->op(1);
482 // e~mu e.mu = Tr ONE
483 if (other - self == 1) {
484 *self = unit.get_metric(mu, mu_toggle, true);
485 *other = dirac_ONE(rl);
488 } else if (other - self == 2) {
489 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) {
490 // e~mu e~alpha e.mu = 2*e~mu B(alpha, mu.toggle_variance())-Tr(B) e~alpha
491 *self = 2 * (*self) * unit.get_metric(alpha, mu_toggle, true) - unit.get_metric(mu, mu_toggle, true) * (*before_other);
492 *before_other = _ex1;
497 // e~mu S e.mu = Tr S ONE
498 *self = unit.get_metric(mu, mu_toggle, true);
499 *other = dirac_ONE(rl);
503 // e~mu S e~alpha e.mu = 2 e~mu S B(alpha, mu.toggle_variance()) - e~mu S e.mu e~alpha
504 // (commutate contracted indices towards each other, simplify_indexed()
505 // will re-expand and re-run the simplification)
506 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) {
510 ex S = ncmul(exvector(self + 1, before_other));
512 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) {
513 *self = 2 * (*self) * S * unit.get_metric(alpha, mu_toggle, true) - (*self) * S * (*other) * (*before_other);
516 *self = (*self) * S * (*other) * (*before_other);
519 std::fill(self + 1, other + 1, _ex1);
529ex clifford::eval_ncmul(const exvector & v) const
534 // Remove superfluous ONEs
535 for (auto & it : v) {
536 if (!is_a<clifford>(it) || !is_a<diracone>(it.op(0)))
540 bool something_changed = false;
543 // Anticommutate gamma5/L/R's to the front
545 auto first = s.begin(), next_to_last = s.end() - 2;
547 auto it = next_to_last;
550 if (is_a<clifford>(*it) && is_a<clifford>(*it2)) {
551 ex e1 = it->op(0), e2 = it2->op(0);
553 if (is_a<diracgamma5>(e2)) {
555 if (is_a<diracgammaL>(e1) || is_a<diracgammaR>(e1)) {
557 // gammaL/R gamma5 -> gamma5 gammaL/R
559 something_changed = true;
561 } else if (!is_a<diracgamma5>(e1)) {
563 // gamma5 gamma5 -> gamma5 gamma5 (do nothing)
564 // x gamma5 -> -gamma5 x
567 something_changed = true;
570 } else if (is_a<diracgammaL>(e2)) {
572 if (is_a<diracgammaR>(e1)) {
574 // gammaR gammaL -> 0
577 } else if (!is_a<diracgammaL>(e1) && !is_a<diracgamma5>(e1)) {
579 // gammaL gammaL -> gammaL gammaL (do nothing)
580 // gamma5 gammaL -> gamma5 gammaL (do nothing)
581 // x gammaL -> gammaR x
583 *it = clifford(diracgammaR(), ex_to<clifford>(*it).get_representation_label());
584 something_changed = true;
587 } else if (is_a<diracgammaR>(e2)) {
589 if (is_a<diracgammaL>(e1)) {
591 // gammaL gammaR -> 0
594 } else if (!is_a<diracgammaR>(e1) && !is_a<diracgamma5>(e1)) {
596 // gammaR gammaR -> gammaR gammaR (do nothing)
597 // gamma5 gammaR -> gamma5 gammaR (do nothing)
598 // x gammaR -> gammaL x
600 *it = clifford(diracgammaL(), ex_to<clifford>(*it).get_representation_label());
601 something_changed = true;
609 if (next_to_last == first)
615 // Remove equal adjacent gammas
617 exvector::iterator it, itend = s.end() - 1;
618 for (it = s.begin(); it != itend; ++it) {
621 if (!is_a<clifford>(a) || !is_a<clifford>(b))
624 const ex & ag = a.op(0);
625 const ex & bg = b.op(0);
626 bool a_is_cliffordunit = is_a<cliffordunit>(ag);
627 bool b_is_cliffordunit = is_a<cliffordunit>(bg);
629 if (a_is_cliffordunit && b_is_cliffordunit && ex_to<clifford>(a).same_metric(b)
630 && (ex_to<clifford>(a).get_commutator_sign() == -1)) {
631 // This is done only for Clifford algebras
633 const ex & ia = a.op(1);
634 const ex & ib = b.op(1);
635 if (ia.is_equal(ib)) { // gamma~alpha gamma~alpha -> g~alpha~alpha
636 a = ex_to<clifford>(a).get_metric(ia, ib, true);
637 b = dirac_ONE(representation_label);
638 something_changed = true;
641 } else if ((is_a<diracgamma5>(ag) && is_a<diracgamma5>(bg))) {
643 // Remove squares of gamma5
644 a = dirac_ONE(representation_label);
645 b = dirac_ONE(representation_label);
646 something_changed = true;
648 } else if ((is_a<diracgammaL>(ag) && is_a<diracgammaL>(bg))
649 || (is_a<diracgammaR>(ag) && is_a<diracgammaR>(bg))) {
651 // Remove squares of gammaL/R
652 b = dirac_ONE(representation_label);
653 something_changed = true;
655 } else if (is_a<diracgammaL>(ag) && is_a<diracgammaR>(bg)) {
657 // gammaL and gammaR are orthogonal
660 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaL>(bg)) {
662 // gamma5 gammaL -> -gammaL
663 a = dirac_ONE(representation_label);
665 something_changed = true;
667 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaR>(bg)) {
669 // gamma5 gammaR -> gammaR
670 a = dirac_ONE(representation_label);
671 something_changed = true;
673 } else if (!a_is_cliffordunit && !b_is_cliffordunit && ag.is_equal(bg)) {
676 varidx ix(dynallocate<symbol>(), ex_to<idx>(a.op(1)).minimal_dim(ex_to<idx>(b.op(1))));
678 a = indexed(ag, ix) * indexed(ag, ix.toggle_variance());
679 b = dirac_ONE(representation_label);
680 something_changed = true;
686 return dirac_ONE(representation_label) * sign;
687 if (something_changed)
688 return reeval_ncmul(s) * sign;
690 return hold_ncmul(s) * sign;
693ex clifford::thiscontainer(const exvector & v) const
695 return clifford(representation_label, metric, commutator_sign, v);
698ex clifford::thiscontainer(exvector && v) const
700 return clifford(representation_label, metric, commutator_sign, std::move(v));
703ex diracgamma5::conjugate() const
705 return _ex_1 * (*this);
708ex diracgammaL::conjugate() const
710 return dynallocate<diracgammaR>();
713ex diracgammaR::conjugate() const
715 return dynallocate<diracgammaL>();
722ex dirac_ONE(unsigned char rl)
724 static ex ONE = dynallocate<diracone>();
725 return clifford(ONE, rl);
728static unsigned get_dim_uint(const ex& e)
731 throw std::invalid_argument("get_dim_uint: argument is not an index
");
732 ex dim = ex_to<idx>(e).get_dim();
733 if (!dim.info(info_flags::posint))
734 throw std::invalid_argument("get_dim_uint: dimension of index should be a positive integer
");
735 unsigned d = ex_to<numeric>(dim).to_int();
739ex clifford_unit(const ex & mu, const ex & metr, unsigned char rl)
741 ex unit = dynallocate<cliffordunit>();
746 exvector indices = metr.get_free_indices();
748 if (indices.size() == 2) {
749 return clifford(unit, mu, metr, rl);
750 } else if (is_a<matrix>(metr)) {
751 matrix M = ex_to<matrix>(metr);
752 unsigned n = M.rows();
753 bool symmetric = true;
755 //static idx xi(dynallocate<symbol>(), n),
756 // chi(dynallocate<symbol>(), n);
757 idx xi(dynallocate<symbol>(), n),
758 chi(dynallocate<symbol>(), n);
759 if ((n == M.cols()) && (n == get_dim_uint(mu))) {
760 for (unsigned i = 0; i < n; i++) {
761 for (unsigned j = i+1; j < n; j++) {
762 if (!M(i, j).is_equal(M(j, i))) {
767 return clifford(unit, mu, indexed(metr, symmetric?symmetric2():not_symmetric(), xi, chi), rl);
769 throw(std::invalid_argument("clifford_unit(): metric for Clifford
unit must be a square
matrix with the same dimensions as index
"));
771 } else if (indices.size() == 0) { // a tensor or other expression without indices
772 //static varidx xi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim()),
773 // chi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim());
774 varidx xi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim()),
775 chi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim());
776 return clifford(unit, mu, indexed(metr, xi, chi), rl);
778 throw(std::invalid_argument("clifford_unit(): metric for Clifford
unit must be of type
tensor,
matrix or an expression with two free indices
"));
781ex dirac_gamma(const ex & mu, unsigned char rl)
783 static ex gamma = dynallocate<diracgamma>();
785 if (!is_a<varidx>(mu))
786 throw(std::invalid_argument("dirac_gamma(): index of Dirac gamma must be of type
varidx"));
788 static varidx xi(dynallocate<symbol>(), ex_to<varidx>(mu).get_dim()),
789 chi(dynallocate<symbol>(), ex_to<varidx>(mu).get_dim());
790 return clifford(gamma, mu, indexed(dynallocate<minkmetric>(), symmetric2(), xi, chi), rl);
793ex dirac_gamma5(unsigned char rl)
795 static ex gamma5 = dynallocate<diracgamma5>();
796 return clifford(gamma5, rl);
799ex dirac_gammaL(unsigned char rl)
801 static ex gammaL = dynallocate<diracgammaL>();
802 return clifford(gammaL, rl);
805ex dirac_gammaR(unsigned char rl)
807 static ex gammaR = dynallocate<diracgammaR>();
808 return clifford(gammaR, rl);
811ex dirac_slash(const ex & e, const ex & dim, unsigned char rl)
813 // Slashed vectors are actually stored as a clifford object with the
814 // vector as its base expression and a (dummy) index that just serves
815 // for storing the space dimensionality
817 static varidx xi(dynallocate<symbol>(), dim),
818 chi(dynallocate<symbol>(), dim);
819 return clifford(e, varidx(0, dim), indexed(dynallocate<minkmetric>(), symmetric2(), xi, chi), rl);
824static unsigned char get_representation_label(const return_type_t& ti)
826 return (unsigned char)ti.rl;
831static ex trace_string(exvector::const_iterator ix, size_t num)
833 // Tr gamma.mu gamma.nu = 4 g.mu.nu
835 return lorentz_g(ix[0], ix[1]);
837 // Tr gamma.mu gamma.nu gamma.rho gamma.sig = 4 (g.mu.nu g.rho.sig + g.nu.rho g.mu.sig - g.mu.rho g.nu.sig )
839 return lorentz_g(ix[0], ix[1]) * lorentz_g(ix[2], ix[3])
840 + lorentz_g(ix[1], ix[2]) * lorentz_g(ix[0], ix[3])
841 - lorentz_g(ix[0], ix[2]) * lorentz_g(ix[1], ix[3]);
843 // Traces of 6 or more gammas are computed recursively:
844 // Tr gamma.mu1 gamma.mu2 ... gamma.mun =
845 // + g.mu1.mu2 * Tr gamma.mu3 ... gamma.mun
846 // - g.mu1.mu3 * Tr gamma.mu2 gamma.mu4 ... gamma.mun
847 // + g.mu1.mu4 * Tr gamma.mu3 gamma.mu3 gamma.mu5 ... gamma.mun
849 // + g.mu1.mun * Tr gamma.mu2 ... gamma.mu(n-1)
853 for (size_t i=1; i<num; i++) {
854 for (size_t n=1, j=0; n<num; n++) {
859 result += sign * lorentz_g(ix[0], ix[i]) * trace_string(v.begin(), num-2);
865ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE)
867 if (is_a<clifford>(e)) {
869 unsigned char rl = ex_to<clifford>(e).get_representation_label();
871 // Are we taking the trace over this object's representation label?
872 if (rls.find(rl) == rls.end())
875 // Yes, all elements are traceless, except for dirac_ONE and dirac_L/R
876 const ex & g = e.op(0);
877 if (is_a<diracone>(g))
879 else if (is_a<diracgammaL>(g) || is_a<diracgammaR>(g))
884 } else if (is_exactly_a<mul>(e)) {
886 // Trace of product: pull out non-clifford factors
888 for (size_t i=0; i<e.nops(); i++) {
889 const ex &o = e.op(i);
890 if (is_clifford_tinfo(o.return_type_tinfo()))
891 prod *= dirac_trace(o, rls, trONE);
897 } else if (is_exactly_a<ncmul>(e)) {
899 unsigned char rl = get_representation_label(e.return_type_tinfo());
901 // Are we taking the trace over this string's representation label?
902 if (rls.find(rl) == rls.end())
905 // Substitute gammaL/R and expand product, if necessary
906 ex e_expanded = e.subs(lst{
907 dirac_gammaL(rl) == (dirac_ONE(rl)-dirac_gamma5(rl))/2,
908 dirac_gammaR(rl) == (dirac_ONE(rl)+dirac_gamma5(rl))/2
909 }, subs_options::no_pattern).expand();
910 if (!is_a<ncmul>(e_expanded))
911 return dirac_trace(e_expanded, rls, trONE);
913 // gamma5 gets moved to the front so this check is enough
914 bool has_gamma5 = is_a<diracgamma5>(e.op(0).op(0));
915 size_t num = e.nops();
919 // Trace of gamma5 * odd number of gammas and trace of
920 // gamma5 * gamma.mu * gamma.nu are zero
921 if ((num & 1) == 0 || num == 3)
924 // Tr gamma5 gamma.mu gamma.nu gamma.rho gamma.sigma = 4I * epsilon(mu, nu, rho, sigma)
925 // (the epsilon is always 4-dimensional)
927 ex b1, i1, b2, i2, b3, i3, b4, i4;
928 base_and_index(e.op(1), b1, i1);
929 base_and_index(e.op(2), b2, i2);
930 base_and_index(e.op(3), b3, i3);
931 base_and_index(e.op(4), b4, i4);
932 return trONE * I * (lorentz_eps(ex_to<idx>(i1).replace_dim(_ex4), ex_to<idx>(i2).replace_dim(_ex4), ex_to<idx>(i3).replace_dim(_ex4), ex_to<idx>(i4).replace_dim(_ex4)) * b1 * b2 * b3 * b4).simplify_indexed();
936 // I/4! * epsilon0123.mu1.mu2.mu3.mu4 * Tr gamma.mu1 gamma.mu2 gamma.mu3 gamma.mu4 S_2k
937 // (the epsilon is always 4-dimensional)
938 exvector ix(num-1), bv(num-1);
939 for (size_t i=1; i<num; i++)
940 base_and_index(e.op(i), bv[i-1], ix[i-1]);
942 int *iv = new int[num];
944 for (size_t i=0; i<num-3; i++) {
946 for (size_t j=i+1; j<num-2; j++) {
948 for (size_t k=j+1; k<num-1; k++) {
950 for (size_t l=k+1; l<num; l++) {
952 iv[0] = i; iv[1] = j; iv[2] = k; iv[3] = l;
955 for (size_t n=0, t=4; n<num; n++) {
956 if (n == i || n == j || n == k || n == l)
961 int sign = permutation_sign(iv, iv + num);
962 result += sign * lorentz_eps(ex_to<idx>(idx1).replace_dim(_ex4), ex_to<idx>(idx2).replace_dim(_ex4), ex_to<idx>(idx3).replace_dim(_ex4), ex_to<idx>(idx4).replace_dim(_ex4))
963 * trace_string(v.begin(), num - 4);
969 return trONE * I * result * mul(bv);
971 } else { // no gamma5
973 // Trace of odd number of gammas is zero
977 // Tr gamma.mu gamma.nu = 4 g.mu.nu
980 base_and_index(e.op(0), b1, i1);
981 base_and_index(e.op(1), b2, i2);
982 return trONE * (lorentz_g(i1, i2) * b1 * b2).simplify_indexed();
985 exvector iv(num), bv(num);
986 for (size_t i=0; i<num; i++)
987 base_and_index(e.op(i), bv[i], iv[i]);
989 return trONE * (trace_string(iv.begin(), num) * mul(bv)).simplify_indexed();
992 } else if (e.nops() > 0) {
994 // Trace maps to all other container classes (this includes sums)
995 pointer_to_map_function_2args<const std::set<unsigned char> &, const ex &> fcn(dirac_trace, rls, trONE);
1002ex dirac_trace(const ex & e, const lst & rll, const ex & trONE)
1004 // Convert list to set
1005 std::set<unsigned char> rls;
1006 for (const auto & i : rll) {
1007 if (i.info(info_flags::nonnegint))
1008 rls.insert(ex_to<numeric>(i).to_int());
1011 return dirac_trace(e, rls, trONE);
1014ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
1016 // Convert label to set
1017 std::set<unsigned char> rls;
1020 return dirac_trace(e, rls, trONE);
1024ex canonicalize_clifford(const ex & e_)
1026 pointer_to_map_function fcn(canonicalize_clifford);
1028 if (is_a<matrix>(e_) // || is_a<pseries>(e) || is_a<integral>(e)
1029 || e_.info(info_flags::list)) {
1032 ex e=simplify_indexed(e_);
1033 // Scan for any ncmul objects
1035 ex aux = e.to_rational(srl);
1036 for (auto & i : srl) {
1041 if (is_exactly_a<ncmul>(rhs)
1042 && rhs.return_type() == return_types::noncommutative
1043 && is_clifford_tinfo(rhs.return_type_tinfo())) {
1045 // Expand product, if necessary
1046 ex rhs_expanded = rhs.expand();
1047 if (!is_a<ncmul>(rhs_expanded)) {
1048 i.second = canonicalize_clifford(rhs_expanded);
1051 } else if (!is_a<clifford>(rhs.op(0)))
1055 v.reserve(rhs.nops());
1056 for (size_t j=0; j<rhs.nops(); j++)
1057 v.push_back(rhs.op(j));
1059 // Stupid recursive bubble sort because we only want to swap adjacent gammas
1060 auto it = v.begin(), next_to_last = v.end() - 1;
1061 if (is_a<diracgamma5>(it->op(0)) || is_a<diracgammaL>(it->op(0)) || is_a<diracgammaR>(it->op(0)))
1064 while (it != next_to_last) {
1065 if (it[0].compare(it[1]) > 0) {
1067 ex save0 = it[0], save1 = it[1];
1069 base_and_index(it[0], b1, i1);
1070 base_and_index(it[1], b2, i2);
1071 // for Clifford algebras (commutator_sign == -1) metric should be symmetrised
1072 it[0] = (ex_to<clifford>(save0).get_metric(i1, i2, ex_to<clifford>(save0).get_commutator_sign() == -1) * b1 * b2).simplify_indexed();
1073 it[1] = v.size() ? _ex2 * dirac_ONE(ex_to<clifford>(save0).get_representation_label()) : _ex2;
1077 sum += ex_to<clifford>(save0).get_commutator_sign() * ncmul(std::move(v));
1078 i.second = canonicalize_clifford(sum);
1086 return aux.subs(srl, subs_options::no_pattern).simplify_indexed();
1090ex clifford_star_bar(const ex & e, bool do_bar, unsigned options)
1092 pointer_to_map_function_2args<bool, unsigned> fcn(clifford_star_bar, do_bar, options | 1);
1094 // is a child, no need to expand
1095 ex e1= (options & 1 ? e : e.expand());
1097 if (is_a<ncmul>(e1) ) { // reversing order of clifford units
1099 ev.reserve(e1.nops());
1100 cv.reserve(e1.nops());
1101 // separate clifford and non-clifford entries
1102 for (size_t i= 0; i < e1.nops(); ++i) {
1103 if (is_a<clifford>(e1.op(i)) && is_a<cliffordunit>(e1.op(i).op(0)))
1104 cv.push_back(e1.op(i));
1106 ev.push_back(e1.op(i));
1108 for (auto i=cv.rbegin(); i!=cv.rend(); ++i) { // reverse order of Clifford units
1109 ev.push_back(i->conjugate());
1111 // For clifford_bar an odd number of clifford units reverts the sign
1112 if (do_bar && (cv.size() % 2 == 1))
1113 return -dynallocate<ncmul>(std::move(ev));
1115 return dynallocate<ncmul>(std::move(ev));
1116 } else if (is_a<clifford>(e1) && is_a<cliffordunit>(e1.op(0))) {
1121 } else if (is_a<power>(e1)) {
1122 // apply the procedure to the base of a power
1123 return pow(clifford_star_bar(e1.op(0), do_bar, 0), e1.op(1));
1124 } else if (is_a<add>(e1) || is_a<mul>(e1) || e.info(info_flags::list)) {
1125 // recurse into subexpressions
1127 } else // nothing meaningful can be done
1131ex clifford_prime(const ex & e)
1133 pointer_to_map_function fcn(clifford_prime);
1134 if (is_a<clifford>(e) && is_a<cliffordunit>(e.op(0))) {
1136 } else if (is_a<add>(e) || is_a<ncmul>(e) || is_a<mul>(e) //|| is_a<pseries>(e) || is_a<integral>(e)
1137 || is_a<matrix>(e) || e.info(info_flags::list)) {
1139 } else if (is_a<power>(e)) {
1140 return pow(clifford_prime(e.op(0)), e.op(1));
1145ex remove_dirac_ONE(const ex & e, unsigned char rl, unsigned options)
1147 pointer_to_map_function_2args<unsigned char, unsigned> fcn(remove_dirac_ONE, rl, options | 1);
1148 bool need_reevaluation = false;
1150 if (! (options & 1) ) { // is not a child
1152 e1 = expand_dummy_sum(e, true);
1153 e1 = canonicalize_clifford(e1);
1156 if (is_a<clifford>(e1) && ex_to<clifford>(e1).get_representation_label() >= rl) {
1157 if (is_a<diracone>(e1.op(0)))
1160 throw(std::invalid_argument("remove_dirac_ONE(): expression is a non-scalar Clifford number!
"));
1161 } else if (is_a<add>(e1) || is_a<ncmul>(e1) || is_a<mul>(e1)
1162 || is_a<matrix>(e1) || e1.info(info_flags::list)) {
1163 if (options & 3) // is a child or was already expanded
1168 } catch (std::exception &p) {
1169 need_reevaluation = true;
1171 } else if (is_a<power>(e1)) {
1172 if (options & 3) // is a child or was already expanded
1173 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1));
1176 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1));
1177 } catch (std::exception &p) {
1178 need_reevaluation = true;
1181 if (need_reevaluation)
1182 return remove_dirac_ONE(e, rl, options | 2);
1186int clifford_max_label(const ex & e, bool ignore_ONE)
1188 if (is_a<clifford>(e))
1189 if (ignore_ONE && is_a<diracone>(e.op(0)))
1192 return ex_to<clifford>(e).get_representation_label();
1195 for (size_t i=0; i < e.nops(); i++)
1196 rl = (rl > clifford_max_label(e.op(i), ignore_ONE)) ? rl : clifford_max_label(e.op(i), ignore_ONE);
1201ex clifford_norm(const ex & e)
1203 return sqrt(remove_dirac_ONE(e * clifford_bar(e)));
1206ex clifford_inverse(const ex & e)
1208 ex norm = clifford_norm(e);
1209 if (!norm.is_zero())
1210 return clifford_bar(e) / pow(norm, 2);
1215ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl)
1217 if (!ex_to<idx>(mu).is_dim_numeric())
1219 ex e = clifford_unit(mu, metr, rl);
1220 return lst_to_clifford(v, e);
1223ex lst_to_clifford(const ex & v, const ex & e) {
1226 if (is_a<clifford>(e)) {
1229 = is_a<varidx>(mu) ? ex_to<varidx>(mu).toggle_variance() : mu;
1230 unsigned dim = get_dim_uint(mu);
1232 if (is_a<matrix>(v)) {
1233 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows()) {
1234 min = ex_to<matrix>(v).rows();
1235 max = ex_to<matrix>(v).cols();
1237 min = ex_to<matrix>(v).cols();
1238 max = ex_to<matrix>(v).rows();
1242 return indexed(v, mu_toggle) * e;
1243 else if (max - dim == 1) {
1244 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows())
1245 return v.op(0) * dirac_ONE(ex_to<clifford>(e).get_representation_label()) + indexed(sub_matrix(ex_to<matrix>(v), 0, 1, 1, dim), mu_toggle) * e;
1247 return v.op(0) * dirac_ONE(ex_to<clifford>(e).get_representation_label()) + indexed(sub_matrix(ex_to<matrix>(v), 1, dim, 0, 1), mu_toggle) * e;
1251 throw(std::invalid_argument("lst_to_clifford(): first argument should be a vector (nx1 or 1xn
matrix)
"));
1252 } else if (v.info(info_flags::list)) {
1253 if (dim == ex_to<lst>(v).nops())
1254 return indexed(matrix(dim, 1, ex_to<lst>(v)), mu_toggle) * e;
1255 else if (ex_to<lst>(v).nops() - dim == 1)
1256 return v.op(0) * dirac_ONE(ex_to<clifford>(e).get_representation_label()) + indexed(sub_matrix(matrix(dim+1, 1, ex_to<lst>(v)), 1, dim, 0, 1), mu_toggle) * e;
1260 throw(std::invalid_argument("lst_to_clifford(): cannot construct from anything but list or vector
"));
1262 throw(std::invalid_argument("lst_to_clifford(): the second argument should be a Clifford
unit"));
1267static ex get_clifford_comp(const ex & e, const ex & c, bool root=true)
1269 // make expansion on the top-level call only
1270 ex e1=(root? e.expand() : e);
1272 pointer_to_map_function_2args<const ex &, bool> fcn(get_clifford_comp, c, false);
1273 int ival = ex_to<numeric>(ex_to<idx>(c.op(1)).get_value()).to_int();
1274 int rl=ex_to<clifford>(c).get_representation_label();
1276 if ( (is_a<add>(e1) || e1.info(info_flags::list) || is_a<matrix>(e1))) {
1278 } else if (is_a<ncmul>(e1) || is_a<mul>(e1)) {
1279 // searches are done within products only
1280 exvector ev, all_dummy=get_all_dummy_indices(e1);
1281 bool found=false, same_value_found=false;
1283 ev.reserve(e1.nops());
1284 for (size_t i=0; i < e1.nops(); ++i) {
1285 // look for a Clifford unit with the same metric and representation label,
1286 // if found remember its index
1287 if (is_a<clifford>(e1.op(i)) && ex_to<clifford>(e1.op(i)).get_representation_label() == rl
1288 && is_a<cliffordunit>(e1.op(i).op(0)) && ex_to<clifford>(e1.op(i)).same_metric(c)) { // same Clifford unit
1290 throw(std::invalid_argument("get_clifford_comp(): expression is a Clifford multi-vector
"));
1292 if (ex_to<idx>(e1.op(i).op(1)).is_numeric() &&
1293 (ival == ex_to<numeric>(ex_to<idx>(e1.op(i).op(1)).get_value()).to_int())) {
1294 same_value_found = true; // desired index value is found
1295 } else if ((std::find(all_dummy.begin(), all_dummy.end(), e1.op(i).op(1)) != all_dummy.end())
1296 || (is_a<varidx>(e1.op(i).op(1))
1297 && std::find(all_dummy.begin(), all_dummy.end(),
1298 ex_to<varidx>(e1.op(i).op(1)).toggle_variance()) != all_dummy.end())) {
1299 dummy_ind=(e1.op(i).op(1)); // suitable dummy index found
1301 ev.push_back(e.op(i)); // another index value
1303 ev.push_back(e1.op(i));
1306 if (! found) // no Clifford units found at all
1307 throw(std::invalid_argument("get_clifford_comp(): expression is not a Clifford vector to the given units
"));
1309 ex res=dynallocate<ncmul>(std::move(ev));
1310 if (same_value_found) {
1312 } else if (! dummy_ind.is_zero()) { // a dummy index was found
1313 if (is_a<varidx>(dummy_ind))
1314 dummy_ind = ex_to<varidx>(dummy_ind).toggle_variance();
1315 return res.subs(dummy_ind==ival, subs_options::no_pattern);
1316 } else // found a Clifford unit with another index
1318 } else if (e1.is_zero()) {
1320 } else if (is_a<clifford>(e1) && is_a<cliffordunit>(e1.op(0)) && ex_to<clifford>(e1).same_metric(c)) {
1321 if (ex_to<idx>(e1.op(1)).is_numeric() &&
1322 (ival == ex_to<numeric>(ex_to<idx>(e1.op(1)).get_value()).to_int()) )
1327 throw(std::invalid_argument("get_clifford_comp(): expression is not usable as a Clifford vector
"));
1330lst clifford_to_lst(const ex & e, const ex & c, bool algebraic)
1332 GINAC_ASSERT(is_a<clifford>(c));
1334 if (! ex_to<idx>(mu).is_dim_numeric())
1336 unsigned int D = ex_to<numeric>(ex_to<idx>(mu).get_dim()).to_int();
1338 if (algebraic) // check if algebraic method is applicable
1339 for (unsigned int i = 0; i < D; i++)
1340 if (pow(c.subs(mu == i, subs_options::no_pattern), 2).is_zero()
1341 || (! is_a<numeric>(pow(c.subs(mu == i, subs_options::no_pattern), 2))))
1344 ex v0 = remove_dirac_ONE(canonicalize_clifford(e+clifford_prime(e)))/2;
1347 ex e1 = canonicalize_clifford(e - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
1349 for (unsigned int i = 0; i < D; i++)
1350 V.append(remove_dirac_ONE(
1351 simplify_indexed(canonicalize_clifford(e1 * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e1))
1352 / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2))));
1355 for (unsigned int i = 0; i < D; i++)
1356 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
1357 } catch (std::exception &p) {
1358 /* Try to expand dummy summations to simplify the expression*/
1359 e1 = canonicalize_clifford(expand_dummy_sum(e, true));
1361 v0 = remove_dirac_ONE(canonicalize_clifford(e1+clifford_prime(e1)))/2;
1362 if (! v0.is_zero()) {
1364 e1 = canonicalize_clifford(e1 - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
1366 for (unsigned int i = 0; i < D; i++)
1367 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
1374ex clifford_moebius_map(const ex & a, const ex & b, const ex & c, const ex & d, const ex & v, const ex & G, unsigned char rl)
1378 if (! is_a<matrix>(v) && ! v.info(info_flags::list))
1379 throw(std::invalid_argument("clifford_moebius_map(): parameter v should be either vector or list
"));
1381 if (is_a<clifford>(G)) {
1384 if (is_a<indexed>(G)) {
1385 D = ex_to<idx>(G.op(1)).get_dim();
1386 varidx mu(dynallocate<symbol>(), D);
1387 cu = clifford_unit(mu, G, rl);
1388 } else if (is_a<matrix>(G)) {
1389 D = ex_to<matrix>(G).rows();
1390 idx mu(dynallocate<symbol>(), D);
1391 cu = clifford_unit(mu, G, rl);
1396 x = lst_to_clifford(v, cu);
1397 ex e = clifford_to_lst(simplify_indexed(canonicalize_clifford((a * x + b) * clifford_inverse(c * x + d))), cu, false);
1398 return (is_a<matrix>(v) ? matrix(ex_to<matrix>(v).rows(), ex_to<matrix>(v).cols(), ex_to<lst>(e)) : e);
1401ex clifford_moebius_map(const ex & M, const ex & v, const ex & G, unsigned char rl)
1403 if (is_a<matrix>(M) && (ex_to<matrix>(M).rows() == 2) && (ex_to<matrix>(M).cols() == 2))
1404 return clifford_moebius_map(M.op(0), M.op(1), M.op(2), M.op(3), v, G, rl);
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
unsigned hashvalue
hash value
void ensure_if_modifiable() const
Ensure the object may be modified without hurting others, throws if this is not the case.
unsigned flags
of type status_flags
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
This class holds an object representing an element of the Clifford algebra (the Dirac gamma matrices)...
ex metric
Metric of the space, all constructors make it an indexed object.
bool match_same_type(const basic &other) const override
Returns true if the attributes of two objects are similar enough for a match.
bool same_metric(const ex &other) const
void do_print_tree(const print_tree &c, unsigned level) const
void do_print_dflt(const print_dflt &c, unsigned level) const
size_t nops() const override
Number of operands/members.
ex & let_op(size_t i) override
Return modifiable operand/member at position i.
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
void do_print_latex(const print_latex &c, unsigned level) const
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
ex op(size_t i) const override
Return operand/member at position i.
int commutator_sign
It is the sign in the definition e~i e~j +/- e~j e~i = B(i, j) + B(j, i)
return_type_t return_type_tinfo() const override
unsigned char representation_label
Representation label to distinguish independent spin lines.
clifford(const ex &b, unsigned char rl=0)
Construct object without any indices.
void read_archive(const archive_node &n, lst &sym_lst) override
Load (deserialize) the object from an archive node.
void archive(archive_node &n) const override
Save (serialize) the object into archive node.
int get_commutator_sign() const
This class represents the Clifford algebra generators (units).
Wrapper template for making GiNaC classes out of STL containers.
This class represents the Dirac gamma5 object which anticommutates with all other gammas.
This class represents the Dirac gammaL object which behaves like 1/2 (1-gamma5).
This class represents the Dirac gammaL object which behaves like 1/2 (1+gamma5).
This class represents the Dirac gamma Lorentz vector.
This class represents the Clifford algebra unity element.
Lightweight wrapper for GiNaC's symbolic objects.
exvector get_free_indices() const
bool is_equal(const ex &other) const
ex subs(const exmap &m, unsigned options=0) const
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
This class holds one index of an indexed object.
This class holds an indexed expression.
friend ex simplify_indexed(const ex &e, exvector &free_indices, exvector &dummy_indices, const scalar_products &sp)
Simplify indexed expression, return list of free indices.
void printindices(const print_context &c, unsigned level) const
ex get_symmetry() const
Return symmetry properties.
indexed(const ex &b)
Construct indexed object with no index.
ex symtree
Index symmetry (tree of symmetry objects)
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Base class for print_contexts.
Context for default (ginsh-parsable) output.
Context for latex-parsable output.
Context for tree-like output for debugging.
@ no_pattern
disable pattern matching
This class holds one of GiNaC's predefined special tensors such as the delta and the metric tensors.
This class holds an index with a variance (co- or contravariant).
Interface to GiNaC's clifford algebra (Dirac gamma) objects.
Interface to GiNaC's light-weight expression handles.
Interface to GiNaC's indices.
Definition of GiNaC's lst.
Interface to symbolic matrices.
Interface to GiNaC's products of expressions.
static bool is_dirac_slash(const ex &seq0)
ex remove_dirac_ONE(const ex &e, unsigned char rl, unsigned options)
Replaces dirac_ONE's (with a representation_label no less than rl) in e with 1.
ex clifford_inverse(const ex &e)
Calculation of the inverse in the Clifford algebra.
const symmetry & not_symmetric()
ex clifford_unit(const ex &mu, const ex &metr, unsigned char rl)
Create a Clifford unit object.
std::map< ex, ex, ex_is_less > exmap
ex clifford_moebius_map(const ex &a, const ex &b, const ex &c, const ex &d, const ex &v, const ex &G, unsigned char rl)
Calculations of Moebius transformations (conformal map) defined by a 2x2 Clifford matrix (a b\c d) in...
static unsigned get_dim_uint(const ex &e)
matrix inverse(const matrix &m)
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
ex dirac_gamma(const ex &mu, unsigned char rl)
Create a Dirac gamma object.
print_func< print_dflt >(&diracone::do_print). print_func< print_latex >(&diracone
static ex get_clifford_comp(const ex &e, const ex &c, bool root=true)
Auxiliary structure to define a function for striping one Clifford unit from vectors.
const symmetry & symmetric2()
ex subs(const ex &thisex, const exmap &m, unsigned options=0)
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq, print_func< print_context >(&add::do_print). print_func< print_latex >(&add::do_print_latex). print_func< print_csrc >(&add::do_print_csrc). print_func< print_tree >(&add::do_print_tree). print_func< print_python_repr >(&add::do_print_python_repr)) add
ex op(const ex &thisex, size_t i)
lst clifford_to_lst(const ex &e, const ex &c, bool algebraic)
An inverse function to lst_to_clifford().
bool find(const ex &thisex, const ex &pattern, exset &found)
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT_T(lst, basic, print_func< print_context >(&lst::do_print). print_func< print_tree >(&lst::do_print_tree)) template<> bool lst GINAC_BIND_UNARCHIVER(lst)
Specialization of container::info() for lst.
ex lst_to_clifford(const ex &v, const ex &mu, const ex &metr, unsigned char rl)
List or vector conversion into the Clifford vector.
std::vector< ex > exvector
Interface to GiNaC's non-commutative products of expressions.
Makes the interface to the underlying bignum package available.
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to relations between expressions.
To distinguish between different kinds of non-commutative objects.
Interface to GiNaC's symbolic objects.
Interface to GiNaC's symmetry definitions.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...
#define DEFAULT_PRINT_LATEX(classname, text, latex)
#define DEFAULT_CTOR(classname)
#define DEFAULT_COMPARE(classname)