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