|
GiNaC
1.6.2
|
00001 00006 /* 00007 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 */ 00023 00024 #include "pseries.h" 00025 #include "add.h" 00026 #include "inifcns.h" // for Order function 00027 #include "lst.h" 00028 #include "mul.h" 00029 #include "power.h" 00030 #include "relational.h" 00031 #include "operators.h" 00032 #include "symbol.h" 00033 #include "integral.h" 00034 #include "archive.h" 00035 #include "utils.h" 00036 00037 #include <limits> 00038 #include <numeric> 00039 #include <stdexcept> 00040 00041 namespace GiNaC { 00042 00043 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(pseries, basic, 00044 print_func<print_context>(&pseries::do_print). 00045 print_func<print_latex>(&pseries::do_print_latex). 00046 print_func<print_tree>(&pseries::do_print_tree). 00047 print_func<print_python>(&pseries::do_print_python). 00048 print_func<print_python_repr>(&pseries::do_print_python_repr)) 00049 00050 00051 /* 00052 * Default constructor 00053 */ 00054 00055 pseries::pseries() { } 00056 00057 00058 /* 00059 * Other ctors 00060 */ 00061 00071 pseries::pseries(const ex &rel_, const epvector &ops_) : seq(ops_) 00072 { 00073 GINAC_ASSERT(is_a<relational>(rel_)); 00074 GINAC_ASSERT(is_a<symbol>(rel_.lhs())); 00075 point = rel_.rhs(); 00076 var = rel_.lhs(); 00077 } 00078 00079 00080 /* 00081 * Archiving 00082 */ 00083 00084 void pseries::read_archive(const archive_node &n, lst &sym_lst) 00085 { 00086 inherited::read_archive(n, sym_lst); 00087 archive_node::archive_node_cit first = n.find_first("coeff"); 00088 archive_node::archive_node_cit last = n.find_last("power"); 00089 ++last; 00090 seq.reserve((last-first)/2); 00091 00092 for (archive_node::archive_node_cit loc = first; loc < last;) { 00093 ex rest; 00094 ex coeff; 00095 n.find_ex_by_loc(loc++, rest, sym_lst); 00096 n.find_ex_by_loc(loc++, coeff, sym_lst); 00097 seq.push_back(expair(rest, coeff)); 00098 } 00099 00100 n.find_ex("var", var, sym_lst); 00101 n.find_ex("point", point, sym_lst); 00102 } 00103 00104 void pseries::archive(archive_node &n) const 00105 { 00106 inherited::archive(n); 00107 epvector::const_iterator i = seq.begin(), iend = seq.end(); 00108 while (i != iend) { 00109 n.add_ex("coeff", i->rest); 00110 n.add_ex("power", i->coeff); 00111 ++i; 00112 } 00113 n.add_ex("var", var); 00114 n.add_ex("point", point); 00115 } 00116 00117 00119 // functions overriding virtual functions from base classes 00121 00122 void pseries::print_series(const print_context & c, const char *openbrace, const char *closebrace, const char *mul_sym, const char *pow_sym, unsigned level) const 00123 { 00124 if (precedence() <= level) 00125 c.s << '('; 00126 00127 // objects of type pseries must not have any zero entries, so the 00128 // trivial (zero) pseries needs a special treatment here: 00129 if (seq.empty()) 00130 c.s << '0'; 00131 00132 epvector::const_iterator i = seq.begin(), end = seq.end(); 00133 while (i != end) { 00134 00135 // print a sign, if needed 00136 if (i != seq.begin()) 00137 c.s << '+'; 00138 00139 if (!is_order_function(i->rest)) { 00140 00141 // print 'rest', i.e. the expansion coefficient 00142 if (i->rest.info(info_flags::numeric) && 00143 i->rest.info(info_flags::positive)) { 00144 i->rest.print(c); 00145 } else { 00146 c.s << openbrace << '('; 00147 i->rest.print(c); 00148 c.s << ')' << closebrace; 00149 } 00150 00151 // print 'coeff', something like (x-1)^42 00152 if (!i->coeff.is_zero()) { 00153 c.s << mul_sym; 00154 if (!point.is_zero()) { 00155 c.s << openbrace << '('; 00156 (var-point).print(c); 00157 c.s << ')' << closebrace; 00158 } else 00159 var.print(c); 00160 if (i->coeff.compare(_ex1)) { 00161 c.s << pow_sym; 00162 c.s << openbrace; 00163 if (i->coeff.info(info_flags::negative)) { 00164 c.s << '('; 00165 i->coeff.print(c); 00166 c.s << ')'; 00167 } else 00168 i->coeff.print(c); 00169 c.s << closebrace; 00170 } 00171 } 00172 } else 00173 Order(power(var-point,i->coeff)).print(c); 00174 ++i; 00175 } 00176 00177 if (precedence() <= level) 00178 c.s << ')'; 00179 } 00180 00181 void pseries::do_print(const print_context & c, unsigned level) const 00182 { 00183 print_series(c, "", "", "*", "^", level); 00184 } 00185 00186 void pseries::do_print_latex(const print_latex & c, unsigned level) const 00187 { 00188 print_series(c, "{", "}", " ", "^", level); 00189 } 00190 00191 void pseries::do_print_python(const print_python & c, unsigned level) const 00192 { 00193 print_series(c, "", "", "*", "**", level); 00194 } 00195 00196 void pseries::do_print_tree(const print_tree & c, unsigned level) const 00197 { 00198 c.s << std::string(level, ' ') << class_name() << " @" << this 00199 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec 00200 << std::endl; 00201 size_t num = seq.size(); 00202 for (size_t i=0; i<num; ++i) { 00203 seq[i].rest.print(c, level + c.delta_indent); 00204 seq[i].coeff.print(c, level + c.delta_indent); 00205 c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl; 00206 } 00207 var.print(c, level + c.delta_indent); 00208 point.print(c, level + c.delta_indent); 00209 } 00210 00211 void pseries::do_print_python_repr(const print_python_repr & c, unsigned level) const 00212 { 00213 c.s << class_name() << "(relational("; 00214 var.print(c); 00215 c.s << ','; 00216 point.print(c); 00217 c.s << "),["; 00218 size_t num = seq.size(); 00219 for (size_t i=0; i<num; ++i) { 00220 if (i) 00221 c.s << ','; 00222 c.s << '('; 00223 seq[i].rest.print(c); 00224 c.s << ','; 00225 seq[i].coeff.print(c); 00226 c.s << ')'; 00227 } 00228 c.s << "])"; 00229 } 00230 00231 int pseries::compare_same_type(const basic & other) const 00232 { 00233 GINAC_ASSERT(is_a<pseries>(other)); 00234 const pseries &o = static_cast<const pseries &>(other); 00235 00236 // first compare the lengths of the series... 00237 if (seq.size()>o.seq.size()) 00238 return 1; 00239 if (seq.size()<o.seq.size()) 00240 return -1; 00241 00242 // ...then the expansion point... 00243 int cmpval = var.compare(o.var); 00244 if (cmpval) 00245 return cmpval; 00246 cmpval = point.compare(o.point); 00247 if (cmpval) 00248 return cmpval; 00249 00250 // ...and if that failed the individual elements 00251 epvector::const_iterator it = seq.begin(), o_it = o.seq.begin(); 00252 while (it!=seq.end() && o_it!=o.seq.end()) { 00253 cmpval = it->compare(*o_it); 00254 if (cmpval) 00255 return cmpval; 00256 ++it; 00257 ++o_it; 00258 } 00259 00260 // so they are equal. 00261 return 0; 00262 } 00263 00265 size_t pseries::nops() const 00266 { 00267 return seq.size(); 00268 } 00269 00271 ex pseries::op(size_t i) const 00272 { 00273 if (i >= seq.size()) 00274 throw (std::out_of_range("op() out of range")); 00275 00276 if (is_order_function(seq[i].rest)) 00277 return Order(power(var-point, seq[i].coeff)); 00278 return seq[i].rest * power(var - point, seq[i].coeff); 00279 } 00280 00284 int pseries::degree(const ex &s) const 00285 { 00286 if (var.is_equal(s)) { 00287 // Return last exponent 00288 if (seq.size()) 00289 return ex_to<numeric>((seq.end()-1)->coeff).to_int(); 00290 else 00291 return 0; 00292 } else { 00293 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00294 if (it == itend) 00295 return 0; 00296 int max_pow = std::numeric_limits<int>::min(); 00297 while (it != itend) { 00298 int pow = it->rest.degree(s); 00299 if (pow > max_pow) 00300 max_pow = pow; 00301 ++it; 00302 } 00303 return max_pow; 00304 } 00305 } 00306 00312 int pseries::ldegree(const ex &s) const 00313 { 00314 if (var.is_equal(s)) { 00315 // Return first exponent 00316 if (seq.size()) 00317 return ex_to<numeric>((seq.begin())->coeff).to_int(); 00318 else 00319 return 0; 00320 } else { 00321 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00322 if (it == itend) 00323 return 0; 00324 int min_pow = std::numeric_limits<int>::max(); 00325 while (it != itend) { 00326 int pow = it->rest.ldegree(s); 00327 if (pow < min_pow) 00328 min_pow = pow; 00329 ++it; 00330 } 00331 return min_pow; 00332 } 00333 } 00334 00342 ex pseries::coeff(const ex &s, int n) const 00343 { 00344 if (var.is_equal(s)) { 00345 if (seq.empty()) 00346 return _ex0; 00347 00348 // Binary search in sequence for given power 00349 numeric looking_for = numeric(n); 00350 int lo = 0, hi = seq.size() - 1; 00351 while (lo <= hi) { 00352 int mid = (lo + hi) / 2; 00353 GINAC_ASSERT(is_exactly_a<numeric>(seq[mid].coeff)); 00354 int cmp = ex_to<numeric>(seq[mid].coeff).compare(looking_for); 00355 switch (cmp) { 00356 case -1: 00357 lo = mid + 1; 00358 break; 00359 case 0: 00360 return seq[mid].rest; 00361 case 1: 00362 hi = mid - 1; 00363 break; 00364 default: 00365 throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1")); 00366 } 00367 } 00368 return _ex0; 00369 } else 00370 return convert_to_poly().coeff(s, n); 00371 } 00372 00374 ex pseries::collect(const ex &s, bool distributed) const 00375 { 00376 return *this; 00377 } 00378 00380 ex pseries::eval(int level) const 00381 { 00382 if (level == 1) 00383 return this->hold(); 00384 00385 if (level == -max_recursion_level) 00386 throw (std::runtime_error("pseries::eval(): recursion limit exceeded")); 00387 00388 // Construct a new series with evaluated coefficients 00389 epvector new_seq; 00390 new_seq.reserve(seq.size()); 00391 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00392 while (it != itend) { 00393 new_seq.push_back(expair(it->rest.eval(level-1), it->coeff)); 00394 ++it; 00395 } 00396 return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated); 00397 } 00398 00400 ex pseries::evalf(int level) const 00401 { 00402 if (level == 1) 00403 return *this; 00404 00405 if (level == -max_recursion_level) 00406 throw (std::runtime_error("pseries::evalf(): recursion limit exceeded")); 00407 00408 // Construct a new series with evaluated coefficients 00409 epvector new_seq; 00410 new_seq.reserve(seq.size()); 00411 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00412 while (it != itend) { 00413 new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff)); 00414 ++it; 00415 } 00416 return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated); 00417 } 00418 00419 ex pseries::conjugate() const 00420 { 00421 if(!var.info(info_flags::real)) 00422 return conjugate_function(*this).hold(); 00423 00424 epvector * newseq = conjugateepvector(seq); 00425 ex newpoint = point.conjugate(); 00426 00427 if (!newseq && are_ex_trivially_equal(point, newpoint)) { 00428 return *this; 00429 } 00430 00431 ex result = (new pseries(var==newpoint, newseq ? *newseq : seq))->setflag(status_flags::dynallocated); 00432 delete newseq; 00433 return result; 00434 } 00435 00436 ex pseries::real_part() const 00437 { 00438 if(!var.info(info_flags::real)) 00439 return real_part_function(*this).hold(); 00440 ex newpoint = point.real_part(); 00441 if(newpoint != point) 00442 return real_part_function(*this).hold(); 00443 00444 epvector v; 00445 v.reserve(seq.size()); 00446 for(epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) 00447 v.push_back(expair((i->rest).real_part(), i->coeff)); 00448 return (new pseries(var==point, v))->setflag(status_flags::dynallocated); 00449 } 00450 00451 ex pseries::imag_part() const 00452 { 00453 if(!var.info(info_flags::real)) 00454 return imag_part_function(*this).hold(); 00455 ex newpoint = point.real_part(); 00456 if(newpoint != point) 00457 return imag_part_function(*this).hold(); 00458 00459 epvector v; 00460 v.reserve(seq.size()); 00461 for(epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) 00462 v.push_back(expair((i->rest).imag_part(), i->coeff)); 00463 return (new pseries(var==point, v))->setflag(status_flags::dynallocated); 00464 } 00465 00466 ex pseries::eval_integ() const 00467 { 00468 epvector *newseq = NULL; 00469 for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { 00470 if (newseq) { 00471 newseq->push_back(expair(i->rest.eval_integ(), i->coeff)); 00472 continue; 00473 } 00474 ex newterm = i->rest.eval_integ(); 00475 if (!are_ex_trivially_equal(newterm, i->rest)) { 00476 newseq = new epvector; 00477 newseq->reserve(seq.size()); 00478 for (epvector::const_iterator j=seq.begin(); j!=i; ++j) 00479 newseq->push_back(*j); 00480 newseq->push_back(expair(newterm, i->coeff)); 00481 } 00482 } 00483 00484 ex newpoint = point.eval_integ(); 00485 if (newseq || !are_ex_trivially_equal(newpoint, point)) 00486 return (new pseries(var==newpoint, *newseq)) 00487 ->setflag(status_flags::dynallocated); 00488 return *this; 00489 } 00490 00491 ex pseries::evalm() const 00492 { 00493 // evalm each coefficient 00494 epvector newseq; 00495 bool something_changed = false; 00496 for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { 00497 if (something_changed) { 00498 ex newcoeff = i->rest.evalm(); 00499 if (!newcoeff.is_zero()) 00500 newseq.push_back(expair(newcoeff, i->coeff)); 00501 } 00502 else { 00503 ex newcoeff = i->rest.evalm(); 00504 if (!are_ex_trivially_equal(newcoeff, i->rest)) { 00505 something_changed = true; 00506 newseq.reserve(seq.size()); 00507 std::copy(seq.begin(), i, std::back_inserter<epvector>(newseq)); 00508 if (!newcoeff.is_zero()) 00509 newseq.push_back(expair(newcoeff, i->coeff)); 00510 } 00511 } 00512 } 00513 if (something_changed) 00514 return (new pseries(var==point, newseq))->setflag(status_flags::dynallocated); 00515 else 00516 return *this; 00517 } 00518 00519 ex pseries::subs(const exmap & m, unsigned options) const 00520 { 00521 // If expansion variable is being substituted, convert the series to a 00522 // polynomial and do the substitution there because the result might 00523 // no longer be a power series 00524 if (m.find(var) != m.end()) 00525 return convert_to_poly(true).subs(m, options); 00526 00527 // Otherwise construct a new series with substituted coefficients and 00528 // expansion point 00529 epvector newseq; 00530 newseq.reserve(seq.size()); 00531 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00532 while (it != itend) { 00533 newseq.push_back(expair(it->rest.subs(m, options), it->coeff)); 00534 ++it; 00535 } 00536 return (new pseries(relational(var,point.subs(m, options)), newseq))->setflag(status_flags::dynallocated); 00537 } 00538 00541 ex pseries::expand(unsigned options) const 00542 { 00543 epvector newseq; 00544 epvector::const_iterator i = seq.begin(), end = seq.end(); 00545 while (i != end) { 00546 ex restexp = i->rest.expand(); 00547 if (!restexp.is_zero()) 00548 newseq.push_back(expair(restexp, i->coeff)); 00549 ++i; 00550 } 00551 return (new pseries(relational(var,point), newseq)) 00552 ->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); 00553 } 00554 00557 ex pseries::derivative(const symbol & s) const 00558 { 00559 epvector new_seq; 00560 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00561 00562 if (s == var) { 00563 00564 // FIXME: coeff might depend on var 00565 while (it != itend) { 00566 if (is_order_function(it->rest)) { 00567 new_seq.push_back(expair(it->rest, it->coeff - 1)); 00568 } else { 00569 ex c = it->rest * it->coeff; 00570 if (!c.is_zero()) 00571 new_seq.push_back(expair(c, it->coeff - 1)); 00572 } 00573 ++it; 00574 } 00575 00576 } else { 00577 00578 while (it != itend) { 00579 if (is_order_function(it->rest)) { 00580 new_seq.push_back(*it); 00581 } else { 00582 ex c = it->rest.diff(s); 00583 if (!c.is_zero()) 00584 new_seq.push_back(expair(c, it->coeff)); 00585 } 00586 ++it; 00587 } 00588 } 00589 00590 return pseries(relational(var,point), new_seq); 00591 } 00592 00593 ex pseries::convert_to_poly(bool no_order) const 00594 { 00595 ex e; 00596 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00597 00598 while (it != itend) { 00599 if (is_order_function(it->rest)) { 00600 if (!no_order) 00601 e += Order(power(var - point, it->coeff)); 00602 } else 00603 e += it->rest * power(var - point, it->coeff); 00604 ++it; 00605 } 00606 return e; 00607 } 00608 00609 bool pseries::is_terminating() const 00610 { 00611 return seq.empty() || !is_order_function((seq.end()-1)->rest); 00612 } 00613 00614 ex pseries::coeffop(size_t i) const 00615 { 00616 if (i >=nops()) 00617 throw (std::out_of_range("coeffop() out of range")); 00618 return seq[i].rest; 00619 } 00620 00621 ex pseries::exponop(size_t i) const 00622 { 00623 if (i >= nops()) 00624 throw (std::out_of_range("exponop() out of range")); 00625 return seq[i].coeff; 00626 } 00627 00628 00629 /* 00630 * Implementations of series expansion 00631 */ 00632 00635 ex basic::series(const relational & r, int order, unsigned options) const 00636 { 00637 epvector seq; 00638 const symbol &s = ex_to<symbol>(r.lhs()); 00639 00640 // default for order-values that make no sense for Taylor expansion 00641 if ((order <= 0) && this->has(s)) { 00642 seq.push_back(expair(Order(_ex1), order)); 00643 return pseries(r, seq); 00644 } 00645 00646 // do Taylor expansion 00647 numeric fac = 1; 00648 ex deriv = *this; 00649 ex coeff = deriv.subs(r, subs_options::no_pattern); 00650 00651 if (!coeff.is_zero()) { 00652 seq.push_back(expair(coeff, _ex0)); 00653 } 00654 00655 int n; 00656 for (n=1; n<order; ++n) { 00657 fac = fac.mul(n); 00658 // We need to test for zero in order to see if the series terminates. 00659 // The problem is that there is no such thing as a perfect test for 00660 // zero. Expanding the term occasionally helps a little... 00661 deriv = deriv.diff(s).expand(); 00662 if (deriv.is_zero()) // Series terminates 00663 return pseries(r, seq); 00664 00665 coeff = deriv.subs(r, subs_options::no_pattern); 00666 if (!coeff.is_zero()) 00667 seq.push_back(expair(fac.inverse() * coeff, n)); 00668 } 00669 00670 // Higher-order terms, if present 00671 deriv = deriv.diff(s); 00672 if (!deriv.expand().is_zero()) 00673 seq.push_back(expair(Order(_ex1), n)); 00674 return pseries(r, seq); 00675 } 00676 00677 00680 ex symbol::series(const relational & r, int order, unsigned options) const 00681 { 00682 epvector seq; 00683 const ex point = r.rhs(); 00684 GINAC_ASSERT(is_a<symbol>(r.lhs())); 00685 00686 if (this->is_equal_same_type(ex_to<symbol>(r.lhs()))) { 00687 if (order > 0 && !point.is_zero()) 00688 seq.push_back(expair(point, _ex0)); 00689 if (order > 1) 00690 seq.push_back(expair(_ex1, _ex1)); 00691 else 00692 seq.push_back(expair(Order(_ex1), numeric(order))); 00693 } else 00694 seq.push_back(expair(*this, _ex0)); 00695 return pseries(r, seq); 00696 } 00697 00698 00704 ex pseries::add_series(const pseries &other) const 00705 { 00706 // Adding two series with different variables or expansion points 00707 // results in an empty (constant) series 00708 if (!is_compatible_to(other)) { 00709 epvector nul; 00710 nul.push_back(expair(Order(_ex1), _ex0)); 00711 return pseries(relational(var,point), nul); 00712 } 00713 00714 // Series addition 00715 epvector new_seq; 00716 epvector::const_iterator a = seq.begin(); 00717 epvector::const_iterator b = other.seq.begin(); 00718 epvector::const_iterator a_end = seq.end(); 00719 epvector::const_iterator b_end = other.seq.end(); 00720 int pow_a = std::numeric_limits<int>::max(), pow_b = std::numeric_limits<int>::max(); 00721 for (;;) { 00722 // If a is empty, fill up with elements from b and stop 00723 if (a == a_end) { 00724 while (b != b_end) { 00725 new_seq.push_back(*b); 00726 ++b; 00727 } 00728 break; 00729 } else 00730 pow_a = ex_to<numeric>((*a).coeff).to_int(); 00731 00732 // If b is empty, fill up with elements from a and stop 00733 if (b == b_end) { 00734 while (a != a_end) { 00735 new_seq.push_back(*a); 00736 ++a; 00737 } 00738 break; 00739 } else 00740 pow_b = ex_to<numeric>((*b).coeff).to_int(); 00741 00742 // a and b are non-empty, compare powers 00743 if (pow_a < pow_b) { 00744 // a has lesser power, get coefficient from a 00745 new_seq.push_back(*a); 00746 if (is_order_function((*a).rest)) 00747 break; 00748 ++a; 00749 } else if (pow_b < pow_a) { 00750 // b has lesser power, get coefficient from b 00751 new_seq.push_back(*b); 00752 if (is_order_function((*b).rest)) 00753 break; 00754 ++b; 00755 } else { 00756 // Add coefficient of a and b 00757 if (is_order_function((*a).rest) || is_order_function((*b).rest)) { 00758 new_seq.push_back(expair(Order(_ex1), (*a).coeff)); 00759 break; // Order term ends the sequence 00760 } else { 00761 ex sum = (*a).rest + (*b).rest; 00762 if (!(sum.is_zero())) 00763 new_seq.push_back(expair(sum, numeric(pow_a))); 00764 ++a; 00765 ++b; 00766 } 00767 } 00768 } 00769 return pseries(relational(var,point), new_seq); 00770 } 00771 00772 00776 ex add::series(const relational & r, int order, unsigned options) const 00777 { 00778 ex acc; // Series accumulator 00779 00780 // Get first term from overall_coeff 00781 acc = overall_coeff.series(r, order, options); 00782 00783 // Add remaining terms 00784 epvector::const_iterator it = seq.begin(); 00785 epvector::const_iterator itend = seq.end(); 00786 for (; it!=itend; ++it) { 00787 ex op; 00788 if (is_exactly_a<pseries>(it->rest)) 00789 op = it->rest; 00790 else 00791 op = it->rest.series(r, order, options); 00792 if (!it->coeff.is_equal(_ex1)) 00793 op = ex_to<pseries>(op).mul_const(ex_to<numeric>(it->coeff)); 00794 00795 // Series addition 00796 acc = ex_to<pseries>(acc).add_series(ex_to<pseries>(op)); 00797 } 00798 return acc; 00799 } 00800 00801 00807 ex pseries::mul_const(const numeric &other) const 00808 { 00809 epvector new_seq; 00810 new_seq.reserve(seq.size()); 00811 00812 epvector::const_iterator it = seq.begin(), itend = seq.end(); 00813 while (it != itend) { 00814 if (!is_order_function(it->rest)) 00815 new_seq.push_back(expair(it->rest * other, it->coeff)); 00816 else 00817 new_seq.push_back(*it); 00818 ++it; 00819 } 00820 return pseries(relational(var,point), new_seq); 00821 } 00822 00823 00829 ex pseries::mul_series(const pseries &other) const 00830 { 00831 // Multiplying two series with different variables or expansion points 00832 // results in an empty (constant) series 00833 if (!is_compatible_to(other)) { 00834 epvector nul; 00835 nul.push_back(expair(Order(_ex1), _ex0)); 00836 return pseries(relational(var,point), nul); 00837 } 00838 00839 if (seq.empty() || other.seq.empty()) { 00840 return (new pseries(var==point, epvector())) 00841 ->setflag(status_flags::dynallocated); 00842 } 00843 00844 // Series multiplication 00845 epvector new_seq; 00846 int a_max = degree(var); 00847 int b_max = other.degree(var); 00848 int a_min = ldegree(var); 00849 int b_min = other.ldegree(var); 00850 int cdeg_min = a_min + b_min; 00851 int cdeg_max = a_max + b_max; 00852 00853 int higher_order_a = std::numeric_limits<int>::max(); 00854 int higher_order_b = std::numeric_limits<int>::max(); 00855 if (is_order_function(coeff(var, a_max))) 00856 higher_order_a = a_max + b_min; 00857 if (is_order_function(other.coeff(var, b_max))) 00858 higher_order_b = b_max + a_min; 00859 int higher_order_c = std::min(higher_order_a, higher_order_b); 00860 if (cdeg_max >= higher_order_c) 00861 cdeg_max = higher_order_c - 1; 00862 00863 for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) { 00864 ex co = _ex0; 00865 // c(i)=a(0)b(i)+...+a(i)b(0) 00866 for (int i=a_min; cdeg-i>=b_min; ++i) { 00867 ex a_coeff = coeff(var, i); 00868 ex b_coeff = other.coeff(var, cdeg-i); 00869 if (!is_order_function(a_coeff) && !is_order_function(b_coeff)) 00870 co += a_coeff * b_coeff; 00871 } 00872 if (!co.is_zero()) 00873 new_seq.push_back(expair(co, numeric(cdeg))); 00874 } 00875 if (higher_order_c < std::numeric_limits<int>::max()) 00876 new_seq.push_back(expair(Order(_ex1), numeric(higher_order_c))); 00877 return pseries(relational(var, point), new_seq); 00878 } 00879 00880 00884 ex mul::series(const relational & r, int order, unsigned options) const 00885 { 00886 pseries acc; // Series accumulator 00887 00888 GINAC_ASSERT(is_a<symbol>(r.lhs())); 00889 const ex& sym = r.lhs(); 00890 00891 // holds ldegrees of the series of individual factors 00892 std::vector<int> ldegrees; 00893 std::vector<bool> ldegree_redo; 00894 00895 // find minimal degrees 00896 const epvector::const_iterator itbeg = seq.begin(); 00897 const epvector::const_iterator itend = seq.end(); 00898 // first round: obtain a bound up to which minimal degrees have to be 00899 // considered 00900 for (epvector::const_iterator it=itbeg; it!=itend; ++it) { 00901 00902 ex expon = it->coeff; 00903 int factor = 1; 00904 ex buf; 00905 if (expon.info(info_flags::integer)) { 00906 buf = it->rest; 00907 factor = ex_to<numeric>(expon).to_int(); 00908 } else { 00909 buf = recombine_pair_to_ex(*it); 00910 } 00911 00912 int real_ldegree = 0; 00913 bool flag_redo = false; 00914 try { 00915 real_ldegree = buf.expand().ldegree(sym-r.rhs()); 00916 } catch (std::runtime_error) {} 00917 00918 if (real_ldegree == 0) { 00919 if ( factor < 0 ) { 00920 // This case must terminate, otherwise we would have division by 00921 // zero. 00922 int orderloop = 0; 00923 do { 00924 orderloop++; 00925 real_ldegree = buf.series(r, orderloop, options).ldegree(sym); 00926 } while (real_ldegree == orderloop); 00927 } else { 00928 // Here it is possible that buf does not have a ldegree, therefore 00929 // check only if ldegree is negative, otherwise reconsider the case 00930 // in the second round. 00931 real_ldegree = buf.series(r, 0, options).ldegree(sym); 00932 if (real_ldegree == 0) 00933 flag_redo = true; 00934 } 00935 } 00936 00937 ldegrees.push_back(factor * real_ldegree); 00938 ldegree_redo.push_back(flag_redo); 00939 } 00940 00941 int degbound = order-std::accumulate(ldegrees.begin(), ldegrees.end(), 0); 00942 // Second round: determine the remaining positive ldegrees by the series 00943 // method. 00944 // here we can ignore ldegrees larger than degbound 00945 size_t j = 0; 00946 for (epvector::const_iterator it=itbeg; it!=itend; ++it) { 00947 if ( ldegree_redo[j] ) { 00948 ex expon = it->coeff; 00949 int factor = 1; 00950 ex buf; 00951 if (expon.info(info_flags::integer)) { 00952 buf = it->rest; 00953 factor = ex_to<numeric>(expon).to_int(); 00954 } else { 00955 buf = recombine_pair_to_ex(*it); 00956 } 00957 int real_ldegree = 0; 00958 int orderloop = 0; 00959 do { 00960 orderloop++; 00961 real_ldegree = buf.series(r, orderloop, options).ldegree(sym); 00962 } while ((real_ldegree == orderloop) 00963 && ( factor*real_ldegree < degbound)); 00964 ldegrees[j] = factor * real_ldegree; 00965 degbound -= factor * real_ldegree; 00966 } 00967 j++; 00968 } 00969 00970 int degsum = std::accumulate(ldegrees.begin(), ldegrees.end(), 0); 00971 00972 if (degsum >= order) { 00973 epvector epv; 00974 epv.push_back(expair(Order(_ex1), order)); 00975 return (new pseries(r, epv))->setflag(status_flags::dynallocated); 00976 } 00977 00978 // Multiply with remaining terms 00979 std::vector<int>::const_iterator itd = ldegrees.begin(); 00980 for (epvector::const_iterator it=itbeg; it!=itend; ++it, ++itd) { 00981 00982 // do series expansion with adjusted order 00983 ex op = recombine_pair_to_ex(*it).series(r, order-degsum+(*itd), options); 00984 00985 // Series multiplication 00986 if (it == itbeg) 00987 acc = ex_to<pseries>(op); 00988 else 00989 acc = ex_to<pseries>(acc.mul_series(ex_to<pseries>(op))); 00990 } 00991 00992 return acc.mul_const(ex_to<numeric>(overall_coeff)); 00993 } 00994 00995 01000 ex pseries::power_const(const numeric &p, int deg) const 01001 { 01002 // method: 01003 // (due to Leonhard Euler) 01004 // let A(x) be this series and for the time being let it start with a 01005 // constant (later we'll generalize): 01006 // A(x) = a_0 + a_1*x + a_2*x^2 + ... 01007 // We want to compute 01008 // C(x) = A(x)^p 01009 // C(x) = c_0 + c_1*x + c_2*x^2 + ... 01010 // Taking the derivative on both sides and multiplying with A(x) one 01011 // immediately arrives at 01012 // C'(x)*A(x) = p*C(x)*A'(x) 01013 // Multiplying this out and comparing coefficients we get the recurrence 01014 // formula 01015 // c_i = (i*p*a_i*c_0 + ((i-1)*p-1)*a_{i-1}*c_1 + ... 01016 // ... + (p-(i-1))*a_1*c_{i-1})/(a_0*i) 01017 // which can easily be solved given the starting value c_0 = (a_0)^p. 01018 // For the more general case where the leading coefficient of A(x) is not 01019 // a constant, just consider A2(x) = A(x)*x^m, with some integer m and 01020 // repeat the above derivation. The leading power of C2(x) = A2(x)^2 is 01021 // then of course x^(p*m) but the recurrence formula still holds. 01022 01023 if (seq.empty()) { 01024 // as a special case, handle the empty (zero) series honoring the 01025 // usual power laws such as implemented in power::eval() 01026 if (p.real().is_zero()) 01027 throw std::domain_error("pseries::power_const(): pow(0,I) is undefined"); 01028 else if (p.real().is_negative()) 01029 throw pole_error("pseries::power_const(): division by zero",1); 01030 else 01031 return *this; 01032 } 01033 01034 const int ldeg = ldegree(var); 01035 if (!(p*ldeg).is_integer()) 01036 throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series"); 01037 01038 // adjust number of coefficients 01039 int numcoeff = deg - (p*ldeg).to_int(); 01040 if (numcoeff <= 0) { 01041 epvector epv; 01042 epv.reserve(1); 01043 epv.push_back(expair(Order(_ex1), deg)); 01044 return (new pseries(relational(var,point), epv)) 01045 ->setflag(status_flags::dynallocated); 01046 } 01047 01048 // O(x^n)^(-m) is undefined 01049 if (seq.size() == 1 && is_order_function(seq[0].rest) && p.real().is_negative()) 01050 throw pole_error("pseries::power_const(): division by zero",1); 01051 01052 // Compute coefficients of the powered series 01053 exvector co; 01054 co.reserve(numcoeff); 01055 co.push_back(power(coeff(var, ldeg), p)); 01056 for (int i=1; i<numcoeff; ++i) { 01057 ex sum = _ex0; 01058 for (int j=1; j<=i; ++j) { 01059 ex c = coeff(var, j + ldeg); 01060 if (is_order_function(c)) { 01061 co.push_back(Order(_ex1)); 01062 break; 01063 } else 01064 sum += (p * j - (i - j)) * co[i - j] * c; 01065 } 01066 co.push_back(sum / coeff(var, ldeg) / i); 01067 } 01068 01069 // Construct new series (of non-zero coefficients) 01070 epvector new_seq; 01071 bool higher_order = false; 01072 for (int i=0; i<numcoeff; ++i) { 01073 if (!co[i].is_zero()) 01074 new_seq.push_back(expair(co[i], p * ldeg + i)); 01075 if (is_order_function(co[i])) { 01076 higher_order = true; 01077 break; 01078 } 01079 } 01080 if (!higher_order) 01081 new_seq.push_back(expair(Order(_ex1), p * ldeg + numcoeff)); 01082 01083 return pseries(relational(var,point), new_seq); 01084 } 01085 01086 01088 pseries pseries::shift_exponents(int deg) const 01089 { 01090 epvector newseq = seq; 01091 epvector::iterator i = newseq.begin(), end = newseq.end(); 01092 while (i != end) { 01093 i->coeff += deg; 01094 ++i; 01095 } 01096 return pseries(relational(var, point), newseq); 01097 } 01098 01099 01103 ex power::series(const relational & r, int order, unsigned options) const 01104 { 01105 // If basis is already a series, just power it 01106 if (is_exactly_a<pseries>(basis)) 01107 return ex_to<pseries>(basis).power_const(ex_to<numeric>(exponent), order); 01108 01109 // Basis is not a series, may there be a singularity? 01110 bool must_expand_basis = false; 01111 try { 01112 basis.subs(r, subs_options::no_pattern); 01113 } catch (pole_error) { 01114 must_expand_basis = true; 01115 } 01116 01117 bool exponent_is_regular = true; 01118 try { 01119 exponent.subs(r, subs_options::no_pattern); 01120 } catch (pole_error) { 01121 exponent_is_regular = false; 01122 } 01123 01124 if (!exponent_is_regular) { 01125 ex l = exponent*log(basis); 01126 // this == exp(l); 01127 ex le = l.series(r, order, options); 01128 // Note: expanding exp(l) won't help, since that will attempt 01129 // Taylor expansion, and fail (because exponent is "singular") 01130 // Still l itself might be expanded in Taylor series. 01131 // Examples: 01132 // sin(x)/x*log(cos(x)) 01133 // 1/x*log(1 + x) 01134 return exp(le).series(r, order, options); 01135 // Note: if l happens to have a Laurent expansion (with 01136 // negative powers of (var - point)), expanding exp(le) 01137 // will barf (which is The Right Thing). 01138 } 01139 01140 // Is the expression of type something^(-int)? 01141 if (!must_expand_basis && !exponent.info(info_flags::negint) 01142 && (!is_a<add>(basis) || !is_a<numeric>(exponent))) 01143 return basic::series(r, order, options); 01144 01145 // Is the expression of type 0^something? 01146 if (!must_expand_basis && !basis.subs(r, subs_options::no_pattern).is_zero() 01147 && (!is_a<add>(basis) || !is_a<numeric>(exponent))) 01148 return basic::series(r, order, options); 01149 01150 // Singularity encountered, is the basis equal to (var - point)? 01151 if (basis.is_equal(r.lhs() - r.rhs())) { 01152 epvector new_seq; 01153 if (ex_to<numeric>(exponent).to_int() < order) 01154 new_seq.push_back(expair(_ex1, exponent)); 01155 else 01156 new_seq.push_back(expair(Order(_ex1), exponent)); 01157 return pseries(r, new_seq); 01158 } 01159 01160 // No, expand basis into series 01161 01162 numeric numexp; 01163 if (is_a<numeric>(exponent)) { 01164 numexp = ex_to<numeric>(exponent); 01165 } else { 01166 numexp = 0; 01167 } 01168 const ex& sym = r.lhs(); 01169 // find existing minimal degree 01170 ex eb = basis.expand(); 01171 int real_ldegree = 0; 01172 if (eb.info(info_flags::rational_function)) 01173 real_ldegree = eb.ldegree(sym-r.rhs()); 01174 if (real_ldegree == 0) { 01175 int orderloop = 0; 01176 do { 01177 orderloop++; 01178 real_ldegree = basis.series(r, orderloop, options).ldegree(sym); 01179 } while (real_ldegree == orderloop); 01180 } 01181 01182 if (!(real_ldegree*numexp).is_integer()) 01183 throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series"); 01184 ex e = basis.series(r, (order + real_ldegree*(1-numexp)).to_int(), options); 01185 01186 ex result; 01187 try { 01188 result = ex_to<pseries>(e).power_const(numexp, order); 01189 } catch (pole_error) { 01190 epvector ser; 01191 ser.push_back(expair(Order(_ex1), order)); 01192 result = pseries(r, ser); 01193 } 01194 01195 return result; 01196 } 01197 01198 01200 ex pseries::series(const relational & r, int order, unsigned options) const 01201 { 01202 const ex p = r.rhs(); 01203 GINAC_ASSERT(is_a<symbol>(r.lhs())); 01204 const symbol &s = ex_to<symbol>(r.lhs()); 01205 01206 if (var.is_equal(s) && point.is_equal(p)) { 01207 if (order > degree(s)) 01208 return *this; 01209 else { 01210 epvector new_seq; 01211 epvector::const_iterator it = seq.begin(), itend = seq.end(); 01212 while (it != itend) { 01213 int o = ex_to<numeric>(it->coeff).to_int(); 01214 if (o >= order) { 01215 new_seq.push_back(expair(Order(_ex1), o)); 01216 break; 01217 } 01218 new_seq.push_back(*it); 01219 ++it; 01220 } 01221 return pseries(r, new_seq); 01222 } 01223 } else 01224 return convert_to_poly().series(r, order, options); 01225 } 01226 01227 ex integral::series(const relational & r, int order, unsigned options) const 01228 { 01229 if (x.subs(r) != x) 01230 throw std::logic_error("Cannot series expand wrt dummy variable"); 01231 01232 // Expanding integrant with r substituted taken in boundaries. 01233 ex fseries = f.series(r, order, options); 01234 epvector fexpansion; 01235 fexpansion.reserve(fseries.nops()); 01236 for (size_t i=0; i<fseries.nops(); ++i) { 01237 ex currcoeff = ex_to<pseries>(fseries).coeffop(i); 01238 currcoeff = (currcoeff == Order(_ex1)) 01239 ? currcoeff 01240 : integral(x, a.subs(r), b.subs(r), currcoeff); 01241 if (currcoeff != 0) 01242 fexpansion.push_back( 01243 expair(currcoeff, ex_to<pseries>(fseries).exponop(i))); 01244 } 01245 01246 // Expanding lower boundary 01247 ex result = (new pseries(r, fexpansion))->setflag(status_flags::dynallocated); 01248 ex aseries = (a-a.subs(r)).series(r, order, options); 01249 fseries = f.series(x == (a.subs(r)), order, options); 01250 for (size_t i=0; i<fseries.nops(); ++i) { 01251 ex currcoeff = ex_to<pseries>(fseries).coeffop(i); 01252 if (is_order_function(currcoeff)) 01253 break; 01254 ex currexpon = ex_to<pseries>(fseries).exponop(i); 01255 int orderforf = order-ex_to<numeric>(currexpon).to_int()-1; 01256 currcoeff = currcoeff.series(r, orderforf); 01257 ex term = ex_to<pseries>(aseries).power_const(ex_to<numeric>(currexpon+1),order); 01258 term = ex_to<pseries>(term).mul_const(ex_to<numeric>(-1/(currexpon+1))); 01259 term = ex_to<pseries>(term).mul_series(ex_to<pseries>(currcoeff)); 01260 result = ex_to<pseries>(result).add_series(ex_to<pseries>(term)); 01261 } 01262 01263 // Expanding upper boundary 01264 ex bseries = (b-b.subs(r)).series(r, order, options); 01265 fseries = f.series(x == (b.subs(r)), order, options); 01266 for (size_t i=0; i<fseries.nops(); ++i) { 01267 ex currcoeff = ex_to<pseries>(fseries).coeffop(i); 01268 if (is_order_function(currcoeff)) 01269 break; 01270 ex currexpon = ex_to<pseries>(fseries).exponop(i); 01271 int orderforf = order-ex_to<numeric>(currexpon).to_int()-1; 01272 currcoeff = currcoeff.series(r, orderforf); 01273 ex term = ex_to<pseries>(bseries).power_const(ex_to<numeric>(currexpon+1),order); 01274 term = ex_to<pseries>(term).mul_const(ex_to<numeric>(1/(currexpon+1))); 01275 term = ex_to<pseries>(term).mul_series(ex_to<pseries>(currcoeff)); 01276 result = ex_to<pseries>(result).add_series(ex_to<pseries>(term)); 01277 } 01278 01279 return result; 01280 } 01281 01282 01292 ex ex::series(const ex & r, int order, unsigned options) const 01293 { 01294 ex e; 01295 relational rel_; 01296 01297 if (is_a<relational>(r)) 01298 rel_ = ex_to<relational>(r); 01299 else if (is_a<symbol>(r)) 01300 rel_ = relational(r,_ex0); 01301 else 01302 throw (std::logic_error("ex::series(): expansion point has unknown type")); 01303 01304 e = bp->series(rel_, order, options); 01305 return e; 01306 } 01307 01308 GINAC_BIND_UNARCHIVER(pseries); 01309 01310 } // namespace GiNaC