]> www.ginac.de Git - ginac.git/blob - ginac/basic.cpp
- Changed a few switches.
[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 /** Output to stream formatted to be useful as ginsh input. */
114 void basic::print(ostream & os, unsigned upper_precedence) const
115 {
116     debugmsg("basic print",LOGLEVEL_PRINT);
117     os << "[basic object]";
118 }
119
120 /** Output to stream in ugly raw format, so brave developers can have a look
121  * at the underlying structure. */
122 void basic::printraw(ostream & os) const
123 {
124     debugmsg("basic printraw",LOGLEVEL_PRINT);
125     os << "[basic object]";
126 }
127
128 /** Output to stream formatted in tree- (indented-) form, so developers can
129  *  have a look at the underlying structure. */
130 void basic::printtree(ostream & os, unsigned indent) const
131 {
132     debugmsg("basic printtree",LOGLEVEL_PRINT);
133     os << string(indent,' ') << "type=" << typeid(*this).name()
134        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
135        << ", flags=" << flags
136        << ", nops=" << nops() << endl;
137     for (int i=0; i<nops(); ++i) {
138         op(i).printtree(os,indent+delta_indent);
139     }
140 }
141
142 /** Output to stream formatted as C-source.
143  *
144  *  @param os a stream for output
145  *  @param type variable type (one of the csrc_types)
146  *  @param upper_precedence operator precedence of caller
147  *  @see ex::printcsrc */
148 void basic::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
149 {
150     debugmsg("basic print csrc", LOGLEVEL_PRINT);
151 }
152
153 /** Little wrapper arount print to be called within a debugger. */
154 void basic::dbgprint(void) const
155 {
156     print(cerr);
157     cerr << endl;
158 }
159
160 /** Little wrapper arount printtree to be called within a debugger. */
161 void basic::dbgprinttree(void) const
162 {
163     printtree(cerr,0);
164 }
165
166 basic * basic::duplicate() const
167 {
168     debugmsg("basic duplicate",LOGLEVEL_DUPLICATE);
169     return new basic(*this);
170 }
171
172 bool basic::info(unsigned inf) const
173 {
174     return false; // all possible properties are false for basic objects
175 }
176
177 int basic::nops() const
178 {
179     return 0;
180 }
181
182 ex basic::op(int const i) const
183 {
184     return (const_cast<basic *>(this))->let_op(i);
185 }
186
187 ex & basic::let_op(int const i)
188 {
189     throw(std::out_of_range("op() out of range"));
190 }
191
192 ex basic::operator[](ex const & index) const
193 {
194     if (is_exactly_of_type(*index.bp,numeric)) {
195         return op(static_cast<numeric const &>(*index.bp).to_int());
196     }
197     throw(std::invalid_argument("non-numeric indices not supported by this type"));
198 }
199
200 ex basic::operator[](int const i) const
201 {
202     return op(i);
203 }
204
205 bool basic::has(ex const & other) const
206 {
207     GINAC_ASSERT(other.bp!=0);
208     if (is_equal(*other.bp)) return true;
209     if (nops()>0) {
210         for (int i=0; i<nops(); i++) {
211             if (op(i).has(other)) return true;
212         }
213     }
214     return false;
215 }
216
217 int basic::degree(symbol const & s) const
218 {
219     return 0;
220 }
221
222 int basic::ldegree(symbol const & s) const
223 {
224     return 0;
225 }
226
227 ex basic::coeff(symbol const & s, int const n) const
228 {
229     return n==0 ? *this : _ex0();
230 }
231
232 ex basic::collect(symbol const & s) const
233 {
234     ex x;
235     int ldeg=ldegree(s);
236     int deg=degree(s);
237     for (int n=ldeg; n<=deg; n++) {
238         x += coeff(s,n)*power(s,n);
239     }
240     return x;
241 }
242
243 ex basic::eval(int level) const
244 {
245     return this->hold();
246 }
247
248 ex basic::evalf(int level) const
249 {
250     return *this;
251 }
252
253 ex basic::subs(lst const & ls, lst const & lr) const
254 {
255     return *this;
256 }
257
258 exvector basic::get_indices(void) const
259 {
260     return exvector(); // return an empty exvector
261 }
262
263 ex basic::simplify_ncmul(exvector const & v) const
264 {
265     return simplified_ncmul(v);
266 }
267
268 // protected
269
270 int basic::compare_same_type(basic const & other) const
271 {
272     return compare_pointers(this, &other);
273 }
274
275 bool basic::is_equal_same_type(basic const & other) const
276 {
277     return compare_same_type(other)==0;
278 }
279
280 unsigned basic::return_type(void) const
281 {
282     return return_types::commutative;
283 }
284
285 unsigned basic::return_type_tinfo(void) const
286 {
287     return tinfo();
288 }
289
290 unsigned basic::calchash(void) const
291 {
292     unsigned v=golden_ratio_hash(tinfo());
293     for (int i=0; i<nops(); i++) {
294         v=rotate_left_31(v);
295         v ^= (const_cast<basic *>(this))->let_op(i).gethash();
296     }
297
298     v = v & 0x7FFFFFFFU;
299     
300     // store calculated hash value only if object is already evaluated
301     if (flags & status_flags::evaluated) {
302         setflag(status_flags::hash_calculated);
303         hashvalue=v;
304     }
305
306     return v;
307 }
308
309 ex basic::expand(unsigned options) const
310 {
311     return this->setflag(status_flags::expanded);
312 }
313
314 //////////
315 // non-virtual functions in this class
316 //////////
317
318 // public
319
320 ex basic::subs(ex const & e) const
321 {
322     // accept 2 types of replacement expressions:
323     //   - symbol==ex
324     //   - lst(symbol1==ex1,symbol2==ex2,...)
325     // convert to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...))
326     // additionally, idx can be used instead of symbol
327     if (e.info(info_flags::relation_equal)) {
328         return subs(lst(e));
329     }
330     if (!e.info(info_flags::list)) {
331         throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
332     }
333     lst ls;
334     lst lr;
335     for (int i=0; i<e.nops(); i++) {
336         if (!e.op(i).info(info_flags::relation_equal)) {
337             throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
338         }
339         if (!e.op(i).op(0).info(info_flags::symbol)) {
340             if (!e.op(i).op(0).info(info_flags::idx)) {
341                 throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
342             }
343         }
344         ls.append(e.op(i).op(0));
345         lr.append(e.op(i).op(1));
346     }
347     return subs(ls,lr);
348 }
349
350 /** Compare objects to establish canonical order.
351  *  All compare functions return: -1 for *this less than other, 0 equal,
352  *  1 greater. */
353 int basic::compare(basic const & other) const
354 {
355     unsigned hash_this = gethash();
356     unsigned hash_other = other.gethash();
357
358     if (hash_this<hash_other) return -1;
359     if (hash_this>hash_other) return 1;
360
361     unsigned typeid_this = tinfo();
362     unsigned typeid_other = other.tinfo();
363
364     if (typeid_this<typeid_other) {
365         /*
366         cout << "hash collision, different types: " 
367              << *this << " and " << other << endl;
368         this->printraw(cout);
369         cout << " and ";
370         other.printraw(cout);
371         cout << endl;
372         */
373         return -1;
374     }
375     if (typeid_this>typeid_other) {
376         /*
377         cout << "hash collision, different types: " 
378              << *this << " and " << other << endl;
379         this->printraw(cout);
380         cout << " and ";
381         other.printraw(cout);
382         cout << endl;
383         */
384         return 1;
385     }
386
387     GINAC_ASSERT(typeid(*this)==typeid(other));
388
389     int cmpval=compare_same_type(other);
390     if ((cmpval!=0)&&(hash_this<0x80000000U)) {
391         /*
392         cout << "hash collision, same type: " 
393              << *this << " and " << other << endl;
394         this->printraw(cout);
395         cout << " and ";
396         other.printraw(cout);
397         cout << endl;
398         */
399     }
400     return cmpval;
401 }
402
403 bool basic::is_equal(basic const & other) const
404 {
405     unsigned hash_this = gethash();
406     unsigned hash_other = other.gethash();
407
408     if (hash_this!=hash_other) return false;
409
410     unsigned typeid_this = tinfo();
411     unsigned typeid_other = other.tinfo();
412
413     if (typeid_this!=typeid_other) return false;
414
415     GINAC_ASSERT(typeid(*this)==typeid(other));
416
417     return is_equal_same_type(other);
418 }
419
420 // protected
421
422 basic const & basic::hold(void) const
423 {
424     return setflag(status_flags::evaluated);
425 }
426
427 void basic::ensure_if_modifiable(void) const
428 {
429     if (refcount>1) {
430         throw(std::runtime_error("cannot modify multiply referenced object"));
431     }
432 }
433
434 //////////
435 // static member variables
436 //////////
437
438 // protected
439
440 unsigned basic::precedence=70;
441 unsigned basic::delta_indent=4;
442
443 //////////
444 // global constants
445 //////////
446
447 const basic some_basic;
448 type_info const & typeid_basic=typeid(some_basic);
449
450 //////////
451 // global variables
452 //////////
453
454 int max_recursion_level=1024;
455
456 #ifndef NO_GINAC_NAMESPACE
457 } // namespace GiNaC
458 #endif // ndef NO_GINAC_NAMESPACE