GiNaC  1.6.2
ex.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 "ex.h"
00024 #include "add.h"
00025 #include "mul.h"
00026 #include "ncmul.h"
00027 #include "numeric.h"
00028 #include "matrix.h"
00029 #include "power.h"
00030 #include "lst.h"
00031 #include "relational.h"
00032 #include "utils.h"
00033 
00034 #include <iostream>
00035 #include <stdexcept>
00036 
00037 namespace GiNaC {
00038 
00040 // other constructors
00042 
00043 // none (all inlined)
00044 
00046 // non-virtual functions in this class
00048 
00049 // public
00050     
00056 void ex::print(const print_context & c, unsigned level) const
00057 {
00058     bp->print(c, level);
00059 }
00060 
00062 void ex::dbgprint() const
00063 {
00064     bp->dbgprint();
00065 }
00066 
00068 void ex::dbgprinttree() const
00069 {
00070     bp->dbgprinttree();
00071 }
00072 
00073 ex ex::expand(unsigned options) const
00074 {
00075     if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
00076         return *this;
00077     else
00078         return bp->expand(options);
00079 }
00080 
00086 ex ex::diff(const symbol & s, unsigned nth) const
00087 {
00088     if (!nth)
00089         return *this;
00090     else
00091         return bp->diff(s, nth);
00092 }
00093 
00095 bool ex::match(const ex & pattern) const
00096 {
00097     exmap repl_lst;
00098     return bp->match(pattern, repl_lst);
00099 }
00100 
00105 bool ex::find(const ex & pattern, exset& found) const
00106 {
00107     if (match(pattern)) {
00108         found.insert(*this);
00109         return true;
00110     }
00111     bool any_found = false;
00112     for (size_t i=0; i<nops(); i++)
00113         if (op(i).find(pattern, found))
00114             any_found = true;
00115     return any_found;
00116 }
00117 
00120 ex ex::subs(const lst & ls, const lst & lr, unsigned options) const
00121 {
00122     GINAC_ASSERT(ls.nops() == lr.nops());
00123 
00124     // Convert the lists to a map
00125     exmap m;
00126     for (lst::const_iterator its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
00127         m.insert(std::make_pair(*its, *itr));
00128 
00129         // Search for products and powers in the expressions to be substituted
00130         // (for an optimization in expairseq::subs())
00131         if (is_exactly_a<mul>(*its) || is_exactly_a<power>(*its))
00132             options |= subs_options::pattern_is_product;
00133     }
00134     if (!(options & subs_options::pattern_is_product))
00135         options |= subs_options::pattern_is_not_product;
00136 
00137     return bp->subs(m, options);
00138 }
00139 
00144 ex ex::subs(const ex & e, unsigned options) const
00145 {
00146     if (e.info(info_flags::relation_equal)) {
00147 
00148         // Argument is a relation: convert it to a map
00149         exmap m;
00150         const ex & s = e.op(0);
00151         m.insert(std::make_pair(s, e.op(1)));
00152 
00153         if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
00154             options |= subs_options::pattern_is_product;
00155         else
00156             options |= subs_options::pattern_is_not_product;
00157 
00158         return bp->subs(m, options);
00159 
00160     } else if (e.info(info_flags::list)) {
00161 
00162         // Argument is a list: convert it to a map
00163         exmap m;
00164         GINAC_ASSERT(is_a<lst>(e));
00165         for (lst::const_iterator it = ex_to<lst>(e).begin(); it != ex_to<lst>(e).end(); ++it) {
00166             ex r = *it;
00167             if (!r.info(info_flags::relation_equal))
00168                 throw(std::invalid_argument("basic::subs(ex): argument must be a list of equations"));
00169             const ex & s = r.op(0);
00170             m.insert(std::make_pair(s, r.op(1)));
00171 
00172             // Search for products and powers in the expressions to be substituted
00173             // (for an optimization in expairseq::subs())
00174             if (is_exactly_a<mul>(s) || is_exactly_a<power>(s))
00175                 options |= subs_options::pattern_is_product;
00176         }
00177         if (!(options & subs_options::pattern_is_product))
00178             options |= subs_options::pattern_is_not_product;
00179 
00180         return bp->subs(m, options);
00181 
00182     } else
00183         throw(std::invalid_argument("ex::subs(ex): argument must be a relation_equal or a list"));
00184 }
00185 
00187 void ex::traverse_preorder(visitor & v) const
00188 {
00189     accept(v);
00190 
00191     size_t n = nops();
00192     for (size_t i = 0; i < n; ++i)
00193         op(i).traverse_preorder(v);
00194 }
00195 
00197 void ex::traverse_postorder(visitor & v) const
00198 {
00199     size_t n = nops();
00200     for (size_t i = 0; i < n; ++i)
00201         op(i).traverse_postorder(v);
00202 
00203     accept(v);
00204 }
00205 
00207 ex & ex::let_op(size_t i)
00208 {
00209     makewriteable();
00210     return bp->let_op(i);
00211 }
00212 
00213 ex & ex::operator[](const ex & index)
00214 {
00215     makewriteable();
00216     return (*bp)[index];
00217 }
00218 
00219 ex & ex::operator[](size_t i)
00220 {
00221     makewriteable();
00222     return (*bp)[i];
00223 }
00224 
00226 ex ex::lhs() const
00227 {
00228     if (!is_a<relational>(*this))
00229         throw std::runtime_error("ex::lhs(): not a relation");
00230     return bp->op(0);
00231 }
00232 
00234 ex ex::rhs() const
00235 {
00236     if (!is_a<relational>(*this))
00237         throw std::runtime_error("ex::rhs(): not a relation");
00238     return bp->op(1);
00239 }
00240 
00242 bool ex::is_polynomial(const ex & vars) const
00243 {
00244     if (is_a<lst>(vars)) {
00245         const lst & varlst = ex_to<lst>(vars);
00246         for (lst::const_iterator i=varlst.begin(); i!=varlst.end(); ++i)
00247             if (!bp->is_polynomial(*i))
00248                 return false;
00249         return true;
00250     }
00251     else
00252         return bp->is_polynomial(vars);
00253 }
00254 
00256 bool ex::is_zero_matrix() const
00257 {
00258     if (is_zero())
00259         return  true;
00260     else {
00261         ex e = evalm();
00262         return is_a<matrix>(e) && ex_to<matrix>(e).is_zero_matrix();
00263     }
00264 }
00265 
00266 // private
00267 
00270 void ex::makewriteable()
00271 {
00272     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
00273     bp.makewritable();
00274     GINAC_ASSERT(bp->get_refcount() == 1);
00275 }
00276 
00279 void ex::share(const ex & other) const
00280 {
00281     if ((bp->flags | other.bp->flags) & status_flags::not_shareable)
00282         return;
00283 
00284     if (bp->get_refcount() <= other.bp->get_refcount())
00285         bp = other.bp;
00286     else
00287         other.bp = bp;
00288 }
00289 
00293 ptr<basic> ex::construct_from_basic(const basic & other)
00294 {
00295     if (!(other.flags & status_flags::evaluated)) {
00296 
00297         // The object is not yet evaluated, so call eval() to evaluate
00298         // the top level. This will return either
00299         //  a) the original object with status_flags::evaluated set (when the
00300         //     eval() implementation calls hold())
00301         // or
00302         //  b) a different expression.
00303         //
00304         // eval() returns an ex, not a basic&, so this will go through
00305         // construct_from_basic() a second time. In case a) we end up in
00306         // the "else" branch below. In case b) we end up here again and
00307         // apply eval() once more. The recursion stops when eval() calls
00308         // hold() or returns an object that already has its "evaluated"
00309         // flag set, such as a symbol or a numeric.
00310         const ex & tmpex = other.eval(1);
00311 
00312         // Eventually, the eval() recursion goes through the "else" branch
00313         // below, which assures that the object pointed to by tmpex.bp is
00314         // allocated on the heap (either it was already on the heap or it
00315         // is a heap-allocated duplicate of another object).
00316         GINAC_ASSERT(tmpex.bp->flags & status_flags::dynallocated); 
00317 
00318         // If the original object is not referenced but heap-allocated,
00319         // it means that eval() hit case b) above. The original object is
00320         // no longer needed (it evaluated into something different), so we
00321         // delete it (because nobody else will).
00322         if ((other.get_refcount() == 0) && (other.flags & status_flags::dynallocated))
00323             delete &other; // yes, you can apply delete to a const pointer
00324 
00325         // We can't return a basic& here because the tmpex is destroyed as
00326         // soon as we leave the function, which would deallocate the
00327         // evaluated object.
00328         return tmpex.bp;
00329 
00330     } else {
00331 
00332         // The easy case: making an "ex" out of an evaluated object.
00333         if (other.flags & status_flags::dynallocated) {
00334 
00335             // The object is already heap-allocated, so we can just make
00336             // another reference to it.
00337             return ptr<basic>(const_cast<basic &>(other));
00338 
00339         } else {
00340 
00341             // The object is not heap-allocated, so we create a duplicate
00342             // on the heap.
00343             basic *bp = other.duplicate();
00344             bp->setflag(status_flags::dynallocated);
00345             GINAC_ASSERT(bp->get_refcount() == 0);
00346             return bp;
00347         }
00348     }
00349 }
00350 
00351 basic & ex::construct_from_int(int i)
00352 {
00353     switch (i) {  // prefer flyweights over new objects
00354     case -12:
00355         return *const_cast<numeric *>(_num_12_p);
00356     case -11:
00357         return *const_cast<numeric *>(_num_11_p);
00358     case -10:
00359         return *const_cast<numeric *>(_num_10_p);
00360     case -9:
00361         return *const_cast<numeric *>(_num_9_p);
00362     case -8:
00363         return *const_cast<numeric *>(_num_8_p);
00364     case -7:
00365         return *const_cast<numeric *>(_num_7_p);
00366     case -6:
00367         return *const_cast<numeric *>(_num_6_p);
00368     case -5:
00369         return *const_cast<numeric *>(_num_5_p);
00370     case -4:
00371         return *const_cast<numeric *>(_num_4_p);
00372     case -3:
00373         return *const_cast<numeric *>(_num_3_p);
00374     case -2:
00375         return *const_cast<numeric *>(_num_2_p);
00376     case -1:
00377         return *const_cast<numeric *>(_num_1_p);
00378     case 0:
00379         return *const_cast<numeric *>(_num0_p);
00380     case 1:
00381         return *const_cast<numeric *>(_num1_p);
00382     case 2:
00383         return *const_cast<numeric *>(_num2_p);
00384     case 3:
00385         return *const_cast<numeric *>(_num3_p);
00386     case 4:
00387         return *const_cast<numeric *>(_num4_p);
00388     case 5:
00389         return *const_cast<numeric *>(_num5_p);
00390     case 6:
00391         return *const_cast<numeric *>(_num6_p);
00392     case 7:
00393         return *const_cast<numeric *>(_num7_p);
00394     case 8:
00395         return *const_cast<numeric *>(_num8_p);
00396     case 9:
00397         return *const_cast<numeric *>(_num9_p);
00398     case 10:
00399         return *const_cast<numeric *>(_num10_p);
00400     case 11:
00401         return *const_cast<numeric *>(_num11_p);
00402     case 12:
00403         return *const_cast<numeric *>(_num12_p);
00404     default:
00405         basic *bp = new numeric(i);
00406         bp->setflag(status_flags::dynallocated);
00407         GINAC_ASSERT(bp->get_refcount() == 0);
00408         return *bp;
00409     }
00410 }
00411     
00412 basic & ex::construct_from_uint(unsigned int i)
00413 {
00414     switch (i) {  // prefer flyweights over new objects
00415     case 0:
00416         return *const_cast<numeric *>(_num0_p);
00417     case 1:
00418         return *const_cast<numeric *>(_num1_p);
00419     case 2:
00420         return *const_cast<numeric *>(_num2_p);
00421     case 3:
00422         return *const_cast<numeric *>(_num3_p);
00423     case 4:
00424         return *const_cast<numeric *>(_num4_p);
00425     case 5:
00426         return *const_cast<numeric *>(_num5_p);
00427     case 6:
00428         return *const_cast<numeric *>(_num6_p);
00429     case 7:
00430         return *const_cast<numeric *>(_num7_p);
00431     case 8:
00432         return *const_cast<numeric *>(_num8_p);
00433     case 9:
00434         return *const_cast<numeric *>(_num9_p);
00435     case 10:
00436         return *const_cast<numeric *>(_num10_p);
00437     case 11:
00438         return *const_cast<numeric *>(_num11_p);
00439     case 12:
00440         return *const_cast<numeric *>(_num12_p);
00441     default:
00442         basic *bp = new numeric(i);
00443         bp->setflag(status_flags::dynallocated);
00444         GINAC_ASSERT(bp->get_refcount() == 0);
00445         return *bp;
00446     }
00447 }
00448     
00449 basic & ex::construct_from_long(long i)
00450 {
00451     switch (i) {  // prefer flyweights over new objects
00452     case -12:
00453         return *const_cast<numeric *>(_num_12_p);
00454     case -11:
00455         return *const_cast<numeric *>(_num_11_p);
00456     case -10:
00457         return *const_cast<numeric *>(_num_10_p);
00458     case -9:
00459         return *const_cast<numeric *>(_num_9_p);
00460     case -8:
00461         return *const_cast<numeric *>(_num_8_p);
00462     case -7:
00463         return *const_cast<numeric *>(_num_7_p);
00464     case -6:
00465         return *const_cast<numeric *>(_num_6_p);
00466     case -5:
00467         return *const_cast<numeric *>(_num_5_p);
00468     case -4:
00469         return *const_cast<numeric *>(_num_4_p);
00470     case -3:
00471         return *const_cast<numeric *>(_num_3_p);
00472     case -2:
00473         return *const_cast<numeric *>(_num_2_p);
00474     case -1:
00475         return *const_cast<numeric *>(_num_1_p);
00476     case 0:
00477         return *const_cast<numeric *>(_num0_p);
00478     case 1:
00479         return *const_cast<numeric *>(_num1_p);
00480     case 2:
00481         return *const_cast<numeric *>(_num2_p);
00482     case 3:
00483         return *const_cast<numeric *>(_num3_p);
00484     case 4:
00485         return *const_cast<numeric *>(_num4_p);
00486     case 5:
00487         return *const_cast<numeric *>(_num5_p);
00488     case 6:
00489         return *const_cast<numeric *>(_num6_p);
00490     case 7:
00491         return *const_cast<numeric *>(_num7_p);
00492     case 8:
00493         return *const_cast<numeric *>(_num8_p);
00494     case 9:
00495         return *const_cast<numeric *>(_num9_p);
00496     case 10:
00497         return *const_cast<numeric *>(_num10_p);
00498     case 11:
00499         return *const_cast<numeric *>(_num11_p);
00500     case 12:
00501         return *const_cast<numeric *>(_num12_p);
00502     default:
00503         basic *bp = new numeric(i);
00504         bp->setflag(status_flags::dynallocated);
00505         GINAC_ASSERT(bp->get_refcount() == 0);
00506         return *bp;
00507     }
00508 }
00509     
00510 basic & ex::construct_from_ulong(unsigned long i)
00511 {
00512     switch (i) {  // prefer flyweights over new objects
00513     case 0:
00514         return *const_cast<numeric *>(_num0_p);
00515     case 1:
00516         return *const_cast<numeric *>(_num1_p);
00517     case 2:
00518         return *const_cast<numeric *>(_num2_p);
00519     case 3:
00520         return *const_cast<numeric *>(_num3_p);
00521     case 4:
00522         return *const_cast<numeric *>(_num4_p);
00523     case 5:
00524         return *const_cast<numeric *>(_num5_p);
00525     case 6:
00526         return *const_cast<numeric *>(_num6_p);
00527     case 7:
00528         return *const_cast<numeric *>(_num7_p);
00529     case 8:
00530         return *const_cast<numeric *>(_num8_p);
00531     case 9:
00532         return *const_cast<numeric *>(_num9_p);
00533     case 10:
00534         return *const_cast<numeric *>(_num10_p);
00535     case 11:
00536         return *const_cast<numeric *>(_num11_p);
00537     case 12:
00538         return *const_cast<numeric *>(_num12_p);
00539     default:
00540         basic *bp = new numeric(i);
00541         bp->setflag(status_flags::dynallocated);
00542         GINAC_ASSERT(bp->get_refcount() == 0);
00543         return *bp;
00544     }
00545 }
00546     
00547 basic & ex::construct_from_double(double d)
00548 {
00549     basic *bp = new numeric(d);
00550     bp->setflag(status_flags::dynallocated);
00551     GINAC_ASSERT(bp->get_refcount() == 0);
00552     return *bp;
00553 }
00554 
00556 // static member variables
00558 
00559 // none
00560 
00562 // functions which are not member functions
00564 
00565 // none
00566 
00568 // global functions
00570 
00571 // none
00572 
00573 
00574 } // namespace GiNaC

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