- modified GiNaC headers to Alexander's liking
[ginac.git] / ginac / idx.cpp
1 /** @file idx.cpp
2  *
3  *  Implementation of GiNaC's indices.
4  *
5  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdexcept>
23
24 #include "idx.h"
25 #include "ex.h"
26 #include "lst.h"
27 #include "relational.h"
28 #include "utils.h"
29
30 //////////
31 // default constructor, destructor, copy constructor assignment operator and helpers
32 //////////
33
34 // public
35
36 idx::idx() : basic(TINFO_idx), symbolic(true), covariant(false)
37 {
38     debugmsg("idx default constructor",LOGLEVEL_CONSTRUCT);
39     serial=next_serial++;
40     name="index"+ToString(serial);
41 }
42
43 idx::~idx() 
44 {
45     debugmsg("idx destructor",LOGLEVEL_DESTRUCT);
46     destroy(0);
47 }
48
49 idx::idx(idx const & other)
50 {
51     debugmsg("idx copy constructor",LOGLEVEL_CONSTRUCT);
52     copy(other);
53 }
54
55 idx const & idx::operator=(idx const & other)
56 {
57     debugmsg("idx operator=",LOGLEVEL_ASSIGNMENT);
58     if (this != &other) {
59         destroy(1);
60         copy(other);
61     }
62     return *this;
63 }
64
65 // protected
66
67 void idx::copy(idx const & other)
68 {
69     basic::copy(other);
70     serial=other.serial;
71     symbolic=other.symbolic;
72     name=other.name;
73     value=other.value;
74     covariant=other.covariant;
75 }
76
77 void idx::destroy(bool call_parent)
78 {
79     if (call_parent) basic::destroy(call_parent);
80 }
81
82 //////////
83 // other constructors
84 //////////
85
86 // public
87
88 idx::idx(bool cov) : basic(TINFO_idx), symbolic(true), covariant(cov)
89 {
90     debugmsg("idx constructor from bool",LOGLEVEL_CONSTRUCT);
91     serial=next_serial++;
92     name="index"+ToString(serial);
93 }
94
95 idx::idx(string const & n, bool cov) : basic(TINFO_idx),  
96     symbolic(true), name(n), covariant(cov)
97 {
98     debugmsg("idx constructor from string,bool",LOGLEVEL_CONSTRUCT);
99     serial=next_serial++;
100 }
101
102 idx::idx(char const * n, bool cov) : basic(TINFO_idx),  
103     symbolic(true), name(n), covariant(cov)
104 {
105     debugmsg("idx constructor from char*,bool",LOGLEVEL_CONSTRUCT);
106     serial=next_serial++;
107 }
108
109 idx::idx(unsigned const v, bool cov) : basic(TINFO_idx),
110     symbolic(false), value(v), covariant(cov)
111 {
112     debugmsg("idx constructor from unsigned,bool",LOGLEVEL_CONSTRUCT);
113     serial=0;
114 }
115
116
117 //////////
118 // functions overriding virtual functions from bases classes
119 //////////
120
121 // public
122
123 basic * idx::duplicate() const
124 {
125     debugmsg("idx duplicate",LOGLEVEL_DUPLICATE);
126     return new idx(*this);
127 }
128
129 void idx::printraw(ostream & os) const
130 {
131     debugmsg("idx printraw",LOGLEVEL_PRINT);
132
133     os << "idx(";
134
135     if (symbolic) {
136         os << "symbolic,name=" << name;
137     } else {
138         os << "non symbolic,value=" << value;
139     }
140
141     if (covariant) {
142         os << ",covariant";
143     } else {
144         os << ",contravariant";
145     }
146
147     os << ",serial=" << serial;
148     os << ",hash=" << hashvalue << ",flags=" << flags;
149     os << ")";
150 }
151
152 void idx::printtree(ostream & os, unsigned indent) const
153 {
154     debugmsg("idx printtree",LOGLEVEL_PRINT);
155
156     os << string(indent,' ') << "idx: ";
157
158     if (symbolic) {
159         os << "symbolic,name=" << name;
160     } else {
161         os << "non symbolic,value=" << value;
162     }
163
164     if (covariant) {
165         os << ",covariant";
166     } else {
167         os << ",contravariant";
168     }
169
170     os << ", serial=" << serial
171        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
172        << ", flags=" << flags << endl;
173 }
174
175 void idx::print(ostream & os, unsigned upper_precedence) const
176 {
177     debugmsg("idx print",LOGLEVEL_PRINT);
178
179     if (covariant) {
180         os << "_";
181     } else {
182         os << "~";
183     }
184     if (symbolic) {
185         os << name;
186     } else {
187         os << value;
188     }
189 }
190
191 bool idx::info(unsigned inf) const
192 {
193     if (inf==info_flags::idx) return true;
194     return basic::info(inf);
195 }
196
197 ex idx::subs(lst const & ls, lst const & lr) const
198 {
199     ASSERT(ls.nops()==lr.nops());
200 #ifdef DOASSERT
201     for (int i=0; i<ls.nops(); i++) {
202         ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
203                is_ex_of_type(ls.op(i),idx));
204     }
205 #endif // def DOASSERT
206
207     for (int i=0; i<ls.nops(); i++) {
208         if (is_equal(*(ls.op(i)).bp)) {
209             return lr.op(i);
210         }
211     }
212     return *this;
213 }
214
215 // protected
216
217 int idx::compare_same_type(basic const & other) const
218 {
219     ASSERT(is_of_type(other,idx));
220     idx const & o=static_cast<idx const &>
221                              (const_cast<basic &>(other));
222
223     if (covariant!=o.covariant) {
224         // different co/contravariant
225         return covariant ? -1 : 1;
226     }
227     if ((!symbolic) && (!o.symbolic)) {
228         // non-symbolic, of equal type: compare values
229         if (value==o.value) {
230             return 0;
231         }
232         return value<o.value ? -1 : 1;
233     }
234     if (symbolic && o.symbolic) {
235         // both symbolic: compare serials
236         if (serial==o.serial) {
237             return 0;
238         }
239         return serial<o.serial ? -1 : 1;
240     }
241     // one symbolic, one value: value is sorted first
242     return o.symbolic ? -1 : 1;
243 }
244
245 bool idx::is_equal_same_type(basic const & other) const
246 {
247     ASSERT(is_of_type(other,idx));
248     idx const & o=static_cast<idx const &>
249                              (const_cast<basic &>(other));
250
251     if (covariant!=o.covariant) return false;
252     if (symbolic!=o.symbolic) return false;
253     if (symbolic && o.symbolic) return serial==o.serial;
254     return value==o.value;
255 }    
256
257 unsigned idx::calchash(void) const
258 {
259     hashvalue=golden_ratio_hash(golden_ratio_hash(tinfo_key ^ serial));
260     setflag(status_flags::hash_calculated);
261     return hashvalue;
262 }
263
264 //////////
265 // new virtual functions which can be overridden by derived classes
266 //////////
267
268 // public
269
270 bool idx::is_co_contra_pair(basic const & other) const
271 {
272     // like is_equal_same_type(), but tests for different covariant status
273     ASSERT(is_of_type(other,idx));
274     idx const & o=static_cast<idx const &>
275                              (const_cast<basic &>(other));
276
277     if (covariant==o.covariant) return false;
278     if (symbolic!=o.symbolic) return false;
279     if (symbolic && o.symbolic) return serial==o.serial;
280     return value==o.value;
281 }    
282
283 bool idx::is_symbolic(void) const
284 {
285     return symbolic;
286 }
287
288 unsigned idx::get_value(void) const
289 {
290     return value;
291 }
292
293 bool idx::is_covariant(void) const
294 {
295     return covariant;
296 }
297
298 ex idx::toggle_covariant(void) const
299 {
300     idx * i_copy=static_cast<idx *>(duplicate());
301     i_copy->covariant = !i_copy->covariant;
302     i_copy->clearflag(status_flags::hash_calculated);
303     return i_copy->setflag(status_flags::dynallocated);
304 }
305
306 //////////
307 // non-virtual functions in this class
308 //////////
309
310 // none
311
312 //////////
313 // static member variables
314 //////////
315
316 // protected
317
318 unsigned idx::next_serial=0;
319
320 //////////
321 // global constants
322 //////////
323
324 const idx some_idx;
325 type_info const & typeid_idx=typeid(some_idx);
326
327 //////////
328 // other functions
329 //////////
330
331 int canonicalize_indices(exvector & iv, bool antisymmetric)
332 {
333     if (iv.size()<2) {
334         // nothing do to for 0 or 1 indices
335         return INT_MAX;
336     }
337
338     bool something_changed=false;
339     int sig=1;
340     // simple bubble sort algorithm should be sufficient for the small number of indices needed
341     exvector::const_iterator last_idx=iv.end();
342     exvector::const_iterator next_to_last_idx=iv.end()-1;
343     for (exvector::iterator it1=iv.begin(); it1!=next_to_last_idx; ++it1) {
344         for (exvector::iterator it2=it1+1; it2!=last_idx; ++it2) {
345             int cmpval=(*it1).compare(*it2);
346             if (cmpval==1) {
347                 iter_swap(it1,it2);
348                 something_changed=true;
349                 if (antisymmetric) sig=-sig;
350             } else if ((cmpval==0) && antisymmetric) {
351                 something_changed=true;
352                 sig=0;
353             }
354         }
355     }
356     return something_changed ? sig : INT_MAX;
357 }
358
359 exvector idx_intersect(exvector const & iv1, exvector const & iv2)
360 {
361     // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
362     // assumes (but does not test) that each index occurs at most twice
363     exvector iv_intersect;
364     for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
365         ASSERT(is_ex_of_type(*cit1,idx));
366         if (ex_to_idx(*cit1).is_symbolic()) {
367             for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
368                 ASSERT(is_ex_of_type(*cit2,idx));
369                 if ((*cit1).is_equal(*cit2)) {
370                     iv_intersect.push_back(*cit1);
371                     break;
372                 }
373             }
374         }
375     }
376     return iv_intersect;
377 }
378
379 #define TEST_PERMUTATION(A,B,C,P) \
380     if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
381         if (antisymmetric) *sig=P; \
382         return iv3[A]; \
383     }
384
385 ex permute_free_index_to_front(exvector const & iv3, exvector const & iv2,
386                                bool antisymmetric, int * sig)
387 {
388     // match (return value,iv2) to iv3 by permuting indices
389     // iv3 is always cyclic
390
391     ASSERT(iv3.size()==3);
392     ASSERT(iv2.size()==2);
393
394     *sig=1;
395     
396     TEST_PERMUTATION(0,1,2,  1);
397     TEST_PERMUTATION(0,2,1, -1);
398     TEST_PERMUTATION(1,0,2, -1);
399     TEST_PERMUTATION(1,2,0,  1);
400     TEST_PERMUTATION(2,0,1,  1);
401     TEST_PERMUTATION(2,1,0, -1);
402     throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
403 }
404     
405 unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir)
406 {
407     exvector::iterator it;
408     unsigned replacements=0;
409     unsigned current_replacements;
410
411     ASSERT(is_ex_of_type(is,idx));
412     ASSERT(is_ex_of_type(ir,idx));
413    
414     for (it=v.begin(); it!=v.end(); ++it) {
415         current_replacements=count_index(*it,is);
416         if (current_replacements>0) {
417             (*it)=(*it).subs(is==ir);
418         }
419         replacements += current_replacements;
420     }
421     return replacements;
422 }
423
424 unsigned count_index(ex const & e, ex const & i)
425 {
426     exvector idxv=e.get_indices();
427     unsigned count=0;
428     for (exvector::const_iterator cit=idxv.begin(); cit!=idxv.end(); ++cit) {
429         if ((*cit).is_equal(i)) count++;
430     }
431     return count;
432 }
433
434 ex subs_indices(ex const & e, exvector const & idxv_subs,
435                 exvector const & idxv_repl)
436 {
437     ASSERT(idxv_subs.size()==idxv_repl.size());
438     ex res=e;
439     for (unsigned i=0; i<idxv_subs.size(); ++i) {
440         res=res.subs(idxv_subs[i]==idxv_repl[i]);
441     }
442     return res;
443 }
444
445
446
447