symbol: don't bother to set TeX name if user did not specified one.
[ginac.git] / ginac / symbol.cpp
1 /** @file symbol.cpp
2  *
3  *  Implementation of GiNaC's symbolic objects. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <string>
24 #include <stdexcept>
25 #include <map>
26
27 #include "symbol.h"
28 #include "lst.h"
29 #include "archive.h"
30 #include "tostring.h"
31 #include "utils.h"
32 #include "inifcns.h"
33
34 namespace GiNaC {
35
36 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(symbol, basic,
37   print_func<print_context>(&symbol::do_print).
38   print_func<print_latex>(&symbol::do_print_latex).
39   print_func<print_tree>(&symbol::do_print_tree).
40   print_func<print_python_repr>(&symbol::do_print_python_repr))
41
42 //////////
43 // default constructor
44 //////////
45
46 // symbol
47
48 symbol::symbol()
49  :  serial(next_serial++), name(""), TeX_name(""), domain(domain::complex)
50 {
51         setflag(status_flags::evaluated | status_flags::expanded);
52 }
53
54 // realsymbol
55
56 realsymbol::realsymbol()
57 {
58         domain = domain::real;
59 }
60
61 // possymbol
62
63 possymbol::possymbol()
64 {
65         domain = domain::positive;
66 }
67
68 //////////
69 // other constructors
70 //////////
71
72 // public
73
74 // symbol
75
76 symbol::symbol(const std::string & initname, unsigned domain) :
77         serial(next_serial++), name(initname), TeX_name(""),
78         domain(domain)
79 {
80         setflag(status_flags::evaluated | status_flags::expanded);
81 }
82
83 symbol::symbol(const std::string & initname, const std::string & texname, unsigned domain) :
84         serial(next_serial++), name(initname), TeX_name(texname), domain(domain)
85 {
86         setflag(status_flags::evaluated | status_flags::expanded);
87 }
88
89 // realsymbol
90         
91 realsymbol::realsymbol(const std::string & initname, unsigned domain)
92  : symbol(initname, domain) { }
93
94 realsymbol::realsymbol(const std::string & initname, const std::string & texname, unsigned domain)
95  : symbol(initname, texname, domain) { }
96
97 // possymbol
98         
99 possymbol::possymbol(const std::string & initname, unsigned domain)
100  : symbol(initname, domain) { }
101
102 possymbol::possymbol(const std::string & initname, const std::string & texname, unsigned domain)
103  : symbol(initname, texname, domain) { }
104
105 //////////
106 // archiving
107 //////////
108
109 /** Construct object from archive_node. */
110 symbol::symbol(const archive_node &n, lst &sym_lst)
111  : inherited(n, sym_lst), serial(next_serial++)
112 {
113         if (!n.find_string("name", name))
114                 name = std::string("");
115         if (!n.find_string("TeXname", TeX_name))
116                 TeX_name = std::string("");
117         if (!n.find_unsigned("domain", domain))
118                 domain = domain::complex;
119         setflag(status_flags::evaluated | status_flags::expanded);
120 }
121
122 /** Unarchive the object. */
123 ex symbol::unarchive(const archive_node &n, lst &sym_lst)
124 {
125         ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
126
127         // If symbol is in sym_lst, return the existing symbol
128         for (lst::const_iterator it = sym_lst.begin(); it != sym_lst.end(); ++it) {
129                 if (is_a<symbol>(*it) && (ex_to<symbol>(*it).name == ex_to<symbol>(s).name))
130                         return *it;
131         }
132
133         // Otherwise add new symbol to list and return it
134         sym_lst.append(s);
135         return s;
136 }
137
138 /** Archive the object. */
139 void symbol::archive(archive_node &n) const
140 {
141         inherited::archive(n);
142         // XXX: we should not archive anonymous symbols.
143         if (!name.empty())
144                 n.add_string("name", name);
145         if (!TeX_name.empty())
146                 n.add_string("TeX_name", TeX_name);
147         if (domain != domain::complex)
148                 n.add_unsigned("domain", domain);
149 }
150
151 //////////
152 // functions overriding virtual functions from base classes
153 //////////
154
155 /** Return default TeX name for symbol. This recognizes some greek letters. */
156 static const std::string& get_default_TeX_name(const std::string& name);
157
158 // public
159
160 void symbol::do_print(const print_context & c, unsigned level) const
161 {
162         if (!name.empty())
163                 c.s << name;
164         else
165                 c.s << "symbol" << serial;
166 }
167
168 void symbol::do_print_latex(const print_latex & c, unsigned level) const
169 {
170         if (!TeX_name.empty())
171                 c.s << TeX_name;
172         else if (!name.empty())
173                 c.s << get_default_TeX_name(name);
174         else
175                 c.s << "symbol" << serial;
176 }
177
178 void symbol::do_print_tree(const print_tree & c, unsigned level) const
179 {
180         c.s << std::string(level, ' ') << name << " (" << class_name() << ")" << " @" << this
181             << ", serial=" << serial
182             << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
183             << ", domain=" << domain
184             << std::endl;
185 }
186
187 void symbol::do_print_python_repr(const print_python_repr & c, unsigned level) const
188 {
189         c.s << class_name() << "('";
190         if (!name.empty())
191                 c.s << name;
192         else
193                 c.s << "symbol" << serial;
194         if (!TeX_name.empty())
195                 c.s << "','" << TeX_name;
196         c.s << "')";
197 }
198
199 bool symbol::info(unsigned inf) const
200 {
201         switch (inf) {
202                 case info_flags::symbol:
203                 case info_flags::polynomial:
204                 case info_flags::integer_polynomial: 
205                 case info_flags::cinteger_polynomial: 
206                 case info_flags::rational_polynomial: 
207                 case info_flags::crational_polynomial: 
208                 case info_flags::rational_function: 
209                 case info_flags::expanded:
210                         return true;
211                 case info_flags::real:
212                         return domain == domain::real || domain == domain::positive;
213                 case info_flags::positive:
214                 case info_flags::nonnegative:
215                         return domain == domain::positive;
216                 case info_flags::has_indices:
217                         return false;
218         }
219         return inherited::info(inf);
220 }
221
222 ex symbol::conjugate() const
223 {
224         if (this->domain == domain::complex) {
225                 return conjugate_function(*this).hold();
226         } else {
227                 return *this;
228         }
229 }
230
231 ex symbol::real_part() const
232 {
233         if (domain==domain::real || domain==domain::positive)
234                 return *this;
235         return real_part_function(*this).hold();
236 }
237
238 ex symbol::imag_part() const
239 {
240         if (domain==domain::real || domain==domain::positive)
241                 return 0;
242         return imag_part_function(*this).hold();
243 }
244
245 bool symbol::is_polynomial(const ex & var) const
246 {
247         return true;
248 }
249
250 // protected
251
252 /** Implementation of ex::diff() for single differentiation of a symbol.
253  *  It returns 1 or 0.
254  *
255  *  @see ex::diff */
256 ex symbol::derivative(const symbol & s) const
257 {
258         if (compare_same_type(s))
259                 return _ex0;
260         else
261                 return _ex1;
262 }
263
264 int symbol::compare_same_type(const basic & other) const
265 {
266         GINAC_ASSERT(is_a<symbol>(other));
267         const symbol *o = static_cast<const symbol *>(&other);
268         if (serial==o->serial) return 0;
269         return serial < o->serial ? -1 : 1;
270 }
271
272 bool symbol::is_equal_same_type(const basic & other) const
273 {
274         GINAC_ASSERT(is_a<symbol>(other));
275         const symbol *o = static_cast<const symbol *>(&other);
276         return serial==o->serial;
277 }
278
279 unsigned symbol::calchash() const
280 {
281         const void* this_tinfo = (const void*)typeid(*this).name();
282         hashvalue = golden_ratio_hash((p_int)this_tinfo ^ serial);
283         setflag(status_flags::hash_calculated);
284         return hashvalue;
285 }
286
287 //////////
288 // virtual functions which can be overridden by derived classes
289 //////////
290
291 // none
292
293 //////////
294 // non-virtual functions in this class
295 //////////
296
297 /** Return default TeX name for symbol. This recognizes some greek letters. */
298 static const std::string& get_default_TeX_name(const std::string& name)
299 {
300         static std::map<std::string, std::string> standard_names;
301         static bool names_initialized = false;
302         if (!names_initialized) {
303                 standard_names["alpha"] = std::string("\\alpha");
304                 standard_names["beta"] = std::string("\\beta");;
305                 standard_names["gamma"] = std::string("\\gamma");;
306                 standard_names["delta"] = std::string("\\delta");;
307                 standard_names["epsilon"] = std::string("\\epsilon");
308                 standard_names["varepsilon"] = std::string("\\varepsilon");
309                 standard_names["zeta"] = std::string("\\zeta");
310                 standard_names["eta" ] = std::string("\\eta" );
311                 standard_names["theta"] = std::string("\\theta");
312                 standard_names["vartheta"] = std::string("\\vartheta");
313                 standard_names["iota"] = std::string("\\iota");
314                 standard_names["kappa"] = std::string("\\kappa");
315                 standard_names["lambda"] = std::string("\\lambda");
316                 standard_names["mu"] = std::string("\\mu");
317                 standard_names["nu"] = std::string("\\nu");
318                 standard_names["xi"] = std::string("\\xi");
319                 standard_names["omicron"] = std::string("\\omicron");
320                 standard_names["pi"] = std::string("\\pi");
321                 standard_names["varpi"] = std::string("\\varpi");
322                 standard_names["rho"] = std::string("\\rho");
323                 standard_names["varrho"] = std::string("\\varrho");
324                 standard_names["sigma"] = std::string("\\sigma");
325                 standard_names["varsigma"] = std::string("\\varsigma");
326                 standard_names["tau"] = std::string("\\tau");
327                 standard_names["upsilon"] = std::string("\\upsilon");
328                 standard_names["phi"] = std::string("\\phi");
329                 standard_names["varphi"] = std::string("\\varphi");
330                 standard_names["chi"] = std::string("\\chi");
331                 standard_names["psi"] = std::string("\\psi");
332                 standard_names["omega"] = std::string("\\omega");
333                 standard_names["Gamma"] = std::string("\\Gamma");
334                 standard_names["Delta"] = std::string("\\Delta");
335                 standard_names["Theta"] = std::string("\\Theta");
336                 standard_names["Lambda"] = std::string("\\Lambda");
337                 standard_names["Xi"] = std::string("\\Xi");
338                 standard_names["Pi"] = std::string("\\Pi");
339                 standard_names["Sigma"] = std::string("\\Sigma");
340                 standard_names["Upsilon"] = std::string("\\Upsilon");
341                 standard_names["Phi"] = std::string("\\Phi");
342                 standard_names["Psi"] = std::string("\\Psi");
343                 standard_names["Omega"] = std::string("\\Omega");
344                 names_initialized = true;
345         }
346         std::map<std::string, std::string>::const_iterator it = standard_names.find(name);
347         if (it != standard_names.end())
348                 return it->second;
349         else
350                 return name;
351 }
352
353 //////////
354 // static member variables
355 //////////
356
357 // private
358
359 unsigned symbol::next_serial = 0;
360
361 } // namespace GiNaC