|
GiNaC
1.6.2
|
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