- Cleanups: My evil plot of making ex::bp private may finally be carried
[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 "print.h"
28 #include "archive.h"
29 #include "utils.h"
30 #include "debugmsg.h"
31
32 namespace GiNaC {
33
34 GINAC_IMPLEMENT_REGISTERED_CLASS(relational, basic)
35
36 //////////
37 // default ctor, dtor, copy ctor assignment operator and helpers
38 //////////
39
40 relational::relational() : basic(TINFO_relational)
41 {
42         debugmsg("relational default ctor",LOGLEVEL_CONSTRUCT);
43 }
44
45 void relational::copy(const relational & other)
46 {
47         basic::copy(other);
48         lh=other.lh;
49         rh=other.rh;
50         o=other.o;
51 }
52
53 DEFAULT_DESTROY(relational)
54
55 //////////
56 // other ctors
57 //////////
58
59 // public
60
61 relational::relational(const ex & lhs, const ex & rhs, operators oper) : basic(TINFO_relational)
62 {
63         debugmsg("relational ctor ex,ex,operator",LOGLEVEL_CONSTRUCT);
64         lh=lhs;
65         rh=rhs;
66         o=oper;
67 }
68
69 //////////
70 // archiving
71 //////////
72
73 relational::relational(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
74 {
75         debugmsg("relational ctor from archive_node", LOGLEVEL_CONSTRUCT);
76         unsigned int opi;
77         if (!(n.find_unsigned("op", opi)))
78                 throw (std::runtime_error("unknown relational operator in archive"));
79         o = (operators)opi;
80         n.find_ex("lh", lh, sym_lst);
81         n.find_ex("rh", rh, sym_lst);
82 }
83
84 void relational::archive(archive_node &n) const
85 {
86         inherited::archive(n);
87         n.add_ex("lh", lh);
88         n.add_ex("rh", rh);
89         n.add_unsigned("op", o);
90 }
91
92 DEFAULT_UNARCHIVE(relational)
93
94 //////////
95 // functions overriding virtual functions from base classes
96 //////////
97
98 // public
99
100 void relational::print(const print_context & c, unsigned level) const
101 {
102         debugmsg("relational print",LOGLEVEL_PRINT);
103
104         if (is_a<print_tree>(c)) {
105
106                 inherited::print(c, level);
107
108         } else {
109
110                 if (precedence() <= level)
111                         c.s << "(";
112                 lh.print(c, precedence());
113                 switch (o) {
114                 case equal:
115                         c.s << "==";
116                         break;
117                 case not_equal:
118                         c.s << "!=";
119                         break;
120                 case less:
121                         c.s << "<";
122                         break;
123                 case less_or_equal:
124                         c.s << "<=";
125                         break;
126                 case greater:
127                         c.s << ">";
128                         break;
129                 case greater_or_equal:
130                         c.s << ">=";
131                         break;
132                 default:
133                         c.s << "(INVALID RELATIONAL OPERATOR)";
134                 }
135                 rh.print(c, precedence());
136                 if (precedence() <= level)
137                         c.s << ")";
138         }
139 }
140
141 bool relational::info(unsigned inf) const
142 {
143         switch (inf) {
144         case info_flags::relation:
145                 return 1;
146         case info_flags::relation_equal:
147                 return o==equal;
148         case info_flags::relation_not_equal:
149                 return o==not_equal;
150         case info_flags::relation_less:
151                 return o==less;
152         case info_flags::relation_less_or_equal:
153                 return o==less_or_equal;
154         case info_flags::relation_greater:
155                 return o==greater;
156         case info_flags::relation_greater_or_equal:
157                 return o==greater_or_equal;
158         }
159         return 0;
160 }
161
162 unsigned relational::nops() const
163 {
164         return 2;
165 }
166
167 ex & relational::let_op(int i)
168 {
169         GINAC_ASSERT(i>=0);
170         GINAC_ASSERT(i<2);
171
172         return i==0 ? lh : rh;
173 }
174
175 ex relational::eval(int level) const
176 {
177         if (level==1)
178                 return this->hold();
179         
180         if (level == -max_recursion_level)
181                 throw(std::runtime_error("max recursion level reached"));
182         
183         return (new relational(lh.eval(level-1),rh.eval(level-1),o))->setflag(status_flags::dynallocated | status_flags::evaluated);
184 }
185
186 ex relational::simplify_ncmul(const exvector & v) const
187 {
188         return lh.simplify_ncmul(v);
189 }
190
191 // protected
192
193 int relational::compare_same_type(const basic & other) const
194 {
195         GINAC_ASSERT(is_exactly_a<relational>(other));
196         const relational &oth = static_cast<const relational &>(other);
197         
198         if (o == oth.o) {
199                 int cmpval = lh.compare(oth.lh);
200                 if (cmpval)
201                         return cmpval;
202                 else
203                         return rh.compare(oth.rh);
204         }
205         return (o < oth.o) ? -1 : 1;
206 }
207
208 bool relational::match_same_type(const basic & other) const
209 {
210         GINAC_ASSERT(is_exactly_a<relational>(other));
211         const relational &oth = static_cast<const relational &>(other);
212
213         return o == oth.o;
214 }
215
216 unsigned relational::return_type(void) const
217 {
218         GINAC_ASSERT(lh.return_type()==rh.return_type());
219         return lh.return_type();
220 }
221    
222 unsigned relational::return_type_tinfo(void) const
223 {
224         GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
225         return lh.return_type_tinfo();
226 }
227
228 //////////
229 // new virtual functions which can be overridden by derived classes
230 //////////
231
232 /** Left hand side of relational. */
233 ex relational::lhs(void) const
234 {
235         return lh;
236 }
237
238 /** Right hand side of relational. */
239 ex relational::rhs(void) const
240 {
241         return rh;    
242 }
243
244 //////////
245 // non-virtual functions in this class
246 //////////
247
248 /** Cast the relational into a boolean, mainly for evaluation within an 
249  *  if-statement.  Note that (a<b) == false does not imply (a>=b) == true in
250  *  the general symbolic case.  A false result means the comparison is either
251  *  false or undecidable (except of course for !=, where true means either
252  *  unequal or undecidable). */
253 relational::operator bool() const
254 {
255         const ex df = lh-rh;
256         if (!is_ex_exactly_of_type(df,numeric))
257                 // cannot decide on non-numerical results
258                 return o==not_equal ? true : false;
259         
260         switch (o) {
261         case equal:
262                 return ex_to<numeric>(df).is_zero();
263         case not_equal:
264                 return !ex_to<numeric>(df).is_zero();
265         case less:
266                 return ex_to<numeric>(df)<_num0();
267         case less_or_equal:
268                 return ex_to<numeric>(df)<=_num0();
269         case greater:
270                 return ex_to<numeric>(df)>_num0();
271         case greater_or_equal:
272                 return ex_to<numeric>(df)>=_num0();
273         default:
274                 throw(std::logic_error("invalid relational operator"));
275         }
276 }
277
278 } // namespace GiNaC