GiNaC  1.6.2
ncmul.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 "ncmul.h"
00024 #include "ex.h"
00025 #include "add.h"
00026 #include "mul.h"
00027 #include "clifford.h"
00028 #include "matrix.h"
00029 #include "archive.h"
00030 #include "indexed.h"
00031 #include "utils.h"
00032 
00033 #include <algorithm>
00034 #include <iostream>
00035 #include <stdexcept>
00036 
00037 namespace GiNaC {
00038 
00039 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(ncmul, exprseq,
00040   print_func<print_context>(&ncmul::do_print).
00041   print_func<print_tree>(&ncmul::do_print_tree).
00042   print_func<print_csrc>(&ncmul::do_print_csrc).
00043   print_func<print_python_repr>(&ncmul::do_print_csrc))
00044 
00045 
00046 
00047 // default constructor
00049 
00050 ncmul::ncmul()
00051 {
00052 }
00053 
00055 // other constructors
00057 
00058 // public
00059 
00060 ncmul::ncmul(const ex & lh, const ex & rh) : inherited(lh,rh)
00061 {
00062 }
00063 
00064 ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3) : inherited(f1,f2,f3)
00065 {
00066 }
00067 
00068 ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
00069              const ex & f4) : inherited(f1,f2,f3,f4)
00070 {
00071 }
00072 
00073 ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
00074              const ex & f4, const ex & f5) : inherited(f1,f2,f3,f4,f5)
00075 {
00076 }
00077 
00078 ncmul::ncmul(const ex & f1, const ex & f2, const ex & f3,
00079              const ex & f4, const ex & f5, const ex & f6) : inherited(f1,f2,f3,f4,f5,f6)
00080 {
00081 }
00082 
00083 ncmul::ncmul(const exvector & v, bool discardable) : inherited(v,discardable)
00084 {
00085 }
00086 
00087 ncmul::ncmul(std::auto_ptr<exvector> vp) : inherited(vp)
00088 {
00089 }
00090 
00092 // archiving
00094 
00095 
00097 // functions overriding virtual functions from base classes
00099 
00100 // public
00101 
00102 void ncmul::do_print(const print_context & c, unsigned level) const
00103 {
00104     printseq(c, '(', '*', ')', precedence(), level);
00105 }
00106 
00107 void ncmul::do_print_csrc(const print_context & c, unsigned level) const
00108 {
00109     c.s << class_name();
00110     printseq(c, '(', ',', ')', precedence(), precedence());
00111 }
00112 
00113 bool ncmul::info(unsigned inf) const
00114 {
00115     return inherited::info(inf);
00116 }
00117 
00118 typedef std::vector<std::size_t> uintvector;
00119 
00120 ex ncmul::expand(unsigned options) const
00121 {
00122     // First, expand the children
00123     std::auto_ptr<exvector> vp = expandchildren(options);
00124     const exvector &expanded_seq = vp.get() ? *vp : this->seq;
00125     
00126     // Now, look for all the factors that are sums and remember their
00127     // position and number of terms.
00128     uintvector positions_of_adds(expanded_seq.size());
00129     uintvector number_of_add_operands(expanded_seq.size());
00130 
00131     size_t number_of_adds = 0;
00132     size_t number_of_expanded_terms = 1;
00133 
00134     size_t current_position = 0;
00135     exvector::const_iterator last = expanded_seq.end();
00136     for (exvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
00137         if (is_exactly_a<add>(*cit)) {
00138             positions_of_adds[number_of_adds] = current_position;
00139             size_t num_ops = cit->nops();
00140             number_of_add_operands[number_of_adds] = num_ops;
00141             number_of_expanded_terms *= num_ops;
00142             number_of_adds++;
00143         }
00144         ++current_position;
00145     }
00146 
00147     // If there are no sums, we are done
00148     if (number_of_adds == 0) {
00149         if (vp.get())
00150             return (new ncmul(vp))->
00151                     setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0));
00152         else
00153             return *this;
00154     }
00155 
00156     // Now, form all possible products of the terms of the sums with the
00157     // remaining factors, and add them together
00158     exvector distrseq;
00159     distrseq.reserve(number_of_expanded_terms);
00160 
00161     uintvector k(number_of_adds);
00162 
00163     /* Rename indices in the static members of the product */
00164     exvector expanded_seq_mod;
00165     size_t j = 0;
00166     exvector va;
00167 
00168     for (size_t i=0; i<expanded_seq.size(); i++) {
00169         if (i == positions_of_adds[j]) {
00170             expanded_seq_mod.push_back(_ex1);
00171             j++;
00172         } else {
00173             expanded_seq_mod.push_back(rename_dummy_indices_uniquely(va, expanded_seq[i], true));
00174         }
00175     }
00176 
00177     while (true) {
00178         exvector term = expanded_seq_mod;
00179         for (size_t i=0; i<number_of_adds; i++) {
00180             term[positions_of_adds[i]] = rename_dummy_indices_uniquely(va, expanded_seq[positions_of_adds[i]].op(k[i]), true);
00181         }
00182 
00183         distrseq.push_back((new ncmul(term, true))->
00184                             setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)));
00185 
00186         // increment k[]
00187         int l = number_of_adds-1;
00188         while ((l>=0) && ((++k[l]) >= number_of_add_operands[l])) {
00189             k[l] = 0;
00190             l--;
00191         }
00192         if (l<0)
00193             break;
00194     }
00195 
00196     return (new add(distrseq))->
00197             setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0));
00198 }
00199 
00200 int ncmul::degree(const ex & s) const
00201 {
00202     if (is_equal(ex_to<basic>(s)))
00203         return 1;
00204 
00205     // Sum up degrees of factors
00206     int deg_sum = 0;
00207     exvector::const_iterator i = seq.begin(), end = seq.end();
00208     while (i != end) {
00209         deg_sum += i->degree(s);
00210         ++i;
00211     }
00212     return deg_sum;
00213 }
00214 
00215 int ncmul::ldegree(const ex & s) const
00216 {
00217     if (is_equal(ex_to<basic>(s)))
00218         return 1;
00219 
00220     // Sum up degrees of factors
00221     int deg_sum = 0;
00222     exvector::const_iterator i = seq.begin(), end = seq.end();
00223     while (i != end) {
00224         deg_sum += i->degree(s);
00225         ++i;
00226     }
00227     return deg_sum;
00228 }
00229 
00230 ex ncmul::coeff(const ex & s, int n) const
00231 {
00232     if (is_equal(ex_to<basic>(s)))
00233         return n==1 ? _ex1 : _ex0;
00234 
00235     exvector coeffseq;
00236     coeffseq.reserve(seq.size());
00237 
00238     if (n == 0) {
00239         // product of individual coeffs
00240         // if a non-zero power of s is found, the resulting product will be 0
00241         exvector::const_iterator it=seq.begin();
00242         while (it!=seq.end()) {
00243             coeffseq.push_back((*it).coeff(s,n));
00244             ++it;
00245         }
00246         return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
00247     }
00248          
00249     exvector::const_iterator i = seq.begin(), end = seq.end();
00250     bool coeff_found = false;
00251     while (i != end) {
00252         ex c = i->coeff(s,n);
00253         if (c.is_zero()) {
00254             coeffseq.push_back(*i);
00255         } else {
00256             coeffseq.push_back(c);
00257             coeff_found = true;
00258         }
00259         ++i;
00260     }
00261 
00262     if (coeff_found) return (new ncmul(coeffseq,1))->setflag(status_flags::dynallocated);
00263     
00264     return _ex0;
00265 }
00266 
00267 size_t ncmul::count_factors(const ex & e) const
00268 {
00269     if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
00270         (is_exactly_a<ncmul>(e))) {
00271         size_t factors=0;
00272         for (size_t i=0; i<e.nops(); i++)
00273             factors += count_factors(e.op(i));
00274         
00275         return factors;
00276     }
00277     return 1;
00278 }
00279         
00280 void ncmul::append_factors(exvector & v, const ex & e) const
00281 {
00282     if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
00283         (is_exactly_a<ncmul>(e))) {
00284         for (size_t i=0; i<e.nops(); i++)
00285             append_factors(v, e.op(i));
00286     } else 
00287         v.push_back(e);
00288 }
00289 
00290 typedef std::vector<unsigned> unsignedvector;
00291 typedef std::vector<exvector> exvectorvector;
00292 
00304 ex ncmul::eval(int level) const
00305 {
00306     // The following additional rule would be nice, but produces a recursion,
00307     // which must be trapped by introducing a flag that the sub-ncmuls()
00308     // are already evaluated (maybe later...)
00309     //                  ncmul(x1,x2,...,X,y1,y2,...) ->
00310     //                      ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
00311     //                      (X noncommutative_composite)
00312 
00313     if ((level==1) && (flags & status_flags::evaluated)) {
00314         return *this;
00315     }
00316 
00317     exvector evaledseq=evalchildren(level);
00318 
00319     // ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
00320     //     ncmul(...,x1,x2,...,x3,x4,...)  (associativity)
00321     size_t factors = 0;
00322     exvector::const_iterator cit = evaledseq.begin(), citend = evaledseq.end();
00323     while (cit != citend)
00324         factors += count_factors(*cit++);
00325     
00326     exvector assocseq;
00327     assocseq.reserve(factors);
00328     cit = evaledseq.begin();
00329     make_flat_inserter mf(evaledseq, true);
00330     while (cit != citend)
00331     {   ex factor = mf.handle_factor(*(cit++), 1);
00332         append_factors(assocseq, factor);
00333     }
00334     
00335     // ncmul(x) -> x
00336     if (assocseq.size()==1) return *(seq.begin());
00337  
00338     // ncmul() -> 1
00339     if (assocseq.empty()) return _ex1;
00340 
00341     // determine return types
00342     unsignedvector rettypes(assocseq.size());
00343     size_t i = 0;
00344     size_t count_commutative=0;
00345     size_t count_noncommutative=0;
00346     size_t count_noncommutative_composite=0;
00347     cit = assocseq.begin(); citend = assocseq.end();
00348     while (cit != citend) {
00349         rettypes[i] = cit->return_type();
00350         switch (rettypes[i]) {
00351         case return_types::commutative:
00352             count_commutative++;
00353             break;
00354         case return_types::noncommutative:
00355             count_noncommutative++;
00356             break;
00357         case return_types::noncommutative_composite:
00358             count_noncommutative_composite++;
00359             break;
00360         default:
00361             throw(std::logic_error("ncmul::eval(): invalid return type"));
00362         }
00363         ++i; ++cit;
00364     }
00365     GINAC_ASSERT(count_commutative+count_noncommutative+count_noncommutative_composite==assocseq.size());
00366 
00367     // ncmul(...,c1,...,c2,...) ->
00368     //     *(c1,c2,ncmul(...)) (pull out commutative elements)
00369     if (count_commutative!=0) {
00370         exvector commutativeseq;
00371         commutativeseq.reserve(count_commutative+1);
00372         exvector noncommutativeseq;
00373         noncommutativeseq.reserve(assocseq.size()-count_commutative);
00374         size_t num = assocseq.size();
00375         for (size_t i=0; i<num; ++i) {
00376             if (rettypes[i]==return_types::commutative)
00377                 commutativeseq.push_back(assocseq[i]);
00378             else
00379                 noncommutativeseq.push_back(assocseq[i]);
00380         }
00381         commutativeseq.push_back((new ncmul(noncommutativeseq,1))->setflag(status_flags::dynallocated));
00382         return (new mul(commutativeseq))->setflag(status_flags::dynallocated);
00383     }
00384         
00385     // ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2))
00386     //     (collect elements of same type)
00387 
00388     if (count_noncommutative_composite==0) {
00389         // there are neither commutative nor noncommutative_composite
00390         // elements in assocseq
00391         GINAC_ASSERT(count_commutative==0);
00392 
00393         size_t assoc_num = assocseq.size();
00394         exvectorvector evv;
00395         std::vector<return_type_t> rttinfos;
00396         evv.reserve(assoc_num);
00397         rttinfos.reserve(assoc_num);
00398 
00399         cit = assocseq.begin(), citend = assocseq.end();
00400         while (cit != citend) {
00401             return_type_t ti = cit->return_type_tinfo();
00402             size_t rtt_num = rttinfos.size();
00403             // search type in vector of known types
00404             for (i=0; i<rtt_num; ++i) {
00405                 if(ti == rttinfos[i]) {
00406                     evv[i].push_back(*cit);
00407                     break;
00408                 }
00409             }
00410             if (i >= rtt_num) {
00411                 // new type
00412                 rttinfos.push_back(ti);
00413                 evv.push_back(exvector());
00414                 (evv.end()-1)->reserve(assoc_num);
00415                 (evv.end()-1)->push_back(*cit);
00416             }
00417             ++cit;
00418         }
00419 
00420         size_t evv_num = evv.size();
00421 #ifdef DO_GINAC_ASSERT
00422         GINAC_ASSERT(evv_num == rttinfos.size());
00423         GINAC_ASSERT(evv_num > 0);
00424         size_t s=0;
00425         for (i=0; i<evv_num; ++i)
00426             s += evv[i].size();
00427         GINAC_ASSERT(s == assoc_num);
00428 #endif // def DO_GINAC_ASSERT
00429         
00430         // if all elements are of same type, simplify the string
00431         if (evv_num == 1) {
00432             return evv[0][0].eval_ncmul(evv[0]);
00433         }
00434         
00435         exvector splitseq;
00436         splitseq.reserve(evv_num);
00437         for (i=0; i<evv_num; ++i)
00438             splitseq.push_back((new ncmul(evv[i]))->setflag(status_flags::dynallocated));
00439         
00440         return (new mul(splitseq))->setflag(status_flags::dynallocated);
00441     }
00442     
00443     return (new ncmul(assocseq))->setflag(status_flags::dynallocated |
00444                                           status_flags::evaluated);
00445 }
00446 
00447 ex ncmul::evalm() const
00448 {
00449     // Evaluate children first
00450     std::auto_ptr<exvector> s(new exvector);
00451     s->reserve(seq.size());
00452     exvector::const_iterator it = seq.begin(), itend = seq.end();
00453     while (it != itend) {
00454         s->push_back(it->evalm());
00455         it++;
00456     }
00457 
00458     // If there are only matrices, simply multiply them
00459     it = s->begin(); itend = s->end();
00460     if (is_a<matrix>(*it)) {
00461         matrix prod(ex_to<matrix>(*it));
00462         it++;
00463         while (it != itend) {
00464             if (!is_a<matrix>(*it))
00465                 goto no_matrix;
00466             prod = prod.mul(ex_to<matrix>(*it));
00467             it++;
00468         }
00469         return prod;
00470     }
00471 
00472 no_matrix:
00473     return (new ncmul(s))->setflag(status_flags::dynallocated);
00474 }
00475 
00476 ex ncmul::thiscontainer(const exvector & v) const
00477 {
00478     return (new ncmul(v))->setflag(status_flags::dynallocated);
00479 }
00480 
00481 ex ncmul::thiscontainer(std::auto_ptr<exvector> vp) const
00482 {
00483     return (new ncmul(vp))->setflag(status_flags::dynallocated);
00484 }
00485 
00486 ex ncmul::conjugate() const
00487 {
00488     if (return_type() != return_types::noncommutative) {
00489         return exprseq::conjugate();
00490     }
00491 
00492     if (!is_clifford_tinfo(return_type_tinfo())) {
00493         return exprseq::conjugate();
00494     }
00495 
00496     exvector ev;
00497     ev.reserve(nops());
00498     for (const_iterator i=end(); i!=begin();) {
00499         --i;
00500         ev.push_back(i->conjugate());
00501     }
00502     return (new ncmul(ev, true))->setflag(status_flags::dynallocated).eval();
00503 }
00504 
00505 ex ncmul::real_part() const
00506 {
00507     return basic::real_part();
00508 }
00509 
00510 ex ncmul::imag_part() const
00511 {
00512     return basic::imag_part();
00513 }
00514 
00515 // protected
00516 
00520 ex ncmul::derivative(const symbol & s) const
00521 {
00522     size_t num = seq.size();
00523     exvector addseq;
00524     addseq.reserve(num);
00525     
00526     // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
00527     exvector ncmulseq = seq;
00528     for (size_t i=0; i<num; ++i) {
00529         ex e = seq[i].diff(s);
00530         e.swap(ncmulseq[i]);
00531         addseq.push_back((new ncmul(ncmulseq))->setflag(status_flags::dynallocated));
00532         e.swap(ncmulseq[i]);
00533     }
00534     return (new add(addseq))->setflag(status_flags::dynallocated);
00535 }
00536 
00537 int ncmul::compare_same_type(const basic & other) const
00538 {
00539     return inherited::compare_same_type(other);
00540 }
00541 
00542 unsigned ncmul::return_type() const
00543 {
00544     if (seq.empty())
00545         return return_types::commutative;
00546 
00547     bool all_commutative = true;
00548     exvector::const_iterator noncommutative_element; // point to first found nc element
00549 
00550     exvector::const_iterator i = seq.begin(), end = seq.end();
00551     while (i != end) {
00552         unsigned rt = i->return_type();
00553         if (rt == return_types::noncommutative_composite)
00554             return rt; // one ncc -> mul also ncc
00555         if ((rt == return_types::noncommutative) && (all_commutative)) {
00556             // first nc element found, remember position
00557             noncommutative_element = i;
00558             all_commutative = false;
00559         }
00560         if ((rt == return_types::noncommutative) && (!all_commutative)) {
00561             // another nc element found, compare type_infos
00562             if(noncommutative_element->return_type_tinfo() != i->return_type_tinfo())
00563                     return return_types::noncommutative_composite;
00564         }
00565         ++i;
00566     }
00567     // all factors checked
00568     GINAC_ASSERT(!all_commutative); // not all factors should commutate, because this is a ncmul();
00569     return all_commutative ? return_types::commutative : return_types::noncommutative;
00570 }
00571    
00572 return_type_t ncmul::return_type_tinfo() const
00573 {
00574     if (seq.empty())
00575         return make_return_type_t<ncmul>();
00576 
00577     // return type_info of first noncommutative element
00578     exvector::const_iterator i = seq.begin(), end = seq.end();
00579     while (i != end) {
00580         if (i->return_type() == return_types::noncommutative)
00581             return i->return_type_tinfo();
00582         ++i;
00583     }
00584 
00585     // no noncommutative element found, should not happen
00586     return make_return_type_t<ncmul>();
00587 }
00588 
00590 // new virtual functions which can be overridden by derived classes
00592 
00593 // none
00594 
00596 // non-virtual functions in this class
00598 
00599 std::auto_ptr<exvector> ncmul::expandchildren(unsigned options) const
00600 {
00601     const_iterator cit = this->seq.begin(), end = this->seq.end();
00602     while (cit != end) {
00603         const ex & expanded_ex = cit->expand(options);
00604         if (!are_ex_trivially_equal(*cit, expanded_ex)) {
00605 
00606             // copy first part of seq which hasn't changed
00607             std::auto_ptr<exvector> s(new exvector(this->seq.begin(), cit));
00608             reserve(*s, this->seq.size());
00609 
00610             // insert changed element
00611             s->push_back(expanded_ex);
00612             ++cit;
00613 
00614             // copy rest
00615             while (cit != end) {
00616                 s->push_back(cit->expand(options));
00617                 ++cit;
00618             }
00619 
00620             return s;
00621         }
00622 
00623         ++cit;
00624     }
00625 
00626     return std::auto_ptr<exvector>(0); // nothing has changed
00627 }
00628 
00629 const exvector & ncmul::get_factors() const
00630 {
00631     return seq;
00632 }
00633 
00635 // friend functions
00637 
00638 ex reeval_ncmul(const exvector & v)
00639 {
00640     return (new ncmul(v))->setflag(status_flags::dynallocated);
00641 }
00642 
00643 ex hold_ncmul(const exvector & v)
00644 {
00645     if (v.empty())
00646         return _ex1;
00647     else if (v.size() == 1)
00648         return v[0];
00649     else
00650         return (new ncmul(v))->setflag(status_flags::dynallocated |
00651                                        status_flags::evaluated);
00652 }
00653 
00654 GINAC_BIND_UNARCHIVER(ncmul);
00655 
00656 } // namespace GiNaC

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