GiNaC  1.6.2
tensor.cpp
Go to the documentation of this file.
00001 
00005 /*
00006  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022 
00023 #include "tensor.h"
00024 #include "idx.h"
00025 #include "indexed.h"
00026 #include "symmetry.h"
00027 #include "relational.h"
00028 #include "operators.h"
00029 #include "lst.h"
00030 #include "numeric.h"
00031 #include "matrix.h"
00032 #include "archive.h"
00033 #include "utils.h"
00034 
00035 #include <iostream>
00036 #include <stdexcept>
00037 #include <vector>
00038 
00039 namespace GiNaC {
00040 
00041 GINAC_IMPLEMENT_REGISTERED_CLASS(tensor, basic)
00042 
00043 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(tensdelta, tensor,
00044   print_func<print_dflt>(&tensdelta::do_print).
00045   print_func<print_latex>(&tensdelta::do_print_latex))
00046 
00047 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(tensmetric, tensor,
00048   print_func<print_dflt>(&tensmetric::do_print).
00049   print_func<print_latex>(&tensmetric::do_print))
00050 
00051 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(minkmetric, tensmetric,
00052   print_func<print_dflt>(&minkmetric::do_print).
00053   print_func<print_latex>(&minkmetric::do_print_latex))
00054 
00055 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(spinmetric, tensmetric,
00056   print_func<print_dflt>(&spinmetric::do_print).
00057   print_func<print_latex>(&spinmetric::do_print_latex))
00058 
00059 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(tensepsilon, tensor,
00060   print_func<print_dflt>(&tensepsilon::do_print).
00061   print_func<print_latex>(&tensepsilon::do_print_latex))
00062 
00064 // constructors
00066 
00067 tensor::tensor()
00068 {
00069     setflag(status_flags::evaluated | status_flags::expanded);
00070 }
00071 
00072 DEFAULT_CTOR(tensdelta)
00073 DEFAULT_CTOR(tensmetric)
00074 
00075 minkmetric::minkmetric() : pos_sig(false)
00076 {
00077 }
00078 
00079 spinmetric::spinmetric()
00080 {
00081 }
00082 
00083 minkmetric::minkmetric(bool ps) : pos_sig(ps)
00084 {
00085 }
00086 
00087 tensepsilon::tensepsilon() : minkowski(false), pos_sig(false)
00088 {
00089 }
00090 
00091 tensepsilon::tensepsilon(bool mink, bool ps) : minkowski(mink), pos_sig(ps)
00092 {
00093 }
00094 
00096 // archiving
00098 
00099 void minkmetric::read_archive(const archive_node& n, lst& sym_lst)
00100 {
00101     inherited::read_archive(n, sym_lst);
00102     n.find_bool("pos_sig", pos_sig);
00103 }
00104 GINAC_BIND_UNARCHIVER(minkmetric);
00105 
00106 void minkmetric::archive(archive_node &n) const
00107 {
00108     inherited::archive(n);
00109     n.add_bool("pos_sig", pos_sig);
00110 }
00111 
00112 void tensepsilon::read_archive(const archive_node& n, lst& sym_lst)
00113 {
00114     inherited::read_archive(n, sym_lst);
00115     n.find_bool("minkowski", minkowski);
00116     n.find_bool("pos_sig", pos_sig);
00117 }
00118 GINAC_BIND_UNARCHIVER(tensepsilon);
00119 
00120 void tensepsilon::archive(archive_node &n) const
00121 {
00122     inherited::archive(n);
00123     n.add_bool("minkowski", minkowski);
00124     n.add_bool("pos_sig", pos_sig);
00125 }
00126 
00127 GINAC_BIND_UNARCHIVER(tensdelta);
00128 GINAC_BIND_UNARCHIVER(tensmetric);
00129 GINAC_BIND_UNARCHIVER(spinmetric);
00130 
00132 // functions overriding virtual functions from base classes
00134 
00135 DEFAULT_COMPARE(tensor)
00136 DEFAULT_COMPARE(tensdelta)
00137 DEFAULT_COMPARE(tensmetric)
00138 DEFAULT_COMPARE(spinmetric)
00139 
00140 bool tensdelta::info(unsigned inf) const
00141 {
00142     if(inf == info_flags::real)
00143         return true;
00144 
00145     return false;
00146 }
00147 
00148 bool tensmetric::info(unsigned inf) const
00149 {
00150     if(inf == info_flags::real)
00151         return true;
00152 
00153     return false;
00154 }
00155 
00156 int minkmetric::compare_same_type(const basic & other) const
00157 {
00158     GINAC_ASSERT(is_a<minkmetric>(other));
00159     const minkmetric &o = static_cast<const minkmetric &>(other);
00160 
00161     if (pos_sig != o.pos_sig)
00162         return pos_sig ? -1 : 1;
00163     else
00164         return inherited::compare_same_type(other);
00165 }
00166 
00167 bool minkmetric::info(unsigned inf) const
00168 {
00169     if(inf == info_flags::real)
00170         return true;
00171 
00172     return false;
00173 }
00174 
00175 int tensepsilon::compare_same_type(const basic & other) const
00176 {
00177     GINAC_ASSERT(is_a<tensepsilon>(other));
00178     const tensepsilon &o = static_cast<const tensepsilon &>(other);
00179 
00180     if (minkowski != o.minkowski)
00181         return minkowski ? -1 : 1;
00182     else if (pos_sig != o.pos_sig)
00183         return pos_sig ? -1 : 1;
00184     else
00185         return inherited::compare_same_type(other);
00186 }
00187 
00188 bool tensepsilon::info(unsigned inf) const
00189 {
00190     if(inf == info_flags::real)
00191         return true;
00192 
00193     return false;
00194 }
00195 
00196 bool spinmetric::info(unsigned inf) const
00197 {
00198     if(inf == info_flags::real)
00199         return true;
00200 
00201     return false;
00202 }
00203 
00204 DEFAULT_PRINT_LATEX(tensdelta, "delta", "\\delta")
00205 DEFAULT_PRINT(tensmetric, "g")
00206 DEFAULT_PRINT_LATEX(minkmetric, "eta", "\\eta")
00207 DEFAULT_PRINT_LATEX(spinmetric, "eps", "\\varepsilon")
00208 DEFAULT_PRINT_LATEX(tensepsilon, "eps", "\\varepsilon")
00209 
00211 ex tensdelta::eval_indexed(const basic & i) const
00212 {
00213     GINAC_ASSERT(is_a<indexed>(i));
00214     GINAC_ASSERT(i.nops() == 3);
00215     GINAC_ASSERT(is_a<tensdelta>(i.op(0)));
00216 
00217     const idx & i1 = ex_to<idx>(i.op(1));
00218     const idx & i2 = ex_to<idx>(i.op(2));
00219 
00220     // The dimension of the indices must be equal, otherwise we use the minimal
00221     // dimension
00222     if (!i1.get_dim().is_equal(i2.get_dim())) {
00223         ex min_dim = i1.minimal_dim(i2);
00224         exmap m;
00225         m[i1] = i1.replace_dim(min_dim);
00226         m[i2] = i2.replace_dim(min_dim);
00227         return i.subs(m, subs_options::no_pattern);
00228     }
00229 
00230     // Trace of delta tensor is the (effective) dimension of the space
00231     if (is_dummy_pair(i1, i2)) {
00232         try {
00233             return i1.minimal_dim(i2);
00234         } catch (std::exception &e) {
00235             return i.hold();
00236         }
00237     }
00238 
00239     // Numeric evaluation
00240     if (static_cast<const indexed &>(i).all_index_values_are(info_flags::integer)) {
00241         int n1 = ex_to<numeric>(i1.get_value()).to_int(), n2 = ex_to<numeric>(i2.get_value()).to_int();
00242         if (n1 == n2)
00243             return _ex1;
00244         else
00245             return _ex0;
00246     }
00247 
00248     // No further simplifications
00249     return i.hold();
00250 }
00251 
00253 ex tensmetric::eval_indexed(const basic & i) const
00254 {
00255     GINAC_ASSERT(is_a<indexed>(i));
00256     GINAC_ASSERT(i.nops() == 3);
00257     GINAC_ASSERT(is_a<tensmetric>(i.op(0)));
00258     GINAC_ASSERT(is_a<varidx>(i.op(1)));
00259     GINAC_ASSERT(is_a<varidx>(i.op(2)));
00260 
00261     const varidx & i1 = ex_to<varidx>(i.op(1));
00262     const varidx & i2 = ex_to<varidx>(i.op(2));
00263 
00264     // The dimension of the indices must be equal, otherwise we use the minimal
00265     // dimension
00266     if (!i1.get_dim().is_equal(i2.get_dim())) {
00267         ex min_dim = i1.minimal_dim(i2);
00268         exmap m;
00269         m[i1] = i1.replace_dim(min_dim);
00270         m[i2] = i2.replace_dim(min_dim);
00271         return i.subs(m, subs_options::no_pattern);
00272     }
00273 
00274     // A metric tensor with one covariant and one contravariant index gets
00275     // replaced by a delta tensor
00276     if (i1.is_covariant() != i2.is_covariant())
00277         return delta_tensor(i1, i2);
00278 
00279     // No further simplifications
00280     return i.hold();
00281 }
00282 
00284 ex minkmetric::eval_indexed(const basic & i) const
00285 {
00286     GINAC_ASSERT(is_a<indexed>(i));
00287     GINAC_ASSERT(i.nops() == 3);
00288     GINAC_ASSERT(is_a<minkmetric>(i.op(0)));
00289     GINAC_ASSERT(is_a<varidx>(i.op(1)));
00290     GINAC_ASSERT(is_a<varidx>(i.op(2)));
00291 
00292     const varidx & i1 = ex_to<varidx>(i.op(1));
00293     const varidx & i2 = ex_to<varidx>(i.op(2));
00294 
00295     // Numeric evaluation
00296     if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
00297         int n1 = ex_to<numeric>(i1.get_value()).to_int(), n2 = ex_to<numeric>(i2.get_value()).to_int();
00298         if (n1 != n2)
00299             return _ex0;
00300         else if (n1 == 0)
00301             return pos_sig ? _ex_1 : _ex1;
00302         else
00303             return pos_sig ? _ex1 : _ex_1;
00304     }
00305 
00306     // Perform the usual evaluations of a metric tensor
00307     return inherited::eval_indexed(i);
00308 }
00309 
00311 ex spinmetric::eval_indexed(const basic & i) const
00312 {
00313     GINAC_ASSERT(is_a<indexed>(i));
00314     GINAC_ASSERT(i.nops() == 3);
00315     GINAC_ASSERT(is_a<spinmetric>(i.op(0)));
00316     GINAC_ASSERT(is_a<spinidx>(i.op(1)));
00317     GINAC_ASSERT(is_a<spinidx>(i.op(2)));
00318 
00319     const spinidx & i1 = ex_to<spinidx>(i.op(1));
00320     const spinidx & i2 = ex_to<spinidx>(i.op(2));
00321 
00322     // Convolutions are zero
00323     if (!(static_cast<const indexed &>(i).get_dummy_indices().empty()))
00324         return _ex0;
00325 
00326     // Numeric evaluation
00327     if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
00328         int n1 = ex_to<numeric>(i1.get_value()).to_int(), n2 = ex_to<numeric>(i2.get_value()).to_int();
00329         if (n1 == n2)
00330             return _ex0;
00331         else if (n1 < n2)
00332             return _ex1;
00333         else
00334             return _ex_1;
00335     }
00336 
00337     // No further simplifications
00338     return i.hold();
00339 }
00340 
00342 ex tensepsilon::eval_indexed(const basic & i) const
00343 {
00344     GINAC_ASSERT(is_a<indexed>(i));
00345     GINAC_ASSERT(i.nops() > 1);
00346     GINAC_ASSERT(is_a<tensepsilon>(i.op(0)));
00347 
00348     // Convolutions are zero
00349     if (!(static_cast<const indexed &>(i).get_dummy_indices().empty()))
00350         return _ex0;
00351 
00352     // Numeric evaluation
00353     if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
00354 
00355         // Get sign of index permutation (the indices should already be in
00356         // a canonic order but we can't assume what exactly that order is)
00357         std::vector<int> v;
00358         v.reserve(i.nops() - 1);
00359         for (size_t j=1; j<i.nops(); j++)
00360             v.push_back(ex_to<numeric>(ex_to<idx>(i.op(j)).get_value()).to_int());
00361         int sign = permutation_sign(v.begin(), v.end());
00362 
00363         // In a Minkowski space, check for covariant indices
00364         if (minkowski) {
00365             for (size_t j=1; j<i.nops(); j++) {
00366                 const ex & x = i.op(j);
00367                 if (!is_a<varidx>(x)) {
00368                     throw(std::runtime_error("indices of epsilon tensor in Minkowski space must be of type varidx"));
00369                 }
00370                 if (ex_to<varidx>(x).is_covariant()) {
00371                     if (ex_to<idx>(x).get_value().is_zero()) {
00372                         sign = (pos_sig ? -sign : sign);
00373                     }
00374                     else {
00375                         sign = (pos_sig ? sign : -sign);
00376                     }
00377                 }
00378             }
00379         }
00380 
00381         return sign;
00382     }
00383 
00384     // No further simplifications
00385     return i.hold();
00386 }
00387 
00388 bool tensor::replace_contr_index(exvector::iterator self, exvector::iterator other) const
00389 {
00390     // Try to contract the first index
00391     const idx *self_idx = &ex_to<idx>(self->op(1));
00392     const idx *free_idx = &ex_to<idx>(self->op(2));
00393     bool first_index_tried = false;
00394 
00395 again:
00396     if (self_idx->is_symbolic()) {
00397         for (size_t i=1; i<other->nops(); i++) {
00398             if (! is_a<idx>(other->op(i)))
00399                 continue;
00400             const idx &other_idx = ex_to<idx>(other->op(i));
00401             if (is_dummy_pair(*self_idx, other_idx)) {
00402 
00403                 // Contraction found, remove this tensor and substitute the
00404                 // index in the second object
00405                 try {
00406                     // minimal_dim() throws an exception when index dimensions are not comparable
00407                     ex min_dim = self_idx->minimal_dim(other_idx);
00408                     *other = other->subs(other_idx == free_idx->replace_dim(min_dim));
00409                     *self = _ex1; // *other is assigned first because assigning *self invalidates free_idx
00410                     return true;
00411                 } catch (std::exception &e) {
00412                     return false;
00413                 }
00414             }
00415         }
00416     }
00417 
00418     if (!first_index_tried) {
00419 
00420         // No contraction with the first index found, try the second index
00421         self_idx = &ex_to<idx>(self->op(2));
00422         free_idx = &ex_to<idx>(self->op(1));
00423         first_index_tried = true;
00424         goto again;
00425     }
00426 
00427     return false;
00428 }
00429 
00431 bool tensdelta::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
00432 {
00433     GINAC_ASSERT(is_a<indexed>(*self));
00434     GINAC_ASSERT(is_a<indexed>(*other));
00435     GINAC_ASSERT(self->nops() == 3);
00436     GINAC_ASSERT(is_a<tensdelta>(self->op(0)));
00437 
00438     // Replace the dummy index with this tensor's other index and remove
00439     // the tensor (this is valid for contractions with all other tensors)
00440     return replace_contr_index(self, other);
00441 }
00442 
00444 bool tensmetric::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
00445 {
00446     GINAC_ASSERT(is_a<indexed>(*self));
00447     GINAC_ASSERT(is_a<indexed>(*other));
00448     GINAC_ASSERT(self->nops() == 3);
00449     GINAC_ASSERT(is_a<tensmetric>(self->op(0)));
00450 
00451     // If contracting with the delta tensor, let the delta do it
00452     // (don't raise/lower delta indices)
00453     if (is_a<tensdelta>(other->op(0)))
00454         return false;
00455 
00456     // Replace the dummy index with this tensor's other index and remove
00457     // the tensor
00458     return replace_contr_index(self, other);
00459 }
00460 
00462 bool spinmetric::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
00463 {
00464     GINAC_ASSERT(is_a<indexed>(*self));
00465     GINAC_ASSERT(is_a<indexed>(*other));
00466     GINAC_ASSERT(self->nops() == 3);
00467     GINAC_ASSERT(is_a<spinmetric>(self->op(0)));
00468 
00469     // Contractions between spinor metrics
00470     if (is_a<spinmetric>(other->op(0))) {
00471         const idx &self_i1 = ex_to<idx>(self->op(1));
00472         const idx &self_i2 = ex_to<idx>(self->op(2));
00473         const idx &other_i1 = ex_to<idx>(other->op(1));
00474         const idx &other_i2 = ex_to<idx>(other->op(2));
00475 
00476         if (is_dummy_pair(self_i1, other_i1)) {
00477             if (is_dummy_pair(self_i2, other_i2))
00478                 *self = _ex2;
00479             else
00480                 *self = delta_tensor(self_i2, other_i2);
00481             *other = _ex1;
00482             return true;
00483         } else if (is_dummy_pair(self_i1, other_i2)) {
00484             if (is_dummy_pair(self_i2, other_i1))
00485                 *self = _ex_2;
00486             else
00487                 *self = -delta_tensor(self_i2, other_i1);
00488             *other = _ex1;
00489             return true;
00490         } else if (is_dummy_pair(self_i2, other_i1)) {
00491             *self = -delta_tensor(self_i1, other_i2);
00492             *other = _ex1;
00493             return true;
00494         } else if (is_dummy_pair(self_i2, other_i2)) {
00495             *self = delta_tensor(self_i1, other_i1);
00496             *other = _ex1;
00497             return true;
00498         }
00499     }
00500 
00501     // If contracting with the delta tensor, let the delta do it
00502     // (don't raise/lower delta indices)
00503     if (is_a<tensdelta>(other->op(0)))
00504         return false;
00505 
00506     // Try to contract first index
00507     const idx *self_idx = &ex_to<idx>(self->op(1));
00508     const idx *free_idx = &ex_to<idx>(self->op(2));
00509     bool first_index_tried = false;
00510     int sign = 1;
00511 
00512 again:
00513     if (self_idx->is_symbolic()) {
00514         for (size_t i=1; i<other->nops(); i++) {
00515             const idx &other_idx = ex_to<idx>(other->op(i));
00516             if (is_dummy_pair(*self_idx, other_idx)) {
00517 
00518                 // Contraction found, remove metric tensor and substitute
00519                 // index in second object (assign *self last because this
00520                 // invalidates free_idx)
00521                 *other = other->subs(other_idx == *free_idx);
00522                 *self = (static_cast<const spinidx *>(self_idx)->is_covariant() ? sign : -sign);
00523                 return true;
00524             }
00525         }
00526     }
00527 
00528     if (!first_index_tried) {
00529 
00530         // No contraction with first index found, try second index
00531         self_idx = &ex_to<idx>(self->op(2));
00532         free_idx = &ex_to<idx>(self->op(1));
00533         first_index_tried = true;
00534         sign = -sign;
00535         goto again;
00536     }
00537 
00538     return false;
00539 }
00540 
00542 bool tensepsilon::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
00543 {
00544     GINAC_ASSERT(is_a<indexed>(*self));
00545     GINAC_ASSERT(is_a<indexed>(*other));
00546     GINAC_ASSERT(is_a<tensepsilon>(self->op(0)));
00547     size_t num = self->nops() - 1;
00548 
00549     if (is_exactly_a<tensepsilon>(other->op(0)) && num+1 == other->nops()) {
00550 
00551         // Contraction of two epsilon tensors is a determinant
00552         bool variance = is_a<varidx>(self->op(1));
00553         matrix M(num, num);
00554         for (size_t i=0; i<num; i++) {
00555             for (size_t j=0; j<num; j++) {
00556                 if (minkowski)
00557                     M(i, j) = lorentz_g(self->op(i+1), other->op(j+1), pos_sig);
00558                 else if (variance)
00559                     M(i, j) = metric_tensor(self->op(i+1), other->op(j+1));
00560                 else
00561                     M(i, j) = delta_tensor(self->op(i+1), other->op(j+1));
00562             }
00563         }
00564         int sign = minkowski ? -1 : 1;
00565         *self = sign * M.determinant().simplify_indexed();
00566         *other = _ex1;
00567         return true;
00568     }
00569 
00570     return false;
00571 }
00572 
00574 // global functions
00576 
00577 ex delta_tensor(const ex & i1, const ex & i2)
00578 {
00579     static ex delta = (new tensdelta)->setflag(status_flags::dynallocated);
00580 
00581     if (!is_a<idx>(i1) || !is_a<idx>(i2))
00582         throw(std::invalid_argument("indices of delta tensor must be of type idx"));
00583 
00584     return indexed(delta, symmetric2(), i1, i2);
00585 }
00586 
00587 ex metric_tensor(const ex & i1, const ex & i2)
00588 {
00589     static ex metric = (new tensmetric)->setflag(status_flags::dynallocated);
00590 
00591     if (!is_a<varidx>(i1) || !is_a<varidx>(i2))
00592         throw(std::invalid_argument("indices of metric tensor must be of type varidx"));
00593 
00594     return indexed(metric, symmetric2(), i1, i2);
00595 }
00596 
00597 ex lorentz_g(const ex & i1, const ex & i2, bool pos_sig)
00598 {
00599     static ex metric_neg = (new minkmetric(false))->setflag(status_flags::dynallocated);
00600     static ex metric_pos = (new minkmetric(true))->setflag(status_flags::dynallocated);
00601 
00602     if (!is_a<varidx>(i1) || !is_a<varidx>(i2))
00603         throw(std::invalid_argument("indices of metric tensor must be of type varidx"));
00604 
00605     return indexed(pos_sig ? metric_pos : metric_neg, symmetric2(), i1, i2);
00606 }
00607 
00608 ex spinor_metric(const ex & i1, const ex & i2)
00609 {
00610     static ex metric = (new spinmetric)->setflag(status_flags::dynallocated);
00611 
00612     if (!is_a<spinidx>(i1) || !is_a<spinidx>(i2))
00613         throw(std::invalid_argument("indices of spinor metric must be of type spinidx"));
00614     if (!ex_to<idx>(i1).get_dim().is_equal(2) || !ex_to<idx>(i2).get_dim().is_equal(2))
00615         throw(std::runtime_error("index dimension for spinor metric must be 2"));
00616 
00617     return indexed(metric, antisymmetric2(), i1, i2);
00618 }
00619 
00620 ex epsilon_tensor(const ex & i1, const ex & i2)
00621 {
00622     static ex epsilon = (new tensepsilon)->setflag(status_flags::dynallocated);
00623 
00624     if (!is_a<idx>(i1) || !is_a<idx>(i2))
00625         throw(std::invalid_argument("indices of epsilon tensor must be of type idx"));
00626 
00627     ex dim = ex_to<idx>(i1).get_dim();
00628     if (!dim.is_equal(ex_to<idx>(i2).get_dim()))
00629         throw(std::invalid_argument("all indices of epsilon tensor must have the same dimension"));
00630     if (!ex_to<idx>(i1).get_dim().is_equal(_ex2))
00631         throw(std::runtime_error("index dimension of epsilon tensor must match number of indices"));
00632 
00633     if(is_a<wildcard>(i1.op(0))||is_a<wildcard>(i2.op(0)))
00634         return indexed(epsilon, antisymmetric2(), i1, i2).hold();
00635 
00636     return indexed(epsilon, antisymmetric2(), i1, i2);
00637 }
00638 
00639 ex epsilon_tensor(const ex & i1, const ex & i2, const ex & i3)
00640 {
00641     static ex epsilon = (new tensepsilon)->setflag(status_flags::dynallocated);
00642 
00643     if (!is_a<idx>(i1) || !is_a<idx>(i2) || !is_a<idx>(i3))
00644         throw(std::invalid_argument("indices of epsilon tensor must be of type idx"));
00645 
00646     ex dim = ex_to<idx>(i1).get_dim();
00647     if (!dim.is_equal(ex_to<idx>(i2).get_dim()) || !dim.is_equal(ex_to<idx>(i3).get_dim()))
00648         throw(std::invalid_argument("all indices of epsilon tensor must have the same dimension"));
00649     if (!ex_to<idx>(i1).get_dim().is_equal(_ex3))
00650         throw(std::runtime_error("index dimension of epsilon tensor must match number of indices"));
00651 
00652     if(is_a<wildcard>(i1.op(0))||is_a<wildcard>(i2.op(0))||is_a<wildcard>(i3.op(0)))
00653         return indexed(epsilon, antisymmetric3(), i1, i2, i3).hold();
00654 
00655     return indexed(epsilon, antisymmetric3(), i1, i2, i3);
00656 }
00657 
00658 ex lorentz_eps(const ex & i1, const ex & i2, const ex & i3, const ex & i4, bool pos_sig)
00659 {
00660     static ex epsilon_neg = (new tensepsilon(true, false))->setflag(status_flags::dynallocated);
00661     static ex epsilon_pos = (new tensepsilon(true, true))->setflag(status_flags::dynallocated);
00662 
00663     if (!is_a<varidx>(i1) || !is_a<varidx>(i2) || !is_a<varidx>(i3) || !is_a<varidx>(i4))
00664         throw(std::invalid_argument("indices of Lorentz epsilon tensor must be of type varidx"));
00665 
00666     ex dim = ex_to<idx>(i1).get_dim();
00667     if (!dim.is_equal(ex_to<idx>(i2).get_dim()) || !dim.is_equal(ex_to<idx>(i3).get_dim()) || !dim.is_equal(ex_to<idx>(i4).get_dim()))
00668         throw(std::invalid_argument("all indices of epsilon tensor must have the same dimension"));
00669     if (!ex_to<idx>(i1).get_dim().is_equal(_ex4))
00670         throw(std::runtime_error("index dimension of epsilon tensor must match number of indices"));
00671 
00672     if(is_a<wildcard>(i1.op(0))||is_a<wildcard>(i2.op(0))||is_a<wildcard>(i3.op(0))||is_a<wildcard>(i4.op(0)))
00673         return indexed(pos_sig ? epsilon_pos : epsilon_neg, antisymmetric4(), i1, i2, i3, i4).hold();
00674 
00675     return indexed(pos_sig ? epsilon_pos : epsilon_neg, antisymmetric4(), i1, i2, i3, i4);
00676 }
00677 
00678 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.