]> www.ginac.de Git - ginac.git/blob - ginac/basic.cpp
- changed behaviour of numeric::is_rational() and added numeric::is_cinteger()
[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 objects to establish canonical order.
298  *  All compare functions return: -1 for *this less than other, 0 equal,
299  *  1 greater. */
300 int basic::compare(basic const & other) const
301 {
302     unsigned hash_this = gethash();
303     unsigned hash_other = other.gethash();
304
305     if (hash_this<hash_other) return -1;
306     if (hash_this>hash_other) return 1;
307
308     unsigned typeid_this = tinfo();
309     unsigned typeid_other = other.tinfo();
310
311     if (typeid_this<typeid_other) {
312         /*
313         cout << "hash collision, different types: " 
314              << *this << " and " << other << endl;
315         this->printraw(cout);
316         cout << " and ";
317         other.printraw(cout);
318         cout << endl;
319         */
320         return -1;
321     }
322     if (typeid_this>typeid_other) {
323         /*
324         cout << "hash collision, different types: " 
325              << *this << " and " << other << endl;
326         this->printraw(cout);
327         cout << " and ";
328         other.printraw(cout);
329         cout << endl;
330         */
331         return 1;
332     }
333
334     GINAC_ASSERT(typeid(*this)==typeid(other));
335
336     int cmpval=compare_same_type(other);
337     if ((cmpval!=0)&&(hash_this<0x80000000U)) {
338         /*
339         cout << "hash collision, same type: " 
340              << *this << " and " << other << endl;
341         this->printraw(cout);
342         cout << " and ";
343         other.printraw(cout);
344         cout << endl;
345         */
346     }
347     return cmpval;
348 }
349
350 bool basic::is_equal(basic const & other) const
351 {
352     unsigned hash_this = gethash();
353     unsigned hash_other = other.gethash();
354
355     if (hash_this!=hash_other) return false;
356
357     unsigned typeid_this = tinfo();
358     unsigned typeid_other = other.tinfo();
359
360     if (typeid_this!=typeid_other) return false;
361
362     GINAC_ASSERT(typeid(*this)==typeid(other));
363
364     return is_equal_same_type(other);
365 }
366
367 // protected
368
369 basic const & basic::hold(void) const
370 {
371     return setflag(status_flags::evaluated);
372 }
373
374 void basic::ensure_if_modifiable(void) const
375 {
376     if (refcount>1) {
377         throw(std::runtime_error("cannot modify multiply referenced object"));
378     }
379 }
380
381 //////////
382 // static member variables
383 //////////
384
385 // protected
386
387 unsigned basic::precedence=70;
388 unsigned basic::delta_indent=4;
389
390 //////////
391 // global constants
392 //////////
393
394 const basic some_basic;
395 type_info const & typeid_basic=typeid(some_basic);
396
397 //////////
398 // global variables
399 //////////
400
401 int max_recursion_level=1024;
402
403 #ifndef NO_GINAC_NAMESPACE
404 } // namespace GiNaC
405 #endif // ndef NO_GINAC_NAMESPACE