GiNaC  1.6.2
add.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 "add.h"
00024 #include "mul.h"
00025 #include "archive.h"
00026 #include "operators.h"
00027 #include "matrix.h"
00028 #include "utils.h"
00029 #include "clifford.h"
00030 #include "ncmul.h"
00031 #include "compiler.h"
00032 
00033 #include <iostream>
00034 #include <limits>
00035 #include <stdexcept>
00036 #include <string>
00037 
00038 namespace GiNaC {
00039 
00040 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq,
00041   print_func<print_context>(&add::do_print).
00042   print_func<print_latex>(&add::do_print_latex).
00043   print_func<print_csrc>(&add::do_print_csrc).
00044   print_func<print_tree>(&add::do_print_tree).
00045   print_func<print_python_repr>(&add::do_print_python_repr))
00046 
00047 
00048 // default constructor
00050 
00051 add::add()
00052 {
00053 }
00054 
00056 // other constructors
00058 
00059 // public
00060 
00061 add::add(const ex & lh, const ex & rh)
00062 {
00063     overall_coeff = _ex0;
00064     construct_from_2_ex(lh,rh);
00065     GINAC_ASSERT(is_canonical());
00066 }
00067 
00068 add::add(const exvector & v)
00069 {
00070     overall_coeff = _ex0;
00071     construct_from_exvector(v);
00072     GINAC_ASSERT(is_canonical());
00073 }
00074 
00075 add::add(const epvector & v)
00076 {
00077     overall_coeff = _ex0;
00078     construct_from_epvector(v);
00079     GINAC_ASSERT(is_canonical());
00080 }
00081 
00082 add::add(const epvector & v, const ex & oc)
00083 {
00084     overall_coeff = oc;
00085     construct_from_epvector(v);
00086     GINAC_ASSERT(is_canonical());
00087 }
00088 
00089 add::add(std::auto_ptr<epvector> vp, const ex & oc)
00090 {
00091     GINAC_ASSERT(vp.get()!=0);
00092     overall_coeff = oc;
00093     construct_from_epvector(*vp);
00094     GINAC_ASSERT(is_canonical());
00095 }
00096 
00098 // archiving
00100 
00101 GINAC_BIND_UNARCHIVER(add);
00102 
00104 // functions overriding virtual functions from base classes
00106 
00107 // public
00108 
00109 void add::print_add(const print_context & c, const char *openbrace, const char *closebrace, const char *mul_sym, unsigned level) const
00110 {
00111     if (precedence() <= level)
00112         c.s << openbrace << '(';
00113 
00114     numeric coeff;
00115     bool first = true;
00116 
00117     // First print the overall numeric coefficient, if present
00118     if (!overall_coeff.is_zero()) {
00119         overall_coeff.print(c, 0);
00120         first = false;
00121     }
00122 
00123     // Then proceed with the remaining factors
00124     epvector::const_iterator it = seq.begin(), itend = seq.end();
00125     while (it != itend) {
00126         coeff = ex_to<numeric>(it->coeff);
00127         if (!first) {
00128             if (coeff.csgn() == -1) c.s << '-'; else c.s << '+';
00129         } else {
00130             if (coeff.csgn() == -1) c.s << '-';
00131             first = false;
00132         }
00133         if (!coeff.is_equal(*_num1_p) &&
00134             !coeff.is_equal(*_num_1_p)) {
00135             if (coeff.is_rational()) {
00136                 if (coeff.is_negative())
00137                     (-coeff).print(c);
00138                 else
00139                     coeff.print(c);
00140             } else {
00141                 if (coeff.csgn() == -1)
00142                     (-coeff).print(c, precedence());
00143                 else
00144                     coeff.print(c, precedence());
00145             }
00146             c.s << mul_sym;
00147         }
00148         it->rest.print(c, precedence());
00149         ++it;
00150     }
00151 
00152     if (precedence() <= level)
00153         c.s << ')' << closebrace;
00154 }
00155 
00156 void add::do_print(const print_context & c, unsigned level) const
00157 {
00158     print_add(c, "", "", "*", level);
00159 }
00160 
00161 void add::do_print_latex(const print_latex & c, unsigned level) const
00162 {
00163     print_add(c, "{", "}", " ", level);
00164 }
00165 
00166 void add::do_print_csrc(const print_csrc & c, unsigned level) const
00167 {
00168     if (precedence() <= level)
00169         c.s << "(";
00170     
00171     // Print arguments, separated by "+" or "-"
00172     epvector::const_iterator it = seq.begin(), itend = seq.end();
00173     char separator = ' ';
00174     while (it != itend) {
00175         
00176         // If the coefficient is negative, separator is "-"
00177         if (it->coeff.is_equal(_ex_1) || 
00178             ex_to<numeric>(it->coeff).numer().is_equal(*_num_1_p))
00179             separator = '-';
00180         c.s << separator;
00181         if (it->coeff.is_equal(_ex1) || it->coeff.is_equal(_ex_1)) {
00182             it->rest.print(c, precedence());
00183         } else if (ex_to<numeric>(it->coeff).numer().is_equal(*_num1_p) ||
00184                  ex_to<numeric>(it->coeff).numer().is_equal(*_num_1_p))
00185         {
00186             it->rest.print(c, precedence());
00187             c.s << '/';
00188             ex_to<numeric>(it->coeff).denom().print(c, precedence());
00189         } else {
00190             it->coeff.print(c, precedence());
00191             c.s << '*';
00192             it->rest.print(c, precedence());
00193         }
00194         
00195         ++it;
00196         separator = '+';
00197     }
00198     
00199     if (!overall_coeff.is_zero()) {
00200         if (overall_coeff.info(info_flags::positive)
00201          || is_a<print_csrc_cl_N>(c) || !overall_coeff.info(info_flags::real))  // sign inside ctor argument
00202             c.s << '+';
00203         overall_coeff.print(c, precedence());
00204     }
00205         
00206     if (precedence() <= level)
00207         c.s << ")";
00208 }
00209 
00210 void add::do_print_python_repr(const print_python_repr & c, unsigned level) const
00211 {
00212     c.s << class_name() << '(';
00213     op(0).print(c);
00214     for (size_t i=1; i<nops(); ++i) {
00215         c.s << ',';
00216         op(i).print(c);
00217     }
00218     c.s << ')';
00219 }
00220 
00221 bool add::info(unsigned inf) const
00222 {
00223     switch (inf) {
00224         case info_flags::polynomial:
00225         case info_flags::integer_polynomial:
00226         case info_flags::cinteger_polynomial:
00227         case info_flags::rational_polynomial:
00228         case info_flags::real:
00229         case info_flags::rational:
00230         case info_flags::integer:
00231         case info_flags::crational:
00232         case info_flags::cinteger:
00233         case info_flags::positive:
00234         case info_flags::nonnegative:
00235         case info_flags::posint:
00236         case info_flags::nonnegint:
00237         case info_flags::even:
00238         case info_flags::crational_polynomial:
00239         case info_flags::rational_function: {
00240             epvector::const_iterator i = seq.begin(), end = seq.end();
00241             while (i != end) {
00242                 if (!(recombine_pair_to_ex(*i).info(inf)))
00243                     return false;
00244                 ++i;
00245             }
00246             if (overall_coeff.is_zero() && (inf == info_flags::positive || inf == info_flags::posint))
00247                 return true;
00248             return overall_coeff.info(inf);
00249         }
00250         case info_flags::algebraic: {
00251             epvector::const_iterator i = seq.begin(), end = seq.end();
00252             while (i != end) {
00253                 if ((recombine_pair_to_ex(*i).info(inf)))
00254                     return true;
00255                 ++i;
00256             }
00257             return false;
00258         }
00259     }
00260     return inherited::info(inf);
00261 }
00262 
00263 bool add::is_polynomial(const ex & var) const
00264 {
00265     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
00266         if (!(i->rest).is_polynomial(var)) {
00267             return false;
00268         }
00269     }
00270     return true;
00271 }
00272 
00273 int add::degree(const ex & s) const
00274 {
00275     int deg = std::numeric_limits<int>::min();
00276     if (!overall_coeff.is_zero())
00277         deg = 0;
00278     
00279     // Find maximum of degrees of individual terms
00280     epvector::const_iterator i = seq.begin(), end = seq.end();
00281     while (i != end) {
00282         int cur_deg = i->rest.degree(s);
00283         if (cur_deg > deg)
00284             deg = cur_deg;
00285         ++i;
00286     }
00287     return deg;
00288 }
00289 
00290 int add::ldegree(const ex & s) const
00291 {
00292     int deg = std::numeric_limits<int>::max();
00293     if (!overall_coeff.is_zero())
00294         deg = 0;
00295     
00296     // Find minimum of degrees of individual terms
00297     epvector::const_iterator i = seq.begin(), end = seq.end();
00298     while (i != end) {
00299         int cur_deg = i->rest.ldegree(s);
00300         if (cur_deg < deg)
00301             deg = cur_deg;
00302         ++i;
00303     }
00304     return deg;
00305 }
00306 
00307 ex add::coeff(const ex & s, int n) const
00308 {
00309     std::auto_ptr<epvector> coeffseq(new epvector);
00310     std::auto_ptr<epvector> coeffseq_cliff(new epvector);
00311     int rl = clifford_max_label(s);
00312     bool do_clifford = (rl != -1);
00313     bool nonscalar = false;
00314 
00315     // Calculate sum of coefficients in each term
00316     epvector::const_iterator i = seq.begin(), end = seq.end();
00317     while (i != end) {
00318         ex restcoeff = i->rest.coeff(s, n);
00319         if (!restcoeff.is_zero()) {
00320             if (do_clifford) {
00321                 if (clifford_max_label(restcoeff) == -1) {
00322                     coeffseq_cliff->push_back(combine_ex_with_coeff_to_pair(ncmul(restcoeff, dirac_ONE(rl)), i->coeff));
00323                 } else {
00324                     coeffseq_cliff->push_back(combine_ex_with_coeff_to_pair(restcoeff, i->coeff));
00325                     nonscalar = true;
00326                 }
00327             }
00328             coeffseq->push_back(combine_ex_with_coeff_to_pair(restcoeff, i->coeff));
00329         }
00330         ++i;
00331     }
00332 
00333     return (new add(nonscalar ? coeffseq_cliff : coeffseq,
00334                     n==0 ? overall_coeff : _ex0))->setflag(status_flags::dynallocated);
00335 }
00336 
00344 ex add::eval(int level) const
00345 {
00346     std::auto_ptr<epvector> evaled_seqp = evalchildren(level);
00347     if (evaled_seqp.get()) {
00348         // do more evaluation later
00349         return (new add(evaled_seqp, overall_coeff))->
00350                setflag(status_flags::dynallocated);
00351     }
00352     
00353 #ifdef DO_GINAC_ASSERT
00354     epvector::const_iterator i = seq.begin(), end = seq.end();
00355     while (i != end) {
00356         GINAC_ASSERT(!is_exactly_a<add>(i->rest));
00357         ++i;
00358     }
00359 #endif // def DO_GINAC_ASSERT
00360     
00361     if (flags & status_flags::evaluated) {
00362         GINAC_ASSERT(seq.size()>0);
00363         GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
00364         return *this;
00365     }
00366     
00367     int seq_size = seq.size();
00368     if (seq_size == 0) {
00369         // +(;c) -> c
00370         return overall_coeff;
00371     } else if (seq_size == 1 && overall_coeff.is_zero()) {
00372         // +(x;0) -> x
00373         return recombine_pair_to_ex(*(seq.begin()));
00374     } else if (!overall_coeff.is_zero() && seq[0].rest.return_type() != return_types::commutative) {
00375         throw (std::logic_error("add::eval(): sum of non-commutative objects has non-zero numeric term"));
00376     }
00377     
00378     // if any terms in the sum still are purely numeric, then they are more
00379     // appropriately collected into the overall coefficient
00380     epvector::const_iterator last = seq.end();
00381     epvector::const_iterator j = seq.begin();
00382     int terms_to_collect = 0;
00383     while (j != last) {
00384         if (unlikely(is_a<numeric>(j->rest)))
00385             ++terms_to_collect;
00386         ++j;
00387     }
00388     if (terms_to_collect) {
00389         std::auto_ptr<epvector> s(new epvector);
00390         s->reserve(seq_size - terms_to_collect);
00391         numeric oc = *_num1_p;
00392         j = seq.begin();
00393         while (j != last) {
00394             if (unlikely(is_a<numeric>(j->rest)))
00395                 oc = oc.mul(ex_to<numeric>(j->rest)).mul(ex_to<numeric>(j->coeff));
00396             else
00397                 s->push_back(*j);
00398             ++j;
00399         }
00400         return (new add(s, ex_to<numeric>(overall_coeff).add_dyn(oc)))
00401                 ->setflag(status_flags::dynallocated);
00402     }
00403     
00404     return this->hold();
00405 }
00406 
00407 ex add::evalm() const
00408 {
00409     // Evaluate children first and add up all matrices. Stop if there's one
00410     // term that is not a matrix.
00411     std::auto_ptr<epvector> s(new epvector);
00412     s->reserve(seq.size());
00413 
00414     bool all_matrices = true;
00415     bool first_term = true;
00416     matrix sum;
00417 
00418     epvector::const_iterator it = seq.begin(), itend = seq.end();
00419     while (it != itend) {
00420         const ex &m = recombine_pair_to_ex(*it).evalm();
00421         s->push_back(split_ex_to_pair(m));
00422         if (is_a<matrix>(m)) {
00423             if (first_term) {
00424                 sum = ex_to<matrix>(m);
00425                 first_term = false;
00426             } else
00427                 sum = sum.add(ex_to<matrix>(m));
00428         } else
00429             all_matrices = false;
00430         ++it;
00431     }
00432 
00433     if (all_matrices)
00434         return sum + overall_coeff;
00435     else
00436         return (new add(s, overall_coeff))->setflag(status_flags::dynallocated);
00437 }
00438 
00439 ex add::conjugate() const
00440 {
00441     exvector *v = 0;
00442     for (size_t i=0; i<nops(); ++i) {
00443         if (v) {
00444             v->push_back(op(i).conjugate());
00445             continue;
00446         }
00447         ex term = op(i);
00448         ex ccterm = term.conjugate();
00449         if (are_ex_trivially_equal(term, ccterm))
00450             continue;
00451         v = new exvector;
00452         v->reserve(nops());
00453         for (size_t j=0; j<i; ++j)
00454             v->push_back(op(j));
00455         v->push_back(ccterm);
00456     }
00457     if (v) {
00458         ex result = add(*v);
00459         delete v;
00460         return result;
00461     }
00462     return *this;
00463 }
00464 
00465 ex add::real_part() const
00466 {
00467     epvector v;
00468     v.reserve(seq.size());
00469     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
00470         if ((i->coeff).info(info_flags::real)) {
00471             ex rp = (i->rest).real_part();
00472             if (!rp.is_zero())
00473                 v.push_back(expair(rp, i->coeff));
00474         } else {
00475             ex rp=recombine_pair_to_ex(*i).real_part();
00476             if (!rp.is_zero())
00477                 v.push_back(split_ex_to_pair(rp));
00478         }
00479     return (new add(v, overall_coeff.real_part()))
00480         -> setflag(status_flags::dynallocated);
00481 }
00482 
00483 ex add::imag_part() const
00484 {
00485     epvector v;
00486     v.reserve(seq.size());
00487     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
00488         if ((i->coeff).info(info_flags::real)) {
00489             ex ip = (i->rest).imag_part();
00490             if (!ip.is_zero())
00491                 v.push_back(expair(ip, i->coeff));
00492         } else {
00493             ex ip=recombine_pair_to_ex(*i).imag_part();
00494             if (!ip.is_zero())
00495                 v.push_back(split_ex_to_pair(ip));
00496         }
00497     return (new add(v, overall_coeff.imag_part()))
00498         -> setflag(status_flags::dynallocated);
00499 }
00500 
00501 ex add::eval_ncmul(const exvector & v) const
00502 {
00503     if (seq.empty())
00504         return inherited::eval_ncmul(v);
00505     else
00506         return seq.begin()->rest.eval_ncmul(v);
00507 }    
00508 
00509 // protected
00510 
00513 ex add::derivative(const symbol & y) const
00514 {
00515     std::auto_ptr<epvector> s(new epvector);
00516     s->reserve(seq.size());
00517     
00518     // Only differentiate the "rest" parts of the expairs. This is faster
00519     // than the default implementation in basic::derivative() although
00520     // if performs the same function (differentiate each term).
00521     epvector::const_iterator i = seq.begin(), end = seq.end();
00522     while (i != end) {
00523         s->push_back(combine_ex_with_coeff_to_pair(i->rest.diff(y), i->coeff));
00524         ++i;
00525     }
00526     return (new add(s, _ex0))->setflag(status_flags::dynallocated);
00527 }
00528 
00529 int add::compare_same_type(const basic & other) const
00530 {
00531     return inherited::compare_same_type(other);
00532 }
00533 
00534 unsigned add::return_type() const
00535 {
00536     if (seq.empty())
00537         return return_types::commutative;
00538     else
00539         return seq.begin()->rest.return_type();
00540 }
00541 
00542 return_type_t add::return_type_tinfo() const
00543 {
00544     if (seq.empty())
00545         return make_return_type_t<add>();
00546     else
00547         return seq.begin()->rest.return_type_tinfo();
00548 }
00549 
00550 // Note: do_index_renaming is ignored because it makes no sense for an add.
00551 ex add::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
00552 {
00553     return (new add(v,oc))->setflag(status_flags::dynallocated);
00554 }
00555 
00556 // Note: do_index_renaming is ignored because it makes no sense for an add.
00557 ex add::thisexpairseq(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming) const
00558 {
00559     return (new add(vp,oc))->setflag(status_flags::dynallocated);
00560 }
00561 
00562 expair add::split_ex_to_pair(const ex & e) const
00563 {
00564     if (is_exactly_a<mul>(e)) {
00565         const mul &mulref(ex_to<mul>(e));
00566         const ex &numfactor = mulref.overall_coeff;
00567         mul *mulcopyp = new mul(mulref);
00568         mulcopyp->overall_coeff = _ex1;
00569         mulcopyp->clearflag(status_flags::evaluated);
00570         mulcopyp->clearflag(status_flags::hash_calculated);
00571         mulcopyp->setflag(status_flags::dynallocated);
00572         return expair(*mulcopyp,numfactor);
00573     }
00574     return expair(e,_ex1);
00575 }
00576 
00577 expair add::combine_ex_with_coeff_to_pair(const ex & e,
00578                                           const ex & c) const
00579 {
00580     GINAC_ASSERT(is_exactly_a<numeric>(c));
00581     if (is_exactly_a<mul>(e)) {
00582         const mul &mulref(ex_to<mul>(e));
00583         const ex &numfactor = mulref.overall_coeff;
00584         mul *mulcopyp = new mul(mulref);
00585         mulcopyp->overall_coeff = _ex1;
00586         mulcopyp->clearflag(status_flags::evaluated);
00587         mulcopyp->clearflag(status_flags::hash_calculated);
00588         mulcopyp->setflag(status_flags::dynallocated);
00589         if (c.is_equal(_ex1))
00590             return expair(*mulcopyp, numfactor);
00591         else if (numfactor.is_equal(_ex1))
00592             return expair(*mulcopyp, c);
00593         else
00594             return expair(*mulcopyp, ex_to<numeric>(numfactor).mul_dyn(ex_to<numeric>(c)));
00595     } else if (is_exactly_a<numeric>(e)) {
00596         if (c.is_equal(_ex1))
00597             return expair(e, _ex1);
00598         return expair(ex_to<numeric>(e).mul_dyn(ex_to<numeric>(c)), _ex1);
00599     }
00600     return expair(e, c);
00601 }
00602 
00603 expair add::combine_pair_with_coeff_to_pair(const expair & p,
00604                                             const ex & c) const
00605 {
00606     GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
00607     GINAC_ASSERT(is_exactly_a<numeric>(c));
00608 
00609     if (is_exactly_a<numeric>(p.rest)) {
00610         GINAC_ASSERT(ex_to<numeric>(p.coeff).is_equal(*_num1_p)); // should be normalized
00611         return expair(ex_to<numeric>(p.rest).mul_dyn(ex_to<numeric>(c)),_ex1);
00612     }
00613 
00614     return expair(p.rest,ex_to<numeric>(p.coeff).mul_dyn(ex_to<numeric>(c)));
00615 }
00616 
00617 ex add::recombine_pair_to_ex(const expair & p) const
00618 {
00619     if (ex_to<numeric>(p.coeff).is_equal(*_num1_p))
00620         return p.rest;
00621     else
00622         return (new mul(p.rest,p.coeff))->setflag(status_flags::dynallocated);
00623 }
00624 
00625 ex add::expand(unsigned options) const
00626 {
00627     std::auto_ptr<epvector> vp = expandchildren(options);
00628     if (vp.get() == 0) {
00629         // the terms have not changed, so it is safe to declare this expanded
00630         return (options == 0) ? setflag(status_flags::expanded) : *this;
00631     }
00632 
00633     return (new add(vp, overall_coeff))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0));
00634 }
00635 
00636 } // namespace GiNaC

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