- carried on with felonious plot about making ex::bp private.
[ginac.git] / ginac / symbol.cpp
1 /** @file symbol.cpp
2  *
3  *  Implementation of GiNaC's symbolic objects. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2001 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 "print.h"
29 #include "archive.h"
30 #include "debugmsg.h"
31 #include "tostring.h"
32 #include "utils.h"
33
34 namespace GiNaC {
35
36 GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(symbol, basic)
37
38 //////////
39 // default ctor, dtor, copy ctor assignment operator and helpers
40 //////////
41
42 symbol::symbol() : inherited(TINFO_symbol), serial(next_serial++)
43 {
44         debugmsg("symbol default ctor", LOGLEVEL_CONSTRUCT);
45         name = TeX_name = autoname_prefix()+ToString(serial);
46         asexinfop = new assigned_ex_info;
47         setflag(status_flags::evaluated | status_flags::expanded);
48 }
49
50 /** For use by copy ctor and assignment operator. */
51 void symbol::copy(const symbol & other)
52 {
53         inherited::copy(other);
54         name = other.name;
55         TeX_name = other.TeX_name;
56         serial = other.serial;
57         asexinfop = other.asexinfop;
58         ++asexinfop->refcount;
59 }
60
61 void symbol::destroy(bool call_parent)
62 {
63         if (--asexinfop->refcount == 0)
64                 delete asexinfop;
65         if (call_parent)
66                 inherited::destroy(call_parent);
67 }
68
69 //////////
70 // other ctors
71 //////////
72
73 // public
74
75 symbol::symbol(const symbol & other)
76 {
77         debugmsg("symbol copy ctor", LOGLEVEL_CONSTRUCT);
78         copy(other);
79 }
80
81 symbol::symbol(const std::string & initname) : inherited(TINFO_symbol)
82 {
83         debugmsg("symbol ctor from string", LOGLEVEL_CONSTRUCT);
84         name = initname;
85         TeX_name = default_TeX_name();
86         serial = next_serial++;
87         asexinfop = new assigned_ex_info;
88         setflag(status_flags::evaluated | status_flags::expanded);
89 }
90
91 symbol::symbol(const std::string & initname, const std::string & texname) : inherited(TINFO_symbol)
92 {
93         debugmsg("symbol ctor from string", LOGLEVEL_CONSTRUCT);
94         name = initname;
95         TeX_name = texname;
96         serial = next_serial++;
97         asexinfop = new assigned_ex_info;
98         setflag(status_flags::evaluated | status_flags::expanded);
99 }
100
101 //////////
102 // archiving
103 //////////
104
105 /** Construct object from archive_node. */
106 symbol::symbol(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
107 {
108         debugmsg("symbol ctor from archive_node", LOGLEVEL_CONSTRUCT);
109         serial = next_serial++;
110         if (!(n.find_string("name", name)))
111                 name = autoname_prefix() + ToString(serial);
112         if (!(n.find_string("TeXname", TeX_name)))
113                 TeX_name = default_TeX_name();
114         asexinfop = new assigned_ex_info;
115         setflag(status_flags::evaluated);
116 }
117
118 /** Unarchive the object. */
119 ex symbol::unarchive(const archive_node &n, const lst &sym_lst)
120 {
121         ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
122         
123         // If symbol is in sym_lst, return the existing symbol
124         for (unsigned i=0; i<sym_lst.nops(); i++) {
125                 if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to<symbol>(sym_lst.op(i)).name == ex_to<symbol>(s).name))
126                         return sym_lst.op(i);
127         }
128         return s;
129 }
130
131 /** Archive the object. */
132 void symbol::archive(archive_node &n) const
133 {
134         inherited::archive(n);
135         n.add_string("name", name);
136         if (TeX_name != default_TeX_name())
137                 n.add_string("TeX_name", TeX_name);
138 }
139
140 //////////
141 // functions overriding virtual functions from base classes
142 //////////
143
144 // public
145
146 basic *symbol::duplicate() const
147 {
148         debugmsg("symbol duplicate", LOGLEVEL_DUPLICATE);
149         return new symbol(*this);
150 }
151
152 void symbol::print(const print_context & c, unsigned level) const
153 {
154         debugmsg("symbol print", LOGLEVEL_PRINT);
155
156         if (is_of_type(c, print_tree)) {
157
158                 c.s << std::string(level, ' ') << name << " (" << class_name() << ")"
159                     << ", serial=" << serial
160                     << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
161                     << std::endl;
162
163         } else if (is_of_type(c, print_latex))
164                 c.s << TeX_name;
165         else
166                 c.s << name;
167 }
168
169 bool symbol::info(unsigned inf) const
170 {
171         if (inf==info_flags::symbol) return true;
172         if (inf==info_flags::polynomial ||
173             inf==info_flags::integer_polynomial ||
174             inf==info_flags::cinteger_polynomial ||
175             inf==info_flags::rational_polynomial ||
176             inf==info_flags::crational_polynomial ||
177             inf==info_flags::rational_function)
178                 return true;
179         else
180                 return inherited::info(inf);
181 }
182
183 int symbol::degree(const ex & s) const
184 {
185         return is_equal(ex_to<basic>(s)) ? 1 : 0;
186 }
187
188 int symbol::ldegree(const ex & s) const
189 {
190         return is_equal(ex_to<basic>(s)) ? 1 : 0;
191 }
192
193 ex symbol::coeff(const ex & s, int n) const
194 {
195         if (is_equal(ex_to<basic>(s)))
196                 return n==1 ? _ex1() : _ex0();
197         else
198                 return n==0 ? *this : _ex0();
199 }
200
201 ex symbol::eval(int level) const
202 {
203         if (level == -max_recursion_level)
204                 throw(std::runtime_error("max recursion level reached"));
205         
206         if (asexinfop->is_assigned) {
207                 setflag(status_flags::evaluated);
208                 if (level==1)
209                         return (asexinfop->assigned_expression);
210                 else
211                         return (asexinfop->assigned_expression).eval(level);
212         } else {
213                 return this->hold();
214         }
215 }
216
217 // protected
218
219 /** Implementation of ex::diff() for single differentiation of a symbol.
220  *  It returns 1 or 0.
221  *
222  *  @see ex::diff */
223 ex symbol::derivative(const symbol & s) const
224 {
225         if (compare_same_type(s))
226                 return _ex0();
227         else
228                 return _ex1();
229 }
230
231 int symbol::compare_same_type(const basic & other) const
232 {
233         GINAC_ASSERT(is_of_type(other,symbol));
234         const symbol *o = static_cast<const symbol *>(&other);
235         if (serial==o->serial) return 0;
236         return serial < o->serial ? -1 : 1;
237 }
238
239 bool symbol::is_equal_same_type(const basic & other) const
240 {
241         GINAC_ASSERT(is_of_type(other,symbol));
242         const symbol *o = static_cast<const symbol *>(&other);
243         return serial==o->serial;
244 }
245
246 unsigned symbol::calchash(void) const
247 {
248         // this is where the schoolbook method
249         // (golden_ratio_hash(tinfo()) ^ serial)
250         // is not good enough yet...
251         hashvalue = golden_ratio_hash(golden_ratio_hash(tinfo()) ^ serial);
252         setflag(status_flags::hash_calculated);
253         return hashvalue;
254 }
255
256 //////////
257 // virtual functions which can be overridden by derived classes
258 //////////
259
260 // none
261
262 //////////
263 // non-virtual functions in this class
264 //////////
265
266 // public
267
268 void symbol::assign(const ex & value)
269 {
270         asexinfop->is_assigned = 1;
271         asexinfop->assigned_expression = value;
272         clearflag(status_flags::evaluated | status_flags::expanded);
273 }
274
275 void symbol::unassign(void)
276 {
277         if (asexinfop->is_assigned) {
278                 asexinfop->is_assigned = 0;
279                 asexinfop->assigned_expression = _ex0();
280         }
281         setflag(status_flags::evaluated | status_flags::expanded);
282 }
283
284 // private
285
286 /** Symbols not constructed with a string get one assigned using this
287  *  prefix and a number. */
288 std::string & symbol::autoname_prefix(void)
289 {
290         static std::string *s = new std::string("symbol");
291         return *s;
292 }
293
294 /** Return default TeX name for symbol. This recognizes some greek letters. */
295 std::string symbol::default_TeX_name(void) const
296 {
297         if (name=="alpha"        || name=="beta"         || name=="gamma"
298          || name=="delta"        || name=="epsilon"      || name=="varepsilon"
299          || name=="zeta"         || name=="eta"          || name=="theta"
300          || name=="vartheta"     || name=="iota"         || name=="kappa"
301          || name=="lambda"       || name=="mu"           || name=="nu"
302          || name=="xi"           || name=="omicron"      || name=="pi"
303          || name=="varpi"        || name=="rho"          || name=="varrho"
304          || name=="sigma"        || name=="varsigma"     || name=="tau"
305          || name=="upsilon"      || name=="phi"          || name=="varphi"
306          || name=="chi"          || name=="psi"          || name=="omega"
307          || name=="Gamma"        || name=="Delta"        || name=="Theta"
308          || name=="Lambda"       || name=="Xi"           || name=="Pi"
309          || name=="Sigma"        || name=="Upsilon"      || name=="Phi"
310          || name=="Psi"          || name=="Omega")
311                 return "\\" + name;
312         else
313                 return name;
314 }
315
316 //////////
317 // static member variables
318 //////////
319
320 // private
321
322 unsigned symbol::next_serial = 0;
323
324 //////////
325 // subclass assigned_ex_info
326 //////////
327
328 /** Default ctor.  Defaults to unassigned. */
329 symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
330 {
331 }
332
333 } // namespace GiNaC