|
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 "clifford.h" 00024 00025 #include "ex.h" 00026 #include "idx.h" 00027 #include "ncmul.h" 00028 #include "symbol.h" 00029 #include "numeric.h" // for I 00030 #include "symmetry.h" 00031 #include "lst.h" 00032 #include "relational.h" 00033 #include "operators.h" 00034 #include "add.h" 00035 #include "mul.h" 00036 #include "power.h" 00037 #include "matrix.h" 00038 #include "archive.h" 00039 #include "utils.h" 00040 00041 #include <stdexcept> 00042 00043 namespace GiNaC { 00044 00045 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(clifford, indexed, 00046 print_func<print_dflt>(&clifford::do_print_dflt). 00047 print_func<print_latex>(&clifford::do_print_latex)) 00048 00049 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracone, tensor, 00050 print_func<print_dflt>(&diracone::do_print). 00051 print_func<print_latex>(&diracone::do_print_latex)) 00052 00053 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(cliffordunit, tensor, 00054 print_func<print_dflt>(&cliffordunit::do_print). 00055 print_func<print_latex>(&cliffordunit::do_print_latex)) 00056 00057 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgamma, cliffordunit, 00058 print_func<print_dflt>(&diracgamma::do_print). 00059 print_func<print_latex>(&diracgamma::do_print_latex)) 00060 00061 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgamma5, tensor, 00062 print_func<print_dflt>(&diracgamma5::do_print). 00063 print_func<print_latex>(&diracgamma5::do_print_latex)) 00064 00065 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgammaL, tensor, 00066 print_func<print_context>(&diracgammaL::do_print). 00067 print_func<print_latex>(&diracgammaL::do_print_latex)) 00068 00069 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(diracgammaR, tensor, 00070 print_func<print_context>(&diracgammaR::do_print). 00071 print_func<print_latex>(&diracgammaR::do_print_latex)) 00072 00074 // default constructors 00076 00077 clifford::clifford() : representation_label(0), metric(0), commutator_sign(-1) 00078 { 00079 } 00080 00081 DEFAULT_CTOR(diracone) 00082 DEFAULT_CTOR(cliffordunit) 00083 DEFAULT_CTOR(diracgamma) 00084 DEFAULT_CTOR(diracgamma5) 00085 DEFAULT_CTOR(diracgammaL) 00086 DEFAULT_CTOR(diracgammaR) 00087 00089 // other constructors 00091 00095 clifford::clifford(const ex & b, unsigned char rl) : inherited(b), representation_label(rl), metric(0), commutator_sign(-1) 00096 { 00097 } 00098 00103 clifford::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) 00104 { 00105 GINAC_ASSERT(is_a<idx>(mu)); 00106 } 00107 00108 clifford::clifford(unsigned char rl, const ex & metr, int comm_sign, const exvector & v, bool discardable) : inherited(not_symmetric(), v, discardable), representation_label(rl), metric(metr), commutator_sign(comm_sign) 00109 { 00110 } 00111 00112 clifford::clifford(unsigned char rl, const ex & metr, int comm_sign, std::auto_ptr<exvector> vp) : inherited(not_symmetric(), vp), representation_label(rl), metric(metr), commutator_sign(comm_sign) 00113 { 00114 } 00115 00116 return_type_t clifford::return_type_tinfo() const 00117 { 00118 return make_return_type_t<clifford>(representation_label); 00119 } 00120 00122 // archiving 00124 00125 void clifford::read_archive(const archive_node& n, lst& sym_lst) 00126 { 00127 inherited::read_archive(n, sym_lst); 00128 unsigned rl; 00129 n.find_unsigned("label", rl); 00130 representation_label = rl; 00131 n.find_ex("metric", metric, sym_lst); 00132 n.find_unsigned("commutator_sign+1", rl); 00133 commutator_sign = rl - 1; 00134 } 00135 00136 void clifford::archive(archive_node & n) const 00137 { 00138 inherited::archive(n); 00139 n.add_unsigned("label", representation_label); 00140 n.add_ex("metric", metric); 00141 n.add_unsigned("commutator_sign+1", commutator_sign+1); 00142 } 00143 00144 GINAC_BIND_UNARCHIVER(clifford); 00145 GINAC_BIND_UNARCHIVER(diracone); 00146 GINAC_BIND_UNARCHIVER(diracgamma); 00147 GINAC_BIND_UNARCHIVER(diracgamma5); 00148 GINAC_BIND_UNARCHIVER(diracgammaL); 00149 GINAC_BIND_UNARCHIVER(diracgammaR); 00150 00151 00152 ex clifford::get_metric(const ex & i, const ex & j, bool symmetrised) const 00153 { 00154 if (is_a<indexed>(metric)) { 00155 if (symmetrised && !(ex_to<symmetry>(ex_to<indexed>(metric).get_symmetry()).has_symmetry())) { 00156 if (is_a<matrix>(metric.op(0))) { 00157 return indexed((ex_to<matrix>(metric.op(0)).add(ex_to<matrix>(metric.op(0)).transpose())).mul(numeric(1, 2)), 00158 symmetric2(), i, j); 00159 } else { 00160 return simplify_indexed(indexed(metric.op(0)*_ex1_2, i, j) + indexed(metric.op(0)*_ex1_2, j, i)); 00161 } 00162 } else { 00163 return metric.subs(lst(metric.op(1) == i, metric.op(2) == j), subs_options::no_pattern); 00164 } 00165 } else { 00166 exvector indices = metric.get_free_indices(); 00167 if (symmetrised) 00168 return _ex1_2*simplify_indexed(metric.subs(lst(indices[0] == i, indices[1] == j), subs_options::no_pattern) 00169 + metric.subs(lst(indices[0] == j, indices[1] == i), subs_options::no_pattern)); 00170 else 00171 return metric.subs(lst(indices[0] == i, indices[1] == j), subs_options::no_pattern); 00172 } 00173 } 00174 00175 bool clifford::same_metric(const ex & other) const 00176 { 00177 ex metr; 00178 if (is_a<clifford>(other)) 00179 metr = ex_to<clifford>(other).get_metric(); 00180 else 00181 metr = other; 00182 00183 if (is_a<indexed>(metr)) 00184 return metr.op(0).is_equal(get_metric().op(0)); 00185 else { 00186 exvector indices = metr.get_free_indices(); 00187 return (indices.size() == 2) 00188 && simplify_indexed(get_metric(indices[0], indices[1])-metr).is_zero(); 00189 } 00190 } 00191 00193 // functions overriding virtual functions from base classes 00195 00196 ex clifford::op(size_t i) const 00197 { 00198 GINAC_ASSERT(i<nops()); 00199 if (nops()-i == 1) 00200 return representation_label; 00201 else 00202 return inherited::op(i); 00203 } 00204 00205 ex & clifford::let_op(size_t i) 00206 { 00207 GINAC_ASSERT(i<nops()); 00208 00209 static ex rl = numeric(representation_label); 00210 ensure_if_modifiable(); 00211 if (nops()-i == 1) 00212 return rl; 00213 else 00214 return inherited::let_op(i); 00215 } 00216 00217 ex clifford::subs(const exmap & m, unsigned options) const 00218 { 00219 ex subsed = inherited::subs(m, options); 00220 if(is_a<clifford>(subsed)) { 00221 ex prevmetric = ex_to<clifford>(subsed).metric; 00222 ex newmetric = prevmetric.subs(m, options); 00223 if(!are_ex_trivially_equal(prevmetric, newmetric)) { 00224 clifford c = ex_to<clifford>(subsed); 00225 c.metric = newmetric; 00226 subsed = c; 00227 } 00228 } 00229 return subsed; 00230 } 00231 00232 int clifford::compare_same_type(const basic & other) const 00233 { 00234 GINAC_ASSERT(is_a<clifford>(other)); 00235 const clifford &o = static_cast<const clifford &>(other); 00236 00237 if (representation_label != o.representation_label) { 00238 // different representation label 00239 return representation_label < o.representation_label ? -1 : 1; 00240 } 00241 00242 return inherited::compare_same_type(other); 00243 } 00244 00245 bool clifford::match_same_type(const basic & other) const 00246 { 00247 GINAC_ASSERT(is_a<clifford>(other)); 00248 const clifford &o = static_cast<const clifford &>(other); 00249 00250 return ((representation_label == o.representation_label) && (commutator_sign == o.get_commutator_sign()) && same_metric(o)); 00251 } 00252 00253 static bool is_dirac_slash(const ex & seq0) 00254 { 00255 return !is_a<diracgamma5>(seq0) && !is_a<diracgammaL>(seq0) && 00256 !is_a<diracgammaR>(seq0) && !is_a<cliffordunit>(seq0) && 00257 !is_a<diracone>(seq0); 00258 } 00259 00260 void clifford::do_print_dflt(const print_dflt & c, unsigned level) const 00261 { 00262 // dirac_slash() object is printed differently 00263 if (is_dirac_slash(seq[0])) { 00264 seq[0].print(c, precedence()); 00265 c.s << "\\"; 00266 } else { // We do not print representation label if it is 0 00267 if (representation_label == 0) { 00268 this->print_dispatch<inherited>(c, level); 00269 } else { // otherwise we put it before indices in square brackets; the code is borrowed from indexed.cpp 00270 if (precedence() <= level) { 00271 c.s << '('; 00272 } 00273 seq[0].print(c, precedence()); 00274 c.s << '[' << int(representation_label) << ']'; 00275 printindices(c, level); 00276 if (precedence() <= level) { 00277 c.s << ')'; 00278 } 00279 } 00280 } 00281 } 00282 00283 void clifford::do_print_latex(const print_latex & c, unsigned level) const 00284 { 00285 // dirac_slash() object is printed differently 00286 if (is_dirac_slash(seq[0])) { 00287 c.s << "{"; 00288 seq[0].print(c, precedence()); 00289 c.s << "\\hspace{-1.0ex}/}"; 00290 } else { 00291 c.s << "\\clifford[" << int(representation_label) << "]"; 00292 this->print_dispatch<inherited>(c, level); 00293 } 00294 } 00295 00296 DEFAULT_COMPARE(diracone) 00297 DEFAULT_COMPARE(cliffordunit) 00298 DEFAULT_COMPARE(diracgamma) 00299 DEFAULT_COMPARE(diracgamma5) 00300 DEFAULT_COMPARE(diracgammaL) 00301 DEFAULT_COMPARE(diracgammaR) 00302 00303 DEFAULT_PRINT_LATEX(diracone, "ONE", "\\mathbf{1}") 00304 DEFAULT_PRINT_LATEX(cliffordunit, "e", "e") 00305 DEFAULT_PRINT_LATEX(diracgamma, "gamma", "\\gamma") 00306 DEFAULT_PRINT_LATEX(diracgamma5, "gamma5", "{\\gamma^5}") 00307 DEFAULT_PRINT_LATEX(diracgammaL, "gammaL", "{\\gamma_L}") 00308 DEFAULT_PRINT_LATEX(diracgammaR, "gammaR", "{\\gamma_R}") 00309 00311 static void base_and_index(const ex & c, ex & b, ex & i) 00312 { 00313 GINAC_ASSERT(is_a<clifford>(c)); 00314 GINAC_ASSERT(c.nops() == 2+1); 00315 00316 if (is_a<cliffordunit>(c.op(0))) { // proper dirac gamma object or clifford unit 00317 i = c.op(1); 00318 b = _ex1; 00319 } else if (is_a<diracgamma5>(c.op(0)) || is_a<diracgammaL>(c.op(0)) || is_a<diracgammaR>(c.op(0))) { // gamma5/L/R 00320 i = _ex0; 00321 b = _ex1; 00322 } else { // slash object, generate new dummy index 00323 varidx ix((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(c.op(1)).get_dim()); 00324 b = indexed(c.op(0), ix.toggle_variance()); 00325 i = ix; 00326 } 00327 } 00328 00330 struct is_not_a_clifford : public std::unary_function<ex, bool> { 00331 bool operator()(const ex & e) 00332 { 00333 return !is_a<clifford>(e); 00334 } 00335 }; 00336 00338 bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const 00339 { 00340 GINAC_ASSERT(is_a<clifford>(*self)); 00341 GINAC_ASSERT(is_a<indexed>(*other)); 00342 GINAC_ASSERT(is_a<diracgamma>(self->op(0))); 00343 unsigned char rl = ex_to<clifford>(*self).get_representation_label(); 00344 00345 ex dim = ex_to<idx>(self->op(1)).get_dim(); 00346 if (other->nops() > 1) 00347 dim = minimal_dim(dim, ex_to<idx>(other->op(1)).get_dim()); 00348 00349 if (is_a<clifford>(*other)) { 00350 00351 // Contraction only makes sense if the represenation labels are equal 00352 if (ex_to<clifford>(*other).get_representation_label() != rl) 00353 return false; 00354 00355 size_t num = other - self; 00356 00357 // gamma~mu gamma.mu = dim ONE 00358 if (num == 1) { 00359 *self = dim; 00360 *other = dirac_ONE(rl); 00361 return true; 00362 00363 // gamma~mu gamma~alpha gamma.mu = (2-dim) gamma~alpha 00364 } else if (num == 2 00365 && is_a<clifford>(self[1])) { 00366 *self = 2 - dim; 00367 *other = _ex1; 00368 return true; 00369 00370 // gamma~mu gamma~alpha gamma~beta gamma.mu = 4 g~alpha~beta + (dim-4) gamam~alpha gamma~beta 00371 } else if (num == 3 00372 && is_a<clifford>(self[1]) 00373 && is_a<clifford>(self[2])) { 00374 ex b1, i1, b2, i2; 00375 base_and_index(self[1], b1, i1); 00376 base_and_index(self[2], b2, i2); 00377 *self = 4 * lorentz_g(i1, i2) * b1 * b2 * dirac_ONE(rl) + (dim - 4) * self[1] * self[2]; 00378 self[1] = _ex1; 00379 self[2] = _ex1; 00380 *other = _ex1; 00381 return true; 00382 00383 // 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 00384 } else if (num == 4 00385 && is_a<clifford>(self[1]) 00386 && is_a<clifford>(self[2]) 00387 && is_a<clifford>(self[3])) { 00388 *self = -2 * self[3] * self[2] * self[1] - (dim - 4) * self[1] * self[2] * self[3]; 00389 self[1] = _ex1; 00390 self[2] = _ex1; 00391 self[3] = _ex1; 00392 *other = _ex1; 00393 return true; 00394 00395 // gamma~mu Sodd gamma.mu = -2 Sodd_R 00396 // (Chisholm identity in 4 dimensions) 00397 } else if (!((other - self) & 1) && dim.is_equal(4)) { 00398 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) 00399 return false; 00400 00401 *self = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(other), std::reverse_iterator<exvector::const_iterator>(self + 1)), true); 00402 std::fill(self + 1, other, _ex1); 00403 *other = _ex_2; 00404 return true; 00405 00406 // gamma~mu Sodd gamma~alpha gamma.mu = 2 gamma~alpha Sodd + 2 Sodd_R gamma~alpha 00407 // (commutate contracted indices towards each other, then use 00408 // Chisholm identity in 4 dimensions) 00409 } else if (((other - self) & 1) && dim.is_equal(4)) { 00410 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) 00411 return false; 00412 00413 exvector::iterator next_to_last = other - 1; 00414 ex S = ncmul(exvector(self + 1, next_to_last), true); 00415 ex SR = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(next_to_last), std::reverse_iterator<exvector::const_iterator>(self + 1)), true); 00416 00417 *self = (*next_to_last) * S + SR * (*next_to_last); 00418 std::fill(self + 1, other, _ex1); 00419 *other = _ex2; 00420 return true; 00421 00422 // gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha 00423 // (commutate contracted indices towards each other, simplify_indexed() 00424 // will re-expand and re-run the simplification) 00425 } else { 00426 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) 00427 return false; 00428 00429 exvector::iterator next_to_last = other - 1; 00430 ex S = ncmul(exvector(self + 1, next_to_last), true); 00431 00432 *self = 2 * (*next_to_last) * S - (*self) * S * (*other) * (*next_to_last); 00433 std::fill(self + 1, other + 1, _ex1); 00434 return true; 00435 } 00436 00437 } else if (is_a<symbol>(other->op(0)) && other->nops() == 2) { 00438 00439 // x.mu gamma~mu -> x-slash 00440 *self = dirac_slash(other->op(0), dim, rl); 00441 *other = _ex1; 00442 return true; 00443 } 00444 00445 return false; 00446 } 00447 00449 bool cliffordunit::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const 00450 { 00451 GINAC_ASSERT(is_a<clifford>(*self)); 00452 GINAC_ASSERT(is_a<indexed>(*other)); 00453 GINAC_ASSERT(is_a<cliffordunit>(self->op(0))); 00454 clifford unit = ex_to<clifford>(*self); 00455 unsigned char rl = unit.get_representation_label(); 00456 00457 if (is_a<clifford>(*other)) { 00458 // Contraction only makes sense if the represenation labels are equal 00459 // and the metrics are the same 00460 if ((ex_to<clifford>(*other).get_representation_label() != rl) 00461 && unit.same_metric(*other)) 00462 return false; 00463 00464 exvector::iterator before_other = other - 1; 00465 ex mu = self->op(1); 00466 ex mu_toggle = other->op(1); 00467 ex alpha = before_other->op(1); 00468 00469 // e~mu e.mu = Tr ONE 00470 if (other - self == 1) { 00471 *self = unit.get_metric(mu, mu_toggle, true); 00472 *other = dirac_ONE(rl); 00473 return true; 00474 00475 } else if (other - self == 2) { 00476 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) { 00477 // e~mu e~alpha e.mu = 2*e~mu B(alpha, mu.toggle_variance())-Tr(B) e~alpha 00478 *self = 2 * (*self) * unit.get_metric(alpha, mu_toggle, true) - unit.get_metric(mu, mu_toggle, true) * (*before_other); 00479 *before_other = _ex1; 00480 *other = _ex1; 00481 return true; 00482 00483 } else { 00484 // e~mu S e.mu = Tr S ONE 00485 *self = unit.get_metric(mu, mu_toggle, true); 00486 *other = dirac_ONE(rl); 00487 return true; 00488 } 00489 } else { 00490 // e~mu S e~alpha e.mu = 2 e~mu S B(alpha, mu.toggle_variance()) - e~mu S e.mu e~alpha 00491 // (commutate contracted indices towards each other, simplify_indexed() 00492 // will re-expand and re-run the simplification) 00493 if (std::find_if(self + 1, other, is_not_a_clifford()) != other) { 00494 return false; 00495 } 00496 00497 ex S = ncmul(exvector(self + 1, before_other), true); 00498 00499 if (is_a<clifford>(*before_other) && ex_to<clifford>(*before_other).get_representation_label() == rl) { 00500 *self = 2 * (*self) * S * unit.get_metric(alpha, mu_toggle, true) - (*self) * S * (*other) * (*before_other); 00501 } else { 00502 // simply commutes 00503 *self = (*self) * S * (*other) * (*before_other); 00504 } 00505 00506 std::fill(self + 1, other + 1, _ex1); 00507 return true; 00508 } 00509 } 00510 return false; 00511 } 00512 00516 ex clifford::eval_ncmul(const exvector & v) const 00517 { 00518 exvector s; 00519 s.reserve(v.size()); 00520 00521 // Remove superfluous ONEs 00522 exvector::const_iterator cit = v.begin(), citend = v.end(); 00523 while (cit != citend) { 00524 if (!is_a<clifford>(*cit) || !is_a<diracone>(cit->op(0))) 00525 s.push_back(*cit); 00526 cit++; 00527 } 00528 00529 bool something_changed = false; 00530 int sign = 1; 00531 00532 // Anticommutate gamma5/L/R's to the front 00533 if (s.size() >= 2) { 00534 exvector::iterator first = s.begin(), next_to_last = s.end() - 2; 00535 while (true) { 00536 exvector::iterator it = next_to_last; 00537 while (true) { 00538 exvector::iterator it2 = it + 1; 00539 if (is_a<clifford>(*it) && is_a<clifford>(*it2)) { 00540 ex e1 = it->op(0), e2 = it2->op(0); 00541 00542 if (is_a<diracgamma5>(e2)) { 00543 00544 if (is_a<diracgammaL>(e1) || is_a<diracgammaR>(e1)) { 00545 00546 // gammaL/R gamma5 -> gamma5 gammaL/R 00547 it->swap(*it2); 00548 something_changed = true; 00549 00550 } else if (!is_a<diracgamma5>(e1)) { 00551 00552 // gamma5 gamma5 -> gamma5 gamma5 (do nothing) 00553 // x gamma5 -> -gamma5 x 00554 it->swap(*it2); 00555 sign = -sign; 00556 something_changed = true; 00557 } 00558 00559 } else if (is_a<diracgammaL>(e2)) { 00560 00561 if (is_a<diracgammaR>(e1)) { 00562 00563 // gammaR gammaL -> 0 00564 return _ex0; 00565 00566 } else if (!is_a<diracgammaL>(e1) && !is_a<diracgamma5>(e1)) { 00567 00568 // gammaL gammaL -> gammaL gammaL (do nothing) 00569 // gamma5 gammaL -> gamma5 gammaL (do nothing) 00570 // x gammaL -> gammaR x 00571 it->swap(*it2); 00572 *it = clifford(diracgammaR(), ex_to<clifford>(*it).get_representation_label()); 00573 something_changed = true; 00574 } 00575 00576 } else if (is_a<diracgammaR>(e2)) { 00577 00578 if (is_a<diracgammaL>(e1)) { 00579 00580 // gammaL gammaR -> 0 00581 return _ex0; 00582 00583 } else if (!is_a<diracgammaR>(e1) && !is_a<diracgamma5>(e1)) { 00584 00585 // gammaR gammaR -> gammaR gammaR (do nothing) 00586 // gamma5 gammaR -> gamma5 gammaR (do nothing) 00587 // x gammaR -> gammaL x 00588 it->swap(*it2); 00589 *it = clifford(diracgammaL(), ex_to<clifford>(*it).get_representation_label()); 00590 something_changed = true; 00591 } 00592 } 00593 } 00594 if (it == first) 00595 break; 00596 --it; 00597 } 00598 if (next_to_last == first) 00599 break; 00600 --next_to_last; 00601 } 00602 } 00603 00604 // Remove equal adjacent gammas 00605 if (s.size() >= 2) { 00606 exvector::iterator it, itend = s.end() - 1; 00607 for (it = s.begin(); it != itend; ++it) { 00608 ex & a = it[0]; 00609 ex & b = it[1]; 00610 if (!is_a<clifford>(a) || !is_a<clifford>(b)) 00611 continue; 00612 00613 const ex & ag = a.op(0); 00614 const ex & bg = b.op(0); 00615 bool a_is_cliffordunit = is_a<cliffordunit>(ag); 00616 bool b_is_cliffordunit = is_a<cliffordunit>(bg); 00617 00618 if (a_is_cliffordunit && b_is_cliffordunit && ex_to<clifford>(a).same_metric(b) 00619 && (ex_to<clifford>(a).get_commutator_sign() == -1)) { 00620 // This is done only for Clifford algebras 00621 00622 const ex & ia = a.op(1); 00623 const ex & ib = b.op(1); 00624 if (ia.is_equal(ib)) { // gamma~alpha gamma~alpha -> g~alpha~alpha 00625 a = ex_to<clifford>(a).get_metric(ia, ib, true); 00626 b = dirac_ONE(representation_label); 00627 something_changed = true; 00628 } 00629 00630 } else if ((is_a<diracgamma5>(ag) && is_a<diracgamma5>(bg))) { 00631 00632 // Remove squares of gamma5 00633 a = dirac_ONE(representation_label); 00634 b = dirac_ONE(representation_label); 00635 something_changed = true; 00636 00637 } else if ((is_a<diracgammaL>(ag) && is_a<diracgammaL>(bg)) 00638 || (is_a<diracgammaR>(ag) && is_a<diracgammaR>(bg))) { 00639 00640 // Remove squares of gammaL/R 00641 b = dirac_ONE(representation_label); 00642 something_changed = true; 00643 00644 } else if (is_a<diracgammaL>(ag) && is_a<diracgammaR>(bg)) { 00645 00646 // gammaL and gammaR are orthogonal 00647 return _ex0; 00648 00649 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaL>(bg)) { 00650 00651 // gamma5 gammaL -> -gammaL 00652 a = dirac_ONE(representation_label); 00653 sign = -sign; 00654 something_changed = true; 00655 00656 } else if (is_a<diracgamma5>(ag) && is_a<diracgammaR>(bg)) { 00657 00658 // gamma5 gammaR -> gammaR 00659 a = dirac_ONE(representation_label); 00660 something_changed = true; 00661 00662 } else if (!a_is_cliffordunit && !b_is_cliffordunit && ag.is_equal(bg)) { 00663 00664 // a\ a\ -> a^2 00665 varidx ix((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(a.op(1)).minimal_dim(ex_to<idx>(b.op(1)))); 00666 00667 a = indexed(ag, ix) * indexed(ag, ix.toggle_variance()); 00668 b = dirac_ONE(representation_label); 00669 something_changed = true; 00670 } 00671 } 00672 } 00673 00674 if (s.empty()) 00675 return dirac_ONE(representation_label) * sign; 00676 if (something_changed) 00677 return reeval_ncmul(s) * sign; 00678 else 00679 return hold_ncmul(s) * sign; 00680 } 00681 00682 ex clifford::thiscontainer(const exvector & v) const 00683 { 00684 return clifford(representation_label, metric, commutator_sign, v); 00685 } 00686 00687 ex clifford::thiscontainer(std::auto_ptr<exvector> vp) const 00688 { 00689 return clifford(representation_label, metric, commutator_sign, vp); 00690 } 00691 00692 ex diracgamma5::conjugate() const 00693 { 00694 return _ex_1 * (*this); 00695 } 00696 00697 ex diracgammaL::conjugate() const 00698 { 00699 return (new diracgammaR)->setflag(status_flags::dynallocated); 00700 } 00701 00702 ex diracgammaR::conjugate() const 00703 { 00704 return (new diracgammaL)->setflag(status_flags::dynallocated); 00705 } 00706 00708 // global functions 00710 00711 ex dirac_ONE(unsigned char rl) 00712 { 00713 static ex ONE = (new diracone)->setflag(status_flags::dynallocated); 00714 return clifford(ONE, rl); 00715 } 00716 00717 static unsigned get_dim_uint(const ex& e) 00718 { 00719 if (!is_a<idx>(e)) 00720 throw std::invalid_argument("get_dim_uint: argument is not an index"); 00721 ex dim = ex_to<idx>(e).get_dim(); 00722 if (!dim.info(info_flags::posint)) 00723 throw std::invalid_argument("get_dim_uint: dimension of index should be a positive integer"); 00724 unsigned d = ex_to<numeric>(dim).to_int(); 00725 return d; 00726 } 00727 00728 ex clifford_unit(const ex & mu, const ex & metr, unsigned char rl) 00729 { 00730 //static ex unit = (new cliffordunit)->setflag(status_flags::dynallocated); 00731 ex unit = (new cliffordunit)->setflag(status_flags::dynallocated); 00732 00733 if (!is_a<idx>(mu)) 00734 throw(std::invalid_argument("clifford_unit(): index of Clifford unit must be of type idx or varidx")); 00735 00736 exvector indices = metr.get_free_indices(); 00737 00738 if (indices.size() == 2) { 00739 return clifford(unit, mu, metr, rl); 00740 } else if (is_a<matrix>(metr)) { 00741 matrix M = ex_to<matrix>(metr); 00742 unsigned n = M.rows(); 00743 bool symmetric = true; 00744 00745 //static idx xi((new symbol)->setflag(status_flags::dynallocated), n), 00746 // chi((new symbol)->setflag(status_flags::dynallocated), n); 00747 idx xi((new symbol)->setflag(status_flags::dynallocated), n), 00748 chi((new symbol)->setflag(status_flags::dynallocated), n); 00749 if ((n == M.cols()) && (n == get_dim_uint(mu))) { 00750 for (unsigned i = 0; i < n; i++) { 00751 for (unsigned j = i+1; j < n; j++) { 00752 if (!M(i, j).is_equal(M(j, i))) { 00753 symmetric = false; 00754 } 00755 } 00756 } 00757 return clifford(unit, mu, indexed(metr, symmetric?symmetric2():not_symmetric(), xi, chi), rl); 00758 } else { 00759 throw(std::invalid_argument("clifford_unit(): metric for Clifford unit must be a square matrix with the same dimensions as index")); 00760 } 00761 } else if (indices.size() == 0) { // a tensor or other expression without indices 00762 //static varidx xi((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(mu).get_dim()), 00763 // chi((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(mu).get_dim()); 00764 varidx xi((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(mu).get_dim()), 00765 chi((new symbol)->setflag(status_flags::dynallocated), ex_to<idx>(mu).get_dim()); 00766 return clifford(unit, mu, indexed(metr, xi, chi), rl); 00767 } else 00768 throw(std::invalid_argument("clifford_unit(): metric for Clifford unit must be of type tensor, matrix or an expression with two free indices")); 00769 } 00770 00771 ex dirac_gamma(const ex & mu, unsigned char rl) 00772 { 00773 static ex gamma = (new diracgamma)->setflag(status_flags::dynallocated); 00774 00775 if (!is_a<varidx>(mu)) 00776 throw(std::invalid_argument("dirac_gamma(): index of Dirac gamma must be of type varidx")); 00777 00778 static varidx xi((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(mu).get_dim()), 00779 chi((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(mu).get_dim()); 00780 return clifford(gamma, mu, indexed((new minkmetric)->setflag(status_flags::dynallocated), symmetric2(), xi, chi), rl); 00781 } 00782 00783 ex dirac_gamma5(unsigned char rl) 00784 { 00785 static ex gamma5 = (new diracgamma5)->setflag(status_flags::dynallocated); 00786 return clifford(gamma5, rl); 00787 } 00788 00789 ex dirac_gammaL(unsigned char rl) 00790 { 00791 static ex gammaL = (new diracgammaL)->setflag(status_flags::dynallocated); 00792 return clifford(gammaL, rl); 00793 } 00794 00795 ex dirac_gammaR(unsigned char rl) 00796 { 00797 static ex gammaR = (new diracgammaR)->setflag(status_flags::dynallocated); 00798 return clifford(gammaR, rl); 00799 } 00800 00801 ex dirac_slash(const ex & e, const ex & dim, unsigned char rl) 00802 { 00803 // Slashed vectors are actually stored as a clifford object with the 00804 // vector as its base expression and a (dummy) index that just serves 00805 // for storing the space dimensionality 00806 00807 static varidx xi((new symbol)->setflag(status_flags::dynallocated), dim), 00808 chi((new symbol)->setflag(status_flags::dynallocated), dim); 00809 return clifford(e, varidx(0, dim), indexed((new minkmetric)->setflag(status_flags::dynallocated), symmetric2(), xi, chi), rl); 00810 } 00811 00814 static unsigned char get_representation_label(const return_type_t& ti) 00815 { 00816 return (unsigned char)ti.rl; 00817 } 00818 00821 static ex trace_string(exvector::const_iterator ix, size_t num) 00822 { 00823 // Tr gamma.mu gamma.nu = 4 g.mu.nu 00824 if (num == 2) 00825 return lorentz_g(ix[0], ix[1]); 00826 00827 // 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 ) 00828 else if (num == 4) 00829 return lorentz_g(ix[0], ix[1]) * lorentz_g(ix[2], ix[3]) 00830 + lorentz_g(ix[1], ix[2]) * lorentz_g(ix[0], ix[3]) 00831 - lorentz_g(ix[0], ix[2]) * lorentz_g(ix[1], ix[3]); 00832 00833 // Traces of 6 or more gammas are computed recursively: 00834 // Tr gamma.mu1 gamma.mu2 ... gamma.mun = 00835 // + g.mu1.mu2 * Tr gamma.mu3 ... gamma.mun 00836 // - g.mu1.mu3 * Tr gamma.mu2 gamma.mu4 ... gamma.mun 00837 // + g.mu1.mu4 * Tr gamma.mu3 gamma.mu3 gamma.mu5 ... gamma.mun 00838 // - ... 00839 // + g.mu1.mun * Tr gamma.mu2 ... gamma.mu(n-1) 00840 exvector v(num - 2); 00841 int sign = 1; 00842 ex result; 00843 for (size_t i=1; i<num; i++) { 00844 for (size_t n=1, j=0; n<num; n++) { 00845 if (n == i) 00846 continue; 00847 v[j++] = ix[n]; 00848 } 00849 result += sign * lorentz_g(ix[0], ix[i]) * trace_string(v.begin(), num-2); 00850 sign = -sign; 00851 } 00852 return result; 00853 } 00854 00855 ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE) 00856 { 00857 if (is_a<clifford>(e)) { 00858 00859 unsigned char rl = ex_to<clifford>(e).get_representation_label(); 00860 00861 // Are we taking the trace over this object's representation label? 00862 if (rls.find(rl) == rls.end()) 00863 return e; 00864 00865 // Yes, all elements are traceless, except for dirac_ONE and dirac_L/R 00866 const ex & g = e.op(0); 00867 if (is_a<diracone>(g)) 00868 return trONE; 00869 else if (is_a<diracgammaL>(g) || is_a<diracgammaR>(g)) 00870 return trONE/2; 00871 else 00872 return _ex0; 00873 00874 } else if (is_exactly_a<mul>(e)) { 00875 00876 // Trace of product: pull out non-clifford factors 00877 ex prod = _ex1; 00878 for (size_t i=0; i<e.nops(); i++) { 00879 const ex &o = e.op(i); 00880 if (is_clifford_tinfo(o.return_type_tinfo())) 00881 prod *= dirac_trace(o, rls, trONE); 00882 else 00883 prod *= o; 00884 } 00885 return prod; 00886 00887 } else if (is_exactly_a<ncmul>(e)) { 00888 00889 unsigned char rl = get_representation_label(e.return_type_tinfo()); 00890 00891 // Are we taking the trace over this string's representation label? 00892 if (rls.find(rl) == rls.end()) 00893 return e; 00894 00895 // Substitute gammaL/R and expand product, if necessary 00896 ex e_expanded = e.subs(lst( 00897 dirac_gammaL(rl) == (dirac_ONE(rl)-dirac_gamma5(rl))/2, 00898 dirac_gammaR(rl) == (dirac_ONE(rl)+dirac_gamma5(rl))/2 00899 ), subs_options::no_pattern).expand(); 00900 if (!is_a<ncmul>(e_expanded)) 00901 return dirac_trace(e_expanded, rls, trONE); 00902 00903 // gamma5 gets moved to the front so this check is enough 00904 bool has_gamma5 = is_a<diracgamma5>(e.op(0).op(0)); 00905 size_t num = e.nops(); 00906 00907 if (has_gamma5) { 00908 00909 // Trace of gamma5 * odd number of gammas and trace of 00910 // gamma5 * gamma.mu * gamma.nu are zero 00911 if ((num & 1) == 0 || num == 3) 00912 return _ex0; 00913 00914 // Tr gamma5 gamma.mu gamma.nu gamma.rho gamma.sigma = 4I * epsilon(mu, nu, rho, sigma) 00915 // (the epsilon is always 4-dimensional) 00916 if (num == 5) { 00917 ex b1, i1, b2, i2, b3, i3, b4, i4; 00918 base_and_index(e.op(1), b1, i1); 00919 base_and_index(e.op(2), b2, i2); 00920 base_and_index(e.op(3), b3, i3); 00921 base_and_index(e.op(4), b4, i4); 00922 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(); 00923 } 00924 00925 // Tr gamma5 S_2k = 00926 // I/4! * epsilon0123.mu1.mu2.mu3.mu4 * Tr gamma.mu1 gamma.mu2 gamma.mu3 gamma.mu4 S_2k 00927 // (the epsilon is always 4-dimensional) 00928 exvector ix(num-1), bv(num-1); 00929 for (size_t i=1; i<num; i++) 00930 base_and_index(e.op(i), bv[i-1], ix[i-1]); 00931 num--; 00932 int *iv = new int[num]; 00933 ex result; 00934 for (size_t i=0; i<num-3; i++) { 00935 ex idx1 = ix[i]; 00936 for (size_t j=i+1; j<num-2; j++) { 00937 ex idx2 = ix[j]; 00938 for (size_t k=j+1; k<num-1; k++) { 00939 ex idx3 = ix[k]; 00940 for (size_t l=k+1; l<num; l++) { 00941 ex idx4 = ix[l]; 00942 iv[0] = i; iv[1] = j; iv[2] = k; iv[3] = l; 00943 exvector v; 00944 v.reserve(num - 4); 00945 for (size_t n=0, t=4; n<num; n++) { 00946 if (n == i || n == j || n == k || n == l) 00947 continue; 00948 iv[t++] = n; 00949 v.push_back(ix[n]); 00950 } 00951 int sign = permutation_sign(iv, iv + num); 00952 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)) 00953 * trace_string(v.begin(), num - 4); 00954 } 00955 } 00956 } 00957 } 00958 delete[] iv; 00959 return trONE * I * result * mul(bv); 00960 00961 } else { // no gamma5 00962 00963 // Trace of odd number of gammas is zero 00964 if ((num & 1) == 1) 00965 return _ex0; 00966 00967 // Tr gamma.mu gamma.nu = 4 g.mu.nu 00968 if (num == 2) { 00969 ex b1, i1, b2, i2; 00970 base_and_index(e.op(0), b1, i1); 00971 base_and_index(e.op(1), b2, i2); 00972 return trONE * (lorentz_g(i1, i2) * b1 * b2).simplify_indexed(); 00973 } 00974 00975 exvector iv(num), bv(num); 00976 for (size_t i=0; i<num; i++) 00977 base_and_index(e.op(i), bv[i], iv[i]); 00978 00979 return trONE * (trace_string(iv.begin(), num) * mul(bv)).simplify_indexed(); 00980 } 00981 00982 } else if (e.nops() > 0) { 00983 00984 // Trace maps to all other container classes (this includes sums) 00985 pointer_to_map_function_2args<const std::set<unsigned char> &, const ex &> fcn(dirac_trace, rls, trONE); 00986 return e.map(fcn); 00987 00988 } else 00989 return _ex0; 00990 } 00991 00992 ex dirac_trace(const ex & e, const lst & rll, const ex & trONE) 00993 { 00994 // Convert list to set 00995 std::set<unsigned char> rls; 00996 for (lst::const_iterator i = rll.begin(); i != rll.end(); ++i) { 00997 if (i->info(info_flags::nonnegint)) 00998 rls.insert(ex_to<numeric>(*i).to_int()); 00999 } 01000 01001 return dirac_trace(e, rls, trONE); 01002 } 01003 01004 ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE) 01005 { 01006 // Convert label to set 01007 std::set<unsigned char> rls; 01008 rls.insert(rl); 01009 01010 return dirac_trace(e, rls, trONE); 01011 } 01012 01013 01014 ex canonicalize_clifford(const ex & e_) 01015 { 01016 pointer_to_map_function fcn(canonicalize_clifford); 01017 01018 if (is_a<matrix>(e_) // || is_a<pseries>(e) || is_a<integral>(e) 01019 || e_.info(info_flags::list)) { 01020 return e_.map(fcn); 01021 } else { 01022 ex e=simplify_indexed(e_); 01023 // Scan for any ncmul objects 01024 exmap srl; 01025 ex aux = e.to_rational(srl); 01026 for (exmap::iterator i = srl.begin(); i != srl.end(); ++i) { 01027 01028 ex lhs = i->first; 01029 ex rhs = i->second; 01030 01031 if (is_exactly_a<ncmul>(rhs) 01032 && rhs.return_type() == return_types::noncommutative 01033 && is_clifford_tinfo(rhs.return_type_tinfo())) { 01034 01035 // Expand product, if necessary 01036 ex rhs_expanded = rhs.expand(); 01037 if (!is_a<ncmul>(rhs_expanded)) { 01038 i->second = canonicalize_clifford(rhs_expanded); 01039 continue; 01040 01041 } else if (!is_a<clifford>(rhs.op(0))) 01042 continue; 01043 01044 exvector v; 01045 v.reserve(rhs.nops()); 01046 for (size_t j=0; j<rhs.nops(); j++) 01047 v.push_back(rhs.op(j)); 01048 01049 // Stupid recursive bubble sort because we only want to swap adjacent gammas 01050 exvector::iterator it = v.begin(), next_to_last = v.end() - 1; 01051 if (is_a<diracgamma5>(it->op(0)) || is_a<diracgammaL>(it->op(0)) || is_a<diracgammaR>(it->op(0))) 01052 ++it; 01053 01054 while (it != next_to_last) { 01055 if (it[0].compare(it[1]) > 0) { 01056 01057 ex save0 = it[0], save1 = it[1]; 01058 ex b1, i1, b2, i2; 01059 base_and_index(it[0], b1, i1); 01060 base_and_index(it[1], b2, i2); 01061 // for Clifford algebras (commutator_sign == -1) metric should be symmetrised 01062 it[0] = (ex_to<clifford>(save0).get_metric(i1, i2, ex_to<clifford>(save0).get_commutator_sign() == -1) * b1 * b2).simplify_indexed(); 01063 it[1] = v.size() ? _ex2 * dirac_ONE(ex_to<clifford>(save0).get_representation_label()) : _ex2; 01064 ex sum = ncmul(v); 01065 it[0] = save1; 01066 it[1] = save0; 01067 sum += ex_to<clifford>(save0).get_commutator_sign() * ncmul(v, true); 01068 i->second = canonicalize_clifford(sum); 01069 goto next_sym; 01070 } 01071 ++it; 01072 } 01073 next_sym: ; 01074 } 01075 } 01076 return aux.subs(srl, subs_options::no_pattern).simplify_indexed(); 01077 } 01078 } 01079 01080 ex clifford_prime(const ex & e) 01081 { 01082 pointer_to_map_function fcn(clifford_prime); 01083 if (is_a<clifford>(e) && is_a<cliffordunit>(e.op(0))) { 01084 return -e; 01085 } else if (is_a<add>(e) || is_a<ncmul>(e) || is_a<mul>(e) //|| is_a<pseries>(e) || is_a<integral>(e) 01086 || is_a<matrix>(e) || e.info(info_flags::list)) { 01087 return e.map(fcn); 01088 } else if (is_a<power>(e)) { 01089 return pow(clifford_prime(e.op(0)), e.op(1)); 01090 } else 01091 return e; 01092 } 01093 01094 ex remove_dirac_ONE(const ex & e, unsigned char rl, unsigned options) 01095 { 01096 pointer_to_map_function_2args<unsigned char, unsigned> fcn(remove_dirac_ONE, rl, options | 1); 01097 bool need_reevaluation = false; 01098 ex e1 = e; 01099 if (! (options & 1) ) { // is not a child 01100 if (options & 2) 01101 e1 = expand_dummy_sum(e, true); 01102 e1 = canonicalize_clifford(e1); 01103 } 01104 01105 if (is_a<clifford>(e1) && ex_to<clifford>(e1).get_representation_label() >= rl) { 01106 if (is_a<diracone>(e1.op(0))) 01107 return 1; 01108 else 01109 throw(std::invalid_argument("remove_dirac_ONE(): expression is a non-scalar Clifford number!")); 01110 } else if (is_a<add>(e1) || is_a<ncmul>(e1) || is_a<mul>(e1) 01111 || is_a<matrix>(e1) || e1.info(info_flags::list)) { 01112 if (options & 3) // is a child or was already expanded 01113 return e1.map(fcn); 01114 else 01115 try { 01116 return e1.map(fcn); 01117 } catch (std::exception &p) { 01118 need_reevaluation = true; 01119 } 01120 } else if (is_a<power>(e1)) { 01121 if (options & 3) // is a child or was already expanded 01122 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1)); 01123 else 01124 try { 01125 return pow(remove_dirac_ONE(e1.op(0), rl, options | 1), e1.op(1)); 01126 } catch (std::exception &p) { 01127 need_reevaluation = true; 01128 } 01129 } 01130 if (need_reevaluation) 01131 return remove_dirac_ONE(e, rl, options | 2); 01132 return e1; 01133 } 01134 01135 int clifford_max_label(const ex & e, bool ignore_ONE) 01136 { 01137 if (is_a<clifford>(e)) 01138 if (ignore_ONE && is_a<diracone>(e.op(0))) 01139 return -1; 01140 else 01141 return ex_to<clifford>(e).get_representation_label(); 01142 else { 01143 int rl = -1; 01144 for (size_t i=0; i < e.nops(); i++) 01145 rl = (rl > clifford_max_label(e.op(i), ignore_ONE)) ? rl : clifford_max_label(e.op(i), ignore_ONE); 01146 return rl; 01147 } 01148 } 01149 01150 ex clifford_norm(const ex & e) 01151 { 01152 return sqrt(remove_dirac_ONE(e * clifford_bar(e))); 01153 } 01154 01155 ex clifford_inverse(const ex & e) 01156 { 01157 ex norm = clifford_norm(e); 01158 if (!norm.is_zero()) 01159 return clifford_bar(e) / pow(norm, 2); 01160 else 01161 throw(std::invalid_argument("clifford_inverse(): cannot find inverse of Clifford number with zero norm!")); 01162 } 01163 01164 ex lst_to_clifford(const ex & v, const ex & mu, const ex & metr, unsigned char rl) 01165 { 01166 if (!ex_to<idx>(mu).is_dim_numeric()) 01167 throw(std::invalid_argument("lst_to_clifford(): Index should have a numeric dimension")); 01168 ex e = clifford_unit(mu, metr, rl); 01169 return lst_to_clifford(v, e); 01170 } 01171 01172 ex lst_to_clifford(const ex & v, const ex & e) { 01173 unsigned min, max; 01174 01175 if (is_a<clifford>(e)) { 01176 ex mu = e.op(1); 01177 ex mu_toggle 01178 = is_a<varidx>(mu) ? ex_to<varidx>(mu).toggle_variance() : mu; 01179 unsigned dim = get_dim_uint(mu); 01180 01181 if (is_a<matrix>(v)) { 01182 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows()) { 01183 min = ex_to<matrix>(v).rows(); 01184 max = ex_to<matrix>(v).cols(); 01185 } else { 01186 min = ex_to<matrix>(v).cols(); 01187 max = ex_to<matrix>(v).rows(); 01188 } 01189 if (min == 1) { 01190 if (dim == max) 01191 return indexed(v, mu_toggle) * e; 01192 else if (max - dim == 1) { 01193 if (ex_to<matrix>(v).cols() > ex_to<matrix>(v).rows()) 01194 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; 01195 else 01196 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; 01197 } else 01198 throw(std::invalid_argument("lst_to_clifford(): dimensions of vector and clifford unit mismatch")); 01199 } else 01200 throw(std::invalid_argument("lst_to_clifford(): first argument should be a vector (nx1 or 1xn matrix)")); 01201 } else if (v.info(info_flags::list)) { 01202 if (dim == ex_to<lst>(v).nops()) 01203 return indexed(matrix(dim, 1, ex_to<lst>(v)), mu_toggle) * e; 01204 else if (ex_to<lst>(v).nops() - dim == 1) 01205 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; 01206 else 01207 throw(std::invalid_argument("lst_to_clifford(): list length and dimension of clifford unit mismatch")); 01208 } else 01209 throw(std::invalid_argument("lst_to_clifford(): cannot construct from anything but list or vector")); 01210 } else 01211 throw(std::invalid_argument("lst_to_clifford(): the second argument should be a Clifford unit")); 01212 } 01213 01216 static ex get_clifford_comp(const ex & e, const ex & c) 01217 { 01218 pointer_to_map_function_1arg<const ex &> fcn(get_clifford_comp, c); 01219 int ival = ex_to<numeric>(ex_to<idx>(c.op(1)).get_value()).to_int(); 01220 01221 if (is_a<add>(e) || e.info(info_flags::list) // || is_a<pseries>(e) || is_a<integral>(e) 01222 || is_a<matrix>(e)) 01223 return e.map(fcn); 01224 else if (is_a<ncmul>(e) || is_a<mul>(e)) { 01225 // find a Clifford unit with the same metric, delete it and substitute its index 01226 size_t ind = e.nops() + 1; 01227 for (size_t j = 0; j < e.nops(); j++) { 01228 if (is_a<clifford>(e.op(j)) && ex_to<clifford>(c).same_metric(e.op(j))) { 01229 if (ind > e.nops()) { 01230 ind = j; 01231 } else { 01232 throw(std::invalid_argument("get_clifford_comp(): expression is a Clifford multi-vector")); 01233 } 01234 } 01235 } 01236 if (ind < e.nops()) { 01237 ex S = 1; 01238 bool same_value_index, found_dummy; 01239 same_value_index = ( ex_to<idx>(e.op(ind).op(1)).is_numeric() 01240 && (ival == ex_to<numeric>(ex_to<idx>(e.op(ind).op(1)).get_value()).to_int()) ); 01241 found_dummy = same_value_index; 01242 // Run through the expression collecting all non-clifford factors 01243 for (size_t j=0; j < e.nops(); j++) { 01244 if (j != ind) { 01245 if (same_value_index) { 01246 S = S * e.op(j); 01247 } else { 01248 exvector ind_vec; 01249 if (is_a<indexed>(e.op(j))) 01250 ind_vec = ex_to<indexed>(e.op(j)).get_dummy_indices(ex_to<indexed>(e.op(ind))); 01251 01252 if (ind_vec.size() > 0) { 01253 found_dummy = true; 01254 exvector::const_iterator it = ind_vec.begin(), itend = ind_vec.end(); 01255 while (it != itend) { 01256 ex curridx = *it; 01257 ex curridx_toggle = is_a<varidx>(curridx) 01258 ? ex_to<varidx>(curridx).toggle_variance() 01259 : curridx; 01260 S = S * e.op(j).subs(lst(curridx == ival, 01261 curridx_toggle == ival), subs_options::no_pattern); 01262 ++it; 01263 } 01264 } else 01265 S = S * e.op(j); 01266 } 01267 } 01268 } 01269 return (found_dummy ? S : 0); 01270 } else 01271 throw(std::invalid_argument("get_clifford_comp(): expression is not a Clifford vector to the given units")); 01272 } else if (e.is_zero()) 01273 return e; 01274 else if (is_a<clifford>(e) && ex_to<clifford>(e).same_metric(c)) 01275 if ( ex_to<idx>(e.op(1)).is_numeric() && 01276 (ival != ex_to<numeric>(ex_to<idx>(e.op(1)).get_value()).to_int()) ) 01277 return 0; 01278 else 01279 return 1; 01280 else 01281 throw(std::invalid_argument("get_clifford_comp(): expression is not usable as a Clifford vector")); 01282 } 01283 01284 01285 lst clifford_to_lst(const ex & e, const ex & c, bool algebraic) 01286 { 01287 GINAC_ASSERT(is_a<clifford>(c)); 01288 ex mu = c.op(1); 01289 if (! ex_to<idx>(mu).is_dim_numeric()) 01290 throw(std::invalid_argument("clifford_to_lst(): index should have a numeric dimension")); 01291 unsigned int D = ex_to<numeric>(ex_to<idx>(mu).get_dim()).to_int(); 01292 01293 if (algebraic) // check if algebraic method is applicable 01294 for (unsigned int i = 0; i < D; i++) 01295 if (pow(c.subs(mu == i, subs_options::no_pattern), 2).is_zero() 01296 || (! is_a<numeric>(pow(c.subs(mu == i, subs_options::no_pattern), 2)))) 01297 algebraic = false; 01298 lst V; 01299 ex v0 = remove_dirac_ONE(canonicalize_clifford(e+clifford_prime(e)).normal())/2; 01300 if (! v0.is_zero()) 01301 V.append(v0); 01302 ex e1 = canonicalize_clifford(e - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label())); 01303 if (algebraic) { 01304 for (unsigned int i = 0; i < D; i++) 01305 V.append(remove_dirac_ONE( 01306 simplify_indexed(canonicalize_clifford(e1 * c.subs(mu == i, subs_options::no_pattern) + c.subs(mu == i, subs_options::no_pattern) * e1)) 01307 / (2*pow(c.subs(mu == i, subs_options::no_pattern), 2)))); 01308 } else { 01309 try { 01310 for (unsigned int i = 0; i < D; i++) 01311 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern))); 01312 } catch (std::exception &p) { 01313 /* Try to expand dummy summations to simplify the expression*/ 01314 e1 = canonicalize_clifford(expand_dummy_sum(e, true)); 01315 V.remove_all(); 01316 v0 = remove_dirac_ONE(canonicalize_clifford(e1+clifford_prime(e1)).normal())/2; 01317 if (! v0.is_zero()) { 01318 V.append(v0); 01319 e1 = canonicalize_clifford(e1 - v0 * dirac_ONE(ex_to<clifford>(c).get_representation_label())); 01320 } 01321 for (unsigned int i = 0; i < D; i++) 01322 V.append(get_clifford_comp(e1, c.subs(c.op(1) == i, subs_options::no_pattern))); 01323 } 01324 } 01325 return V; 01326 } 01327 01328 01329 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) 01330 { 01331 ex x, D, cu; 01332 01333 if (! is_a<matrix>(v) && ! v.info(info_flags::list)) 01334 throw(std::invalid_argument("clifford_moebius_map(): parameter v should be either vector or list")); 01335 01336 if (is_a<clifford>(G)) { 01337 cu = G; 01338 } else { 01339 if (is_a<indexed>(G)) { 01340 D = ex_to<idx>(G.op(1)).get_dim(); 01341 varidx mu((new symbol)->setflag(status_flags::dynallocated), D); 01342 cu = clifford_unit(mu, G, rl); 01343 } else if (is_a<matrix>(G)) { 01344 D = ex_to<matrix>(G).rows(); 01345 idx mu((new symbol)->setflag(status_flags::dynallocated), D); 01346 cu = clifford_unit(mu, G, rl); 01347 } else throw(std::invalid_argument("clifford_moebius_map(): metric should be an indexed object, matrix, or a Clifford unit")); 01348 01349 } 01350 01351 x = lst_to_clifford(v, cu); 01352 ex e = clifford_to_lst(simplify_indexed(canonicalize_clifford((a * x + b) * clifford_inverse(c * x + d))), cu, false); 01353 return (is_a<matrix>(v) ? matrix(ex_to<matrix>(v).rows(), ex_to<matrix>(v).cols(), ex_to<lst>(e)) : e); 01354 } 01355 01356 ex clifford_moebius_map(const ex & M, const ex & v, const ex & G, unsigned char rl) 01357 { 01358 if (is_a<matrix>(M) && (ex_to<matrix>(M).rows() == 2) && (ex_to<matrix>(M).cols() == 2)) 01359 return clifford_moebius_map(M.op(0), M.op(1), M.op(2), M.op(3), v, G, rl); 01360 else 01361 throw(std::invalid_argument("clifford_moebius_map(): parameter M should be a 2x2 matrix")); 01362 } 01363 01364 } // namespace GiNaC