- modified GiNaC headers to Alexander's liking
[ginac.git] / ginac / basic.cpp
1 /** @file basic.cpp
2  *
3  *  Implementation of GiNaC's ABC.
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 <iostream>
23 #include <typeinfo>
24 #include <stdexcept>
25
26 #include "basic.h"
27 #include "ex.h"
28 #include "numeric.h"
29 #include "power.h"
30 #include "symbol.h"
31 #include "lst.h"
32 #include "ncmul.h"
33 #include "utils.h"
34
35 //////////
36 // default constructor, destructor, copy constructor assignment operator and helpers
37 //////////
38
39 // public
40
41 #ifndef INLINE_BASIC_CONSTRUCTORS
42 basic::basic() : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
43 {
44     debugmsg("basic default constructor",LOGLEVEL_CONSTRUCT);
45     // nothing to do
46 }
47
48 basic::~basic() 
49 {
50     debugmsg("basic destructor",LOGLEVEL_DESTRUCT);
51     destroy(0);
52     ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
53 }
54
55 basic::basic(basic const & other) : flags(0), refcount(0), tinfo_key(TINFO_BASIC)
56 {
57     debugmsg("basic copy constructor",LOGLEVEL_CONSTRUCT);
58     copy(other);
59 }
60 #endif
61
62 basic const & basic::operator=(basic const & other)
63 {
64     debugmsg("basic operator=",LOGLEVEL_ASSIGNMENT);
65     if (this != &other) {
66         destroy(1);
67         copy(other);
68     }
69     return *this;
70 }
71
72 // protected
73
74 #if 0
75 void basic::copy(basic const & other)
76 {
77     flags=other.flags & ~ status_flags::dynallocated;
78     hashvalue=other.hashvalue;
79     tinfo_key=other.tinfo_key;
80 }
81 #endif
82
83 //////////
84 // other constructors
85 //////////
86
87 #ifndef INLINE_BASIC_CONSTRUCTORS
88 basic::basic(unsigned ti) : flags(0), refcount(0), tinfo_key(ti)
89 {
90     debugmsg("basic constructor with tinfo_key",LOGLEVEL_CONSTRUCT);
91     // nothing to do
92 }
93 #endif
94
95 //////////
96 // functions overriding virtual functions from bases classes
97 //////////
98
99 // none
100
101 //////////
102 // new virtual functions which can be overridden by derived classes
103 //////////
104
105 // public
106
107 basic * basic::duplicate() const
108 {
109     debugmsg("basic duplicate",LOGLEVEL_DUPLICATE);
110     return new basic(*this);
111 }
112
113 bool basic::info(unsigned inf) const
114 {
115     return false; // all possible properties are false for basic objects
116 }
117
118 int basic::nops() const
119 {
120     return 0;
121 }
122
123 ex basic::op(int const i) const
124 {
125     return (const_cast<basic *>(this))->let_op(i);
126 }
127
128 ex & basic::let_op(int const i)
129 {
130     throw(std::out_of_range("op() out of range"));
131 }
132
133 ex basic::operator[](ex const & index) const
134 {
135     if (is_exactly_of_type(*index.bp,numeric)) {
136         return op(static_cast<numeric const &>(*index.bp).to_int());
137     }
138     throw(std::invalid_argument("non-numeric indices not supported by this type"));
139 }
140
141 ex basic::operator[](int const i) const
142 {
143     return op(i);
144 }
145
146 bool basic::has(ex const & other) const
147 {
148     ASSERT(other.bp!=0);
149     if (is_equal(*other.bp)) return true;
150     if (nops()>0) {
151         for (int i=0; i<nops(); i++) {
152             if (op(i).has(other)) return true;
153         }
154     }
155     return false;
156 }
157
158 int basic::degree(symbol const & s) const
159 {
160     return 0;
161 }
162
163 int basic::ldegree(symbol const & s) const
164 {
165     return 0;
166 }
167
168 ex basic::coeff(symbol const & s, int const n) const
169 {
170     return n==0 ? *this : exZERO();
171 }
172
173 ex basic::collect(symbol const & s) const
174 {
175     ex x;
176     int ldeg=ldegree(s);
177     int deg=degree(s);
178     for (int n=ldeg; n<=deg; n++) {
179         x += coeff(s,n)*power(s,n);
180     }
181     return x;
182 }
183
184 ex basic::eval(int level) const
185 {
186     return this->hold();
187 }
188
189 ex basic::evalf(int level) const
190 {
191     return *this;
192 }
193
194 ex basic::subs(lst const & ls, lst const & lr) const
195 {
196     return *this;
197 }
198
199 exvector basic::get_indices(void) const
200 {
201     return exvector(); // return an empty exvector
202 }
203
204 ex basic::simplify_ncmul(exvector const & v) const
205 {
206     return simplified_ncmul(v);
207 }
208
209 // protected
210
211 int basic::compare_same_type(basic const & other) const
212 {
213     return compare_pointers(this, &other);
214 }
215
216 bool basic::is_equal_same_type(basic const & other) const
217 {
218     return compare_same_type(other)==0;
219 }
220
221 unsigned basic::return_type(void) const
222 {
223     return return_types::commutative;
224 }
225
226 unsigned basic::return_type_tinfo(void) const
227 {
228     return tinfo();
229 }
230
231 unsigned basic::calchash(void) const
232 {
233     unsigned v=golden_ratio_hash(tinfo());
234     for (int i=0; i<nops(); i++) {
235         v=rotate_left_31(v);
236         v ^= (const_cast<basic *>(this))->let_op(i).gethash();
237     }
238
239     v = v & 0x7FFFFFFFU;
240     
241     // store calculated hash value only if object is already evaluated
242     if (flags & status_flags::evaluated) {
243         setflag(status_flags::hash_calculated);
244         hashvalue=v;
245     }
246
247     return v;
248 }
249
250 ex basic::expand(unsigned options) const
251 {
252     return this->setflag(status_flags::expanded);
253 }
254
255 //////////
256 // non-virtual functions in this class
257 //////////
258
259 // public
260
261 ex basic::subs(ex const & e) const
262 {
263     // accept 2 types of replacement expressions:
264     //   - symbol==ex
265     //   - lst(symbol1==ex1,symbol2==ex2,...)
266     // convert to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...))
267     // additionally, idx can be used instead of symbol
268     if (e.info(info_flags::relation_equal)) {
269         return subs(lst(e));
270     }
271     if (!e.info(info_flags::list)) {
272         throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
273     }
274     lst ls;
275     lst lr;
276     for (int i=0; i<e.nops(); i++) {
277         if (!e.op(i).info(info_flags::relation_equal)) {
278             throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
279         }
280         if (!e.op(i).op(0).info(info_flags::symbol)) {
281             if (!e.op(i).op(0).info(info_flags::idx)) {
282                 throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
283             }
284         }
285         ls.append(e.op(i).op(0));
286         lr.append(e.op(i).op(1));
287     }
288     return subs(ls,lr);
289 }
290
291 // compare functions to sort expressions canonically
292 // all compare functions return: -1 for *this less than other, 0 equal, 1 greater
293
294 /*
295 int basic::compare(basic const & other) const
296 {
297     const type_info & typeid_this = typeid(*this);
298     const type_info & typeid_other = typeid(other);
299
300     if (typeid_this==typeid_other) {
301         return compare_same_type(other);
302     }
303
304     // special rule: sort numeric() to end
305     if (typeid_this==typeid_numeric) return 1;
306     if (typeid_other==typeid_numeric) return -1;
307
308     // otherwise: sort according to type_info order (arbitrary, but well defined)
309     return typeid_this.before(typeid_other) ? -1 : 1;
310 }
311 */
312
313 int basic::compare(basic const & other) const
314 {
315     unsigned hash_this = gethash();
316     unsigned hash_other = other.gethash();
317
318     if (hash_this<hash_other) return -1;
319     if (hash_this>hash_other) return 1;
320
321     unsigned typeid_this = tinfo();
322     unsigned typeid_other = other.tinfo();
323
324     if (typeid_this<typeid_other) {
325         /*
326         cout << "hash collision, different types: " 
327              << *this << " and " << other << endl;
328         this->printraw(cout);
329         cout << " and ";
330         other.printraw(cout);
331         cout << endl;
332         */
333         return -1;
334     }
335     if (typeid_this>typeid_other) {
336         /*
337         cout << "hash collision, different types: " 
338              << *this << " and " << other << endl;
339         this->printraw(cout);
340         cout << " and ";
341         other.printraw(cout);
342         cout << endl;
343         */
344         return 1;
345     }
346
347     ASSERT(typeid(*this)==typeid(other));
348
349     int cmpval=compare_same_type(other);
350     if ((cmpval!=0)&&(hash_this<0x80000000U)) {
351         /*
352         cout << "hash collision, same type: " 
353              << *this << " and " << other << endl;
354         this->printraw(cout);
355         cout << " and ";
356         other.printraw(cout);
357         cout << endl;
358         */
359     }
360     return cmpval;
361 }
362
363 bool basic::is_equal(basic const & other) const
364 {
365     unsigned hash_this = gethash();
366     unsigned hash_other = other.gethash();
367
368     if (hash_this!=hash_other) return false;
369
370     unsigned typeid_this = tinfo();
371     unsigned typeid_other = other.tinfo();
372
373     if (typeid_this!=typeid_other) return false;
374
375     ASSERT(typeid(*this)==typeid(other));
376
377     return is_equal_same_type(other);
378 }
379
380 // protected
381
382 basic const & basic::hold(void) const
383 {
384     return setflag(status_flags::evaluated);
385 }
386
387 void basic::ensure_if_modifiable(void) const
388 {
389     if (refcount>1) {
390         throw(std::runtime_error("cannot modify multiply referenced object"));
391     }
392 }
393
394 //////////
395 // static member variables
396 //////////
397
398 // protected
399
400 unsigned basic::precedence=70;
401 unsigned basic::delta_indent=4;
402
403 //////////
404 // global constants
405 //////////
406
407 const basic some_basic;
408 type_info const & typeid_basic=typeid(some_basic);
409
410 //////////
411 // global variables
412 //////////
413
414 int max_recursion_level=1024;