1a8ef59cd2a5d0d15f0cd6d2e147c631456b587d
[ginac.git] / ginac / symbol.cpp
1 /** @file symbol.cpp
2  *
3  *  Implementation of GiNaC's symbolic objects. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2000 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 <string>
24 #include <stdexcept>
25
26 #include "symbol.h"
27 #include "lst.h"
28 #include "idx.h"
29 #include "archive.h"
30 #include "debugmsg.h"
31 #include "utils.h"
32
33 #ifndef NO_NAMESPACE_GINAC
34 namespace GiNaC {
35 #endif // ndef NO_NAMESPACE_GINAC
36
37 GINAC_IMPLEMENT_REGISTERED_CLASS(symbol, basic)
38
39 //////////
40 // default constructor, destructor, copy constructor assignment operator and helpers
41 //////////
42
43 symbol::symbol() : inherited(TINFO_symbol)
44 {
45     debugmsg("symbol default constructor", LOGLEVEL_CONSTRUCT);
46     serial=next_serial++;
47     name=autoname_prefix()+ToString(serial);
48     asexinfop=new assigned_ex_info;
49     setflag(status_flags::evaluated);
50 }
51
52 symbol::~symbol()
53 {
54     debugmsg("symbol destructor", LOGLEVEL_DESTRUCT);
55     destroy(0);
56 }
57
58 symbol::symbol(const symbol & other)
59 {
60     debugmsg("symbol copy constructor", LOGLEVEL_CONSTRUCT);
61     copy(other);
62 }
63
64 void symbol::copy(const symbol & other)
65 {
66     inherited::copy(other);
67     name=other.name;
68     serial=other.serial;
69     asexinfop=other.asexinfop;
70     ++asexinfop->refcount;
71 }
72
73 void symbol::destroy(bool call_parent)
74 {
75     if (--asexinfop->refcount == 0) {
76         delete asexinfop;
77     }
78     if (call_parent) {
79         inherited::destroy(call_parent);
80     }
81 }
82
83 // how should the following be interpreted?
84 // symbol x;
85 // symbol y;
86 // x=y;
87 // probably as: x=ex(y);
88
89 //////////
90 // other constructors
91 //////////
92
93 // public
94
95 symbol::symbol(const string & initname) : inherited(TINFO_symbol)
96 {
97     debugmsg("symbol constructor from string", LOGLEVEL_CONSTRUCT);
98     name=initname;
99     serial=next_serial++;
100     asexinfop=new assigned_ex_info;
101     setflag(status_flags::evaluated);
102 }
103
104 //////////
105 // archiving
106 //////////
107
108 /** Construct object from archive_node. */
109 symbol::symbol(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
110 {
111     debugmsg("symbol constructor from archive_node", LOGLEVEL_CONSTRUCT);
112     serial = next_serial++;
113     if (!(n.find_string("name", name)))
114         name = autoname_prefix() + ToString(serial);
115     asexinfop = new assigned_ex_info;
116     setflag(status_flags::evaluated);
117 }
118
119 /** Unarchive the object. */
120 ex symbol::unarchive(const archive_node &n, const lst &sym_lst)
121 {
122     ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
123
124     // If symbol is in sym_lst, return the existing symbol
125     for (unsigned i=0; i<sym_lst.nops(); i++) {
126         if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to_symbol(sym_lst.op(i)).name == ex_to_symbol(s).name))
127             return sym_lst.op(i);
128     }
129     return s;
130 }
131
132 /** Archive the object. */
133 void symbol::archive(archive_node &n) const
134 {
135     inherited::archive(n);
136     n.add_string("name", name);
137 }
138
139 //////////
140 // functions overriding virtual functions from bases classes
141 //////////
142
143 // public
144
145 basic *symbol::duplicate() const
146 {
147     debugmsg("symbol duplicate", LOGLEVEL_DUPLICATE);
148     return new symbol(*this);
149 }
150
151 void symbol::print(ostream & os, unsigned upper_precedence) const
152 {
153     debugmsg("symbol print",LOGLEVEL_PRINT);
154     os << name;
155 }
156
157 void symbol::printraw(ostream & os) const
158 {
159     debugmsg("symbol printraw",LOGLEVEL_PRINT);
160     os << "symbol(" << "name=" << name << ",serial=" << serial
161        << ",hash=" << hashvalue << ",flags=" << flags << ")";
162 }
163
164 void symbol::printtree(ostream & os, unsigned indent) const
165 {
166     debugmsg("symbol printtree",LOGLEVEL_PRINT);
167     os << string(indent,' ') << name << " (symbol): "
168        << "serial=" << serial
169        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
170        << ", flags=" << flags << endl;
171 }
172
173 void symbol::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
174 {
175     debugmsg("symbol print csrc", LOGLEVEL_PRINT);
176     os << name;
177 }
178
179 bool symbol::info(unsigned inf) const
180 {
181     if (inf==info_flags::symbol) return true;
182     if (inf==info_flags::polynomial ||
183         inf==info_flags::integer_polynomial ||
184         inf==info_flags::cinteger_polynomial ||
185         inf==info_flags::rational_polynomial ||
186         inf==info_flags::crational_polynomial ||
187         inf==info_flags::rational_function) {
188         return true;
189     } else {
190         return inherited::info(inf);
191     }
192 }
193
194 ex symbol::expand(unsigned options) const
195 {
196     return this->hold();
197 }
198
199 bool symbol::has(const ex & other) const
200 {
201     if (is_equal(*other.bp)) return true;
202     return false;
203 }
204
205 int symbol::degree(const symbol & s) const
206 {
207     return compare_same_type(s)==0 ? 1 : 0;
208 }
209
210 int symbol::ldegree(const symbol & s) const
211 {
212     return compare_same_type(s)==0 ? 1 : 0;
213 }
214
215 ex symbol::coeff(const symbol & s, int n) const
216 {
217     if (compare_same_type(s)==0) {
218         return n==1 ? _ex1() : _ex0();
219     } else {
220         return n==0 ? *this : _ex0();
221     }
222 }
223
224 ex symbol::eval(int level) const
225 {
226     if (level == -max_recursion_level) {
227         throw(std::runtime_error("max recursion level reached"));
228     }
229     
230     if (asexinfop->is_assigned) {
231         setflag(status_flags::evaluated);
232         if (level==1) {
233             return (asexinfop->assigned_expression);
234         } else {
235             return (asexinfop->assigned_expression).eval(level);
236         }
237     } else {
238         return this->hold();
239     }
240 }
241
242 ex symbol::subs(const lst & ls, const lst & lr) const
243 {
244     GINAC_ASSERT(ls.nops()==lr.nops());
245 #ifdef DO_GINAC_ASSERT
246     for (unsigned i=0; i<ls.nops(); i++) {
247         GINAC_ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
248                is_ex_of_type(ls.op(i),idx));
249     }
250 #endif // def DO_GINAC_ASSERT
251
252     for (unsigned i=0; i<ls.nops(); i++) {
253         if (is_ex_exactly_of_type(ls.op(i),symbol)) {
254             if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
255         }
256     }
257     return *this;
258 }
259
260 // protected
261
262 /** Implementation of ex::diff() for single differentiation of a symbol.
263  *  It returns 1 or 0.
264  *
265  *  @see ex::diff */
266 ex symbol::derivative(const symbol & s) const
267 {
268     if (compare_same_type(s)) {
269         return _ex0();
270     } else {
271         return _ex1();
272     }
273 }
274
275 int symbol::compare_same_type(const basic & other) const
276 {
277     GINAC_ASSERT(is_of_type(other,symbol));
278     const symbol *o = static_cast<const symbol *>(&other);
279     if (serial==o->serial) return 0;
280     return serial < o->serial ? -1 : 1;
281 }
282
283 bool symbol::is_equal_same_type(const basic & other) const
284 {
285     GINAC_ASSERT(is_of_type(other,symbol));
286     const symbol *o = static_cast<const symbol *>(&other);
287     return serial==o->serial;
288 }
289
290 unsigned symbol::return_type(void) const
291 {
292     return return_types::commutative;
293 }
294    
295 unsigned symbol::return_type_tinfo(void) const
296 {
297     return tinfo_key;
298 }
299
300 unsigned symbol::calchash(void) const
301 {
302     // return golden_ratio_hash(tinfo()) ^ serial;
303     hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
304     setflag(status_flags::hash_calculated);
305     return hashvalue;
306 }
307
308 //////////
309 // virtual functions which can be overridden by derived classes
310 //////////
311
312 // none
313
314 //////////
315 // non-virtual functions in this class
316 //////////
317
318 // public
319
320 void symbol::assign(const ex & value)
321 {
322     asexinfop->is_assigned=1;
323     asexinfop->assigned_expression=value;
324     clearflag(status_flags::evaluated);
325 }
326
327 void symbol::unassign(void)
328 {
329     if (asexinfop->is_assigned) {
330         asexinfop->is_assigned=0;
331         asexinfop->assigned_expression=_ex0();
332     }
333     setflag(status_flags::evaluated);
334 }
335
336 // private
337
338 string & symbol::autoname_prefix(void)
339 {
340     static string * s=new string("symbol");
341     return *s;
342 }
343
344 //////////
345 // static member variables
346 //////////
347
348 // private
349
350 unsigned symbol::next_serial=0;
351
352 // string const symbol::autoname_prefix="symbol";
353
354 //////////
355 // global constants
356 //////////
357
358 const symbol some_symbol;
359 const type_info & typeid_symbol=typeid(some_symbol);
360
361 //////////
362 // subclass assigned_ex_info
363 //////////
364
365 /** Default ctor.  Defaults to unassigned. */
366 symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
367 {
368 }
369
370 #ifndef NO_NAMESPACE_GINAC
371 } // namespace GiNaC
372 #endif // ndef NO_NAMESPACE_GINAC