f9d5f44a8196be1eadbfce0c064f7cab21c33ccf
[ginac.git] / ginac / lortensor.cpp
1 /** @file lortensor.cpp
2  *
3  *  Implementation of GiNaC's Lorentz tensors. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <string>
24 #include <list>
25 #include <algorithm>
26 #include <iostream>
27 #include <stdexcept>
28 #include <map>
29
30 #include "basic.h"
31 #include "add.h"
32 #include "mul.h"
33 #include "debugmsg.h"
34 #include "lst.h"
35 #include "lortensor.h"
36 #include "operators.h"
37 #include "tinfos.h"
38 #include "power.h"
39 #include "archive.h"
40 #include "utils.h"
41 #include "config.h"
42
43 #ifndef NO_NAMESPACE_GINAC
44 namespace GiNaC {
45 #endif // ndef NO_NAMESPACE_GINAC
46
47 GINAC_IMPLEMENT_REGISTERED_CLASS(lortensor, indexed)
48
49 //////////
50 // default constructor, destructor, copy constructor assignment operator and helpers
51 //////////
52
53 // public
54
55 lortensor::lortensor() : inherited(TINFO_lortensor), type(invalid)
56 {
57         debugmsg("lortensor default constructor",LOGLEVEL_CONSTRUCT);
58         serial=next_serial++;
59         name=autoname_prefix()+ToString(serial);
60 }
61
62 //protected
63
64 void lortensor::copy(const lortensor & other)
65 {
66         inherited::copy(other);
67         type=other.type;
68         name=other.name;
69         serial=other.serial;
70 }
71
72 void lortensor::destroy(bool call_parent)
73 {
74         if (call_parent) inherited::destroy(call_parent);
75 }
76
77 //////////
78 // other constructors
79 //////////
80
81 // protected
82
83 /** Construct object without any Lorentz index. This constructor is for
84  *  internal use only. */
85 lortensor::lortensor(lortensor_types const lt, const std::string & n) : type(lt), name(n)
86 {
87         debugmsg("lortensor constructor from lortensor_types,string",LOGLEVEL_CONSTRUCT);
88         if (lt == lortensor_symbolic)
89                 serial = next_serial++;
90         else
91                 serial = 0;
92         tinfo_key = TINFO_lortensor;
93 }
94
95 /** Construct object with one Lorentz index. This constructor is for
96  *  internal use only. Use the lortensor_vector() or lortensor_symbolic()
97  *  functions instead.
98  *  @see lortensor_vector
99  *  @see lortensor_symbolic */
100 lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu) : inherited(mu), type(lt), name(n)
101 {
102         debugmsg("lortensor constructor from lortensor_types,string,ex",LOGLEVEL_CONSTRUCT);
103         GINAC_ASSERT(all_of_type_lorentzidx());
104         if (lt == lortensor_symbolic)
105                 serial = next_serial++;
106         else
107                 serial = 0;
108         tinfo_key=TINFO_lortensor;
109 }
110
111 /** Construct object with two Lorentz indices. This constructor is for
112  *  internal use only. Use the lortensor_g(), lortensor_delta() or
113  *  lortensor_symbolic() functions instead.
114  *  @see lortensor_g
115  *  @see lortensor_delta
116  *  @see lortensor_symbolic */
117 lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu) : inherited(mu,nu), type(lt), name(n)
118 {
119         debugmsg("lortensor constructor from lortensor_types,string,ex,ex",LOGLEVEL_CONSTRUCT);
120         GINAC_ASSERT(all_of_type_lorentzidx());
121         if (lt == lortensor_symbolic)
122                 serial = next_serial++;
123         else
124                 serial = 0;
125         tinfo_key=TINFO_lortensor;
126 }
127
128 /** Construct object with three Lorentz indices. This constructor is for
129  *  internal use only. Use the lortensor_symbolic() function instead.
130  *  @see lortensor_symbolic */
131 lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho) : inherited(mu,nu,rho), type(lt), name(n)
132 {
133         debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex",LOGLEVEL_CONSTRUCT);
134         GINAC_ASSERT(all_of_type_lorentzidx());
135         if (lt == lortensor_symbolic)
136                 serial = next_serial++;
137         else
138                 serial = 0;
139         tinfo_key=TINFO_lortensor;
140 }
141
142 /** Construct object with four Lorentz indices. This constructor is for
143  *  internal use only. Use the lortensor_epsilon() or lortensor_symbolic()
144  *  functions instead.
145  *  @see lortensor_epsilon
146  *  @see lortensor_symbolic */
147 lortensor::lortensor(lortensor_types const lt, const std::string & n, const ex & mu, const ex & nu, const ex & rho, const ex & sigma) : inherited(mu,nu,rho,sigma), type(lt), name(n)
148 {
149         debugmsg("lortensor constructor from lortensor_types,string,ex,ex,ex,ex",LOGLEVEL_CONSTRUCT);
150         GINAC_ASSERT(all_of_type_lorentzidx());
151         if (lt == lortensor_symbolic)
152                 serial = next_serial++;
153         else
154                 serial = 0;
155         tinfo_key=TINFO_lortensor;
156 }
157
158 /** Construct object with arbitrary number of Lorentz indices. This
159  *  constructor is for internal use only. Use the lortensor_symbolic()
160  *  function instead.
161  *
162  *  @see lortensor_symbolic */
163 lortensor::lortensor(lortensor_types const lt, const std::string & n, const exvector & iv) : inherited(iv), type(lt), name(n)
164 {
165         debugmsg("lortensor constructor from lortensor_types,string,exvector",LOGLEVEL_CONSTRUCT);
166         GINAC_ASSERT(all_of_type_lorentzidx());
167         if (lt == lortensor_symbolic)
168                 serial = next_serial++;
169         else
170                 serial = 0;
171         tinfo_key=TINFO_lortensor;
172 }
173
174 lortensor::lortensor(lortensor_types const lt, const std::string & n, unsigned s, const exvector & iv) : indexed(iv), type(lt), name(n), serial(s)
175 {
176         debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
177         GINAC_ASSERT(all_of_type_lorentzidx());
178         tinfo_key=TINFO_lortensor;
179 }
180
181 lortensor::lortensor(lortensor_types const lt, const std::string & n, unsigned s, exvector *ivp) : indexed(ivp), type(lt), name(n), serial(s)
182 {
183         debugmsg("lortensor constructor from lortensor_types,string,unsigned,exvector",LOGLEVEL_CONSTRUCT);
184         GINAC_ASSERT(all_of_type_lorentzidx());
185         tinfo_key=TINFO_lortensor;
186 }
187
188
189 //////////
190 // archiving
191 //////////
192
193 /** Construct object from archive_node. */
194 lortensor::lortensor(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
195 {
196         debugmsg("lortensor constructor from archive_node", LOGLEVEL_CONSTRUCT);
197         unsigned int ty;
198         if (!(n.find_unsigned("type", ty)))
199                 throw (std::runtime_error("unknown lortensor type in archive"));
200         type = (lortensor_types)ty;
201         if (type == lortensor_symbolic) {
202                 serial = next_serial++;
203                 if (!(n.find_string("name", name)))
204                         name = autoname_prefix() + ToString(serial);
205         } else
206                 serial = 0;
207 }
208
209 /** Unarchive the object. */
210 ex lortensor::unarchive(const archive_node &n, const lst &sym_lst)
211 {
212         ex s = (new lortensor(n, sym_lst))->setflag(status_flags::dynallocated);
213
214         if (ex_to_lortensor(s).type == lortensor_symbolic) {
215                 // If lortensor is in sym_lst, return the existing lortensor
216                 for (unsigned i=0; i<sym_lst.nops(); i++) {
217                         if (is_ex_of_type(sym_lst.op(i), lortensor) && (ex_to_lortensor(sym_lst.op(i)).name == ex_to_lortensor(s).name))
218                                 return sym_lst.op(i);
219                 }
220         }
221         return s;
222 }
223
224 /** Archive the object. */
225 void lortensor::archive(archive_node &n) const
226 {
227         inherited::archive(n);
228         n.add_unsigned("type", type);
229         if (type == lortensor_symbolic)
230                 n.add_string("name", name);
231 }
232
233
234 //////////
235 // functions overriding virtual functions from bases classes
236 //////////
237
238 //public
239
240 void lortensor::printraw(std::ostream & os) const
241 {
242         debugmsg("lortensor printraw",LOGLEVEL_PRINT);
243         os << "lortensor(type=" << (unsigned)type
244            << ",indices=";
245         printrawindices(os);
246         os << ",serial=" << serial;
247         os << ",hash=" << hashvalue << ",flags=" << flags << ")";
248 }
249
250 void lortensor::printtree(std::ostream & os, unsigned indent) const
251 {
252         debugmsg("lortensor printtree",LOGLEVEL_PRINT);
253         os << std::string(indent,' ') <<"lortensor object: "
254            << "type=" << (unsigned)type << ","
255            << seq.size() << " indices" << std::endl;
256         printtreeindices(os,indent);
257         os << std::string(indent,' ') << "hash=" << hashvalue
258            << " (0x" << std::hex << hashvalue << std::dec << ")"
259            << ", flags=" << flags << std::endl;
260 }
261
262 void lortensor::print(std::ostream & os, unsigned upper_precedence) const
263 {
264         debugmsg("lortensor print",LOGLEVEL_PRINT);
265         switch (type) {
266         case lortensor_g:
267                 os << "g";
268                 break;
269         case lortensor_delta:
270                 os << "delta";
271                 break;
272         case lortensor_epsilon:
273                 os << "epsilon";
274                 break;
275         case lortensor_symbolic:
276                 os << name;
277                 break;
278         case invalid:
279         default:
280                 os << "INVALID_LORTENSOR_OBJECT";
281                 break;
282         }
283         printindices(os);
284 }
285
286 bool lortensor::info(unsigned inf) const
287 {
288         return inherited::info(inf);
289 }
290
291 ex lortensor::eval(int level) const
292 {
293         if (type==lortensor_g) {
294                 // canonicalize indices
295                 exvector iv=seq;
296                 int sig=canonicalize_indices(iv,false); //symmetric
297                 if (sig!=INT_MAX) {
298                         //something has changed while sorting indices, more evaluations later
299                         return ex(sig) *lortensor(type,name,iv);
300                 }
301                 const lorentzidx & idx1=ex_to_lorentzidx(seq[0]);
302                 const lorentzidx & idx2=ex_to_lorentzidx(seq[1]);
303                 if ((!idx1.is_symbolic()) && (!idx2.is_symbolic())) {
304                         //both indices are numeric
305                         if ((idx1.get_value()==idx2.get_value())) {
306                                 //both on diagonal
307                                 if (idx1.get_value()==0){
308                                         // (0,0)
309                                         return _ex1();
310                                 } else {
311                                         if (idx1.is_covariant() != idx2.is_covariant()) {
312                                                 // (_i,~i) or (~i,_i), i = 1...3
313                                                 return _ex1();
314                                         } else {
315                                                 // (_i,_i) or (~i,~i), i= 1...3
316                                                 return _ex_1();
317                                         }
318                                 }
319                         } else {
320                                 // at least one off-diagonal
321                                 return _ex0();
322                         }
323                 } else if (idx1.is_symbolic() && idx1.is_co_contra_pair(idx2)) {
324                         return Dim();
325                 }
326         }
327         return this -> hold();
328 }
329
330 //protected
331
332 int lortensor::compare_same_type(const basic & other) const
333 {
334         GINAC_ASSERT(is_of_type(other,lortensor));
335         const lortensor &o = static_cast<const lortensor &>(other);
336
337         if (type!=o.type) {
338                 // different type
339                 return type < o.type ? -1 : 1;
340         }
341
342         if (type == lortensor_symbolic) {
343                 // symbolic, compare serials
344                 if (serial != o.serial) {
345                         return serial < o.serial ? -1 : 1;
346                 }
347         }
348
349         return inherited::compare_same_type(other);
350 }
351
352 bool lortensor::is_equal_same_type(const basic & other) const
353 {
354         GINAC_ASSERT(is_of_type(other,lortensor));
355         const lortensor &o = static_cast<const lortensor &>(other);
356
357         if (type != o.type) return false;
358         if (type == lortensor_symbolic && serial != o.serial) return false;
359         return inherited::is_equal_same_type(other);            
360 }
361
362 unsigned lortensor::return_type(void) const
363 {
364         return return_types::commutative;
365 }
366
367 unsigned lortensor::return_type_tinfo(void) const
368 {
369         return tinfo_key;
370 }
371
372 ex lortensor::thisexprseq(const exvector & v) const
373 {
374         return lortensor(type,name,serial,v);
375 }
376
377 ex lortensor::thisexprseq(exvector *vp) const
378 {
379         return lortensor(type,name,serial,vp);
380 }
381         
382 //////////
383 // non-virtual functions in this class
384 //////////
385
386 // protected
387
388 /** Check whether all indices are of class lorentzidx or a subclass. This
389  *  function is used internally to make sure that all constructed Lorentz
390  *  tensors really carry Lorentz indices and not some other classes. */
391 bool lortensor::all_of_type_lorentzidx(void) const
392 {
393         for (exvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++ cit) {
394                 if (!is_ex_of_type(*cit,lorentzidx)) return false;
395         }
396         return true;
397 }
398
399 // private
400
401 std::string & lortensor::autoname_prefix(void)
402 {
403         static std::string * s = new std::string("lortensor");
404         return *s;
405 }
406
407 //////////
408 // static member variables
409 //////////
410
411 // private
412
413 unsigned lortensor::next_serial=0;
414
415 //////////
416 // friend functions
417 //////////
418
419 /** Construct an object representing the metric tensor g. The indices must
420  *  be of class lorentzidx.
421  *
422  *  @param mu First index
423  *  @param nu Second index
424  *  @return newly constructed object */
425 lortensor lortensor_g(const ex & mu, const ex & nu)
426 {
427         return lortensor(lortensor::lortensor_g,"",mu,nu);
428 }
429
430 /** Construct an object representing the unity matrix delta. The indices
431  *  must be of class lorentzidx.
432  *
433  *  @param mu First index
434  *  @param nu Second index
435  *  @return newly constructed object */
436 lortensor lortensor_delta(const ex & mu, const ex & nu)
437 {
438         return lortensor(lortensor::lortensor_delta,"",mu,nu);
439 }
440
441 /** Construct an object representing the four-dimensional totally
442  *  antisymmetric tensor epsilon. The indices must be of class lorentzidx.
443  *
444  *  @param mu First index
445  *  @param nu Second index
446  *  @param rho Third index
447  *  @param sigma Fourth index
448  *  @return newly constructed object */
449 lortensor lortensor_epsilon(const ex & mu, const ex & nu, const ex & rho, const ex & sigma)
450 {
451         return lortensor(lortensor::lortensor_epsilon,"",mu,nu,rho,sigma);
452 }
453
454 /** Construct an object representing a symbolic Lorentz vector. The index
455  *  must be of class lorentzidx.
456  *
457  *  @param n Symbolic name
458  *  @param mu Index
459  *  @return newly constructed object */
460 lortensor lortensor_vector(const std::string & n, const ex & mu)
461 {
462         return lortensor(lortensor::lortensor_symbolic,n,mu);
463 }
464
465 /** Construct an object representing a symbolic Lorentz tensor of arbitrary
466  *  rank. The indices must be of class lorentzidx.
467  *
468  *  @param n Symbolic name
469  *  @param iv Vector of indices
470  *  @return newly constructed object */
471 lortensor lortensor_symbolic(const std::string & n, const exvector & iv)
472 {
473         return lortensor(lortensor::lortensor_symbolic,n,iv);
474 }
475
476 ex simplify_lortensor_mul(const ex & m)
477 {
478         GINAC_ASSERT(is_ex_exactly_of_type(m,mul));
479         exvector v_contracted;
480
481         // collect factors in an exvector, store squares twice
482         int n=m.nops();
483         v_contracted.reserve(2*n);
484         for (int i=0; i<n; ++i) {
485                 ex f=m.op(i);
486                 if (is_ex_exactly_of_type(f,power)&&f.op(1).is_equal(_ex2())) {
487                         v_contracted.push_back(f.op(0));
488                         v_contracted.push_back(f.op(0));
489                 } else {
490                         v_contracted.push_back(f);
491                 }
492         }
493
494         unsigned replacements;
495         bool something_changed=false;
496
497         exvector::iterator it=v_contracted.begin();
498         while (it!=v_contracted.end()) {
499                 // process only lor_g objects
500                 if (is_ex_exactly_of_type(*it,lortensor) &&
501                         (ex_to_lortensor(*it).type==lortensor::lortensor_g)) {            
502                         const lortensor & g=ex_to_lortensor(*it);
503                         GINAC_ASSERT(g.seq.size()==2);
504                         const idx & first_idx=ex_to_lorentzidx(g.seq[0]);
505                         const idx & second_idx=ex_to_lorentzidx(g.seq[1]);
506                         // g_{mu,mu} should have been contracted in lortensor::eval()
507                         GINAC_ASSERT(!first_idx.is_equal(second_idx));
508                         ex saved_g=*it; // save to restore it later
509
510                         // try to contract first index
511                         replacements=0;
512                         if (first_idx.is_symbolic()) {
513                                 replacements = subs_index_in_exvector(v_contracted,
514                                                                       first_idx.toggle_covariant(),second_idx);
515                                 if (replacements==0) {
516                                         // not contracted, restore g object
517                                         *it=saved_g;
518                                 } else {
519                                         // a contracted index should occur exactly once
520                                         GINAC_ASSERT(replacements==1);
521                                         *it=_ex1();
522                                         something_changed=true;
523                                 }
524                         }
525
526                         // try second index only if first was not contracted
527                         if ((replacements==0)&&(second_idx.is_symbolic())) {
528                                 // first index not contracted, *it is again the original g object
529                                 replacements = subs_index_in_exvector(v_contracted,
530                                                                       second_idx.toggle_covariant(),first_idx);
531                                 if (replacements==0) {
532                                         // not contracted except in itself, restore g object
533                                         *it=saved_g;
534                                 } else {
535                                         // a contracted index should occur exactly once
536                                         GINAC_ASSERT(replacements==1);
537                                         *it=_ex1();
538                                         something_changed=true;
539                                 }
540                         }
541                 }
542                 ++it;
543         }
544         if (something_changed) {
545                 return mul(v_contracted);
546         }
547         return m;
548 }
549
550 /** Perform some simplifications on an expression containing Lorentz tensors. */
551 ex simplify_lortensor(const ex & e)
552 {
553         // all simplification is done on expanded objects
554         ex e_expanded=e.expand();
555
556         // simplification of sum=sum of simplifications
557         if (is_ex_exactly_of_type(e_expanded,add)) {
558                 ex sum=_ex0();
559                 for (unsigned i=0; i<e_expanded.nops(); ++i) {
560                         sum += simplify_lortensor(e_expanded.op(i));
561                 }
562                 return sum;
563         }
564
565         // simplification of (commutative) product
566         if (is_ex_exactly_of_type(e_expanded,mul)) {
567                 return simplify_lortensor_mul(e);
568         }
569
570         // cannot do anything
571         return e_expanded;
572 }
573
574 #ifndef NO_NAMESPACE_GINAC
575 } // namespace GiNaC
576 #endif // ndef NO_NAMESPACE_GINAC