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