|
GiNaC
1.6.2
|
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