|
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 "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