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