]> www.ginac.de Git - ginac.git/blob - ginac/pseries.cpp
GINAC_DECLARE_REGISTERED_CLASS declares duplicate() and compare_same_type(),
[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"
29 #include "lst.h"
30 #include "mul.h"
31 #include "power.h"
32 #include "relational.h"
33 #include "symbol.h"
34 #include "archive.h"
35 #include "utils.h"
36 #include "debugmsg.h"
37
38 #ifndef NO_NAMESPACE_GINAC
39 namespace GiNaC {
40 #endif // ndef NO_NAMESPACE_GINAC
41
42 GINAC_IMPLEMENT_REGISTERED_CLASS(pseries, basic)
43
44 /*
45  *  Default constructor, destructor, copy constructor, assignment operator and helpers
46  */
47
48 pseries::pseries() : basic(TINFO_pseries)
49 {
50         debugmsg("pseries default constructor", 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 void pseries::destroy(bool call_parent)
62 {
63         if (call_parent)
64                 inherited::destroy(call_parent);
65 }
66
67
68 /*
69  *  Other constructors
70  */
71
72 /** Construct pseries from a vector of coefficients and powers.
73  *  expair.rest holds the coefficient, expair.coeff holds the power.
74  *  The powers must be integers (positive or negative) and in ascending order;
75  *  the last coefficient can be Order(_ex1()) to represent a truncated,
76  *  non-terminating series.
77  *
78  *  @param rel_  expansion variable and point (must hold a relational)
79  *  @param ops_  vector of {coefficient, power} pairs (coefficient must not be zero)
80  *  @return newly constructed pseries */
81 pseries::pseries(const ex &rel_, const epvector &ops_) : basic(TINFO_pseries), seq(ops_)
82 {
83         debugmsg("pseries constructor from ex,epvector", LOGLEVEL_CONSTRUCT);
84         GINAC_ASSERT(is_ex_exactly_of_type(rel_, relational));
85         GINAC_ASSERT(is_ex_exactly_of_type(rel_.lhs(),symbol));
86         point = rel_.rhs();
87         var = *static_cast<symbol *>(rel_.lhs().bp);
88 }
89
90
91 /*
92  *  Archiving
93  */
94
95 /** Construct object from archive_node. */
96 pseries::pseries(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
97 {
98         debugmsg("pseries constructor from archive_node", LOGLEVEL_CONSTRUCT);
99         for (unsigned int i=0; true; ++i) {
100                 ex rest;
101                 ex coeff;
102                 if (n.find_ex("coeff", rest, sym_lst, i) && n.find_ex("power", coeff, sym_lst, i))
103                         seq.push_back(expair(rest, coeff));
104                 else
105                         break;
106         }
107         n.find_ex("var", var, sym_lst);
108         n.find_ex("point", point, sym_lst);
109 }
110
111 /** Unarchive the object. */
112 ex pseries::unarchive(const archive_node &n, const lst &sym_lst)
113 {
114         return (new pseries(n, sym_lst))->setflag(status_flags::dynallocated);
115 }
116
117 /** Archive the object. */
118 void pseries::archive(archive_node &n) const
119 {
120         inherited::archive(n);
121         epvector::const_iterator i = seq.begin(), iend = seq.end();
122         while (i != iend) {
123                 n.add_ex("coeff", i->rest);
124                 n.add_ex("power", i->coeff);
125                 ++i;
126         }
127         n.add_ex("var", var);
128         n.add_ex("point", point);
129 }
130
131 //////////
132 // functions overriding virtual functions from bases classes
133 //////////
134
135 void pseries::print(std::ostream &os, unsigned upper_precedence) const
136 {
137         debugmsg("pseries print", LOGLEVEL_PRINT);
138         if (precedence<=upper_precedence) os << "(";
139         for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
140                 // omit zero terms
141                 if (i->rest.is_zero())
142                         continue;
143                 // print a sign, if needed
144                 if (i!=seq.begin())
145                         os << '+';
146                 if (!is_order_function(i->rest)) {
147                         // print 'rest', i.e. the expansion coefficient
148                         if (i->rest.info(info_flags::numeric) &&
149                                 i->rest.info(info_flags::positive)) {
150                                 os << i->rest;
151                         } else
152                                 os << "(" << i->rest << ')';
153                         // print 'coeff', something like (x-1)^42
154                         if (!i->coeff.is_zero()) {
155                                 os << '*';
156                                 if (!point.is_zero())
157                                         os << '(' << var-point << ')';
158                                 else
159                                         os << var;
160                                 if (i->coeff.compare(_ex1())) {
161                                         os << '^';
162                                         if (i->coeff.info(info_flags::negative))
163                                                 os << '(' << i->coeff << ')';
164                                         else
165                                                 os << i->coeff;
166                                 }
167                         }
168                 } else {
169                         os << Order(power(var-point,i->coeff));
170                 }
171         }
172         if (precedence<=upper_precedence) os << ")";
173 }
174
175
176 void pseries::printraw(std::ostream &os) const
177 {
178         debugmsg("pseries printraw", LOGLEVEL_PRINT);
179         os << "pseries(" << var << ";" << point << ";";
180         for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
181                 os << "(" << (*i).rest << "," << (*i).coeff << "),";
182         }
183         os << ")";
184 }
185
186
187 void pseries::printtree(std::ostream & os, unsigned indent) const
188 {
189         debugmsg("pseries printtree",LOGLEVEL_PRINT);
190         os << std::string(indent,' ') << "pseries " 
191            << ", hash=" << hashvalue
192            << " (0x" << std::hex << hashvalue << std::dec << ")"
193            << ", flags=" << flags << std::endl;
194         for (unsigned i=0; i<seq.size(); ++i) {
195                 seq[i].rest.printtree(os,indent+delta_indent);
196                 seq[i].coeff.printtree(os,indent+delta_indent);
197                 if (i!=seq.size()-1)
198                         os << std::string(indent+delta_indent,' ') << "-----" << std::endl;
199         }
200         var.printtree(os, indent+delta_indent);
201         point.printtree(os, indent+delta_indent);
202 }
203
204 int pseries::compare_same_type(const basic & other) const
205 {
206         GINAC_ASSERT(is_of_type(other, pseries));
207         const pseries &o = static_cast<const pseries &>(other);
208
209         int cmpval = var.compare(o.var);
210         if (cmpval)
211                 return cmpval;
212         cmpval = point.compare(o.point);
213         if (cmpval)
214                 return cmpval;
215
216         epvector::const_iterator it1 = seq.begin(), it2 = o.seq.begin(), it1end = seq.end(), it2end = o.seq.end();
217         while ((it1 != it1end) && (it2 != it2end)) {
218                 cmpval = it1->compare(*it2);
219                 if (cmpval)
220                         return cmpval;
221                 it1++; it2++;
222         }
223         if (it1 == it1end)
224                 return it2 == it2end ? 0 : -1;
225
226         return 0;
227 }
228
229 /** Return the number of operands including a possible order term. */
230 unsigned pseries::nops(void) const
231 {
232         return seq.size();
233 }
234
235
236 /** Return the ith term in the series when represented as a sum. */
237 ex pseries::op(int i) const
238 {
239         if (i < 0 || unsigned(i) >= seq.size())
240                 throw (std::out_of_range("op() out of range"));
241         return seq[i].rest * power(var - point, seq[i].coeff);
242 }
243
244
245 ex &pseries::let_op(int i)
246 {
247         throw (std::logic_error("let_op not defined for pseries"));
248 }
249
250
251 /** Return degree of highest power of the series.  This is usually the exponent
252  *  of the Order term.  If s is not the expansion variable of the series, the
253  *  series is examined termwise. */
254 int pseries::degree(const symbol &s) const
255 {
256         if (var.is_equal(s)) {
257                 // Return last exponent
258                 if (seq.size())
259                         return ex_to_numeric((*(seq.end() - 1)).coeff).to_int();
260                 else
261                         return 0;
262         } else {
263                 epvector::const_iterator it = seq.begin(), itend = seq.end();
264                 if (it == itend)
265                         return 0;
266                 int max_pow = INT_MIN;
267                 while (it != itend) {
268                         int pow = it->rest.degree(s);
269                         if (pow > max_pow)
270                                 max_pow = pow;
271                         ++it;
272                 }
273                 return max_pow;
274         }
275 }
276
277 /** Return degree of lowest power of the series.  This is usually the exponent
278  *  of the leading term.  If s is not the expansion variable of the series, the
279  *  series is examined termwise.  If s is the expansion variable but the
280  *  expansion point is not zero the series is not expanded to find the degree.
281  *  I.e.: (1-x) + (1-x)^2 + Order((1-x)^3) has ldegree(x) 1, not 0. */
282 int pseries::ldegree(const symbol &s) const
283 {
284         if (var.is_equal(s)) {
285                 // Return first exponent
286                 if (seq.size())
287                         return ex_to_numeric((*(seq.begin())).coeff).to_int();
288                 else
289                         return 0;
290         } else {
291                 epvector::const_iterator it = seq.begin(), itend = seq.end();
292                 if (it == itend)
293                         return 0;
294                 int min_pow = INT_MAX;
295                 while (it != itend) {
296                         int pow = it->rest.ldegree(s);
297                         if (pow < min_pow)
298                                 min_pow = pow;
299                         ++it;
300                 }
301                 return min_pow;
302         }
303 }
304
305 ex pseries::coeff(const symbol &s, int n) const
306 {
307         if (var.is_equal(s)) {
308                 if (seq.size() == 0)
309                         return _ex0();
310                 
311                 // Binary search in sequence for given power
312                 numeric looking_for = numeric(n);
313                 int lo = 0, hi = seq.size() - 1;
314                 while (lo <= hi) {
315                         int mid = (lo + hi) / 2;
316                         GINAC_ASSERT(is_ex_exactly_of_type(seq[mid].coeff, numeric));
317                         int cmp = ex_to_numeric(seq[mid].coeff).compare(looking_for);
318                         switch (cmp) {
319                                 case -1:
320                                         lo = mid + 1;
321                                         break;
322                                 case 0:
323                                         return seq[mid].rest;
324                                 case 1:
325                                         hi = mid - 1;
326                                         break;
327                                 default:
328                                         throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
329                         }
330                 }
331                 return _ex0();
332         } else
333                 return convert_to_poly().coeff(s, n);
334 }
335
336
337 ex pseries::collect(const symbol &s) const
338 {
339         return *this;
340 }
341
342
343 /** Evaluate coefficients. */
344 ex pseries::eval(int level) const
345 {
346         if (level == 1)
347                 return this->hold();
348         
349         if (level == -max_recursion_level)
350                 throw (std::runtime_error("pseries::eval(): recursion limit exceeded"));
351         
352         // Construct a new series with evaluated coefficients
353         epvector new_seq;
354         new_seq.reserve(seq.size());
355         epvector::const_iterator it = seq.begin(), itend = seq.end();
356         while (it != itend) {
357                 new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
358                 ++it;
359         }
360         return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
361 }
362
363
364 /** Evaluate coefficients numerically. */
365 ex pseries::evalf(int level) const
366 {
367         if (level == 1)
368                 return *this;
369         
370         if (level == -max_recursion_level)
371                 throw (std::runtime_error("pseries::evalf(): recursion limit exceeded"));
372         
373         // Construct a new series with evaluated coefficients
374         epvector new_seq;
375         new_seq.reserve(seq.size());
376         epvector::const_iterator it = seq.begin(), itend = seq.end();
377         while (it != itend) {
378                 new_seq.push_back(expair(it->rest.evalf(level-1), it->coeff));
379                 ++it;
380         }
381         return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
382 }
383
384
385 ex pseries::subs(const lst & ls, const lst & lr) const
386 {
387         // If expansion variable is being substituted, convert the series to a
388         // polynomial and do the substitution there because the result might
389         // no longer be a power series
390         if (ls.has(var))
391                 return convert_to_poly(true).subs(ls, lr);
392         
393         // Otherwise construct a new series with substituted coefficients and
394         // expansion point
395         epvector newseq;
396         newseq.reserve(seq.size());
397         epvector::const_iterator it = seq.begin(), itend = seq.end();
398         while (it != itend) {
399                 newseq.push_back(expair(it->rest.subs(ls, lr), it->coeff));
400                 ++it;
401         }
402         return (new pseries(relational(var,point.subs(ls, lr)), newseq))->setflag(status_flags::dynallocated);
403 }
404
405
406 /** Implementation of ex::expand() for a power series.  It expands all the
407  *  terms individually and returns the resulting series as a new pseries.
408  *  @see ex::diff */
409 ex pseries::expand(unsigned options) const
410 {
411         epvector newseq;
412         newseq.reserve(seq.size());
413         for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i)
414                 newseq.push_back(expair(i->rest.expand(), i->coeff));
415         return (new pseries(relational(var,point), newseq))
416                 ->setflag(status_flags::dynallocated | status_flags::expanded);
417 }
418
419
420 /** Implementation of ex::diff() for a power series.  It treats the series as a
421  *  polynomial.
422  *  @see ex::diff */
423 ex pseries::derivative(const symbol & s) const
424 {
425         if (s == var) {
426                 epvector new_seq;
427                 epvector::const_iterator it = seq.begin(), itend = seq.end();
428                 
429                 // FIXME: coeff might depend on var
430                 while (it != itend) {
431                         if (is_order_function(it->rest)) {
432                                 new_seq.push_back(expair(it->rest, it->coeff - 1));
433                         } else {
434                                 ex c = it->rest * it->coeff;
435                                 if (!c.is_zero())
436                                         new_seq.push_back(expair(c, it->coeff - 1));
437                         }
438                         ++it;
439                 }
440                 return pseries(relational(var,point), new_seq);
441         } else {
442                 return *this;
443         }
444 }
445
446
447 /*
448  *  Construct ordinary polynomial out of series
449  */
450
451 /** Convert a pseries object to an ordinary polynomial.
452  *
453  *  @param no_order flag: discard higher order terms */
454 ex pseries::convert_to_poly(bool no_order) const
455 {
456         ex e;
457         epvector::const_iterator it = seq.begin(), itend = seq.end();
458         
459         while (it != itend) {
460                 if (is_order_function(it->rest)) {
461                         if (!no_order)
462                                 e += Order(power(var - point, it->coeff));
463                 } else
464                         e += it->rest * power(var - point, it->coeff);
465                 ++it;
466         }
467         return e;
468 }
469
470 /** Returns true if there is no order term, i.e. the series terminates and
471  *  false otherwise. */
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  *  Implementation 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, numeric(0)));
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         const symbol *s = static_cast<symbol *>(r.lhs().bp);
524         
525         if (this->is_equal(*s)) {
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         const symbol *s = static_cast<symbol *>(var.bp);
682         int a_max = degree(*s);
683         int b_max = other.degree(*s);
684         int a_min = ldegree(*s);
685         int b_min = other.ldegree(*s);
686         int cdeg_min = a_min + b_min;
687         int cdeg_max = a_max + b_max;
688         
689         int higher_order_a = INT_MAX;
690         int higher_order_b = INT_MAX;
691         if (is_order_function(coeff(*s, a_max)))
692                 higher_order_a = a_max + b_min;
693         if (is_order_function(other.coeff(*s, b_max)))
694                 higher_order_b = b_max + a_min;
695         int higher_order_c = std::min(higher_order_a, higher_order_b);
696         if (cdeg_max >= higher_order_c)
697                 cdeg_max = higher_order_c - 1;
698         
699         for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) {
700                 ex co = _ex0();
701                 // c(i)=a(0)b(i)+...+a(i)b(0)
702                 for (int i=a_min; cdeg-i>=b_min; ++i) {
703                         ex a_coeff = coeff(*s, i);
704                         ex b_coeff = other.coeff(*s, cdeg-i);
705                         if (!is_order_function(a_coeff) && !is_order_function(b_coeff))
706                                 co += a_coeff * b_coeff;
707                 }
708                 if (!co.is_zero())
709                         new_seq.push_back(expair(co, numeric(cdeg)));
710         }
711         if (higher_order_c < INT_MAX)
712                 new_seq.push_back(expair(Order(_ex1()), numeric(higher_order_c)));
713         return pseries(relational(var,point), new_seq);
714 }
715
716
717 /** Implementation of ex::series() for product. This performs series
718  *  multiplication when multiplying series.
719  *  @see ex::series */
720 ex mul::series(const relational & r, int order, unsigned options) const
721 {
722         ex acc; // Series accumulator
723         
724         // Get first term from overall_coeff
725         acc = overall_coeff.series(r, order, options);
726         
727         // Multiply with remaining terms
728         epvector::const_iterator it = seq.begin();
729         epvector::const_iterator itend = seq.end();
730         for (; it!=itend; ++it) {
731                 ex op = it->rest;
732                 if (op.info(info_flags::numeric)) {
733                         // series * const (special case, faster)
734                         ex f = power(op, it->coeff);
735                         acc = ex_to_pseries(acc).mul_const(ex_to_numeric(f));
736                         continue;
737                 } else if (!is_ex_exactly_of_type(op, pseries))
738                         op = op.series(r, order, options);
739                 if (!it->coeff.is_equal(_ex1()))
740                         op = ex_to_pseries(op).power_const(ex_to_numeric(it->coeff), order);
741
742                 // Series multiplication
743                 acc = ex_to_pseries(acc).mul_series(ex_to_pseries(op));
744         }
745         return acc;
746 }
747
748
749 /** Compute the p-th power of a series.
750  *
751  *  @param p  power to compute
752  *  @param deg  truncation order of series calculation */
753 ex pseries::power_const(const numeric &p, int deg) const
754 {
755         // method:
756         // let A(x) be this series and for the time being let it start with a
757         // constant (later we'll generalize):
758         //     A(x) = a_0 + a_1*x + a_2*x^2 + ...
759         // We want to compute
760         //     C(x) = A(x)^p
761         //     C(x) = c_0 + c_1*x + c_2*x^2 + ...
762         // Taking the derivative on both sides and multiplying with A(x) one
763         // immediately arrives at
764         //     C'(x)*A(x) = p*C(x)*A'(x)
765         // Multiplying this out and comparing coefficients we get the recurrence
766         // formula
767         //     c_i = (i*p*a_i*c_0 + ((i-1)*p-1)*a_{i-1}*c_1 + ...
768         //                    ... + (p-(i-1))*a_1*c_{i-1})/(a_0*i)
769         // which can easily be solved given the starting value c_0 = (a_0)^p.
770         // For the more general case where the leading coefficient of A(x) is not
771         // a constant, just consider A2(x) = A(x)*x^m, with some integer m and
772         // repeat the above derivation.  The leading power of C2(x) = A2(x)^2 is
773         // then of course x^(p*m) but the recurrence formula still holds.
774         const symbol *s = static_cast<symbol *>(var.bp);
775         int ldeg = ldegree(*s);
776         
777         // Compute coefficients of the powered series
778         exvector co;
779         co.reserve(deg);
780         co.push_back(power(coeff(*s, ldeg), p));
781         bool all_sums_zero = true;
782         for (int i=1; i<deg; ++i) {
783                 ex sum = _ex0();
784                 for (int j=1; j<=i; ++j) {
785                         ex c = coeff(*s, j + ldeg);
786                         if (is_order_function(c)) {
787                                 co.push_back(Order(_ex1()));
788                                 break;
789                         } else
790                                 sum += (p * j - (i - j)) * co[i - j] * c;
791                 }
792                 if (!sum.is_zero())
793                         all_sums_zero = false;
794                 co.push_back(sum / coeff(*s, ldeg) / numeric(i));
795         }
796         
797         // Construct new series (of non-zero coefficients)
798         epvector new_seq;
799         bool higher_order = false;
800         for (int i=0; i<deg; ++i) {
801                 if (!co[i].is_zero())
802                         new_seq.push_back(expair(co[i], numeric(i) + p * ldeg));
803                 if (is_order_function(co[i])) {
804                         higher_order = true;
805                         break;
806                 }
807         }
808         if (!higher_order && !all_sums_zero)
809                 new_seq.push_back(expair(Order(_ex1()), numeric(deg) + p * ldeg));
810         return pseries(relational(var,point), new_seq);
811 }
812
813
814 /** Return a new pseries object with the powers shifted by deg. */
815 pseries pseries::shift_exponents(int deg) const
816 {
817         epvector newseq(seq);
818         for (epvector::iterator i=newseq.begin(); i!=newseq.end(); ++i)
819                 i->coeff = i->coeff + deg;
820         return pseries(relational(var, point), newseq);
821 }
822
823
824 /** Implementation of ex::series() for powers. This performs Laurent expansion
825  *  of reciprocals of series at singularities.
826  *  @see ex::series */
827 ex power::series(const relational & r, int order, unsigned options) const
828 {
829         ex e;
830         if (!is_ex_exactly_of_type(basis, pseries)) {
831                 // Basis is not a series, may there be a singularity?
832                 bool must_expand_basis = false;
833                 try {
834                         basis.subs(r);
835                 } catch (pole_error) {
836                         must_expand_basis = true;
837                 }
838                 
839                 // Is the expression of type something^(-int)?
840                 if (!must_expand_basis && !exponent.info(info_flags::negint))
841                         return basic::series(r, order, options);
842                 
843                 // Is the expression of type 0^something?
844                 if (!must_expand_basis && !basis.subs(r).is_zero())
845                         return basic::series(r, order, options);
846                 
847                 // Singularity encountered, expand basis into series
848                 e = basis.series(r, order, options);
849         } else {
850                 // Basis is a series
851                 e = basis;
852         }
853         
854         // Power e
855         return ex_to_pseries(e).power_const(ex_to_numeric(exponent), order);
856 }
857
858
859 /** Re-expansion of a pseries object. */
860 ex pseries::series(const relational & r, int order, unsigned options) const
861 {
862         const ex p = r.rhs();
863         GINAC_ASSERT(is_ex_exactly_of_type(r.lhs(),symbol));
864         const symbol *s = static_cast<symbol *>(r.lhs().bp);
865         
866         if (var.is_equal(*s) && point.is_equal(p)) {
867                 if (order > degree(*s))
868                         return *this;
869                 else {
870                         epvector new_seq;
871                         epvector::const_iterator it = seq.begin(), itend = seq.end();
872                         while (it != itend) {
873                                 int o = ex_to_numeric(it->coeff).to_int();
874                                 if (o >= order) {
875                                         new_seq.push_back(expair(Order(_ex1()), o));
876                                         break;
877                                 }
878                                 new_seq.push_back(*it);
879                                 ++it;
880                         }
881                         return pseries(r, new_seq);
882                 }
883         } else
884                 return convert_to_poly().series(r, order, options);
885 }
886
887
888 /** Compute the truncated series expansion of an expression.
889  *  This function returns an expression containing an object of class pseries 
890  *  to represent the series. If the series does not terminate within the given
891  *  truncation order, the last term of the series will be an order term.
892  *
893  *  @param r  expansion relation, lhs holds variable and rhs holds point
894  *  @param order  truncation order of series calculations
895  *  @param options  of class series_options
896  *  @return an expression holding a pseries object */
897 ex ex::series(const ex & r, int order, unsigned options) const
898 {
899         GINAC_ASSERT(bp!=0);
900         ex e;
901         relational rel_;
902         
903         if (is_ex_exactly_of_type(r,relational))
904                 rel_ = ex_to_relational(r);
905         else if (is_ex_exactly_of_type(r,symbol))
906                 rel_ = relational(r,_ex0());
907         else
908                 throw (std::logic_error("ex::series(): expansion point has unknown type"));
909         
910         try {
911                 e = bp->series(rel_, order, options);
912         } catch (std::exception &x) {
913                 throw (std::logic_error(std::string("unable to compute series (") + x.what() + ")"));
914         }
915         return e;
916 }
917
918 //////////
919 // static member variables
920 //////////
921
922 // protected
923
924 unsigned pseries::precedence = 38;  // for clarity just below add::precedence
925
926 #ifndef NO_NAMESPACE_GINAC
927 } // namespace GiNaC
928 #endif // ndef NO_NAMESPACE_GINAC