GiNaC  1.6.2
relational.cpp
Go to the documentation of this file.
00001 
00005 /*
00006  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022 
00023 #include "relational.h"
00024 #include "operators.h"
00025 #include "numeric.h"
00026 #include "archive.h"
00027 #include "utils.h"
00028 #include "hash_seed.h"
00029 
00030 #include <iostream>
00031 #include <stdexcept>
00032 
00033 namespace GiNaC {
00034 
00035 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(relational, basic,
00036   print_func<print_context>(&relational::do_print).
00037   print_func<print_tree>(&relational::do_print_tree).
00038   print_func<print_python_repr>(&relational::do_print_python_repr))
00039 
00040 
00041 // default constructor
00043 
00044 relational::relational() { }
00045 
00047 // other constructors
00049 
00050 // public
00051 
00052 relational::relational(const ex & lhs, const ex & rhs, operators oper) :
00053     lh(lhs), rh(rhs), o(oper) { }
00054 
00056 // archiving
00058 
00059 void relational::read_archive(const archive_node& n, lst& sym_lst)
00060 {
00061     inherited::read_archive(n, sym_lst);
00062     unsigned int opi;
00063     if (!(n.find_unsigned("op", opi)))
00064         throw (std::runtime_error("unknown relational operator in archive"));
00065     o = (operators)opi;
00066     n.find_ex("lh", lh, sym_lst);
00067     n.find_ex("rh", rh, sym_lst);
00068 }
00069 GINAC_BIND_UNARCHIVER(relational);
00070 
00071 void relational::archive(archive_node &n) const
00072 {
00073     inherited::archive(n);
00074     n.add_ex("lh", lh);
00075     n.add_ex("rh", rh);
00076     n.add_unsigned("op", o);
00077 }
00078 
00080 // functions overriding virtual functions from base classes
00082 
00083 // public
00084 
00085 static void print_operator(const print_context & c, relational::operators o)
00086 {
00087     switch (o) {
00088     case relational::equal:
00089         c.s << "==";
00090         break;
00091     case relational::not_equal:
00092         c.s << "!=";
00093         break;
00094     case relational::less:
00095         c.s << "<";
00096         break;
00097     case relational::less_or_equal:
00098         c.s << "<=";
00099         break;
00100     case relational::greater:
00101         c.s << ">";
00102         break;
00103     case relational::greater_or_equal:
00104         c.s << ">=";
00105         break;
00106     default:
00107         c.s << "(INVALID RELATIONAL OPERATOR)";
00108         break;
00109     }
00110 }
00111 
00112 void relational::do_print(const print_context & c, unsigned level) const
00113 {
00114     if (precedence() <= level)
00115         c.s << "(";
00116     lh.print(c, precedence());
00117     print_operator(c, o);
00118     rh.print(c, precedence());
00119     if (precedence() <= level)
00120         c.s << ")";
00121 }
00122 
00123 void relational::do_print_python_repr(const print_python_repr & c, unsigned level) const
00124 {
00125     c.s << class_name() << '(';
00126     lh.print(c);
00127     c.s << ',';
00128     rh.print(c);
00129     c.s << ",'";
00130     print_operator(c, o);
00131     c.s << "')";
00132 }
00133 
00134 bool relational::info(unsigned inf) const
00135 {
00136     switch (inf) {
00137         case info_flags::relation:
00138             return 1;
00139         case info_flags::relation_equal:
00140             return o==equal;
00141         case info_flags::relation_not_equal:
00142             return o==not_equal;
00143         case info_flags::relation_less:
00144             return o==less;
00145         case info_flags::relation_less_or_equal:
00146             return o==less_or_equal;
00147         case info_flags::relation_greater:
00148             return o==greater;
00149         case info_flags::relation_greater_or_equal:
00150             return o==greater_or_equal;
00151     }
00152     return 0;
00153 }
00154 
00155 size_t relational::nops() const
00156 {
00157     return 2;
00158 }
00159 
00160 ex relational::op(size_t i) const
00161 {
00162     GINAC_ASSERT(i<2);
00163 
00164     return i==0 ? lh : rh;
00165 }
00166 
00167 ex relational::map(map_function & f) const
00168 {
00169     const ex &mapped_lh = f(lh);
00170     const ex &mapped_rh = f(rh);
00171 
00172     if (!are_ex_trivially_equal(lh, mapped_lh)
00173      || !are_ex_trivially_equal(rh, mapped_rh))
00174         return (new relational(mapped_lh, mapped_rh, o))->setflag(status_flags::dynallocated);
00175     else
00176         return *this;
00177 }
00178 
00179 ex relational::eval(int level) const
00180 {
00181     if (level==1)
00182         return this->hold();
00183     
00184     if (level == -max_recursion_level)
00185         throw(std::runtime_error("max recursion level reached"));
00186     
00187     return (new relational(lh.eval(level-1),rh.eval(level-1),o))->setflag(status_flags::dynallocated | status_flags::evaluated);
00188 }
00189 
00190 ex relational::subs(const exmap & m, unsigned options) const
00191 {
00192     const ex & subsed_lh = lh.subs(m, options);
00193     const ex & subsed_rh = rh.subs(m, options);
00194 
00195     if (!are_ex_trivially_equal(lh, subsed_lh) || !are_ex_trivially_equal(rh, subsed_rh))
00196         return relational(subsed_lh, subsed_rh, o).subs_one_level(m, options);
00197     else
00198         return subs_one_level(m, options);
00199 }
00200 
00201 ex relational::eval_ncmul(const exvector & v) const
00202 {
00203     return lh.eval_ncmul(v);
00204 }
00205 
00206 // protected
00207 
00208 int relational::compare_same_type(const basic & other) const
00209 {
00210     GINAC_ASSERT(is_exactly_a<relational>(other));
00211     const relational &oth = static_cast<const relational &>(other);
00212     if (o==oth.o && lh.is_equal(oth.lh) && rh.is_equal(oth.rh))
00213         return 0;
00214     switch (o) {
00215         case equal:
00216         case not_equal:
00217             if (oth.o!=o)
00218                 return (o < oth.o) ? -1 : 1;
00219             break;
00220         case less:
00221             if (oth.o!=greater)
00222                 return (o < oth.o) ? -1 : 1;
00223             break;
00224         case less_or_equal:
00225             if (oth.o!=greater_or_equal)
00226                 return (o < oth.o) ? -1 : 1;
00227             break;
00228         case greater:
00229             if (oth.o!=less)
00230                 return (o < oth.o) ? -1 : 1;
00231             break;
00232         case greater_or_equal:
00233             if (oth.o!=less_or_equal)
00234                 return (o < oth.o) ? -1 : 1;
00235             break;
00236     }
00237     const int lcmpval = lh.compare(oth.rh);
00238     return (lcmpval!=0) ? lcmpval : rh.compare(oth.lh);
00239 }
00240 
00241 bool relational::match_same_type(const basic & other) const
00242 {
00243     GINAC_ASSERT(is_exactly_a<relational>(other));
00244     const relational &oth = static_cast<const relational &>(other);
00245 
00246     return o == oth.o;
00247 }
00248 
00249 unsigned relational::return_type() const
00250 {
00251     GINAC_ASSERT(lh.return_type()==rh.return_type());
00252     return lh.return_type();
00253 }
00254    
00255 return_type_t relational::return_type_tinfo() const
00256 {
00257     GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
00258     return lh.return_type_tinfo();
00259 }
00260 
00261 unsigned relational::calchash() const
00262 {
00263     unsigned v = make_hash_seed(typeid(*this));
00264     unsigned lhash = lh.gethash();
00265     unsigned rhash = rh.gethash();
00266 
00267     v = rotate_left(v);
00268     switch(o) {
00269         case equal:
00270         case not_equal:
00271             if (lhash>rhash) {
00272                 v ^= lhash;
00273                 lhash = rhash;
00274             } else {
00275                 v ^= rhash;
00276             }
00277             break;
00278         case less:
00279         case less_or_equal:
00280             v ^= rhash;
00281             break;
00282         case greater:
00283         case greater_or_equal:
00284             v ^= lhash;
00285             lhash = rhash;
00286             break;
00287     }
00288     v = rotate_left(v);
00289     v ^= lhash;
00290 
00291     // store calculated hash value only if object is already evaluated
00292     if (flags & status_flags::evaluated) {
00293         setflag(status_flags::hash_calculated);
00294         hashvalue = v;
00295     }
00296 
00297     return v;
00298 }
00299 
00301 // new virtual functions which can be overridden by derived classes
00303 
00305 ex relational::lhs() const
00306 {
00307     return lh;
00308 }
00309 
00311 ex relational::rhs() const
00312 {
00313     return rh;    
00314 }
00315 
00317 // non-virtual functions in this class
00319 
00320 relational::safe_bool relational::make_safe_bool(bool cond) const
00321 {
00322     return cond? &safe_bool_helper::nonnull : 0;
00323 }
00324 
00330 relational::operator relational::safe_bool() const
00331 {
00332     const ex df = lh-rh;
00333     if (!is_exactly_a<numeric>(df))
00334         // cannot decide on non-numerical results
00335         return o==not_equal ? make_safe_bool(true) : make_safe_bool(false);
00336 
00337     switch (o) {
00338         case equal:
00339             return make_safe_bool(ex_to<numeric>(df).is_zero());
00340         case not_equal:
00341             return make_safe_bool(!ex_to<numeric>(df).is_zero());
00342         case less:
00343             return make_safe_bool(ex_to<numeric>(df)<(*_num0_p));
00344         case less_or_equal:
00345             return make_safe_bool(ex_to<numeric>(df)<=(*_num0_p));
00346         case greater:
00347             return make_safe_bool(ex_to<numeric>(df)>(*_num0_p));
00348         case greater_or_equal:
00349             return make_safe_bool(ex_to<numeric>(df)>=(*_num0_p));
00350         default:
00351             throw(std::logic_error("invalid relational operator"));
00352     }
00353 }
00354 
00355 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.