GINAC_DECLARE_REGISTERED_CLASS declares duplicate() and compare_same_type(),
[ginac.git] / ginac / relational.cpp
1 /** @file relational.cpp
2  *
3  *  Implementation of relations between expressions */
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 <stdexcept>
24
25 #include "relational.h"
26 #include "numeric.h"
27 #include "archive.h"
28 #include "utils.h"
29 #include "debugmsg.h"
30
31 #ifndef NO_NAMESPACE_GINAC
32 namespace GiNaC {
33 #endif // ndef NO_NAMESPACE_GINAC
34
35 GINAC_IMPLEMENT_REGISTERED_CLASS(relational, basic)
36
37 //////////
38 // default constructor, destructor, copy constructor assignment operator and helpers
39 //////////
40
41 // public
42
43 relational::relational() : basic(TINFO_relational)
44 {
45         debugmsg("relational default constructor",LOGLEVEL_CONSTRUCT);
46 }
47
48 // protected
49
50 void relational::copy(const relational & other)
51 {
52         basic::copy(other);
53         lh=other.lh;
54         rh=other.rh;
55         o=other.o;
56 }
57
58 void relational::destroy(bool call_parent)
59 {
60         if (call_parent) basic::destroy(call_parent);
61 }
62
63 //////////
64 // other constructors
65 //////////
66
67 // public
68
69 relational::relational(const ex & lhs, const ex & rhs, operators oper) : basic(TINFO_relational)
70 {
71         debugmsg("relational constructor ex,ex,operator",LOGLEVEL_CONSTRUCT);
72         lh=lhs;
73         rh=rhs;
74         o=oper;
75 }
76
77 //////////
78 // archiving
79 //////////
80
81 /** Construct object from archive_node. */
82 relational::relational(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
83 {
84         debugmsg("relational constructor from archive_node", LOGLEVEL_CONSTRUCT);
85         unsigned int opi;
86         if (!(n.find_unsigned("op", opi)))
87                 throw (std::runtime_error("unknown relational operator in archive"));
88         o = (operators)opi;
89         n.find_ex("lh", lh, sym_lst);
90         n.find_ex("rh", rh, sym_lst);
91 }
92
93 /** Unarchive the object. */
94 ex relational::unarchive(const archive_node &n, const lst &sym_lst)
95 {
96         return (new relational(n, sym_lst))->setflag(status_flags::dynallocated);
97 }
98
99 /** Archive the object. */
100 void relational::archive(archive_node &n) const
101 {
102         inherited::archive(n);
103         n.add_ex("lh", lh);
104         n.add_ex("rh", rh);
105         n.add_unsigned("op", o);
106 }
107
108 //////////
109 // functions overriding virtual functions from bases classes
110 //////////
111
112 // public
113
114 void relational::print(std::ostream & os, unsigned upper_precedence) const
115 {
116         debugmsg("relational print",LOGLEVEL_PRINT);
117         if (precedence<=upper_precedence) os << "(";
118         lh.print(os,precedence);
119         switch (o) {
120         case equal:
121                 os << "==";
122                 break;
123         case not_equal:
124                 os << "!=";
125                 break;
126         case less:
127                 os << "<";
128                 break;
129         case less_or_equal:
130                 os << "<=";
131                 break;
132         case greater:
133                 os << ">";
134                 break;
135         case greater_or_equal:
136                 os << ">=";
137                 break;
138         default:
139                 os << "(INVALID RELATIONAL OPERATOR)";
140         }
141         rh.print(os,precedence);
142         if (precedence<=upper_precedence) os << ")";
143 }
144
145 void relational::printraw(std::ostream & os) const
146 {
147         debugmsg("relational printraw",LOGLEVEL_PRINT);
148         os << "RELATIONAL(";
149         lh.printraw(os);
150         os << ",";
151         rh.printraw(os);
152         os << ",";
153         switch (o) {
154         case equal:
155                 os << "==";
156                 break;
157         case not_equal:
158                 os << "!=";
159                 break;
160         case less:
161                 os << "<";
162                 break;
163         case less_or_equal:
164                 os << "<=";
165                 break;
166         case greater:
167                 os << ">";
168                 break;
169         case greater_or_equal:
170                 os << ">=";
171                 break;
172         default:
173                 os << "(INVALID RELATIONAL OPERATOR)";
174         }
175         os << ")";
176 }
177
178 void relational::printcsrc(std::ostream & os, unsigned type, unsigned upper_precedence) const
179 {
180         debugmsg("relational print csrc", LOGLEVEL_PRINT);
181         if (precedence<=upper_precedence)
182                 os << "(";
183
184         // Print left-hand expression
185         lh.bp->printcsrc(os, type, precedence);
186
187         // Print relational operator
188         switch (o) {
189                 case equal:
190                         os << "==";
191                         break;
192                 case not_equal:
193                         os << "!=";
194                         break;
195                 case less:
196                         os << "<";
197                         break;
198                 case less_or_equal:
199                         os << "<=";
200                         break;
201                 case greater:
202                         os << ">";
203                         break;
204                 case greater_or_equal:
205                         os << ">=";
206                         break;
207                 default:
208                         os << "(INVALID RELATIONAL OPERATOR)";
209                         break;
210         }
211
212         // Print right-hand operator
213         rh.bp->printcsrc(os, type, precedence);
214
215         if (precedence <= upper_precedence)
216                 os << ")";
217 }
218
219 bool relational::info(unsigned inf) const
220 {
221         switch (inf) {
222         case info_flags::relation:
223                 return 1;
224         case info_flags::relation_equal:
225                 return o==equal;
226         case info_flags::relation_not_equal:
227                 return o==not_equal;
228         case info_flags::relation_less:
229                 return o==less;
230         case info_flags::relation_less_or_equal:
231                 return o==less_or_equal;
232         case info_flags::relation_greater:
233                 return o==greater;
234         case info_flags::relation_greater_or_equal:
235                 return o==greater_or_equal;
236         }
237         return 0;
238 }
239
240 unsigned relational::nops() const
241 {
242         return 2;
243 }
244
245 ex & relational::let_op(int i)
246 {
247         GINAC_ASSERT(i>=0);
248         GINAC_ASSERT(i<2);
249
250         return i==0 ? lh : rh;
251 }
252         
253 ex relational::eval(int level) const
254 {
255         if (level==1) {
256                 return this->hold();
257         }
258         if (level == -max_recursion_level) {
259                 throw(std::runtime_error("max recursion level reached"));
260         }
261         return (new relational(lh.eval(level-1),rh.eval(level-1),o))->setflag(status_flags::dynallocated | status_flags::evaluated);
262 }
263
264 ex relational::evalf(int level) const
265 {
266         if (level==1)
267                 return *this;
268         
269         if (level==-max_recursion_level)
270                 throw(std::runtime_error("max recursion level reached"));
271         
272         return (new relational(lh.eval(level-1),rh.eval(level-1),o))->setflag(status_flags::dynallocated);
273 }
274
275 ex relational::simplify_ncmul(const exvector & v) const
276 {
277         return lh.simplify_ncmul(v);
278 }
279
280 // protected
281
282 int relational::compare_same_type(const basic & other) const
283 {
284         GINAC_ASSERT(is_exactly_of_type(other, relational));
285         const relational & oth=static_cast<const relational &>(const_cast<basic &>(other));
286         
287         int cmpval;
288         
289         if (o == oth.o) {
290                 cmpval = lh.compare(oth.lh);
291                 if (cmpval==0)
292                         return rh.compare(oth.rh);
293                 else
294                         return cmpval;
295         }
296         if (o<oth.o)
297                 return -1;
298         else
299                 return 1;
300 }
301
302 unsigned relational::return_type(void) const
303 {
304         GINAC_ASSERT(lh.return_type()==rh.return_type());
305         return lh.return_type();
306 }
307    
308 unsigned relational::return_type_tinfo(void) const
309 {
310         GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
311         return lh.return_type_tinfo();
312 }
313
314 //////////
315 // new virtual functions which can be overridden by derived classes
316 //////////
317
318 /** Left hand side of relational. */
319 ex relational::lhs(void) const
320 {
321         return lh;
322 }
323
324 /** Right hand side of relational. */
325 ex relational::rhs(void) const
326 {
327         return rh;    
328 }
329
330 //////////
331 // non-virtual functions in this class
332 //////////
333
334 relational::operator bool() const
335 {
336         // please note that (a<b) == false does not imply (a>=b) == true
337         // a false result means the comparison is either false or undecidable
338         // (except for !=, where true means unequal or undecidable)
339         ex df = lh-rh;
340         if (!is_ex_exactly_of_type(df,numeric))
341                 // cannot decide on non-numerical results
342                 return o==not_equal ? true : false;
343         
344         int cmpval = ex_to_numeric(df).compare(_num0());
345         switch (o) {
346         case equal:
347                 return cmpval==0;
348         case not_equal:
349                 return cmpval!=0;
350         case less:
351                 return cmpval<0;
352         case less_or_equal:
353                 return cmpval<=0;
354         case greater:
355                 return cmpval>0;
356         case greater_or_equal:
357                 return cmpval>=0;
358         default:
359                 throw(std::logic_error("invalid relational operator"));
360         }
361 }
362
363 //////////
364 // static member variables
365 //////////
366
367 // protected
368
369 unsigned relational::precedence=20;
370
371 #ifndef NO_NAMESPACE_GINAC
372 } // namespace GiNaC
373 #endif // ndef NO_NAMESPACE_GINAC