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