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