- modified GiNaC headers to Alexander's liking
[ginac.git] / ginac / symbol.cpp
1 /** @file symbol.cpp
2  *
3  *  Implementation of GiNaC's symbolic objects.
4  *
5  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <string>
23 #include <stdexcept>
24
25 #include "symbol.h"
26 #include "lst.h"
27 #include "utils.h"
28
29 //////////
30 // default constructor, destructor, copy constructor assignment operator and helpers
31 //////////
32
33 symbol::symbol() : basic(TINFO_symbol)
34 {
35     debugmsg("symbol default constructor",LOGLEVEL_CONSTRUCT);
36     serial=next_serial++;
37     name=autoname_prefix()+ToString(serial);
38     asexinfop=new assigned_ex_info;
39     setflag(status_flags::evaluated);
40 }
41
42 symbol::~symbol()
43 {
44     debugmsg("symbol destructor",LOGLEVEL_DESTRUCT);
45     destroy(0);
46 }
47
48 symbol::symbol(symbol const & other)
49 {
50     debugmsg("symbol copy constructor",LOGLEVEL_CONSTRUCT);
51     copy(other);
52 }
53
54 void symbol::copy(symbol const & other)
55 {
56     basic::copy(other);
57     name=other.name;
58     serial=other.serial;
59     asexinfop=other.asexinfop;
60     ++asexinfop->refcount;
61 }
62
63 void symbol::destroy(bool call_parent)
64 {
65     if (--asexinfop->refcount == 0) {
66         delete asexinfop;
67     }
68     if (call_parent) {
69         basic::destroy(call_parent);
70     }
71 }
72
73 // how should the following be interpreted?
74 // symbol x;
75 // symbol y;
76 // x=y;
77 // probably as: x=ex(y);
78
79 //////////
80 // other constructors
81 //////////
82
83 // public
84
85 symbol::symbol(string const & initname) : basic(TINFO_symbol)
86 {
87     debugmsg("symbol constructor from string",LOGLEVEL_CONSTRUCT);
88     name=initname;
89     serial=next_serial++;
90     asexinfop=new assigned_ex_info;
91     setflag(status_flags::evaluated);
92 }
93
94 //////////
95 // functions overriding virtual functions from bases classes
96 //////////
97
98 // public
99
100 basic * symbol::duplicate() const
101 {
102     debugmsg("symbol duplicate",LOGLEVEL_DUPLICATE);
103     return new symbol(*this);
104 }
105
106 bool symbol::info(unsigned inf) const
107 {
108     if (inf==info_flags::symbol) return true;
109     if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
110         return true;
111     } else {
112         return basic::info(inf);
113     }
114 }
115
116 ex symbol::expand(unsigned options) const
117 {
118     return this->hold();
119 }
120
121 bool symbol::has(ex const & other) const
122 {
123     if (is_equal(*other.bp)) return true;
124     return false;
125 }
126
127 int symbol::degree(symbol const & s) const
128 {
129     return compare_same_type(s)==0 ? 1 : 0;
130 }
131
132 int symbol::ldegree(symbol const & s) const
133 {
134     return compare_same_type(s)==0 ? 1 : 0;
135 }
136
137 ex symbol::coeff(symbol const & s, int const n) const
138 {
139     if (compare_same_type(s)==0) {
140         return n==1 ? exONE() : exZERO();
141     } else {
142         return n==0 ? *this : exZERO();
143     }
144 }
145
146 ex symbol::eval(int level) const
147 {
148     if (level == -max_recursion_level) {
149         throw(std::runtime_error("max recursion level reached"));
150     }
151     
152     if (asexinfop->is_assigned) {
153         setflag(status_flags::evaluated);
154         if (level==1) {
155             return (asexinfop->assigned_expression);
156         } else {
157             return (asexinfop->assigned_expression).eval(level);
158         }
159     } else {
160         return this->hold();
161     }
162 }
163
164 ex symbol::subs(lst const & ls, lst const & lr) const
165 {
166     ASSERT(ls.nops()==lr.nops());
167 #ifdef DOASSERT
168     for (int i=0; i<ls.nops(); i++) {
169         ASSERT(is_ex_exactly_of_type(ls.op(i),symbol)||
170                is_ex_of_type(ls.op(i),idx));
171     }
172 #endif // def DOASSERT
173
174     for (int i=0; i<ls.nops(); i++) {
175         if (is_ex_exactly_of_type(ls.op(i),symbol)) {
176             if (compare_same_type(ex_to_symbol(ls.op(i)))==0) return lr.op(i);
177         }
178     }
179     return *this;
180 }
181
182 // protected
183
184 int symbol::compare_same_type(basic const & other) const
185 {
186     ASSERT(is_of_type(other,symbol));
187     const symbol *o = static_cast<const symbol *>(&other);
188     if (serial==o->serial) return 0;
189     return serial < o->serial ? -1 : 1;
190 }
191
192 bool symbol::is_equal_same_type(basic const & other) const
193 {
194     ASSERT(is_of_type(other,symbol));
195     const symbol *o = static_cast<const symbol *>(&other);
196     return serial==o->serial;
197 }
198
199 unsigned symbol::return_type(void) const
200 {
201     return return_types::commutative;
202 }
203    
204 unsigned symbol::return_type_tinfo(void) const
205 {
206     return tinfo_key;
207 }
208
209 unsigned symbol::calchash(void) const
210 {
211     // return golden_ratio_hash(tinfo()) ^ serial;
212     hashvalue=golden_ratio_hash(golden_ratio_hash(0x55555555U ^ serial));
213     setflag(status_flags::hash_calculated);
214     return hashvalue;
215 }
216
217 //////////
218 // virtual functions which can be overridden by derived classes
219 //////////
220
221 // none
222
223 //////////
224 // non-virtual functions in this class
225 //////////
226
227 // public
228
229 void symbol::assign(ex const & value)
230 {
231     asexinfop->is_assigned=1;
232     asexinfop->assigned_expression=value;
233     clearflag(status_flags::evaluated);
234 }
235
236 void symbol::unassign(void)
237 {
238     if (asexinfop->is_assigned) {
239         asexinfop->is_assigned=0;
240         asexinfop->assigned_expression=exZERO();
241     }
242     setflag(status_flags::evaluated);
243 }
244
245 // private
246
247 string & symbol::autoname_prefix(void)
248 {
249     static string * s=new string("symbol");
250     return *s;
251 }
252
253 //////////
254 // static member variables
255 //////////
256
257 // private
258
259 unsigned symbol::next_serial=0;
260
261 // string const symbol::autoname_prefix="symbol";
262
263 //////////
264 // global constants
265 //////////
266
267 const symbol some_symbol;
268 type_info const & typeid_symbol=typeid(some_symbol);
269
270 //////////
271 // subclass assigned_ex_info
272 //////////
273
274 /** Default ctor.  Defaults to unassigned. */
275 symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
276 {
277 }