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