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