]> www.ginac.de Git - ginac.git/commitdiff
- color and clifford classes are quite functional now
authorChristian Bauer <Christian.Bauer@uni-mainz.de>
Thu, 10 May 2001 20:41:24 +0000 (20:41 +0000)
committerChristian Bauer <Christian.Bauer@uni-mainz.de>
Thu, 10 May 2001 20:41:24 +0000 (20:41 +0000)
- new "spinidx" class for dotted/undotted indices
- predefined spinor metric tensor (created by spinor_metric())

ginac/clifford.cpp
ginac/clifford.h
ginac/color.cpp
ginac/color.h
ginac/idx.cpp
ginac/idx.h
ginac/indexed.cpp
ginac/indexed.h
ginac/tensor.cpp
ginac/tensor.h
ginac/tinfos.h

index 5a69cfd58db038073f36bd1728d96edbb5a222f8..32096410218b76c5cd4c3e179f902faa12b5920e 100644 (file)
@@ -178,20 +178,6 @@ bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other
                        *other = _ex1();
                        return true;
 
-#if 0
-               // gamma~mu gamma~alpha gamma~beta gamma~delta gamma.mu = -2 gamma~delta gamma~beta gamma~alpha + (4-dim) gamma~alpha gamma~beta gamma~delta
-               } else if (other - self == 4
-                       && is_ex_of_type(self[1], clifford)
-                       && is_ex_of_type(self[2], clifford)
-                       && is_ex_of_type(self[3], clifford)) {
-                       *self = -2 * self[3] * self[2] * self[1] + (4 - dim) * self[1] * self[2] * self[3];
-                       self[1] = _ex1();
-                       self[2] = _ex1();
-                       self[3] = _ex1();
-                       *other = _ex1();
-                       return true;
-#endif
-
                // gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha
                // (commutate contracted indices towards each other, simplify_indexed()
                // will re-expand and re-run the simplification)
@@ -327,6 +313,16 @@ ex dirac_gamma5(unsigned char rl)
        return clifford(diracgamma5(), rl);
 }
 
+ex dirac_gamma6(unsigned char rl)
+{
+       return clifford(diracone(), rl) + clifford(diracgamma5(), rl);
+}
+
+ex dirac_gamma7(unsigned char rl)
+{
+       return clifford(diracone(), rl) - clifford(diracgamma5(), rl);
+}
+
 ex dirac_slash(const ex & e, const ex & dim, unsigned char rl)
 {
        varidx mu((new symbol)->setflag(status_flags::dynallocated), dim);
index af3cb7883568dea7fda15ade6d1abf191fd4ca99..69c9e23a6685a3b19f42fbfa17b9bed4113a4431 100644 (file)
@@ -126,6 +126,12 @@ ex dirac_gamma(const ex & mu, unsigned char rl = 0);
  *  @return newly constructed object */
 ex dirac_gamma5(unsigned char rl = 0);
 
+/** This returns (dirac_ONE(rl) + dirac_gamma5(rl)). */
+ex dirac_gamma6(unsigned char rl = 0);
+
+/** This returns (dirac_ONE(rl) - dirac_gamma5(rl)). */
+ex dirac_gamma7(unsigned char rl = 0);
+
 /** Create a term of the form e_mu * gamma~mu with a unique index mu.
  *
  *  @param dim Dimension of index
index 77cf89c44dee8dc4d98e0dd1f6eeb948727fb45f..9e719ec051cecbb914e3e1b59138f8e4cd8286c4 100644 (file)
@@ -154,10 +154,11 @@ DEFAULT_PRINT(su3d, "d")
  *  objects. This removes superfluous ONEs. */
 ex color::simplify_ncmul(const exvector & v) const
 {
-       //!! TODO: sort by representation label
        exvector s;
        s.reserve(v.size());
+       unsigned rl = ex_to_color(v[0]).get_representation_label();
 
+       // Remove superfluous ONEs
        exvector::const_iterator it = v.begin(), itend = v.end();
        while (it != itend) {
                if (!is_ex_of_type(it->op(0), su3one))
@@ -166,9 +167,7 @@ ex color::simplify_ncmul(const exvector & v) const
        }
 
        if (s.size() == 0)
-               return color(su3one());
-       else if (s.size() == v.size())
-               return simplified_ncmul(v);
+               return color(su3one(), rl);
        else
                return simplified_ncmul(s);
 }
@@ -297,6 +296,56 @@ ex su3f::eval_indexed(const basic & i) const
 }
 
 
+/** Contraction of generator with something else. */
+bool su3t::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
+{
+       GINAC_ASSERT(is_ex_of_type(*self, indexed));
+       GINAC_ASSERT(is_ex_of_type(*other, indexed));
+       GINAC_ASSERT(self->nops() == 2);
+       GINAC_ASSERT(is_ex_of_type(self->op(0), su3t));
+       unsigned char rl = ex_to_color(*self).get_representation_label();
+
+       if (is_ex_exactly_of_type(other->op(0), su3t)) {
+
+               // T.a T.a = 4/3 ONE
+               if (other - self == 1) {
+                       *self = numeric(4, 3);
+                       *other = color_ONE(rl);
+                       return true;
+
+               // T.a T.b T.a = -1/6 T.b
+               } else if (other - self == 2
+                       && is_ex_of_type(self[1], color)) {
+                       *self = numeric(-1, 6);
+                       *other = _ex1();
+                       return true;
+
+               // T.a S T.a = 1/2 Tr(S) - 1/6 S
+               } else {
+                       exvector::iterator it = self + 1;
+                       while (it != other) {
+                               if (!is_ex_of_type(*it, color)) {
+                                       return false;
+                               }
+                               it++;
+                       }
+
+                       it = self + 1;
+                       ex S = _ex1();
+                       while (it != other) {
+                               S *= *it;
+                               *it++ = _ex1();
+                       }
+
+                       *self = color_trace(S, rl) * color_ONE(rl) / 2 - S / 6;
+                       *other = _ex1();
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /** Contraction of an indexed symmetric structure constant with something else. */
 bool su3d::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
 {
index 700493253adad38b154c6040586753b7f6465861..48903e45ffa5b82737142643543e3776367fc6e8 100644 (file)
@@ -85,6 +85,7 @@ class su3t : public tensor
        // functions overriding virtual functions from bases classes
 public:
        void print(const print_context & c, unsigned level = 0) const;
+       bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
 };
 
 /** This class represents the tensor of antisymmetric su(3) structure
index 44427a6ac08e3e7db642bf2d1381e3491ba1612a..90ac3a425a35bfd6b2158e60b40eb8e8d36277fb 100644 (file)
@@ -34,6 +34,7 @@ namespace GiNaC {
 
 GINAC_IMPLEMENT_REGISTERED_CLASS(idx, basic)
 GINAC_IMPLEMENT_REGISTERED_CLASS(varidx, idx)
+GINAC_IMPLEMENT_REGISTERED_CLASS(spinidx, varidx)
 
 //////////
 // default constructor, destructor, copy constructor assignment operator and helpers
@@ -50,6 +51,12 @@ varidx::varidx() : covariant(false)
        tinfo_key = TINFO_varidx;
 }
 
+spinidx::spinidx() : dotted(false)
+{
+       debugmsg("spinidx default constructor", LOGLEVEL_CONSTRUCT);
+       tinfo_key = TINFO_spinidx;
+}
+
 void idx::copy(const idx & other)
 {
        inherited::copy(other);
@@ -63,8 +70,15 @@ void varidx::copy(const varidx & other)
        covariant = other.covariant;
 }
 
+void spinidx::copy(const spinidx & other)
+{
+       inherited::copy(other);
+       dotted = other.dotted;
+}
+
 DEFAULT_DESTROY(idx)
 DEFAULT_DESTROY(varidx)
+DEFAULT_DESTROY(spinidx)
 
 //////////
 // other constructors
@@ -84,6 +98,12 @@ varidx::varidx(const ex & v, const ex & d, bool cov) : inherited(v, d), covarian
        tinfo_key = TINFO_varidx;
 }
 
+spinidx::spinidx(const ex & v, const ex & d, bool cov, bool dot) : inherited(v, d, cov), dotted(dot)
+{
+       debugmsg("spinidx constructor from ex,ex,bool,bool", LOGLEVEL_CONSTRUCT);
+       tinfo_key = TINFO_spinidx;
+}
+
 //////////
 // archiving
 //////////
@@ -101,6 +121,12 @@ varidx::varidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst
        n.find_bool("covariant", covariant);
 }
 
+spinidx::spinidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+{
+       debugmsg("spinidx constructor from archive_node", LOGLEVEL_CONSTRUCT);
+       n.find_bool("dotted", dotted);
+}
+
 void idx::archive(archive_node &n) const
 {
        inherited::archive(n);
@@ -114,8 +140,15 @@ void varidx::archive(archive_node &n) const
        n.add_bool("covariant", covariant);
 }
 
+void spinidx::archive(archive_node &n) const
+{
+       inherited::archive(n);
+       n.add_bool("dotted", dotted);
+}
+
 DEFAULT_UNARCHIVE(idx)
 DEFAULT_UNARCHIVE(varidx)
+DEFAULT_UNARCHIVE(spinidx)
 
 //////////
 // functions overriding virtual functions from bases classes
@@ -178,6 +211,47 @@ void varidx::print(const print_context & c, unsigned level) const
        }
 }
 
+void spinidx::print(const print_context & c, unsigned level) const
+{
+       debugmsg("spinidx print", LOGLEVEL_PRINT);
+
+       if (is_of_type(c, print_tree)) {
+
+               c.s << std::string(level, ' ') << class_name()
+                   << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+                   << (covariant ? ", covariant" : ", contravariant")
+                   << (dotted ? ", dotted" : ", undotted")
+                   << std::endl;
+               unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
+               value.print(c, level + delta_indent);
+               dim.print(c, level + delta_indent);
+
+       } else {
+
+               bool is_tex = is_of_type(c, print_latex);
+               if (!is_tex) {
+                       if (covariant)
+                               c.s << ".";
+                       else
+                               c.s << "~";
+               }
+               if (dotted) {
+                       if (is_tex)
+                               c.s << "\\dot{";
+                       else
+                               c.s << "*";
+               }
+               bool need_parens = !(is_ex_exactly_of_type(value, numeric) || is_ex_of_type(value, symbol));
+               if (need_parens)
+                       c.s << "(";
+               value.print(c);
+               if (need_parens)
+                       c.s << ")";
+               if (is_tex && dotted)
+                       c.s << "}";
+       }
+}
+
 bool idx::info(unsigned inf) const
 {
        if (inf == info_flags::idx)
@@ -225,6 +299,24 @@ int varidx::compare_same_type(const basic & other) const
        return 0;
 }
 
+int spinidx::compare_same_type(const basic & other) const
+{
+       GINAC_ASSERT(is_of_type(other, spinidx));
+       const spinidx &o = static_cast<const spinidx &>(other);
+
+       int cmpval = inherited::compare_same_type(other);
+       if (cmpval)
+               return cmpval;
+
+       // Check variance and dottedness last so dummy indices will end up next to each other
+       if (covariant != o.covariant)
+               return covariant ? -1 : 1;
+       if (dotted != o.dotted)
+               return dotted ? -1 : 1;
+
+       return 0;
+}
+
 ex idx::subs(const lst & ls, const lst & lr) const
 {
        GINAC_ASSERT(ls.nops() == lr.nops());
@@ -287,6 +379,18 @@ bool varidx::is_dummy_pair_same_type(const basic & other) const
        return inherited::is_dummy_pair_same_type(other);
 }
 
+bool spinidx::is_dummy_pair_same_type(const basic & other) const
+{
+       const spinidx &o = static_cast<const spinidx &>(other);
+
+       // Dottedness must be the same
+       if (dotted != o.dotted)
+               return false;
+
+       return inherited::is_dummy_pair_same_type(other);
+}
+
+
 //////////
 // non-virtual functions
 //////////
@@ -299,6 +403,23 @@ ex varidx::toggle_variance(void) const
        return i_copy->setflag(status_flags::dynallocated);
 }
 
+ex spinidx::toggle_dot(void) const
+{
+       spinidx *i_copy = static_cast<spinidx *>(duplicate());
+       i_copy->dotted = !i_copy->dotted;
+       i_copy->clearflag(status_flags::hash_calculated);
+       return i_copy->setflag(status_flags::dynallocated);
+}
+
+ex spinidx::toggle_variance_dot(void) const
+{
+       spinidx *i_copy = static_cast<spinidx *>(duplicate());
+       i_copy->covariant = !i_copy->covariant;
+       i_copy->dotted = !i_copy->dotted;
+       i_copy->clearflag(status_flags::hash_calculated);
+       return i_copy->setflag(status_flags::dynallocated);
+}
+
 //////////
 // global functions
 //////////
index 4981fefca4be57de67c165e6b2faeb57b12b7c54..07ff839202acf8584915bc9ed537d6059e00df49 100644 (file)
@@ -124,6 +124,53 @@ protected:
 };
 
 
+/** This class holds a spinor index that can be dotted or undotted and that
+ *  also has a variance. This is used in the Weyl-van-der-Waerden formalism
+ *  where the dot indicates complex conjugation. There is an associated
+ *  (asymmetric) metric tensor that can be used to raise/lower spinor
+ *  indices. */
+class spinidx : public varidx
+{
+       GINAC_DECLARE_REGISTERED_CLASS(spinidx, varidx)
+
+       // other constructors
+public:
+       /** Construct index with given value, dimension, variance and dot.
+        *
+        *  @param v Value of index (numeric or symbolic)
+        *  @param dim Dimension of index space (numeric or symbolic)
+        *  @param covariant Make covariant index (default is contravariant)
+        *  @param dotted Make covariant dotted (default is undotted)
+        *  @return newly constructed index */
+       spinidx(const ex & v, const ex & dim = 2, bool covariant = false, bool dotted = false);
+
+       // functions overriding virtual functions from bases classes
+public:
+       void print(const print_context & c, unsigned level = 0) const;
+       bool is_dummy_pair_same_type(const basic & other) const;
+
+       // non-virtual functions in this class
+public:
+       /** Check whether the index is dotted. */
+       bool is_dotted(void) const {return dotted;}
+
+       /** Check whether the index is not dotted. */
+       bool is_undotted(void) const {return !dotted;}
+
+       /** Make a new index with the same value and variance but the opposite
+        *  dottedness. */
+       ex toggle_dot(void) const;
+
+       /** Make a new index with the same value but opposite variance and
+        *  dottedness. */
+       ex toggle_variance_dot(void) const;
+
+       // member variables
+protected:
+       bool dotted;
+};
+
+
 // utility functions
 inline const idx &ex_to_idx(const ex & e)
 {
@@ -135,6 +182,11 @@ inline const varidx &ex_to_varidx(const ex & e)
        return static_cast<const varidx &>(*e.bp);
 }
 
+inline const spinidx &ex_to_spinidx(const ex & e)
+{
+       return static_cast<const spinidx &>(*e.bp);
+}
+
 /** Check whether two indices form a dummy pair. */
 bool is_dummy_pair(const idx & i1, const idx & i2);
 
index 3c7005e2a2d4b462defcd31bfe471f2dae95fe1e..3240c8dd7fe86293918c0aabf807cecd91e101b8 100644 (file)
@@ -666,12 +666,16 @@ try_again:
                        }
                        if (contracted) {
 contraction_done:
-                               if (is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
+                               if (non_commutative
+                                || is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
                                 || is_ex_exactly_of_type(*it1, mul) || is_ex_exactly_of_type(*it2, mul)
                                 || is_ex_exactly_of_type(*it1, ncmul) || is_ex_exactly_of_type(*it2, ncmul)) {
 
                                        // One of the factors became a sum or product:
                                        // re-expand expression and run again
+                                       // Non-commutative products are always re-expanded to give
+                                       // simplify_ncmul() the chance to re-order and canonicalize
+                                       // the product
                                        ex r = (non_commutative ? ex(ncmul(v)) : ex(mul(v)));
                                        return simplify_indexed(r, free_indices, sp);
                                }
@@ -785,6 +789,19 @@ void scalar_products::add(const ex & v1, const ex & v2, const ex & sp)
        spm[make_key(v1, v2)] = sp;
 }
 
+void scalar_products::add_vectors(const lst & l)
+{
+       // Add all possible pairs of products
+       unsigned num = l.nops();
+       for (unsigned i=0; i<num; i++) {
+               ex a = l.op(i);
+               for (unsigned j=0; j<num; j++) {
+                       ex b = l.op(j);
+                       add(a, b, a*b);
+               }
+       }
+}
+
 void scalar_products::clear(void)
 {
        spm.clear();
index cba48c88d9d6440ee192300e874a62eae18d6195..0147185ddd4630183ee7e78b23db134015fccadd 100644 (file)
@@ -215,6 +215,11 @@ public:
        /** Register scalar product pair and its value. */
        void add(const ex & v1, const ex & v2, const ex & sp);
 
+       /** Register list of vectors. This adds all possible pairs of products
+        *  a.i * b.i with the value a*b (note that this is not a scalar vector
+        *  product but an ordinary product of scalars). */
+       void add_vectors(const lst & l);
+
        /** Clear all registered scalar products. */
        void clear(void);
 
index 928c6568693ec6687d00569071f5293e9d8f44a6..23be5b0bed201caf8c465dca33be7bcaa1ef746f 100644 (file)
@@ -40,6 +40,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(tensor, basic)
 GINAC_IMPLEMENT_REGISTERED_CLASS(tensdelta, tensor)
 GINAC_IMPLEMENT_REGISTERED_CLASS(tensmetric, tensor)
 GINAC_IMPLEMENT_REGISTERED_CLASS(minkmetric, tensmetric)
+GINAC_IMPLEMENT_REGISTERED_CLASS(spinmetric, tensmetric)
 GINAC_IMPLEMENT_REGISTERED_CLASS(tensepsilon, tensor)
 
 //////////
@@ -54,6 +55,8 @@ tensor::tensor(unsigned ti) : inherited(ti)
 DEFAULT_CTORS(tensor)
 DEFAULT_CTORS(tensdelta)
 DEFAULT_CTORS(tensmetric)
+DEFAULT_COPY(spinmetric)
+DEFAULT_DESTROY(spinmetric)
 DEFAULT_DESTROY(minkmetric)
 DEFAULT_DESTROY(tensepsilon)
 
@@ -63,6 +66,12 @@ minkmetric::minkmetric() : pos_sig(false)
        tinfo_key = TINFO_minkmetric;
 }
 
+spinmetric::spinmetric()
+{
+       debugmsg("spinmetric default constructor", LOGLEVEL_CONSTRUCT);
+       tinfo_key = TINFO_spinmetric;
+}
+
 minkmetric::minkmetric(bool ps) : pos_sig(ps)
 {
        debugmsg("minkmetric constructor from bool", LOGLEVEL_CONSTRUCT);
@@ -101,6 +110,7 @@ void tensepsilon::copy(const tensepsilon & other)
 DEFAULT_ARCHIVING(tensor)
 DEFAULT_ARCHIVING(tensdelta)
 DEFAULT_ARCHIVING(tensmetric)
+DEFAULT_ARCHIVING(spinmetric)
 DEFAULT_UNARCHIVE(minkmetric)
 DEFAULT_UNARCHIVE(tensepsilon)
 
@@ -137,6 +147,7 @@ void tensepsilon::archive(archive_node &n) const
 DEFAULT_COMPARE(tensor)
 DEFAULT_COMPARE(tensdelta)
 DEFAULT_COMPARE(tensmetric)
+DEFAULT_COMPARE(spinmetric)
 
 int minkmetric::compare_same_type(const basic & other) const
 {
@@ -165,7 +176,8 @@ int tensepsilon::compare_same_type(const basic & other) const
 DEFAULT_PRINT_LATEX(tensdelta, "delta", "\\delta")
 DEFAULT_PRINT(tensmetric, "g")
 DEFAULT_PRINT_LATEX(minkmetric, "eta", "\\eta")
-DEFAULT_PRINT_LATEX(tensepsilon, "eps", "\\epsilon")
+DEFAULT_PRINT_LATEX(spinmetric, "eps", "\\varepsilon")
+DEFAULT_PRINT_LATEX(tensepsilon, "eps", "\\varepsilon")
 
 /** Automatic symbolic evaluation of an indexed delta tensor. */
 ex tensdelta::eval_indexed(const basic & i) const
@@ -242,6 +254,37 @@ ex minkmetric::eval_indexed(const basic & i) const
        return inherited::eval_indexed(i);
 }
 
+/** Automatic symbolic evaluation of an indexed metric tensor. */
+ex spinmetric::eval_indexed(const basic & i) const
+{
+       GINAC_ASSERT(is_of_type(i, indexed));
+       GINAC_ASSERT(i.nops() == 3);
+       GINAC_ASSERT(is_ex_of_type(i.op(0), spinmetric));
+       GINAC_ASSERT(is_ex_of_type(i.op(1), spinidx));
+       GINAC_ASSERT(is_ex_of_type(i.op(2), spinidx));
+
+       const spinidx & i1 = ex_to_spinidx(i.op(1));
+       const spinidx & i2 = ex_to_spinidx(i.op(2));
+
+       // Convolutions are zero
+       if (static_cast<const indexed &>(i).get_dummy_indices().size() != 0)
+               return _ex0();
+
+       // Numeric evaluation
+       if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
+               int n1 = ex_to_numeric(i1.get_value()).to_int(), n2 = ex_to_numeric(i2.get_value()).to_int();
+               if (n1 == n2)
+                       return _ex0();
+               else if (n1 < n2)
+                       return _ex1();
+               else
+                       return _ex_1();
+       }
+
+       // No further simplifications
+       return i.hold();
+}
+
 /** Automatic symbolic evaluation of an indexed epsilon tensor. */
 ex tensepsilon::eval_indexed(const basic & i) const
 {
@@ -370,6 +413,85 @@ again:
        return false;
 }
 
+/** Contraction of an indexed spinor metric with something else. */
+bool spinmetric::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
+{
+       GINAC_ASSERT(is_ex_of_type(*self, indexed));
+       GINAC_ASSERT(is_ex_of_type(*other, indexed));
+       GINAC_ASSERT(self->nops() == 3);
+       GINAC_ASSERT(is_ex_of_type(self->op(0), spinmetric));
+
+       // Contractions between spinor metrics
+       if (is_ex_of_type(other->op(0), spinmetric)) {
+               const idx &self_i1 = ex_to_idx(self->op(1));
+               const idx &self_i2 = ex_to_idx(self->op(2));
+               const idx &other_i1 = ex_to_idx(other->op(1));
+               const idx &other_i2 = ex_to_idx(other->op(2));
+
+               if (is_dummy_pair(self_i1, other_i1)) {
+                       if (is_dummy_pair(self_i2, other_i2))
+                               *self = _ex2();
+                       else
+                               *self = delta_tensor(self_i2, other_i2);
+                       *other = _ex1();
+                       return true;
+               } else if (is_dummy_pair(self_i1, other_i2)) {
+                       if (is_dummy_pair(self_i2, other_i1))
+                               *self = _ex_2();
+                       else
+                               *self = -delta_tensor(self_i2, other_i1);
+                       *other = _ex1();
+                       return true;
+               } else if (is_dummy_pair(self_i2, other_i1)) {
+                       *self = -delta_tensor(self_i1, other_i2);
+                       *other = _ex1();
+                       return true;
+               } else if (is_dummy_pair(self_i2, other_i2)) {
+                       *self = delta_tensor(self_i1, other_i1);
+                       *other = _ex1();
+                       return true;
+               }
+       }
+
+       // If contracting with the delta tensor, let the delta do it
+       // (don't raise/lower delta indices)
+       if (is_ex_of_type(other->op(0), tensdelta))
+               return false;
+
+       // Try to contract first index
+       const idx *self_idx = &ex_to_idx(self->op(1));
+       const idx *free_idx = &ex_to_idx(self->op(2));
+       bool first_index_tried = false;
+       int sign = 1;
+
+again:
+       if (self_idx->is_symbolic()) {
+               for (int i=1; i<other->nops(); i++) {
+                       const idx &other_idx = ex_to_idx(other->op(i));
+                       if (is_dummy_pair(*self_idx, other_idx)) {
+
+                               // Contraction found, remove metric tensor and substitute
+                               // index in second object
+                               *self = (static_cast<const spinidx *>(self_idx)->is_covariant() ? sign : -sign);
+                               *other = other->subs(other_idx == *free_idx);
+                               return true;
+                       }
+               }
+       }
+
+       if (!first_index_tried) {
+
+               // No contraction with first index found, try second index
+               self_idx = &ex_to_idx(self->op(2));
+               free_idx = &ex_to_idx(self->op(1));
+               first_index_tried = true;
+               sign = -sign;
+               goto again;
+       }
+
+       return false;
+}
+
 //////////
 // global functions
 //////////
@@ -398,6 +520,16 @@ ex lorentz_g(const ex & i1, const ex & i2, bool pos_sig)
        return indexed(minkmetric(pos_sig), indexed::symmetric, i1, i2);
 }
 
+ex spinor_metric(const ex & i1, const ex & i2)
+{
+       if (!is_ex_of_type(i1, spinidx) || !is_ex_of_type(i2, spinidx))
+               throw(std::invalid_argument("indices of spinor metric must be of type spinidx"));
+       if (!ex_to_idx(i1).get_dim().is_equal(2) || !ex_to_idx(i2).get_dim().is_equal(2))
+               throw(std::runtime_error("index dimension for spinor metric must be 2"));
+
+       return indexed(spinmetric(), indexed::antisymmetric, i1, i2);
+}
+
 ex epsilon_tensor(const ex & i1, const ex & i2)
 {
        if (!is_ex_of_type(i1, idx) || !is_ex_of_type(i2, idx))
index b077ee4d0c927d8e459250bb0092773b8c876163..5698b9b944450e44852b3571cb610dd0051b95ec 100644 (file)
@@ -97,6 +97,22 @@ private:
 };
 
 
+/** This class represents an antisymmetric spinor metric tensor which
+ *  can be used to raise/lower indices of 2-component Weyl spinors. If
+ *  indexed, it must have exactly two indices of the same type which
+ *  must be of class spinidx or a subclass and have dimension 2. */
+class spinmetric : public tensmetric
+{
+       GINAC_DECLARE_REGISTERED_CLASS(spinmetric, tensmetric)
+
+       // functions overriding virtual functions from bases classes
+public:
+       void print(const print_context & c, unsigned level = 0) const;
+       ex eval_indexed(const basic & i) const;
+       bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
+};
+
+
 /** This class represents the totally antisymmetric epsilon tensor. If
  *  indexed, all indices must be of the same type and their number must
  *  be equal to the dimension of the index space. */
@@ -155,6 +171,16 @@ ex metric_tensor(const ex & i1, const ex & i2);
  *  @return newly constructed Lorentz metric tensor */
 ex lorentz_g(const ex & i1, const ex & i2, bool pos_sig = false);
 
+/** Create a spinor metric tensor with specified indices. The indices must be
+ *  of class spinidx or a subclass and have a dimension of 2. The spinor
+ *  metric is an antisymmetric tensor with a matrix representation of
+ *  [[ [[ 0, 1 ]], [[ -1, 0 ]] ]].
+ *
+ *  @param i1 First index
+ *  @param i2 Second index
+ *  @return newly constructed spinor metric tensor */
+ex spinor_metric(const ex & i1, const ex & i2);
+
 /** Create an epsilon tensor in a Euclidean space with two indices. The
  *  indices must be of class idx or a subclass, and have a dimension of 2.
  *
index 7c6994d2eb2ee41d5f4b8f3fedeea0bc8542d07b..2a5fad61672150d1925ec910687e32e5ac5e6d16 100644 (file)
@@ -66,11 +66,13 @@ const unsigned TINFO_structure     = 0x000c0001U;
 
 const unsigned TINFO_idx           = 0x000d0001U;
 const unsigned TINFO_varidx        = 0x000d1001U;
+const unsigned TINFO_spinidx       = 0x000d2001U;
 
 const unsigned TINFO_tensor        = 0x000e0001U;
 const unsigned TINFO_tensdelta     = 0x000e1001U;
 const unsigned TINFO_tensmetric    = 0x000e1002U;
 const unsigned TINFO_minkmetric    = 0x000e2001U;
+const unsigned TINFO_spinmetric    = 0x000e2002U;
 const unsigned TINFO_tensepsilon   = 0x000e1003U;
 const unsigned TINFO_su3one        = 0x000e1008U;
 const unsigned TINFO_su3t          = 0x000e1009U;