79clifford::
clifford() : representation_label(0), metric(0), commutator_sign(-1)
97clifford::
clifford(const
ex & b,
unsigned char rl) : inherited(b), representation_label(rl), metric(0), commutator_sign(-1)
105clifford::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)
129 inherited::read_archive(
n, sym_lst);
131 n.find_unsigned(
"label", rl);
133 n.find_ex(
"metric",
metric, sym_lst);
134 n.find_unsigned(
"commutator_sign+1", rl);
140 inherited::archive(
n);
157 if (is_a<indexed>(
metric)) {
158 if (symmetrised && !(ex_to<symmetry>(ex_to<indexed>(
metric).
get_symmetry()).has_symmetry())) {
181 if (is_a<clifford>(other))
182 metr = ex_to<clifford>(other).get_metric();
186 if (is_a<indexed>(metr))
190 return (indices.size() == 2)
205 return inherited::op(i);
217 return inherited::let_op(i);
223 if(is_a<clifford>(subsed)) {
224 ex prevmetric = ex_to<clifford>(subsed).metric;
228 c.metric = newmetric;
245 return inherited::compare_same_type(other);
258 return !is_a<diracgamma5>(seq0) && !is_a<diracgammaL>(seq0) &&
259 !is_a<diracgammaR>(seq0) && !is_a<cliffordunit>(seq0) &&
260 !is_a<diracone>(seq0);
271 this->print_dispatch<inherited>(
c, level);
292 c.s <<
"\\hspace{-1.0ex}/}";
295 this->print_dispatch<inherited>(
c, level);
301 c.s << std::string(level,
' ') << class_name() <<
" @" <<
this
302 << std::hex <<
", hash=0x" <<
hashvalue <<
", flags=0x" <<
flags << std::dec
303 <<
", " <<
seq.size()-1 <<
" indices"
304 <<
", symmetry=" <<
symtree << std::endl;
306 seq[0].print(
c, level +
c.delta_indent);
321DEFAULT_PRINT_LATEX(diracgammaL, "gammaL
", "{\\gamma_L}
")
322DEFAULT_PRINT_LATEX(diracgammaR, "gammaR
", "{\\gamma_R}
")
325static void base_and_index(const ex & c, ex & b, ex & i)
327 GINAC_ASSERT(is_a<clifford>(c));
328 GINAC_ASSERT(c.nops() == 2+1);
330 if (is_a<cliffordunit>(c.op(0))) { // proper dirac gamma object or clifford unit
333 } else if (is_a<diracgamma5>(c.op(0)) || is_a<diracgammaL>(c.op(0)) || is_a<diracgammaR>(c.op(0))) { // gamma5/L/R
336 } else { // slash object, generate new dummy index
337 varidx ix(dynallocate<symbol>(), ex_to<idx>(c.op(1)).get_dim());
338 b = indexed(c.op(0), ix.toggle_variance());
344struct is_not_a_clifford {
345 bool operator()(const ex & e)
347 return !is_a<clifford>(e);
352bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
354 GINAC_ASSERT(is_a<clifford>(*self));
355 GINAC_ASSERT(is_a<indexed>(*other));
356 GINAC_ASSERT(is_a<diracgamma>(self->op(0)));
357 unsigned char rl = ex_to<clifford>(*self).get_representation_label();
359 ex dim = ex_to<idx>(self->op(1)).get_dim();
360 if (other->nops() > 1)
361 dim = minimal_dim(dim, ex_to<idx>(other->op(1)).get_dim());
363 if (is_a<clifford>(*other)) {
365 // Contraction only makes sense if the representation labels are equal
366 if (ex_to<clifford>(*other).get_representation_label() != rl)
369 size_t num = other - self;
371 // gamma~mu gamma.mu = dim ONE
374 *other = dirac_ONE(rl);
377 // gamma~mu gamma~alpha gamma.mu = (2-dim) gamma~alpha
379 && is_a<clifford>(self[1])) {
384 // gamma~mu gamma~alpha gamma~beta gamma.mu = 4 g~alpha~beta + (dim-4) gamam~alpha gamma~beta
386 && is_a<clifford>(self[1])
387 && is_a<clifford>(self[2])) {
389 base_and_index(self[1], b1, i1);
390 base_and_index(self[2], b2, i2);
391 *self = 4 * lorentz_g(i1, i2) * b1 * b2 * dirac_ONE(rl) + (dim - 4) * self[1] * self[2];
397 // 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
399 && is_a<clifford>(self[1])
400 && is_a<clifford>(self[2])
401 && is_a<clifford>(self[3])) {
402 *self = -2 * self[3] * self[2] * self[1] - (dim - 4) * self[1] * self[2] * self[3];
409 // gamma~mu Sodd gamma.mu = -2 Sodd_R
410 // (Chisholm identity in 4 dimensions)
411 } else if (!((other - self) & 1) && dim.is_equal(4)) {
412 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
415 *self = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(other), std::reverse_iterator<exvector::const_iterator>(self + 1)));
416 std::fill(self + 1, other, _ex1);
420 // gamma~mu Sodd gamma~alpha gamma.mu = 2 gamma~alpha Sodd + 2 Sodd_R gamma~alpha
421 // (commutate contracted indices towards each other, then use
422 // Chisholm identity in 4 dimensions)
423 } else if (((other - self) & 1) && dim.is_equal(4)) {
424 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
427 auto next_to_last = other - 1;
428 ex S = ncmul(exvector(self + 1, next_to_last));
429 ex SR = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(next_to_last), std::reverse_iterator<exvector::const_iterator>(self + 1)));
431 *self = (*next_to_last) * S + SR * (*next_to_last);
432 std::fill(self + 1, other, _ex1);
436 // gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha
437 // (commutate contracted indices towards each other, simplify_indexed()
438 // will re-expand and re-run the simplification)
440 if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
443 auto next_to_last = other - 1;
444 ex S = ncmul(exvector(self + 1, next_to_last));
446 *self = 2 * (*next_to_last) * S - (*self) * S * (*other) * (*next_to_last);
447 std::fill(self + 1, other + 1, _ex1);
451 } else if (is_a<symbol>(other->op(0)) && other->nops() == 2) {
453 // x.mu gamma~mu -> x-slash
454 *self = dirac_slash(other->op(0), dim, rl);
463bool cliffordunit::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
465 GINAC_ASSERT(is_a<clifford>(*self));
466 GINAC_ASSERT(is_a<indexed>(*other));
467 GINAC_ASSERT(is_a<cliffordunit>(self->op(0)));
468 clifford unit = ex_to<clifford>(*self);
469 unsigned char rl = unit.get_representation_label();
471 if (is_a<clifford>(*other)) {
472 // Contraction only makes sense if the representation labels are equal
473 // and the metrics are the same
474 if ((ex_to<clifford>(*other).get_representation_label() != rl)
475 && unit.same_metric(*other))
478 auto before_other = other - 1;
480 ex mu_toggle = other->op(1);
481 ex alpha = before_other->op(1);
483 // e~mu e.mu = Tr ONE
484 if (other - self == 1) {
485 *self = unit.get_metric(mu, mu_toggle, true);
486 *other = dirac_ONE(rl);
489 } else if (other - self == 2) {
490 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) {
491 // e~mu e~alpha e.mu = 2*e~mu B(alpha, mu.toggle_variance())-Tr(B) e~alpha
492 *self = 2 * (*self) * unit.get_metric(alpha, mu_toggle, true) - unit.get_metric(mu, mu_toggle, true) * (*before_other);
493 *before_other = _ex1;
498 // e~mu S e.mu = Tr S ONE
499 *self = unit.get_metric(mu, mu_toggle, true);
500 *other = dirac_ONE(rl);
504 // e~mu S e~alpha e.mu = 2 e~mu S B(alpha, mu.toggle_variance()) - e~mu S e.mu e~alpha
505 // (commutate contracted indices towards each other, simplify_indexed()
506 // will re-expand and re-run the simplification)
507 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) {
511 ex S = ncmul(exvector(self + 1, before_other));
513 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) {
514 *self = 2 * (*self) * S * unit.get_metric(alpha, mu_toggle, true) - (*self) * S * (*other) * (*before_other);
517 *self = (*self) * S * (*other) * (*before_other);
520 std::fill(self + 1, other + 1, _ex1);
530ex clifford::eval_ncmul(const exvector & v) const
535 // Remove superfluous ONEs
536 for (auto & it : v) {
537 if (!is_a<clifford>(it) || !is_a<diracone>(it.op(0)))
541 bool something_changed = false;
544 // Anticommutate gamma5/L/R's to the front
546 auto first = s.begin(), next_to_last = s.end() - 2;
548 auto it = next_to_last;
551 if (is_a<clifford>(*it) && is_a<clifford>(*it2)) {
552 ex e1 = it->op(0), e2 = it2->op(0);
554 if (is_a<diracgamma5>(e2)) {
556 if (is_a<diracgammaL>(e1) || is_a<diracgammaR>(e1)) {
558 // gammaL/R gamma5 -> gamma5 gammaL/R
560 something_changed = true;
562 } else if (!is_a<diracgamma5>(e1)) {
564 // gamma5 gamma5 -> gamma5 gamma5 (do nothing)
565 // x gamma5 -> -gamma5 x
568 something_changed = true;
571 } else if (is_a<diracgammaL>(e2)) {
573 if (is_a<diracgammaR>(e1)) {
575 // gammaR gammaL -> 0
578 } else if (!is_a<diracgammaL>(e1) && !is_a<diracgamma5>(e1)) {
580 // gammaL gammaL -> gammaL gammaL (do nothing)
581 // gamma5 gammaL -> gamma5 gammaL (do nothing)
582 // x gammaL -> gammaR x
584 *it = clifford(diracgammaR(), ex_to<clifford>(*it).get_representation_label());
585 something_changed = true;
588 } else if (is_a<diracgammaR>(e2)) {
590 if (is_a<diracgammaL>(e1)) {
592 // gammaL gammaR -> 0
595 } else if (!is_a<diracgammaR>(e1) && !is_a<diracgamma5>(e1)) {
597 // gammaR gammaR -> gammaR gammaR (do nothing)
598 // gamma5 gammaR -> gamma5 gammaR (do nothing)
599 // x gammaR -> gammaL x
601 *it = clifford(diracgammaL(), ex_to<clifford>(*it).get_representation_label());
602 something_changed = true;
610 if (next_to_last == first)
616 // Remove equal adjacent gammas
618 exvector::iterator it, itend = s.end() - 1;
619 for (it = s.begin(); it != itend; ++it) {
622 if (!is_a<clifford>(a) || !is_a<clifford>(b))
625 const ex & ag = a.op(0);
626 const ex & bg = b.op(0);
627 bool a_is_cliffordunit = is_a<cliffordunit>(ag);
628 bool b_is_cliffordunit = is_a<cliffordunit>(bg);
630 if (a_is_cliffordunit && b_is_cliffordunit && ex_to<clifford>(a).same_metric(b)
631 && (ex_to<clifford>(a).get_commutator_sign() == -1)) {
632 // This is done only for Clifford algebras
634 const ex & ia = a.op(1);
635 const ex & ib = b.op(1);
636 if (ia.is_equal(ib)) { // gamma~alpha gamma~alpha -> g~alpha~alpha
637 a = ex_to<clifford>(a).get_metric(ia, ib, true);
638 b = dirac_ONE(representation_label);
639 something_changed = true;
642 } else if ((is_a<diracgamma5>(ag) && is_a<diracgamma5>(bg))) {
644 // Remove squares of gamma5
645 a = dirac_ONE(representation_label);
646 b = dirac_ONE(representation_label);
647 something_changed = true;
649 } else if ((is_a<diracgammaL>(ag) && is_a<diracgammaL>(bg))
650 || (is_a<diracgammaR>(ag) && is_a<diracgammaR>(bg))) {
652 // Remove squares of gammaL/R
653 b = dirac_ONE(representation_label);
654 something_changed = true;
656 } else if (is_a<diracgammaL>(ag) && is_a<diracgammaR>(bg)) {
658 // gammaL and gammaR are orthogonal
661 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaL>(bg)) {
663 // gamma5 gammaL -> -gammaL
664 a = dirac_ONE(representation_label);
666 something_changed = true;
668 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaR>(bg)) {
670 // gamma5 gammaR -> gammaR
671 a = dirac_ONE(representation_label);
672 something_changed = true;
674 } else if (!a_is_cliffordunit && !b_is_cliffordunit && ag.is_equal(bg)) {
677 varidx ix(dynallocate<symbol>(), ex_to<idx>(a.op(1)).minimal_dim(ex_to<idx>(b.op(1))));
679 a = indexed(ag, ix) * indexed(ag, ix.toggle_variance());
680 b = dirac_ONE(representation_label);
681 something_changed = true;
687 return dirac_ONE(representation_label) * sign;
688 if (something_changed)
689 return reeval_ncmul(s) * sign;
691 return hold_ncmul(s) * sign;
694ex clifford::thiscontainer(const exvector & v) const
696 return clifford(representation_label, metric, commutator_sign, v);
699ex clifford::thiscontainer(exvector && v) const
701 return clifford(representation_label, metric, commutator_sign, std::move(v));
704ex diracgamma5::conjugate() const
706 return _ex_1 * (*this);
709ex diracgammaL::conjugate() const
711 return dynallocate<diracgammaR>();
714ex diracgammaR::conjugate() const
716 return dynallocate<diracgammaL>();
723ex dirac_ONE(unsigned char rl)
725 static ex ONE = dynallocate<diracone>();
726 return clifford(ONE, rl);
729static unsigned get_dim_uint(const ex& e)
732 throw std::invalid_argument("
get_dim_uint: argument is not an index
");
733 ex dim = ex_to<idx>(e).get_dim();
734 if (!dim.info(info_flags::posint))
735 throw std::invalid_argument("get_dim_uint: dimension of index should be a positive integer
");
736 unsigned d = ex_to<numeric>(dim).to_int();
740ex clifford_unit(const ex & mu, const ex & metr, unsigned char rl)
742 ex unit = dynallocate<cliffordunit>();
747 exvector indices = metr.get_free_indices();
749 if (indices.size() == 2) {
750 return clifford(unit, mu, metr, rl);
751 } else if (is_a<matrix>(metr)) {
752 matrix M = ex_to<matrix>(metr);
753 unsigned n = M.rows();
754 bool symmetric = true;
756 //static idx xi(dynallocate<symbol>(), n),
757 // chi(dynallocate<symbol>(), n);
758 idx xi(dynallocate<symbol>(), n),
759 chi(dynallocate<symbol>(), n);
760 if ((n == M.cols()) && (n == get_dim_uint(mu))) {
761 for (unsigned i = 0; i < n; i++) {
762 for (unsigned j = i+1; j < n; j++) {
763 if (!M(i, j).is_equal(M(j, i))) {
768 return clifford(unit, mu, indexed(metr, symmetric?symmetric2():not_symmetric(), xi, chi), rl);
770 throw(std::invalid_argument("clifford_unit(): metric for Clifford
unit must be a square
matrix with the same dimensions as index
"));
772 } else if (indices.size() == 0) { // a tensor or other expression without indices
773 //static varidx xi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim()),
774 // chi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim());
775 varidx xi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim()),
776 chi(dynallocate<symbol>(), ex_to<idx>(mu).get_dim());
777 return clifford(unit, mu, indexed(metr, xi, chi), rl);
779 throw(std::invalid_argument("clifford_unit(): metric for Clifford
unit must be of type
tensor,
matrix or an expression with two free indices
"));
782ex dirac_gamma(const ex & mu, unsigned char rl)
784 static ex gamma = dynallocate<diracgamma>();
786 if (!is_a<varidx>(mu))
787 throw(std::invalid_argument("dirac_gamma(): index of Dirac gamma must be of type
varidx"));
789 static varidx xi(dynallocate<symbol>(), ex_to<varidx>(mu).get_dim()),
790 chi(dynallocate<symbol>(), ex_to<varidx>(mu).get_dim());
791 return clifford(gamma, mu, indexed(dynallocate<minkmetric>(), symmetric2(), xi, chi), rl);
794ex dirac_gamma5(unsigned char rl)
796 static ex gamma5 = dynallocate<diracgamma5>();
797 return clifford(gamma5, rl);
800ex dirac_gammaL(unsigned char rl)
802 static ex gammaL = dynallocate<diracgammaL>();
803 return clifford(gammaL, rl);
806ex dirac_gammaR(unsigned char rl)
808 static ex gammaR = dynallocate<diracgammaR>();
809 return clifford(gammaR, rl);
812ex dirac_slash(const ex & e, const ex & dim, unsigned char rl)
814 // Slashed vectors are actually stored as a clifford object with the
815 // vector as its base expression and a (dummy) index that just serves
816 // for storing the space dimensionality
818 static varidx xi(dynallocate<symbol>(), dim),
819 chi(dynallocate<symbol>(), dim);
820 return clifford(e, varidx(0, dim), indexed(dynallocate<minkmetric>(), symmetric2(), xi, chi), rl);
825static unsigned char get_representation_label(const return_type_t& ti)
827 return (unsigned char)ti.rl;
832static ex trace_string(exvector::const_iterator ix, size_t num)
834 // Tr gamma.mu gamma.nu = 4 g.mu.nu
836 return lorentz_g(ix[0], ix[1]);
838 // 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 )
840 return lorentz_g(ix[0], ix[1]) * lorentz_g(ix[2], ix[3])
841 + lorentz_g(ix[1], ix[2]) * lorentz_g(ix[0], ix[3])
842 - lorentz_g(ix[0], ix[2]) * lorentz_g(ix[1], ix[3]);
844 // Traces of 6 or more gammas are computed recursively:
845 // Tr gamma.mu1 gamma.mu2 ... gamma.mun =
846 // + g.mu1.mu2 * Tr gamma.mu3 ... gamma.mun
847 // - g.mu1.mu3 * Tr gamma.mu2 gamma.mu4 ... gamma.mun
848 // + g.mu1.mu4 * Tr gamma.mu3 gamma.mu3 gamma.mu5 ... gamma.mun
850 // + g.mu1.mun * Tr gamma.mu2 ... gamma.mu(n-1)
854 for (size_t i=1; i<num; i++) {
855 for (size_t n=1, j=0; n<num; n++) {
860 result += sign * lorentz_g(ix[0], ix[i]) * trace_string(v.begin(), num-2);
866ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE)
868 if (is_a<clifford>(e)) {
870 unsigned char rl = ex_to<clifford>(e).get_representation_label();
872 // Are we taking the trace over this object's representation label?
873 if (rls.find(rl) == rls.end())
876 // Yes, all elements are traceless, except for dirac_ONE and dirac_L/R
877 const ex & g = e.op(0);
878 if (is_a<diracone>(g))
880 else if (is_a<diracgammaL>(g) || is_a<diracgammaR>(g))
885 } else if (is_exactly_a<mul>(e)) {
887 // Trace of product: pull out non-clifford factors
889 for (size_t i=0; i<e.nops(); i++) {
890 const ex &o = e.op(i);
891 if (is_clifford_tinfo(o.return_type_tinfo()))
892 prod *= dirac_trace(o, rls, trONE);
898 } else if (is_exactly_a<ncmul>(e)) {
900 unsigned char rl = get_representation_label(e.return_type_tinfo());
902 // Are we taking the trace over this string's representation label?
903 if (rls.find(rl) == rls.end())
906 // Substitute gammaL/R and expand product, if necessary
907 ex e_expanded = e.subs(lst{
908 dirac_gammaL(rl) == (dirac_ONE(rl)-dirac_gamma5(rl))/2,
909 dirac_gammaR(rl) == (dirac_ONE(rl)+dirac_gamma5(rl))/2
910 }, subs_options::no_pattern).expand();
911 if (!is_a<ncmul>(e_expanded))
912 return dirac_trace(e_expanded, rls, trONE);
914 // gamma5 gets moved to the front so this check is enough
915 bool has_gamma5 = is_a<diracgamma5>(e.op(0).op(0));
916 size_t num = e.nops();
920 // Trace of gamma5 * odd number of gammas and trace of
921 // gamma5 * gamma.mu * gamma.nu are zero
922 if ((num & 1) == 0 || num == 3)
925 // Tr gamma5 gamma.mu gamma.nu gamma.rho gamma.sigma = 4I * epsilon(mu, nu, rho, sigma)
926 // (the epsilon is always 4-dimensional)
928 ex b1, i1, b2, i2, b3, i3, b4, i4;
929 base_and_index(e.op(1), b1, i1);
930 base_and_index(e.op(2), b2, i2);
931 base_and_index(e.op(3), b3, i3);
932 base_and_index(e.op(4), b4, i4);
933 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();
937 // I/4! * epsilon0123.mu1.mu2.mu3.mu4 * Tr gamma.mu1 gamma.mu2 gamma.mu3 gamma.mu4 S_2k
938 // (the epsilon is always 4-dimensional)
939 exvector ix(num-1), bv(num-1);
940 for (size_t i=1; i<num; i++)
941 base_and_index(e.op(i), bv[i-1], ix[i-1]);
943 int *iv = new int[num];
945 for (size_t i=0; i<num-3; i++) {
947 for (size_t j=i+1; j<num-2; j++) {
949 for (size_t k=j+1; k<num-1; k++) {
951 for (size_t l=k+1; l<num; l++) {
953 iv[0] = i; iv[1] = j; iv[2] = k; iv[3] = l;
956 for (size_t n=0, t=4; n<num; n++) {
957 if (n == i || n == j || n == k || n == l)
962 int sign = permutation_sign(iv, iv + num);
963 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))
964 * trace_string(v.begin(), num - 4);
970 return trONE * I * result * mul(bv);
972 } else { // no gamma5
974 // Trace of odd number of gammas is zero
978 // Tr gamma.mu gamma.nu = 4 g.mu.nu
981 base_and_index(e.op(0), b1, i1);
982 base_and_index(e.op(1), b2, i2);
983 return trONE * (lorentz_g(i1, i2) * b1 * b2).simplify_indexed();
986 exvector iv(num), bv(num);
987 for (size_t i=0; i<num; i++)
988 base_and_index(e.op(i), bv[i], iv[i]);
990 return trONE * (trace_string(iv.begin(), num) * mul(bv)).simplify_indexed();
993 } else if (e.nops() > 0) {
995 // Trace maps to all other container classes (this includes sums)
996 pointer_to_map_function_2args<const std::set<unsigned char> &, const ex &> fcn(dirac_trace, rls, trONE);
1003ex dirac_trace(const ex & e, const lst & rll, const ex & trONE)
1005 // Convert list to set
1006 std::set<unsigned char> rls;
1007 for (const auto & i : rll) {
1008 if (i.info(info_flags::nonnegint))
1009 rls.insert(ex_to<numeric>(i).to_int());
1012 return dirac_trace(e, rls, trONE);
1015ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
1017 // Convert label to set
1018 std::set<unsigned char> rls;
1021 return dirac_trace(e, rls, trONE);
1025ex canonicalize_clifford(const ex & e_)
1027 pointer_to_map_function fcn(canonicalize_clifford);
1029 if (is_a<matrix>(e_) // || is_a<pseries>(e) || is_a<integral>(e)
1030 || e_.info(info_flags::list)) {
1033 ex e=simplify_indexed(e_);
1034 // Scan for any ncmul objects
1036 ex aux = e.to_rational(srl);
1037 for (auto & i : srl) {
1042 if (is_exactly_a<ncmul>(rhs)
1043 && rhs.return_type() == return_types::noncommutative
1044 && is_clifford_tinfo(rhs.return_type_tinfo())) {
1046 // Expand product, if necessary
1047 ex rhs_expanded = rhs.expand();
1048 if (!is_a<ncmul>(rhs_expanded)) {
1049 i.second = canonicalize_clifford(rhs_expanded);
1052 } else if (!is_a<clifford>(rhs.op(0)))
1056 v.reserve(rhs.nops());
1057 for (size_t j=0; j<rhs.nops(); j++)
1058 v.push_back(rhs.op(j));
1060 // Stupid recursive bubble sort because we only want to swap adjacent gammas
1061 auto it = v.begin(), next_to_last = v.end() - 1;
1062 if (is_a<diracgamma5>(it->op(0)) || is_a<diracgammaL>(it->op(0)) || is_a<diracgammaR>(it->op(0)))
1065 while (it != next_to_last) {
1066 if (it[0].compare(it[1]) > 0) {
1068 ex save0 = it[0], save1 = it[1];
1070 base_and_index(it[0], b1, i1);
1071 base_and_index(it[1], b2, i2);
1072 // for Clifford algebras (commutator_sign == -1) metric should be symmetrised
1073 it[0] = (ex_to<clifford>(save0).get_metric(i1, i2, ex_to<clifford>(save0).get_commutator_sign() == -1) * b1 * b2).simplify_indexed();
1074 it[1] = v.size() ? _ex2 * dirac_ONE(ex_to<clifford>(save0).get_representation_label()) : _ex2;
1078 sum += ex_to<clifford>(save0).get_commutator_sign() * ncmul(std::move(v));
1079 i.second = canonicalize_clifford(sum);
1087 return aux.subs(srl, subs_options::no_pattern).simplify_indexed();
1091ex clifford_star_bar(const ex & e, bool do_bar, unsigned options)
1093 pointer_to_map_function_2args<bool, unsigned> fcn(clifford_star_bar, do_bar, options | 1);
1095 // is a child, no need to expand
1096 ex e1= (options & 1 ? e : e.expand());
1098 if (is_a<ncmul>(e1) ) { // reversing order of clifford units
1100 ev.reserve(e1.nops());
1101 cv.reserve(e1.nops());
1102 // separate clifford and non-clifford entries
1103 for (size_t i= 0; i < e1.nops(); ++i) {
1104 if (is_a<clifford>(e1.op(i)) && is_a<cliffordunit>(e1.op(i).op(0)))
1105 cv.push_back(e1.op(i));
1107 ev.push_back(e1.op(i));
1109 for (auto i=cv.rbegin(); i!=cv.rend(); ++i) { // reverse order of Clifford units
1110 ev.push_back(i->conjugate());
1112 // For clifford_bar an odd number of clifford units reverts the sign
1113 if (do_bar && (cv.size() % 2 == 1))
1114 return -dynallocate<ncmul>(std::move(ev));
1116 return dynallocate<ncmul>(std::move(ev));
1117 } else if (is_a<clifford>(e1) && is_a<cliffordunit>(e1.op(0))) {
1122 } else if (is_a<power>(e1)) {
1123 // apply the procedure to the base of a power
1124 return pow(clifford_star_bar(e1.op(0), do_bar, 0), e1.op(1));
1125 } else if (is_a<add>(e1) || is_a<mul>(e1) || e.info(info_flags::list)) {
1126 // recurse into subexpressions
1128 } else // nothing meaningful can be done
1132ex clifford_prime(const ex & e)
1134 pointer_to_map_function fcn(clifford_prime);
1135 if (is_a<clifford>(e) && is_a<cliffordunit>(e.op(0))) {
1137 } else if (is_a<add>(e) || is_a<ncmul>(e) || is_a<mul>(e) //|| is_a<pseries>(e) || is_a<integral>(e)
1138 || is_a<matrix>(e) || e.info(info_flags::list)) {
1140 } else if (is_a<power>(e)) {
1141 return pow(clifford_prime(e.op(0)), e.op(1));
1146ex remove_dirac_ONE(const ex & e, unsigned char rl, unsigned options)
1148 pointer_to_map_function_2args<unsigned char, unsigned> fcn(remove_dirac_ONE, rl, options | 1);
1149 bool need_reevaluation = false;
1151 if (! (options & 1) ) { // is not a child
1153 e1 = expand_dummy_sum(e, true);
1154 e1 = canonicalize_clifford(e1);
1157 if (is_a<clifford>(e1) && ex_to<clifford>(e1).get_representation_label() >= rl) {
1158 if (is_a<diracone>(e1.op(0)))
1161 throw(std::invalid_argument("
remove_dirac_ONE(): expression is a non-scalar Clifford number!
"));
1162 } else if (is_a<add>(e1) || is_a<ncmul>(e1) || is_a<mul>(e1)
1163 || is_a<matrix>(e1) || e1.info(info_flags::list)) {
1164 if (options & 3) // is a child or was already expanded
1169 } catch (std::exception &p) {
1170 need_reevaluation = true;
1172 } else if (is_a<power>(e1)) {
1173 if (options & 3) // is a child or was already expanded
1174 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1));
1177 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1));
1178 } catch (std::exception &p) {
1179 need_reevaluation = true;
1182 if (need_reevaluation)
1183 return remove_dirac_ONE(e, rl, options | 2);
1187int clifford_max_label(const ex & e, bool ignore_ONE)
1189 if (is_a<clifford>(e))
1190 if (ignore_ONE && is_a<diracone>(e.op(0)))
1193 return ex_to<clifford>(e).get_representation_label();
1196 for (size_t i=0; i < e.nops(); i++)
1197 rl = (rl > clifford_max_label(e.op(i), ignore_ONE)) ? rl : clifford_max_label(e.op(i), ignore_ONE);
1202ex clifford_norm(const ex & e)
1204 return sqrt(remove_dirac_ONE(e * clifford_bar(e)));
1207ex clifford_inverse(const ex & e)
1209 ex norm = clifford_norm(e);
1210 if (!norm.is_zero())
1211 return clifford_bar(e) / pow(norm, 2);
1216ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl)
1218 if (!ex_to<idx>(mu).is_dim_numeric())
1220 ex e = clifford_unit(mu, metr, rl);
1221 return lst_to_clifford(v, e);
1224ex lst_to_clifford(const ex & v, const ex & e) {
1227 if (is_a<clifford>(e)) {
1230 = is_a<varidx>(mu) ? ex_to<varidx>(mu).toggle_variance() : mu;
1231 unsigned dim = get_dim_uint(mu);
1233 if (is_a<matrix>(v)) {
1234 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows()) {
1235 min = ex_to<matrix>(v).rows();
1236 max = ex_to<matrix>(v).cols();
1238 min = ex_to<matrix>(v).cols();
1239 max = ex_to<matrix>(v).rows();
1243 return indexed(v, mu_toggle) * e;
1244 else if (max - dim == 1) {
1245 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows())
1246 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;
1248 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;
1252 throw(std::invalid_argument("lst_to_clifford(): first argument should be a vector (nx1 or 1xn
matrix)
"));
1253 } else if (v.info(info_flags::list)) {
1254 if (dim == ex_to<lst>(v).nops())
1255 return indexed(matrix(dim, 1, ex_to<lst>(v)), mu_toggle) * e;
1256 else if (ex_to<lst>(v).nops() - dim == 1)
1257 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;
1261 throw(std::invalid_argument("lst_to_clifford(): cannot construct from anything but list or vector
"));
1263 throw(std::invalid_argument("lst_to_clifford(): the second argument should be a Clifford
unit"));
1268static ex get_clifford_comp(const ex & e, const ex & c, bool root=true)
1270 // make expansion on the top-level call only
1271 ex e1=(root? e.expand() : e);
1273 pointer_to_map_function_2args<const ex &, bool> fcn(get_clifford_comp, c, false);
1274 int ival = ex_to<numeric>(ex_to<idx>(c.op(1)).get_value()).to_int();
1275 int rl=ex_to<clifford>(c).get_representation_label();
1277 if ( (is_a<add>(e1) || e1.info(info_flags::list) || is_a<matrix>(e1))) {
1279 } else if (is_a<ncmul>(e1) || is_a<mul>(e1)) {
1280 // searches are done within products only
1281 exvector ev, all_dummy=get_all_dummy_indices(e1);
1282 bool found=false, same_value_found=false;
1284 ev.reserve(e1.nops());
1285 for (size_t i=0; i < e1.nops(); ++i) {
1286 // look for a Clifford unit with the same metric and representation label,
1287 // if found remember its index
1288 if (is_a<clifford>(e1.op(i)) && ex_to<clifford>(e1.op(i)).get_representation_label() == rl
1289 && is_a<cliffordunit>(e1.op(i).op(0)) && ex_to<clifford>(e1.op(i)).same_metric(c)) { // same Clifford unit
1291 throw(std::invalid_argument("
get_clifford_comp(): expression is a Clifford multi-vector
"));
1293 if (ex_to<idx>(e1.op(i).op(1)).is_numeric() &&
1294 (ival == ex_to<numeric>(ex_to<idx>(e1.op(i).op(1)).get_value()).to_int())) {
1295 same_value_found = true; // desired index value is found
1296 } else if ((std::find(all_dummy.begin(), all_dummy.end(), e1.op(i).op(1)) != all_dummy.end())
1297 || (is_a<varidx>(e1.op(i).op(1))
1298 && std::find(all_dummy.begin(), all_dummy.end(),
1299 ex_to<varidx>(e1.op(i).op(1)).toggle_variance()) != all_dummy.end())) {
1300 dummy_ind=(e1.op(i).op(1)); // suitable dummy index found
1302 ev.push_back(e.op(i)); // another index value
1304 ev.push_back(e1.op(i));
1307 if (! found) // no Clifford units found at all
1308 throw(std::invalid_argument("get_clifford_comp(): expression is not a Clifford vector to the given units
"));
1310 ex res=dynallocate<ncmul>(std::move(ev));
1311 if (same_value_found) {
1313 } else if (! dummy_ind.is_zero()) { // a dummy index was found
1314 if (is_a<varidx>(dummy_ind))
1315 dummy_ind = ex_to<varidx>(dummy_ind).toggle_variance();
1316 return res.subs(dummy_ind==ival, subs_options::no_pattern);
1317 } else // found a Clifford unit with another index
1319 } else if (e1.is_zero()) {
1321 } else if (is_a<clifford>(e1) && is_a<cliffordunit>(e1.op(0)) && ex_to<clifford>(e1).same_metric(c)) {
1322 if (ex_to<idx>(e1.op(1)).is_numeric() &&
1323 (ival == ex_to<numeric>(ex_to<idx>(e1.op(1)).get_value()).to_int()) )
1328 throw(std::invalid_argument("get_clifford_comp(): expression is not usable as a Clifford vector
"));
1331lst clifford_to_lst(const ex & e, const ex & c, bool algebraic)
1333 GINAC_ASSERT(is_a<clifford>(c));
1335 if (! ex_to<idx>(mu).is_dim_numeric())
1337 unsigned int D = ex_to<numeric>(ex_to<idx>(mu).get_dim()).to_int();
1339 if (algebraic) // check if algebraic method is applicable
1340 for (unsigned int i = 0; i < D; i++)
1341 if (pow(c.subs(mu == i, subs_options::no_pattern), 2).is_zero()
1342 || (! is_a<numeric>(pow(c.subs(mu == i, subs_options::no_pattern), 2))))
1345 ex v0 = remove_dirac_ONE(canonicalize_clifford(e+clifford_prime(e)))/2;
1348 ex e1 = canonicalize_clifford(e - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
1350 for (unsigned int i = 0; i < D; i++)
1351 V.append(remove_dirac_ONE(
1352 simplify_indexed(canonicalize_clifford(e1 * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e1))
1353 / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2))));
1356 for (unsigned int i = 0; i < D; i++)
1357 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
1358 } catch (std::exception &p) {
1359 /* Try to expand dummy summations to simplify the expression*/
1360 e1 = canonicalize_clifford(expand_dummy_sum(e, true));
1362 v0 = remove_dirac_ONE(canonicalize_clifford(e1+clifford_prime(e1)))/2;
1363 if (! v0.is_zero()) {
1365 e1 = canonicalize_clifford(e1 - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label()));
1367 for (unsigned int i = 0; i < D; i++)
1368 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern)));
1375ex clifford_moebius_map(const ex & a, const ex & b, const ex & c, const ex & d, const ex & v, const ex & G, unsigned char rl)
1379 if (! is_a<matrix>(v) && ! v.info(info_flags::list))
1380 throw(std::invalid_argument("clifford_moebius_map(): parameter v should be either vector or list
"));
1382 if (is_a<clifford>(G)) {
1385 if (is_a<indexed>(G)) {
1386 D = ex_to<idx>(G.op(1)).get_dim();
1387 varidx mu(dynallocate<symbol>(), D);
1388 cu = clifford_unit(mu, G, rl);
1389 } else if (is_a<matrix>(G)) {
1390 D = ex_to<matrix>(G).rows();
1391 idx mu(dynallocate<symbol>(), D);
1392 cu = clifford_unit(mu, G, rl);
1397 x = lst_to_clifford(v, cu);
1398 ex e = clifford_to_lst(simplify_indexed(canonicalize_clifford((a * x + b) * clifford_inverse(c * x + d))), cu, false);
1399 return (is_a<matrix>(v) ? matrix(ex_to<matrix>(v).rows(), ex_to<matrix>(v).cols(), ex_to<lst>(e)) : e);
1402ex clifford_moebius_map(const ex & M, const ex & v, const ex & G, unsigned char rl)
1404 if (is_a<matrix>(M) && (ex_to<matrix>(M).rows() == 2) && (ex_to<matrix>(M).cols() == 2))
1405 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.
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()
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).
#define GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(classname, supername, options)
Macro for inclusion in the implementation of each registered class.
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)