1cce02d977fa5018ae8061759251c8f788711622
[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
28 //////////
29 // default constructor, destructor, copy constructor assignment operator and helpers
30 //////////
31
32 // public
33
34 relational::relational() : basic(TINFO_relational)
35 {
36     debugmsg("relational default constructor",LOGLEVEL_CONSTRUCT);
37 }
38
39 relational::~relational()
40 {
41     debugmsg("relational destructor",LOGLEVEL_DESTRUCT);
42     destroy(0);
43 }
44
45 relational::relational(relational const & other)
46 {
47     debugmsg("relational copy constructor",LOGLEVEL_CONSTRUCT);
48     copy(other);
49 }
50
51 relational const & relational::operator=(relational const & other)
52 {
53     debugmsg("relational operator=",LOGLEVEL_ASSIGNMENT);
54     if (this != &other) {
55         destroy(1);
56         copy(other);
57     }
58     return *this;
59 }
60
61 // protected
62
63 void relational::copy(relational const & other)
64 {
65     basic::copy(other);
66     lh=other.lh;
67     rh=other.rh;
68     o=other.o;
69 }
70
71 void relational::destroy(bool call_parent)
72 {
73     if (call_parent) basic::destroy(call_parent);
74 }
75
76 //////////
77 // other constructors
78 //////////
79
80 // public
81
82 relational::relational(ex const & lhs, ex const & rhs, operators oper) : basic(TINFO_relational)
83 {
84     debugmsg("relational constructor ex,ex,operator",LOGLEVEL_CONSTRUCT);
85     lh=lhs;
86     rh=rhs;
87     o=oper;
88 }
89
90 //////////
91 // functions overriding virtual functions from bases classes
92 //////////
93
94 // public
95
96 basic * relational::duplicate() const
97 {
98     debugmsg("relational duplicate",LOGLEVEL_DUPLICATE);
99     return new relational(*this);
100 }
101
102 bool relational::info(unsigned inf) const
103 {
104     switch (inf) {
105     case info_flags::relation:
106         return 1;
107     case info_flags::relation_equal:
108         return o==equal;
109     case info_flags::relation_not_equal:
110         return o==not_equal;
111     case info_flags::relation_less:
112         return o==less;
113     case info_flags::relation_less_or_equal:
114         return o==less_or_equal;
115     case info_flags::relation_greater:
116         return o==greater;
117     case info_flags::relation_greater_or_equal:
118         return o==greater_or_equal;
119     }
120     return 0;
121 }
122
123 int relational::nops() const
124 {
125     return 2;
126 }
127
128 ex & relational::let_op(int const i)
129 {
130     ASSERT(i>=0);
131     ASSERT(i<2);
132
133     return i==0 ? lh : rh;
134 }
135     
136 ex relational::eval(int level) const
137 {
138     if (level==1) {
139         return this->hold();
140     }
141     if (level == -max_recursion_level) {
142         throw(std::runtime_error("max recursion level reached"));
143     }
144     return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
145             setflag(status_flags::dynallocated  |
146                     status_flags::evaluated );
147 }
148
149 ex relational::evalf(int level) const
150 {
151     if (level==1) {
152         return *this;
153     }
154     if (level == -max_recursion_level) {
155         throw(std::runtime_error("max recursion level reached"));
156     }
157     return (new relational(lh.eval(level-1),rh.eval(level-1),o))->
158             setflag(status_flags::dynallocated);
159 }
160
161 ex relational::simplify_ncmul(exvector const & v) const
162 {
163     return lh.simplify_ncmul(v);
164 }
165
166 // protected
167
168 int relational::compare_same_type(basic const & other) const
169 {
170     ASSERT(is_exactly_of_type(other, relational));
171     relational const & oth=static_cast<relational const &>(const_cast<basic &>(other));
172     
173     int cmpval;
174     
175     if (o == oth.o) {
176         cmpval=lh.compare(oth.lh);
177         if (cmpval==0) {
178             return rh.compare(oth.rh);
179         } else {
180             return cmpval;
181         }
182     }
183     if (o<oth.o) {
184         return -1;
185     } else {
186         return 1;
187     }
188 }
189
190 unsigned relational::return_type(void) const
191 {
192     ASSERT(lh.return_type()==rh.return_type());
193     return lh.return_type();
194 }
195    
196 unsigned relational::return_type_tinfo(void) const
197 {
198     ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
199     return lh.return_type_tinfo();
200 }
201
202 //////////
203 // new virtual functions which can be overridden by derived classes
204 //////////
205
206 // none
207
208 //////////
209 // non-virtual functions in this class
210 //////////
211
212 #include <iostream>
213
214 relational::operator bool() const
215 {
216     // please note that (a<b) == false does not imply (a>=b) == true
217     // a false result means the comparison is either false or undecidable
218     // (except for !=, where true means unequal or undecidable)
219     ex df=lh-rh;
220     if (!is_ex_exactly_of_type(df,numeric)) {
221         return o==not_equal ? true : false; // cannot decide on non-numerical results
222     }
223     int cmpval=ex_to_numeric(df).compare(numZERO());
224     switch (o) {
225     case equal:
226         return cmpval==0;
227         break;
228     case not_equal:
229         return cmpval!=0;
230         break;
231     case less:
232         return cmpval<0;
233         break;
234     case less_or_equal:
235         return cmpval<=0;
236         break;
237     case greater:
238         return cmpval>0;
239         break;
240     case greater_or_equal:
241         return cmpval>=0;
242         break;
243     default:
244         throw(std::logic_error("invalid relational operator"));
245     }
246     return 0;
247 }
248
249 //////////
250 // static member variables
251 //////////
252
253 // protected
254
255 unsigned relational::precedence=20;
256
257 //////////
258 // global constants
259 //////////
260
261 const relational some_relational;
262 type_info const & typeid_relational=typeid(some_relational);
263