]> www.ginac.de Git - ginac.git/blob - ginac/pseries.cpp
* Supplement some (now deprecated) macros by inlined template functions:
[ginac.git] / ginac / pseries.cpp
1 /** @file pseries.cpp
2  *
3  *  Implementation of class for extended truncated power series and
4  *  methods for series expansion. */
5
6 /*
7  *  GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <stdexcept>
25
26 #include "pseries.h"
27 #include "add.h"
28 #include "inifcns.h" // for Order function
29 #include "lst.h"
30 #include "mul.h"
31 #include "power.h"
32 #include "relational.h"
33 #include "symbol.h"
34 #include "print.h"
35 #include "archive.h"
36 #include "utils.h"
37 #include "debugmsg.h"
38
39 namespace GiNaC {
40
41 GINAC_IMPLEMENT_REGISTERED_CLASS(pseries, basic)
42
43
44 /*
45  *  Default ctor, dtor, copy ctor, assignment operator and helpers
46  */
47
48 pseries::pseries() : basic(TINFO_pseries)
49 {
50         debugmsg("pseries default ctor", LOGLEVEL_CONSTRUCT);
51 }
52
53 void pseries::copy(const pseries &other)
54 {
55         inherited::copy(other);
56         seq = other.seq;
57         var = other.var;
58         point = other.point;
59 }
60
61 DEFAULT_DESTROY(pseries)
62
63
64 /*
65  *  Other ctors
66  */
67
68 /** Construct pseries from a vector of coefficients and powers.
69  *  expair.rest holds the coefficient, expair.coeff holds the power.
70  *  The powers must be integers (positive or negative) and in ascending order;
71  *  the last coefficient can be Order(_ex1()) to represent a truncated,
72  *  non-terminating series.
73  *
74  *  @param rel_  expansion variable and point (must hold a relational)
75  *  @param ops_  vector of {coefficient, power} pairs (coefficient must not be zero)
76  *  @return newly constructed pseries */
77 pseries::pseries(const ex &rel_, const epvector &ops_) : basic(TINFO_pseries), seq(ops_)
78 {
79         debugmsg("pseries ctor from ex,epvector", LOGLEVEL_CONSTRUCT);
80         GINAC_ASSERT(is_ex_exactly_of_type(rel_, relational));
81         GINAC_ASSERT(is_ex_exactly_of_type(rel_.lhs(),symbol));
82         point = rel_.rhs();
83         var = *static_cast<symbol *>(rel_.lhs().bp);
84 }
85
86
87 /*
88  *  Archiving
89  */
90
91 pseries::pseries(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
92 {
93         debugmsg("pseries ctor from archive_node", LOGLEVEL_CONSTRUCT);
94         for (unsigned int i=0; true; ++i) {
95                 ex rest;
96                 ex coeff;
97                 if (n.find_ex("coeff", rest, sym_lst, i) && n.find_ex("power", coeff, sym_lst, i))
98                         seq.push_back(expair(rest, coeff));
99                 else
100                         break;
101         }
102         n.find_ex("var", var, sym_lst);
103         n.find_ex("point", point, sym_lst);
104 }
105
106 void pseries::archive(archive_node &n) const
107 {
108         inherited::archive(n);
109         epvector::const_iterator i = seq.begin(), iend = seq.end();
110         while (i != iend) {
111                 n.add_ex("coeff", i->rest);
112                 n.add_ex("power", i->coeff);
113                 ++i;
114         }
115         n.add_ex("var", var);
116         n.add_ex("point", point);
117 }
118
119 DEFAULT_UNARCHIVE(pseries)
120
121 //////////
122 // functions overriding virtual functions from bases classes
123 //////////
124
125 void pseries::print(const print_context & c, unsigned level) const
126 {
127         debugmsg("pseries print", LOGLEVEL_PRINT);
128
129         if (is_a<print_tree>(c)) {
130
131                 c.s << std::string(level, ' ') << class_name()
132                     << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
133                     << std::endl;
134                 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
135                 for (unsigned i=0; i<seq.size(); ++i) {
136                         seq[i].rest.print(c, level + delta_indent);
137                         seq[i].coeff.print(c, level + delta_indent);
138                         c.s << std::string(level + delta_indent, ' ') << "-----" << std::endl;
139                 }
140                 var.print(c, level + delta_indent);
141                 point.print(c, level + delta_indent);
142
143         } else {
144
145                 if (precedence() <= level)
146                         c.s << "(";
147                 
148                 std::string par_open = is_a<print_latex>(c) ? "{(" : "(";
149                 std::string par_close = is_a<print_latex>(c) ? ")}" : ")";
150                 
151                 // objects of type pseries must not have any zero entries, so the
152                 // trivial (zero) pseries needs a special treatment here:
153                 if (seq.size() == 0)
154                         c.s << '0';
155                 for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
156                         // print a sign, if needed
157                         if (i != seq.begin())
158                                 c.s << '+';
159                         if (!is_order_function(i->rest)) {
160                                 // print 'rest', i.e. the expansion coefficient
161                                 if (i->rest.info(info_flags::numeric) &&
162                                         i->rest.info(info_flags::positive)) {
163                                         i->rest.print(c);
164                                 } else {
165                                         c.s << par_open;
166                                         i->rest.print(c);
167                                         c.s << par_close;
168                                 }
169                                 // print 'coeff', something like (x-1)^42
170                                 if (!i->coeff.is_zero()) {
171                                         if (is_a<print_latex>(c))
172                                                 c.s << ' ';
173                                         else
174                                                 c.s << '*';
175                                         if (!point.is_zero()) {
176                                                 c.s << par_open;
177                                                 (var-point).print(c);
178                                                 c.s << par_close;
179                                         } else
180                                                 var.print(c);
181                                         if (i->coeff.compare(_ex1())) {
182                                                 c.s << '^';
183                                                 if (i->coeff.info(info_flags::negative)) {
184                                                         c.s << par_open;
185                                                         i->coeff.print(c);
186                                                         c.s << par_close;
187                                                 } else {
188                                                         if (is_a<print_latex>(c)) {
189                                                                 c.s << '{';
190                                                                 i->coeff.print(c);
191                                                                 c.s << '}';
192                                                         } else
193                                                                 i->coeff.print(c);
194                                                 }
195                                         }
196                                 }
197                         } else
198                                 Order(power(var-point,i->coeff)).print(c);
199                 }
200
201                 if (precedence() <= level)
202                         c.s << ")";
203         }
204 }
205
206 int pseries::compare_same_type(const basic & other) const
207 {
208         GINAC_ASSERT(is_of_type(other, pseries));
209         const pseries &o = static_cast<const pseries &>(other);
210         
211         // first compare the lengths of the series...
212         if (seq.size()>o.seq.size())
213                 return 1;
214         if (seq.size()<o.seq.size())
215                 return -1;
216         
217         // ...then the expansion point...
218         int cmpval = var.compare(o.var);
219         if (cmpval)
220                 return cmpval;
221         cmpval = point.compare(o.point);
222         if (cmpval)
223                 return cmpval;
224         
225         // ...and if that failed the individual elements
226         epvector::const_iterator it = seq.begin(), o_it = o.seq.begin();
227         while (it!=seq.end() && o_it!=o.seq.end()) {
228                 cmpval = it->compare(*o_it);
229                 if (cmpval)
230                         return cmpval;
231                 ++it;
232                 ++o_it;
233         }
234
235         // so they are equal.
236         return 0;
237 }
238
239 /** Return the number of operands including a possible order term. */
240 unsigned pseries::nops(void) const
241 {
242         return seq.size();
243 }
244
245 /** Return the ith term in the series when represented as a sum. */
246 ex pseries::op(int i) const
247 {
248         if (i < 0 || unsigned(i) >= seq.size())
249                 throw (std::out_of_range("op() out of range"));
250         return seq[i].rest * power(var - point, seq[i].coeff);
251 }
252
253 ex &pseries::let_op(int i)
254 {
255         throw (std::logic_error("let_op not defined for pseries"));
256 }
257
258 /** Return degree of highest power of the series.  This is usually the exponent
259  *  of the Order term.  If s is not the expansion variable of the series, the
260  *  series is examined termwise. */
261 int pseries::degree(const ex &s) const
262 {
263         if (var.is_equal(s)) {
264                 // Return last exponent
265                 if (seq.size())
266                         return ex_to<numeric>((*(seq.end() - 1)).coeff).to_int();
267                 else
268                         return 0;
269         } else {
270                 epvector::const_iterator it = seq.begin(), itend = seq.end();
271                 if (it == itend)
272                         return 0;
273                 int max_pow = INT_MIN;
274                 while (it != itend) {
275                         int pow = it->rest.degree(s);
276                         if (pow > max_pow)
277                                 max_pow = pow;
278                         ++it;
279                 }
280                 return max_pow;
281         }
282 }
283
284 /** Return degree of lowest power of the series.  This is usually the exponent
285  *  of the leading term.  If s is not the expansion variable of the series, the
286  *  series is examined termwise.  If s is the expansion variable but the
287  *  expansion point is not zero the series is not expanded to find the degree.
288  *  I.e.: (1-x) + (1-x)^2 + Order((1-x)^3) has ldegree(x) 1, not 0. */
289 int pseries::ldegree(const ex &s) const
290 {
291         if (var.is_equal(s)) {
292                 // Return first exponent
293                 if (seq.size())
294                         return ex_to<numeric>((*(seq.begin())).coeff).to_int();
295                 else
296                         return 0;
297         } else {
298                 epvector::const_iterator it = seq.begin(), itend = seq.end();
299                 if (it == itend)
300                         return 0;
301                 int min_pow = INT_MAX;
302                 while (it != itend) {
303                         int pow = it->rest.ldegree(s);
304                         if (pow < min_pow)
305                                 min_pow = pow;
306                         ++it;
307                 }
308                 return min_pow;
309         }
310 }
311
312 /** Return coefficient of degree n in power series if s is the expansion
313  *  variable.  If the expansion point is nonzero, by definition the n=1
314  *  coefficient in s of a+b*(s-z)+c*(s-z)^2+Order((s-z)^3) is b (assuming
315  *  the expansion took place in the s in the first place).
316  *  If s is not the expansion variable, an attempt is made to convert the
317  *  series to a polynomial and return the corresponding coefficient from
318  *  there. */
319 ex pseries::coeff(const ex &s, int n) const
320 {
321         if (var.is_equal(s)) {
322                 if (seq.size() == 0)
323                         return _ex0();
324                 
325                 // Binary search in sequence for given power
326                 numeric looking_for = numeric(n);
327                 int lo = 0, hi = seq.size() - 1;
328                 while (lo <= hi) {
329                         int mid = (lo + hi) / 2;
330                         GINAC_ASSERT(is_ex_exactly_of_type(seq[mid].coeff, numeric));
331                         int cmp = ex_to<numeric>(seq[mid].coeff).compare(looking_for);
332                         switch (cmp) {
333                                 case -1:
334                                         lo = mid + 1;
335                                         break;
336                                 case 0:
337                                         return seq[mid].rest;
338                                 case 1:
339                                         hi = mid - 1;
340                                         break;
341                                 default:
342                                         throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
343                         }
344                 }
345                 return _ex0();
346         } else
347                 return convert_to_poly().coeff(s, n);
348 }
349
350 /** Does nothing. */
351 ex pseries::collect(const ex &s, bool distributed) const
352 {
353         return *this;
354 }
355
356 /** Evaluate coefficients. */
357 ex pseries::eval(int level) const
358 {
359         if (level == 1)
360                 return this->hold();
361         
362         if (level == -max_recursion_level)
363                 throw (std::runtime_error("pseries::eval(): recursion limit exceeded"));
364         
365         // Construct a new series with evaluated coefficients
366         epvector new_seq;
367         new_seq.reserve(seq.size());
368         epvector::const_iterator it = seq.begin(), itend = seq.end();
369         while (it != itend) {
370                 new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
371                 ++it;
372         }
373         return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
374 }
375
376 /** Evaluate coefficients numerically. */
377 ex pseries::evalf(int level) const
378 {
379         if (level == 1)
380                 return *this;
381         
382         if (level == -max_recursion_level)
383                 throw (std::runtime_error("pseries::evalf(): recursion limit exceeded"));
384         
385         // Construct a new series with evaluated coefficients
386         epvector new_seq;
387         new_seq.reserve(seq.size());
388         epvector::const_iterator it = seq.begin(), itend = seq.end();
389         while (it != itend) {
390                 new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff));
391                 ++it;
392         }
393         return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
394 }
395
396 ex pseries::subs(const lst & ls, const lst & lr, bool no_pattern) const
397 {
398         // If expansion variable is being substituted, convert the series to a
399         // polynomial and do the substitution there because the result might
400         // no longer be a power series
401         if (ls.has(var))
402                 return convert_to_poly(true).subs(ls, lr, no_pattern);
403         
404         // Otherwise construct a new series with substituted coefficients and
405         // expansion point
406         epvector newseq;
407         newseq.reserve(seq.size());
408         epvector::const_iterator it = seq.begin(), itend = seq.end();
409         while (it != itend) {
410                 newseq.push_back(expair(it->rest.subs(ls, lr, no_pattern), it->coeff));
411                 ++it;
412         }
413         return (new pseries(relational(var,point.subs(ls, lr, no_pattern)), newseq))->setflag(status_flags::dynallocated);
414 }
415
416 /** Implementation of ex::expand() for a power series.  It expands all the
417  *  terms individually and returns the resulting series as a new pseries. */
418 ex pseries::expand(unsigned options) const
419 {
420         epvector newseq;
421         for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
422                 ex restexp = i->rest.expand();
423                 if (!restexp.is_zero())
424                         newseq.push_back(expair(restexp, i->coeff));
425         }
426         return (new pseries(relational(var,point), newseq))
427                 ->setflag(status_flags::dynallocated | status_flags::expanded);
428 }
429
430 /** Implementation of ex::diff() for a power series.  It treats the series as a
431  *  polynomial.
432  *  @see ex::diff */
433 ex pseries::derivative(const symbol & s) const
434 {
435         if (s == var) {
436                 epvector new_seq;
437                 epvector::const_iterator it = seq.begin(), itend = seq.end();
438                 
439                 // FIXME: coeff might depend on var
440                 while (it != itend) {
441                         if (is_order_function(it->rest)) {
442                                 new_seq.push_back(expair(it->rest, it->coeff - 1));
443                         } else {
444                                 ex c = it->rest * it->coeff;
445                                 if (!c.is_zero())
446                                         new_seq.push_back(expair(c, it->coeff - 1));
447                         }
448                         ++it;
449                 }
450                 return pseries(relational(var,point), new_seq);
451         } else {
452                 return *this;
453         }
454 }
455
456 ex pseries::convert_to_poly(bool no_order) const
457 {
458         ex e;
459         epvector::const_iterator it = seq.begin(), itend = seq.end();
460         
461         while (it != itend) {
462                 if (is_order_function(it->rest)) {
463                         if (!no_order)
464                                 e += Order(power(var - point, it->coeff));
465                 } else
466                         e += it->rest * power(var - point, it->coeff);
467                 ++it;
468         }
469         return e;
470 }
471
472 bool pseries::is_terminating(void) const
473 {
474         return seq.size() == 0 || !is_order_function((seq.end()-1)->rest);
475 }
476
477
478 /*
479  *  Implementations of series expansion
480  */
481
482 /** Default implementation of ex::series(). This performs Taylor expansion.
483  *  @see ex::series */
484 ex basic::series(const relational & r, int order, unsigned options) const
485 {
486         epvector seq;
487         numeric fac(1);
488         ex deriv = *this;
489         ex coeff = deriv.subs(r);
490         const symbol &s = static_cast<symbol &>(*r.lhs().bp);
491         
492         if (!coeff.is_zero())
493                 seq.push_back(expair(coeff, _ex0()));
494         
495         int n;
496         for (n=1; n<order; ++n) {
497                 fac = fac.mul(numeric(n));
498                 deriv = deriv.diff(s).expand();
499                 if (deriv.is_zero()) {
500                         // Series terminates
501                         return pseries(r, seq);
502                 }
503                 coeff = deriv.subs(r);
504                 if (!coeff.is_zero())
505                         seq.push_back(expair(fac.inverse() * coeff, numeric(n)));
506         }
507         
508         // Higher-order terms, if present
509         deriv = deriv.diff(s);
510         if (!deriv.expand().is_zero())
511                 seq.push_back(expair(Order(_ex1()), numeric(n)));
512         return pseries(r, seq);
513 }
514
515
516 /** Implementation of ex::series() for symbols.
517  *  @see ex::series */
518 ex symbol::series(const relational & r, int order, unsigned options) const
519 {
520         epvector seq;
521         const ex point = r.rhs();
522         GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
523         ex s = r.lhs();
524         
525         if (this->is_equal(*s.bp)) {
526                 if (order > 0 && !point.is_zero())
527                         seq.push_back(expair(point, _ex0()));
528                 if (order > 1)
529                         seq.push_back(expair(_ex1(), _ex1()));
530                 else
531                         seq.push_back(expair(Order(_ex1()), numeric(order)));
532         } else
533                 seq.push_back(expair(*this, _ex0()));
534         return pseries(r, seq);
535 }
536
537
538 /** Add one series object to another, producing a pseries object that
539  *  represents the sum.
540  *
541  *  @param other  pseries object to add with
542  *  @return the sum as a pseries */
543 ex pseries::add_series(const pseries &other) const
544 {
545         // Adding two series with different variables or expansion points
546         // results in an empty (constant) series 
547         if (!is_compatible_to(other)) {
548                 epvector nul;
549                 nul.push_back(expair(Order(_ex1()), _ex0()));
550                 return pseries(relational(var,point), nul);
551         }
552         
553         // Series addition
554         epvector new_seq;
555         epvector::const_iterator a = seq.begin();
556         epvector::const_iterator b = other.seq.begin();
557         epvector::const_iterator a_end = seq.end();
558         epvector::const_iterator b_end = other.seq.end();
559         int pow_a = INT_MAX, pow_b = INT_MAX;
560         for (;;) {
561                 // If a is empty, fill up with elements from b and stop
562                 if (a == a_end) {
563                         while (b != b_end) {
564                                 new_seq.push_back(*b);
565                                 ++b;
566                         }
567                         break;
568                 } else
569                         pow_a = ex_to<numeric>((*a).coeff).to_int();
570                 
571                 // If b is empty, fill up with elements from a and stop
572                 if (b == b_end) {
573                         while (a != a_end) {
574                                 new_seq.push_back(*a);
575                                 ++a;
576                         }
577                         break;
578                 } else
579                         pow_b = ex_to<numeric>((*b).coeff).to_int();
580                 
581                 // a and b are non-empty, compare powers
582                 if (pow_a < pow_b) {
583                         // a has lesser power, get coefficient from a
584                         new_seq.push_back(*a);
585                         if (is_order_function((*a).rest))
586                                 break;
587                         ++a;
588                 } else if (pow_b < pow_a) {
589                         // b has lesser power, get coefficient from b
590                         new_seq.push_back(*b);
591                         if (is_order_function((*b).rest))
592                                 break;
593                         ++b;
594                 } else {
595                         // Add coefficient of a and b
596                         if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
597                                 new_seq.push_back(expair(Order(_ex1()), (*a).coeff));
598                                 break;  // Order term ends the sequence
599                         } else {
600                                 ex sum = (*a).rest + (*b).rest;
601                                 if (!(sum.is_zero()))
602                                         new_seq.push_back(expair(sum, numeric(pow_a)));
603                                 ++a;
604                                 ++b;
605                         }
606                 }
607         }
608         return pseries(relational(var,point), new_seq);
609 }
610
611
612 /** Implementation of ex::series() for sums. This performs series addition when
613  *  adding pseries objects.
614  *  @see ex::series */
615 ex add::series(const relational & r, int order, unsigned options) const
616 {
617         ex acc; // Series accumulator
618         
619         // Get first term from overall_coeff
620         acc = overall_coeff.series(r, order, options);
621         
622         // Add remaining terms
623         epvector::const_iterator it = seq.begin();
624         epvector::const_iterator itend = seq.end();
625         for (; it!=itend; ++it) {
626                 ex op;
627                 if (is_ex_exactly_of_type(it->rest, pseries))
628                         op = it->rest;
629                 else
630                         op = it->rest.series(r, order, options);
631                 if (!it->coeff.is_equal(_ex1()))
632                         op = ex_to<pseries>(op).mul_const(ex_to<numeric>(it->coeff));
633                 
634                 // Series addition
635                 acc = ex_to<pseries>(acc).add_series(ex_to<pseries>(op));
636         }
637         return acc;
638 }
639
640
641 /** Multiply a pseries object with a numeric constant, producing a pseries
642  *  object that represents the product.
643  *
644  *  @param other  constant to multiply with
645  *  @return the product as a pseries */
646 ex pseries::mul_const(const numeric &other) const
647 {
648         epvector new_seq;
649         new_seq.reserve(seq.size());
650         
651         epvector::const_iterator it = seq.begin(), itend = seq.end();
652         while (it != itend) {
653                 if (!is_order_function(it->rest))
654                         new_seq.push_back(expair(it->rest * other, it->coeff));
655                 else
656                         new_seq.push_back(*it);
657                 ++it;
658         }
659         return pseries(relational(var,point), new_seq);
660 }
661
662
663 /** Multiply one pseries object to another, producing a pseries object that
664  *  represents the product.
665  *
666  *  @param other  pseries object to multiply with
667  *  @return the product as a pseries */
668 ex pseries::mul_series(const pseries &other) const
669 {
670         // Multiplying two series with different variables or expansion points
671         // results in an empty (constant) series 
672         if (!is_compatible_to(other)) {
673                 epvector nul;
674                 nul.push_back(expair(Order(_ex1()), _ex0()));
675                 return pseries(relational(var,point), nul);
676         }
677         
678         // Series multiplication
679         epvector new_seq;
680         
681         int a_max = degree(var);
682         int b_max = other.degree(var);
683         int a_min = ldegree(var);
684         int b_min = other.ldegree(var);
685         int cdeg_min = a_min + b_min;
686         int cdeg_max = a_max + b_max;
687         
688         int higher_order_a = INT_MAX;
689         int higher_order_b = INT_MAX;
690         if (is_order_function(coeff(var, a_max)))
691                 higher_order_a = a_max + b_min;
692         if (is_order_function(other.coeff(var, b_max)))
693                 higher_order_b = b_max + a_min;
694         int higher_order_c = std::min(higher_order_a, higher_order_b);
695         if (cdeg_max >= higher_order_c)
696                 cdeg_max = higher_order_c - 1;
697         
698         for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) {
699                 ex co = _ex0();
700                 // c(i)=a(0)b(i)+...+a(i)b(0)
701                 for (int i=a_min; cdeg-i>=b_min; ++i) {
702                         ex a_coeff = coeff(var, i);
703                         ex b_coeff = other.coeff(var, cdeg-i);
704                         if (!is_order_function(a_coeff) && !is_order_function(b_coeff))
705                                 co += a_coeff * b_coeff;
706                 }
707                 if (!co.is_zero())
708                         new_seq.push_back(expair(co, numeric(cdeg)));
709         }
710         if (higher_order_c < INT_MAX)
711                 new_seq.push_back(expair(Order(_ex1()), numeric(higher_order_c)));
712         return pseries(relational(var, point), new_seq);
713 }
714
715
716 /** Implementation of ex::series() for product. This performs series
717  *  multiplication when multiplying series.
718  *  @see ex::series */
719 ex mul::series(const relational & r, int order, unsigned options) const
720 {
721         ex acc; // Series accumulator
722         
723         // Get first term from overall_coeff
724         acc = overall_coeff.series(r, order, options);
725         
726         // Multiply with remaining terms
727         epvector::const_iterator it = seq.begin();
728         epvector::const_iterator itend = seq.end();
729         for (; it!=itend; ++it) {
730                 ex op = it->rest;
731                 if (op.info(info_flags::numeric)) {
732                         // series * const (special case, faster)
733                         ex f = power(op, it->coeff);
734                         acc = ex_to<pseries>(acc).mul_const(ex_to<numeric>(f));
735                         continue;
736                 } else if (!is_ex_exactly_of_type(op, pseries))
737                         op = op.series(r, order, options);
738                 if (!it->coeff.is_equal(_ex1()))
739                         op = ex_to<pseries>(op).power_const(ex_to<numeric>(it->coeff), order);
740
741                 // Series multiplication
742                 acc = ex_to<pseries>(acc).mul_series(ex_to<pseries>(op));
743         }
744         return acc;
745 }
746
747
748 /** Compute the p-th power of a series.
749  *
750  *  @param p  power to compute
751  *  @param deg  truncation order of series calculation */
752 ex pseries::power_const(const numeric &p, int deg) const
753 {
754         // method:
755         // let A(x) be this series and for the time being let it start with a
756         // constant (later we'll generalize):
757         //     A(x) = a_0 + a_1*x + a_2*x^2 + ...
758         // We want to compute
759         //     C(x) = A(x)^p
760         //     C(x) = c_0 + c_1*x + c_2*x^2 + ...
761         // Taking the derivative on both sides and multiplying with A(x) one
762         // immediately arrives at
763         //     C'(x)*A(x) = p*C(x)*A'(x)
764         // Multiplying this out and comparing coefficients we get the recurrence
765         // formula
766         //     c_i = (i*p*a_i*c_0 + ((i-1)*p-1)*a_{i-1}*c_1 + ...
767         //                    ... + (p-(i-1))*a_1*c_{i-1})/(a_0*i)
768         // which can easily be solved given the starting value c_0 = (a_0)^p.
769         // For the more general case where the leading coefficient of A(x) is not
770         // a constant, just consider A2(x) = A(x)*x^m, with some integer m and
771         // repeat the above derivation.  The leading power of C2(x) = A2(x)^2 is
772         // then of course x^(p*m) but the recurrence formula still holds.
773         
774         if (seq.size()==0) {
775                 // as a spacial case, handle the empty (zero) series honoring the
776                 // usual power laws such as implemented in power::eval()
777                 if (p.real().is_zero())
778                         throw (std::domain_error("pseries::power_const(): pow(0,I) is undefined"));
779                 else if (p.real().is_negative())
780                         throw (pole_error("pseries::power_const(): division by zero",1));
781                 else
782                         return *this;
783         }
784         
785         int ldeg = ldegree(var);
786         
787         // Compute coefficients of the powered series
788         exvector co;
789         co.reserve(deg);
790         co.push_back(power(coeff(var, ldeg), p));
791         bool all_sums_zero = true;
792         for (int i=1; i<deg; ++i) {
793                 ex sum = _ex0();
794                 for (int j=1; j<=i; ++j) {
795                         ex c = coeff(var, j + ldeg);
796                         if (is_order_function(c)) {
797                                 co.push_back(Order(_ex1()));
798                                 break;
799                         } else
800                                 sum += (p * j - (i - j)) * co[i - j] * c;
801                 }
802                 if (!sum.is_zero())
803                         all_sums_zero = false;
804                 co.push_back(sum / coeff(var, ldeg) / numeric(i));
805         }
806         
807         // Construct new series (of non-zero coefficients)
808         epvector new_seq;
809         bool higher_order = false;
810         for (int i=0; i<deg; ++i) {
811                 if (!co[i].is_zero())
812                         new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
813                 if (is_order_function(co[i])) {
814                         higher_order = true;
815                         break;
816                 }
817         }
818         if (!higher_order && !all_sums_zero)
819                 new_seq.push_back(expair(Order(_ex1()), numeric(deg) + p * ldeg));
820         return pseries(relational(var,point), new_seq);
821 }
822
823
824 /** Return a new pseries object with the powers shifted by deg. */
825 pseries pseries::shift_exponents(int deg) const
826 {
827         epvector newseq(seq);
828         for (epvector::iterator i=newseq.begin(); i!=newseq.end(); ++i)
829                 i->coeff = i->coeff + deg;
830         return pseries(relational(var, point), newseq);
831 }
832
833
834 /** Implementation of ex::series() for powers. This performs Laurent expansion
835  *  of reciprocals of series at singularities.
836  *  @see ex::series */
837 ex power::series(const relational & r, int order, unsigned options) const
838 {
839         ex e;
840         if (!is_ex_exactly_of_type(basis, pseries)) {
841                 // Basis is not a series, may there be a singularity?
842                 bool must_expand_basis = false;
843                 try {
844                         basis.subs(r);
845                 } catch (pole_error) {
846                         must_expand_basis = true;
847                 }
848                 
849                 // Is the expression of type something^(-int)?
850                 if (!must_expand_basis && !exponent.info(info_flags::negint))
851                         return basic::series(r, order, options);
852                 
853                 // Is the expression of type 0^something?
854                 if (!must_expand_basis && !basis.subs(r).is_zero())
855                         return basic::series(r, order, options);
856                 
857                 // Singularity encountered, expand basis into series
858                 e = basis.series(r, order, options);
859         } else {
860                 // Basis is a series
861                 e = basis;
862         }
863         
864         // Power e
865         return ex_to<pseries>(e).power_const(ex_to<numeric>(exponent), order);
866 }
867
868
869 /** Re-expansion of a pseries object. */
870 ex pseries::series(const relational & r, int order, unsigned options) const
871 {
872         const ex p = r.rhs();
873         GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
874         const symbol &s = static_cast<symbol &>(*r.lhs().bp);
875         
876         if (var.is_equal(s) && point.is_equal(p)) {
877                 if (order > degree(s))
878                         return *this;
879                 else {
880                         epvector new_seq;
881                         epvector::const_iterator it = seq.begin(), itend = seq.end();
882                         while (it != itend) {
883                                 int o = ex_to<numeric>(it->coeff).to_int();
884                                 if (o >= order) {
885                                         new_seq.push_back(expair(Order(_ex1()), o));
886                                         break;
887                                 }
888                                 new_seq.push_back(*it);
889                                 ++it;
890                         }
891                         return pseries(r, new_seq);
892                 }
893         } else
894                 return convert_to_poly().series(r, order, options);
895 }
896
897
898 /** Compute the truncated series expansion of an expression.
899  *  This function returns an expression containing an object of class pseries 
900  *  to represent the series. If the series does not terminate within the given
901  *  truncation order, the last term of the series will be an order term.
902  *
903  *  @param r  expansion relation, lhs holds variable and rhs holds point
904  *  @param order  truncation order of series calculations
905  *  @param options  of class series_options
906  *  @return an expression holding a pseries object */
907 ex ex::series(const ex & r, int order, unsigned options) const
908 {
909         GINAC_ASSERT(bp!=0);
910         ex e;
911         relational rel_;
912         
913         if (is_ex_exactly_of_type(r,relational))
914                 rel_ = ex_to<relational>(r);
915         else if (is_ex_exactly_of_type(r,symbol))
916                 rel_ = relational(r,_ex0());
917         else
918                 throw (std::logic_error("ex::series(): expansion point has unknown type"));
919         
920         try {
921                 e = bp->series(rel_, order, options);
922         } catch (std::exception &x) {
923                 throw (std::logic_error(std::string("unable to compute series (") + x.what() + ")"));
924         }
925         return e;
926 }
927
928 } // namespace GiNaC