GiNaC  1.8.0
pseries.cpp
Go to the documentation of this file.
1 
6 /*
7  * GiNaC Copyright (C) 1999-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include "pseries.h"
25 #include "add.h"
26 #include "inifcns.h" // for Order function
27 #include "lst.h"
28 #include "mul.h"
29 #include "power.h"
30 #include "relational.h"
31 #include "operators.h"
32 #include "symbol.h"
33 #include "integral.h"
34 #include "archive.h"
35 #include "utils.h"
36 
37 #include <limits>
38 #include <numeric>
39 #include <stdexcept>
40 
41 namespace GiNaC {
42 
45  print_func<print_latex>(&pseries::do_print_latex).
46  print_func<print_tree>(&pseries::do_print_tree).
47  print_func<print_python>(&pseries::do_print_python).
48  print_func<print_python_repr>(&pseries::do_print_python_repr))
49 
50 
51 /*
52  * Default constructor
53  */
54 
55 pseries::pseries() { }
56 
57 
58 /*
59  * Other ctors
60  */
61 
71 pseries::pseries(const ex &rel_, const epvector &ops_)
72  : seq(ops_)
73 {
74 #ifdef DO_GINAC_ASSERT
75  auto i = seq.begin();
76  while (i != seq.end()) {
77  auto ip1 = i+1;
78  if (ip1 != seq.end())
80  else
81  break;
82  GINAC_ASSERT(is_a<numeric>(i->coeff));
83  GINAC_ASSERT(ex_to<numeric>(i->coeff) < ex_to<numeric>(ip1->coeff));
84  ++i;
85  }
86 #endif // def DO_GINAC_ASSERT
87  GINAC_ASSERT(is_a<relational>(rel_));
88  GINAC_ASSERT(is_a<symbol>(rel_.lhs()));
89  point = rel_.rhs();
90  var = rel_.lhs();
91 }
92 pseries::pseries(const ex &rel_, epvector &&ops_)
93  : seq(std::move(ops_))
94 {
95 #ifdef DO_GINAC_ASSERT
96  auto i = seq.begin();
97  while (i != seq.end()) {
98  auto ip1 = i+1;
99  if (ip1 != seq.end())
100  GINAC_ASSERT(!is_order_function(i->rest));
101  else
102  break;
103  GINAC_ASSERT(is_a<numeric>(i->coeff));
104  GINAC_ASSERT(ex_to<numeric>(i->coeff) < ex_to<numeric>(ip1->coeff));
105  ++i;
106  }
107 #endif // def DO_GINAC_ASSERT
108  GINAC_ASSERT(is_a<relational>(rel_));
109  GINAC_ASSERT(is_a<symbol>(rel_.lhs()));
110  point = rel_.rhs();
111  var = rel_.lhs();
112 }
113 
114 
115 /*
116  * Archiving
117  */
118 
119 void pseries::read_archive(const archive_node &n, lst &sym_lst)
120 {
121  inherited::read_archive(n, sym_lst);
122  auto range = n.find_property_range("coeff", "power");
123  seq.reserve((range.end-range.begin)/2);
124 
125  for (auto loc = range.begin; loc < range.end;) {
126  ex rest;
127  ex coeff;
128  n.find_ex_by_loc(loc++, rest, sym_lst);
129  n.find_ex_by_loc(loc++, coeff, sym_lst);
130  seq.emplace_back(expair(rest, coeff));
131  }
132 
133  n.find_ex("var", var, sym_lst);
134  n.find_ex("point", point, sym_lst);
135 }
136 
138 {
139  inherited::archive(n);
140  for (auto & it : seq) {
141  n.add_ex("coeff", it.rest);
142  n.add_ex("power", it.coeff);
143  }
144  n.add_ex("var", var);
145  n.add_ex("point", point);
146 }
147 
148 
150 // functions overriding virtual functions from base classes
152 
153 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
154 {
155  if (precedence() <= level)
156  c.s << '(';
157 
158  // objects of type pseries must not have any zero entries, so the
159  // trivial (zero) pseries needs a special treatment here:
160  if (seq.empty())
161  c.s << '0';
162 
163  auto i = seq.begin(), end = seq.end();
164  while (i != end) {
165 
166  // print a sign, if needed
167  if (i != seq.begin())
168  c.s << '+';
169 
170  if (!is_order_function(i->rest)) {
171 
172  // print 'rest', i.e. the expansion coefficient
173  if (i->rest.info(info_flags::numeric) &&
174  i->rest.info(info_flags::positive)) {
175  i->rest.print(c);
176  } else {
177  c.s << openbrace << '(';
178  i->rest.print(c);
179  c.s << ')' << closebrace;
180  }
181 
182  // print 'coeff', something like (x-1)^42
183  if (!i->coeff.is_zero()) {
184  c.s << mul_sym;
185  if (!point.is_zero()) {
186  c.s << openbrace << '(';
187  (var-point).print(c);
188  c.s << ')' << closebrace;
189  } else
190  var.print(c);
191  if (i->coeff.compare(_ex1)) {
192  c.s << pow_sym;
193  c.s << openbrace;
194  if (i->coeff.info(info_flags::negative)) {
195  c.s << '(';
196  i->coeff.print(c);
197  c.s << ')';
198  } else
199  i->coeff.print(c);
200  c.s << closebrace;
201  }
202  }
203  } else
204  Order(pow(var - point, i->coeff)).print(c);
205  ++i;
206  }
207 
208  if (precedence() <= level)
209  c.s << ')';
210 }
211 
212 void pseries::do_print(const print_context & c, unsigned level) const
213 {
214  print_series(c, "", "", "*", "^", level);
215 }
216 
217 void pseries::do_print_latex(const print_latex & c, unsigned level) const
218 {
219  print_series(c, "{", "}", " ", "^", level);
220 }
221 
222 void pseries::do_print_python(const print_python & c, unsigned level) const
223 {
224  print_series(c, "", "", "*", "**", level);
225 }
226 
227 void pseries::do_print_tree(const print_tree & c, unsigned level) const
228 {
229  c.s << std::string(level, ' ') << class_name() << " @" << this
230  << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
231  << std::endl;
232  size_t num = seq.size();
233  for (size_t i=0; i<num; ++i) {
234  seq[i].rest.print(c, level + c.delta_indent);
235  seq[i].coeff.print(c, level + c.delta_indent);
236  c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl;
237  }
238  var.print(c, level + c.delta_indent);
239  point.print(c, level + c.delta_indent);
240 }
241 
242 void pseries::do_print_python_repr(const print_python_repr & c, unsigned level) const
243 {
244  c.s << class_name() << "(relational(";
245  var.print(c);
246  c.s << ',';
247  point.print(c);
248  c.s << "),[";
249  size_t num = seq.size();
250  for (size_t i=0; i<num; ++i) {
251  if (i)
252  c.s << ',';
253  c.s << '(';
254  seq[i].rest.print(c);
255  c.s << ',';
256  seq[i].coeff.print(c);
257  c.s << ')';
258  }
259  c.s << "])";
260 }
261 
262 int pseries::compare_same_type(const basic & other) const
263 {
264  GINAC_ASSERT(is_a<pseries>(other));
265  const pseries &o = static_cast<const pseries &>(other);
266 
267  // first compare the lengths of the series...
268  if (seq.size()>o.seq.size())
269  return 1;
270  if (seq.size()<o.seq.size())
271  return -1;
272 
273  // ...then the expansion point...
274  int cmpval = var.compare(o.var);
275  if (cmpval)
276  return cmpval;
277  cmpval = point.compare(o.point);
278  if (cmpval)
279  return cmpval;
280 
281  // ...and if that failed the individual elements
282  auto it = seq.begin(), o_it = o.seq.begin();
283  while (it!=seq.end() && o_it!=o.seq.end()) {
284  cmpval = it->compare(*o_it);
285  if (cmpval)
286  return cmpval;
287  ++it;
288  ++o_it;
289  }
290 
291  // so they are equal.
292  return 0;
293 }
294 
296 size_t pseries::nops() const
297 {
298  return seq.size();
299 }
300 
302 ex pseries::op(size_t i) const
303 {
304  if (i >= seq.size())
305  throw (std::out_of_range("op() out of range"));
306 
307  if (is_order_function(seq[i].rest))
308  return Order(pow(var-point, seq[i].coeff));
309  return seq[i].rest * pow(var - point, seq[i].coeff);
310 }
311 
315 int pseries::degree(const ex &s) const
316 {
317  if (seq.empty())
318  return 0;
319 
320  if (var.is_equal(s))
321  // Return last/greatest exponent
322  return ex_to<numeric>((seq.end()-1)->coeff).to_int();
323 
324  int max_pow = std::numeric_limits<int>::min();
325  for (auto & it : seq)
326  max_pow = std::max(max_pow, it.rest.degree(s));
327  return max_pow;
328 }
329 
335 int pseries::ldegree(const ex &s) const
336 {
337  if (seq.empty())
338  return 0;
339 
340  if (var.is_equal(s))
341  // Return first/smallest exponent
342  return ex_to<numeric>((seq.begin())->coeff).to_int();
343 
344  int min_pow = std::numeric_limits<int>::max();
345  for (auto & it : seq)
346  min_pow = std::min(min_pow, it.rest.degree(s));
347  return min_pow;
348 }
349 
357 ex pseries::coeff(const ex &s, int n) const
358 {
359  if (var.is_equal(s)) {
360  if (seq.empty())
361  return _ex0;
362 
363  // Binary search in sequence for given power
364  numeric looking_for = numeric(n);
365  int lo = 0, hi = seq.size() - 1;
366  while (lo <= hi) {
367  int mid = (lo + hi) / 2;
368  GINAC_ASSERT(is_exactly_a<numeric>(seq[mid].coeff));
369  int cmp = ex_to<numeric>(seq[mid].coeff).compare(looking_for);
370  switch (cmp) {
371  case -1:
372  lo = mid + 1;
373  break;
374  case 0:
375  return seq[mid].rest;
376  case 1:
377  hi = mid - 1;
378  break;
379  default:
380  throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
381  }
382  }
383  return _ex0;
384  } else
385  return convert_to_poly().coeff(s, n);
386 }
387 
389 ex pseries::collect(const ex &s, bool distributed) const
390 {
391  return *this;
392 }
393 
396 {
397  return hold();
398 }
399 
402 {
403  // Construct a new series with evaluated coefficients
404  epvector new_seq;
405  new_seq.reserve(seq.size());
406  for (auto & it : seq)
407  new_seq.emplace_back(expair(it.rest.evalf(), it.coeff));
408 
409  return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
410 }
411 
413 {
415  return conjugate_function(*this).hold();
416 
417  std::unique_ptr<epvector> newseq(conjugateepvector(seq));
418  ex newpoint = point.conjugate();
419 
420  if (!newseq && are_ex_trivially_equal(point, newpoint)) {
421  return *this;
422  }
423 
424  return dynallocate<pseries>(var==newpoint, newseq ? std::move(*newseq) : seq);
425 }
426 
428 {
430  return real_part_function(*this).hold();
431  ex newpoint = point.real_part();
432  if(newpoint != point)
433  return real_part_function(*this).hold();
434 
435  epvector v;
436  v.reserve(seq.size());
437  for (auto & it : seq)
438  v.emplace_back(expair(it.rest.real_part(), it.coeff));
439  return dynallocate<pseries>(var==point, std::move(v));
440 }
441 
443 {
445  return imag_part_function(*this).hold();
446  ex newpoint = point.real_part();
447  if(newpoint != point)
448  return imag_part_function(*this).hold();
449 
450  epvector v;
451  v.reserve(seq.size());
452  for (auto & it : seq)
453  v.emplace_back(expair(it.rest.imag_part(), it.coeff));
454  return dynallocate<pseries>(var==point, std::move(v));
455 }
456 
458 {
459  std::unique_ptr<epvector> newseq(nullptr);
460  for (auto i=seq.begin(); i!=seq.end(); ++i) {
461  if (newseq) {
462  newseq->emplace_back(expair(i->rest.eval_integ(), i->coeff));
463  continue;
464  }
465  ex newterm = i->rest.eval_integ();
466  if (!are_ex_trivially_equal(newterm, i->rest)) {
467  newseq.reset(new epvector);
468  newseq->reserve(seq.size());
469  for (auto j=seq.begin(); j!=i; ++j)
470  newseq->push_back(*j);
471  newseq->emplace_back(expair(newterm, i->coeff));
472  }
473  }
474 
475  ex newpoint = point.eval_integ();
476  if (newseq || !are_ex_trivially_equal(newpoint, point))
477  return dynallocate<pseries>(var==newpoint, std::move(*newseq));
478  return *this;
479 }
480 
482 {
483  // evalm each coefficient
484  epvector newseq;
485  bool something_changed = false;
486  for (auto i=seq.begin(); i!=seq.end(); ++i) {
487  if (something_changed) {
488  ex newcoeff = i->rest.evalm();
489  if (!newcoeff.is_zero())
490  newseq.emplace_back(expair(newcoeff, i->coeff));
491  } else {
492  ex newcoeff = i->rest.evalm();
493  if (!are_ex_trivially_equal(newcoeff, i->rest)) {
494  something_changed = true;
495  newseq.reserve(seq.size());
496  std::copy(seq.begin(), i, std::back_inserter<epvector>(newseq));
497  if (!newcoeff.is_zero())
498  newseq.emplace_back(expair(newcoeff, i->coeff));
499  }
500  }
501  }
502  if (something_changed)
503  return dynallocate<pseries>(var==point, std::move(newseq));
504  else
505  return *this;
506 }
507 
508 ex pseries::subs(const exmap & m, unsigned options) const
509 {
510  // If expansion variable is being substituted, convert the series to a
511  // polynomial and do the substitution there because the result might
512  // no longer be a power series
513  if (m.find(var) != m.end())
514  return convert_to_poly(true).subs(m, options);
515 
516  // Otherwise construct a new series with substituted coefficients and
517  // expansion point
518  epvector newseq;
519  newseq.reserve(seq.size());
520  for (auto & it : seq)
521  newseq.emplace_back(expair(it.rest.subs(m, options), it.coeff));
522  return dynallocate<pseries>(relational(var,point.subs(m, options)), std::move(newseq));
523 }
524 
527 ex pseries::expand(unsigned options) const
528 {
529  epvector newseq;
530  for (auto & it : seq) {
531  ex restexp = it.rest.expand();
532  if (!restexp.is_zero())
533  newseq.emplace_back(expair(restexp, it.coeff));
534  }
535  return dynallocate<pseries>(relational(var,point), std::move(newseq)).setflag(options == 0 ? status_flags::expanded : 0);
536 }
537 
540 ex pseries::derivative(const symbol & s) const
541 {
542  epvector new_seq;
543 
544  if (s == var) {
545 
546  // FIXME: coeff might depend on var
547  for (auto & it : seq) {
548  if (is_order_function(it.rest)) {
549  new_seq.emplace_back(expair(it.rest, it.coeff - 1));
550  } else {
551  ex c = it.rest * it.coeff;
552  if (!c.is_zero())
553  new_seq.emplace_back(expair(c, it.coeff - 1));
554  }
555  }
556 
557  } else {
558 
559  for (auto & it : seq) {
560  if (is_order_function(it.rest)) {
561  new_seq.push_back(it);
562  } else {
563  ex c = it.rest.diff(s);
564  if (!c.is_zero())
565  new_seq.emplace_back(expair(c, it.coeff));
566  }
567  }
568  }
569 
570  return pseries(relational(var,point), std::move(new_seq));
571 }
572 
573 ex pseries::convert_to_poly(bool no_order) const
574 {
575  ex e;
576  for (auto & it : seq) {
577  if (is_order_function(it.rest)) {
578  if (!no_order)
579  e += Order(pow(var - point, it.coeff));
580  } else
581  e += it.rest * pow(var - point, it.coeff);
582  }
583  return e;
584 }
585 
587 {
588  return seq.empty() || !is_order_function((seq.end()-1)->rest);
589 }
590 
591 ex pseries::coeffop(size_t i) const
592 {
593  if (i >= nops())
594  throw (std::out_of_range("coeffop() out of range"));
595  return seq[i].rest;
596 }
597 
598 ex pseries::exponop(size_t i) const
599 {
600  if (i >= nops())
601  throw (std::out_of_range("exponop() out of range"));
602  return seq[i].coeff;
603 }
604 
605 
606 /*
607  * Implementations of series expansion
608  */
609 
612 ex basic::series(const relational & r, int order, unsigned options) const
613 {
614  epvector seq;
615  const symbol &s = ex_to<symbol>(r.lhs());
616 
617  // default for order-values that make no sense for Taylor expansion
618  if ((order <= 0) && this->has(s)) {
619  seq.emplace_back(expair(Order(_ex1), order));
620  return pseries(r, std::move(seq));
621  }
622 
623  // do Taylor expansion
624  numeric fac = 1;
625  ex deriv = *this;
627 
628  if (!coeff.is_zero()) {
629  seq.emplace_back(expair(coeff, _ex0));
630  }
631 
632  int n;
633  for (n=1; n<order; ++n) {
634  fac = fac.div(n);
635  // We need to test for zero in order to see if the series terminates.
636  // The problem is that there is no such thing as a perfect test for
637  // zero. Expanding the term occasionally helps a little...
638  deriv = deriv.diff(s).expand();
639  if (deriv.is_zero()) // Series terminates
640  return pseries(r, std::move(seq));
641 
643  if (!coeff.is_zero())
644  seq.emplace_back(expair(fac * coeff, n));
645  }
646 
647  // Higher-order terms, if present
648  deriv = deriv.diff(s);
649  if (!deriv.expand().is_zero())
650  seq.emplace_back(expair(Order(_ex1), n));
651  return pseries(r, std::move(seq));
652 }
653 
654 
657 ex symbol::series(const relational & r, int order, unsigned options) const
658 {
659  epvector seq;
660  const ex point = r.rhs();
661  GINAC_ASSERT(is_a<symbol>(r.lhs()));
662 
663  if (this->is_equal_same_type(ex_to<symbol>(r.lhs()))) {
664  if (order > 0 && !point.is_zero())
665  seq.emplace_back(expair(point, _ex0));
666  if (order > 1)
667  seq.emplace_back(expair(_ex1, _ex1));
668  else
669  seq.emplace_back(expair(Order(_ex1), numeric(order)));
670  } else
671  seq.emplace_back(expair(*this, _ex0));
672  return pseries(r, std::move(seq));
673 }
674 
675 
681 ex pseries::add_series(const pseries &other) const
682 {
683  // Adding two series with different variables or expansion points
684  // results in an empty (constant) series
685  if (!is_compatible_to(other)) {
686  epvector nul { expair(Order(_ex1), _ex0) };
687  return pseries(relational(var,point), std::move(nul));
688  }
689 
690  // Series addition
691  epvector new_seq;
692  auto a = seq.begin(), a_end = seq.end();
693  auto b = other.seq.begin(), b_end = other.seq.end();
694  int pow_a = std::numeric_limits<int>::max(), pow_b = std::numeric_limits<int>::max();
695  for (;;) {
696  // If a is empty, fill up with elements from b and stop
697  if (a == a_end) {
698  while (b != b_end) {
699  new_seq.push_back(*b);
700  ++b;
701  }
702  break;
703  } else
704  pow_a = ex_to<numeric>((*a).coeff).to_int();
705 
706  // If b is empty, fill up with elements from a and stop
707  if (b == b_end) {
708  while (a != a_end) {
709  new_seq.push_back(*a);
710  ++a;
711  }
712  break;
713  } else
714  pow_b = ex_to<numeric>((*b).coeff).to_int();
715 
716  // a and b are non-empty, compare powers
717  if (pow_a < pow_b) {
718  // a has lesser power, get coefficient from a
719  new_seq.push_back(*a);
720  if (is_order_function((*a).rest))
721  break;
722  ++a;
723  } else if (pow_b < pow_a) {
724  // b has lesser power, get coefficient from b
725  new_seq.push_back(*b);
726  if (is_order_function((*b).rest))
727  break;
728  ++b;
729  } else {
730  // Add coefficient of a and b
731  if (is_order_function((*a).rest) || is_order_function((*b).rest)) {
732  new_seq.emplace_back(expair(Order(_ex1), (*a).coeff));
733  break; // Order term ends the sequence
734  } else {
735  ex sum = (*a).rest + (*b).rest;
736  if (!(sum.is_zero()))
737  new_seq.emplace_back(expair(sum, numeric(pow_a)));
738  ++a;
739  ++b;
740  }
741  }
742  }
743  return pseries(relational(var,point), std::move(new_seq));
744 }
745 
746 
750 ex add::series(const relational & r, int order, unsigned options) const
751 {
752  ex acc; // Series accumulator
753 
754  // Get first term from overall_coeff
756 
757  // Add remaining terms
758  for (auto & it : seq) {
759  ex op;
760  if (is_exactly_a<pseries>(it.rest))
761  op = it.rest;
762  else
763  op = it.rest.series(r, order, options);
764  if (!it.coeff.is_equal(_ex1))
765  op = ex_to<pseries>(op).mul_const(ex_to<numeric>(it.coeff));
766 
767  // Series addition
768  acc = ex_to<pseries>(acc).add_series(ex_to<pseries>(op));
769  }
770  return acc;
771 }
772 
773 
779 ex pseries::mul_const(const numeric &other) const
780 {
781  epvector new_seq;
782  new_seq.reserve(seq.size());
783 
784  for (auto & it : seq) {
785  if (!is_order_function(it.rest))
786  new_seq.emplace_back(expair(it.rest * other, it.coeff));
787  else
788  new_seq.push_back(it);
789  }
790  return pseries(relational(var,point), std::move(new_seq));
791 }
792 
793 
799 ex pseries::mul_series(const pseries &other) const
800 {
801  // Multiplying two series with different variables or expansion points
802  // results in an empty (constant) series
803  if (!is_compatible_to(other)) {
804  epvector nul { expair(Order(_ex1), _ex0) };
805  return pseries(relational(var,point), std::move(nul));
806  }
807 
808  if (seq.empty() || other.seq.empty()) {
809  return dynallocate<pseries>(var==point, epvector());
810  }
811 
812  // Series multiplication
813  epvector new_seq;
814  const int a_max = degree(var);
815  const int b_max = other.degree(var);
816  const int a_min = ldegree(var);
817  const int b_min = other.ldegree(var);
818  const int cdeg_min = a_min + b_min;
819  int cdeg_max = a_max + b_max;
820 
821  int higher_order_a = std::numeric_limits<int>::max();
822  int higher_order_b = std::numeric_limits<int>::max();
823  if (is_order_function(coeff(var, a_max)))
824  higher_order_a = a_max + b_min;
825  if (is_order_function(other.coeff(var, b_max)))
826  higher_order_b = b_max + a_min;
827  const int higher_order_c = std::min(higher_order_a, higher_order_b);
828  if (cdeg_max >= higher_order_c)
829  cdeg_max = higher_order_c - 1;
830 
831  std::map<int, ex> rest_map_a, rest_map_b;
832  for (const auto& it : seq)
833  rest_map_a[ex_to<numeric>(it.coeff).to_int()] = it.rest;
834 
835  if (other.var.is_equal(var))
836  for (const auto& it : other.seq)
837  rest_map_b[ex_to<numeric>(it.coeff).to_int()] = it.rest;
838 
839  for (int cdeg=cdeg_min; cdeg<=cdeg_max; ++cdeg) {
840  ex co = _ex0;
841  // c(i)=a(0)b(i)+...+a(i)b(0)
842  for (int i=a_min; cdeg-i>=b_min; ++i) {
843  const auto& ita = rest_map_a.find(i);
844  if (ita == rest_map_a.end())
845  continue;
846  const auto& itb = rest_map_b.find(cdeg-i);
847  if (itb == rest_map_b.end())
848  continue;
849  if (!is_order_function(ita->second) && !is_order_function(itb->second))
850  co += ita->second * itb->second;
851  }
852  if (!co.is_zero())
853  new_seq.emplace_back(expair(co, numeric(cdeg)));
854  }
855  if (higher_order_c < std::numeric_limits<int>::max())
856  new_seq.emplace_back(expair(Order(_ex1), numeric(higher_order_c)));
857  return pseries(relational(var, point), std::move(new_seq));
858 }
859 
860 
864 ex mul::series(const relational & r, int order, unsigned options) const
865 {
866  pseries acc; // Series accumulator
867 
868  GINAC_ASSERT(is_a<symbol>(r.lhs()));
869  const ex& sym = r.lhs();
870 
871  // holds ldegrees of the series of individual factors
872  std::vector<int> ldegrees;
873  std::vector<bool> ldegree_redo;
874 
875  // find minimal degrees
876  // first round: obtain a bound up to which minimal degrees have to be
877  // considered
878  for (auto & it : seq) {
879 
880  ex expon = it.coeff;
881  int factor = 1;
882  ex buf;
883  if (expon.info(info_flags::integer)) {
884  buf = it.rest;
885  factor = ex_to<numeric>(expon).to_int();
886  } else {
887  buf = recombine_pair_to_ex(it);
888  }
889 
890  int real_ldegree = 0;
891  bool flag_redo = false;
892  try {
893  real_ldegree = buf.expand().ldegree(sym-r.rhs());
894  } catch (std::runtime_error &) {}
895 
896  if (real_ldegree == 0) {
897  if ( factor < 0 ) {
898  // This case must terminate, otherwise we would have division by
899  // zero.
900  int orderloop = 0;
901  do {
902  orderloop++;
903  real_ldegree = buf.series(r, orderloop, options).ldegree(sym);
904  } while (real_ldegree == orderloop);
905  } else {
906  // Here it is possible that buf does not have a ldegree, therefore
907  // check only if ldegree is negative, otherwise reconsider the case
908  // in the second round.
909  real_ldegree = buf.series(r, 0, options).ldegree(sym);
910  if (real_ldegree == 0)
911  flag_redo = true;
912  }
913  }
914 
915  ldegrees.push_back(factor * real_ldegree);
916  ldegree_redo.push_back(flag_redo);
917  }
918 
919  int degbound = order-std::accumulate(ldegrees.begin(), ldegrees.end(), 0);
920  // Second round: determine the remaining positive ldegrees by the series
921  // method.
922  // here we can ignore ldegrees larger than degbound
923  size_t j = 0;
924  for (auto & it : seq) {
925  if ( ldegree_redo[j] ) {
926  ex expon = it.coeff;
927  int factor = 1;
928  ex buf;
929  if (expon.info(info_flags::integer)) {
930  buf = it.rest;
931  factor = ex_to<numeric>(expon).to_int();
932  } else {
933  buf = recombine_pair_to_ex(it);
934  }
935  int real_ldegree = 0;
936  int orderloop = 0;
937  do {
938  orderloop++;
939  real_ldegree = buf.series(r, orderloop, options).ldegree(sym);
940  } while ((real_ldegree == orderloop)
941  && (factor*real_ldegree < degbound));
942  ldegrees[j] = factor * real_ldegree;
943  degbound -= factor * real_ldegree;
944  }
945  j++;
946  }
947 
948  int degsum = std::accumulate(ldegrees.begin(), ldegrees.end(), 0);
949 
950  if (degsum > order) {
951  return dynallocate<pseries>(r, epvector{{Order(_ex1), order}});
952  }
953 
954  // Multiply with remaining terms
955  auto itd = ldegrees.begin();
956  for (auto it=seq.begin(), itend=seq.end(); it!=itend; ++it, ++itd) {
957 
958  // do series expansion with adjusted order
959  ex op = recombine_pair_to_ex(*it).series(r, order-degsum+(*itd), options);
960 
961  // Series multiplication
962  if (it == seq.begin())
963  acc = ex_to<pseries>(op);
964  else
965  acc = ex_to<pseries>(acc.mul_series(ex_to<pseries>(op)));
966  }
967 
968  return acc.mul_const(ex_to<numeric>(overall_coeff));
969 }
970 
971 
976 ex pseries::power_const(const numeric &p, int deg) const
977 {
978  // method:
979  // (due to Leonhard Euler)
980  // let A(x) be this series and for the time being let it start with a
981  // constant (later we'll generalize):
982  // A(x) = a_0 + a_1*x + a_2*x^2 + ...
983  // We want to compute
984  // C(x) = A(x)^p
985  // C(x) = c_0 + c_1*x + c_2*x^2 + ...
986  // Taking the derivative on both sides and multiplying with A(x) one
987  // immediately arrives at
988  // C'(x)*A(x) = p*C(x)*A'(x)
989  // Multiplying this out and comparing coefficients we get the recurrence
990  // formula
991  // c_i = (i*p*a_i*c_0 + ((i-1)*p-1)*a_{i-1}*c_1 + ...
992  // ... + (p-(i-1))*a_1*c_{i-1})/(a_0*i)
993  // which can easily be solved given the starting value c_0 = (a_0)^p.
994  // For the more general case where the leading coefficient of A(x) is not
995  // a constant, just consider A2(x) = A(x)*x^m, with some integer m and
996  // repeat the above derivation. The leading power of C2(x) = A2(x)^2 is
997  // then of course x^(p*m) but the recurrence formula still holds.
998 
999  if (seq.empty()) {
1000  // as a special case, handle the empty (zero) series honoring the
1001  // usual power laws such as implemented in power::eval()
1002  if (p.real().is_zero())
1003  throw std::domain_error("pseries::power_const(): pow(0,I) is undefined");
1004  else if (p.real().is_negative())
1005  throw pole_error("pseries::power_const(): division by zero",1);
1006  else
1007  return *this;
1008  }
1009 
1010  const int ldeg = ldegree(var);
1011  if (!(p*ldeg).is_integer())
1012  throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
1013 
1014  // adjust number of coefficients
1015  int numcoeff = deg - (p*ldeg).to_int();
1016  if (numcoeff <= 0) {
1017  epvector epv { expair(Order(_ex1), deg) };
1018  return dynallocate<pseries>(relational(var,point), std::move(epv));
1019  }
1020 
1021  // O(x^n)^(-m) is undefined
1022  if (seq.size() == 1 && is_order_function(seq[0].rest) && p.real().is_negative())
1023  throw pole_error("pseries::power_const(): division by zero",1);
1024 
1025  // Compute coefficients of the powered series
1026  exvector co;
1027  co.reserve(numcoeff);
1028  co.push_back(pow(coeff(var, ldeg), p));
1029  for (int i=1; i<numcoeff; ++i) {
1030  ex sum = _ex0;
1031  for (int j=1; j<=i; ++j) {
1032  ex c = coeff(var, j + ldeg);
1033  if (is_order_function(c)) {
1034  co.push_back(Order(_ex1));
1035  break;
1036  } else
1037  sum += (p * j - (i - j)) * co[i - j] * c;
1038  }
1039  co.push_back(sum / coeff(var, ldeg) / i);
1040  }
1041 
1042  // Construct new series (of non-zero coefficients)
1043  epvector new_seq;
1044  bool higher_order = false;
1045  for (int i=0; i<numcoeff; ++i) {
1046  if (!co[i].is_zero())
1047  new_seq.emplace_back(expair(co[i], p * ldeg + i));
1048  if (is_order_function(co[i])) {
1049  higher_order = true;
1050  break;
1051  }
1052  }
1053  if (!higher_order)
1054  new_seq.emplace_back(expair(Order(_ex1), p * ldeg + numcoeff));
1055 
1056  return pseries(relational(var,point), std::move(new_seq));
1057 }
1058 
1059 
1062 {
1063  epvector newseq = seq;
1064  for (auto & it : newseq)
1065  it.coeff += deg;
1066  return pseries(relational(var, point), std::move(newseq));
1067 }
1068 
1069 
1073 ex power::series(const relational & r, int order, unsigned options) const
1074 {
1075  // If basis is already a series, just power it
1076  if (is_exactly_a<pseries>(basis))
1077  return ex_to<pseries>(basis).power_const(ex_to<numeric>(exponent), order);
1078 
1079  // Basis is not a series, may there be a singularity?
1080  bool must_expand_basis = false;
1081  try {
1083  } catch (pole_error &) {
1084  must_expand_basis = true;
1085  }
1086 
1087  bool exponent_is_regular = true;
1088  try {
1090  } catch (pole_error &) {
1091  exponent_is_regular = false;
1092  }
1093 
1094  if (!exponent_is_regular) {
1095  ex l = exponent*log(basis);
1096  // this == exp(l);
1097  ex le = l.series(r, order, options);
1098  // Note: expanding exp(l) won't help, since that will attempt
1099  // Taylor expansion, and fail (because exponent is "singular")
1100  // Still l itself might be expanded in Taylor series.
1101  // Examples:
1102  // sin(x)/x*log(cos(x))
1103  // 1/x*log(1 + x)
1104  return exp(le).series(r, order, options);
1105  // Note: if l happens to have a Laurent expansion (with
1106  // negative powers of (var - point)), expanding exp(le)
1107  // will barf (which is The Right Thing).
1108  }
1109 
1110  // Is the expression of type something^(-int)?
1111  if (!must_expand_basis && !exponent.info(info_flags::negint)
1112  && (!is_a<add>(basis) || !is_a<numeric>(exponent)))
1113  return basic::series(r, order, options);
1114 
1115  // Is the expression of type 0^something?
1116  if (!must_expand_basis && !basis.subs(r, subs_options::no_pattern).is_zero()
1117  && (!is_a<add>(basis) || !is_a<numeric>(exponent)))
1118  return basic::series(r, order, options);
1119 
1120  // Singularity encountered, is the basis equal to (var - point)?
1121  if (basis.is_equal(r.lhs() - r.rhs())) {
1122  epvector new_seq;
1123  if (ex_to<numeric>(exponent).to_int() < order)
1124  new_seq.emplace_back(expair(_ex1, exponent));
1125  else
1126  new_seq.emplace_back(expair(Order(_ex1), exponent));
1127  return pseries(r, std::move(new_seq));
1128  }
1129 
1130  // No, expand basis into series
1131 
1132  numeric numexp;
1133  if (is_a<numeric>(exponent)) {
1134  numexp = ex_to<numeric>(exponent);
1135  } else {
1136  numexp = 0;
1137  }
1138  const ex& sym = r.lhs();
1139  // find existing minimal degree
1140  ex eb = basis.expand();
1141  int real_ldegree = 0;
1143  real_ldegree = eb.ldegree(sym-r.rhs());
1144  if (real_ldegree == 0) {
1145  int orderloop = 0;
1146  do {
1147  orderloop++;
1148  real_ldegree = basis.series(r, orderloop, options).ldegree(sym);
1149  } while (real_ldegree == orderloop);
1150  }
1151 
1152  if (!(real_ldegree*numexp).is_integer())
1153  throw std::runtime_error("pseries::power_const(): trying to assemble a Puiseux series");
1154  ex e = basis.series(r, (order + real_ldegree*(1-numexp)).to_int(), options);
1155 
1156  ex result;
1157  try {
1158  result = ex_to<pseries>(e).power_const(numexp, order);
1159  } catch (pole_error &) {
1160  epvector ser { expair(Order(_ex1), order) };
1161  result = pseries(r, std::move(ser));
1162  }
1163 
1164  return result;
1165 }
1166 
1167 
1169 ex pseries::series(const relational & r, int order, unsigned options) const
1170 {
1171  const ex p = r.rhs();
1172  GINAC_ASSERT(is_a<symbol>(r.lhs()));
1173  const symbol &s = ex_to<symbol>(r.lhs());
1174 
1175  if (var.is_equal(s) && point.is_equal(p)) {
1176  if (order > degree(s))
1177  return *this;
1178  else {
1179  epvector new_seq;
1180  for (auto & it : seq) {
1181  int o = ex_to<numeric>(it.coeff).to_int();
1182  if (o >= order) {
1183  new_seq.emplace_back(expair(Order(_ex1), o));
1184  break;
1185  }
1186  new_seq.push_back(it);
1187  }
1188  return pseries(r, std::move(new_seq));
1189  }
1190  } else
1191  return convert_to_poly().series(r, order, options);
1192 }
1193 
1194 ex integral::series(const relational & r, int order, unsigned options) const
1195 {
1196  if (x.subs(r) != x)
1197  throw std::logic_error("Cannot series expand wrt dummy variable");
1198 
1199  // Expanding integrand with r substituted taken in boundaries.
1200  ex fseries = f.series(r, order, options);
1201  epvector fexpansion;
1202  fexpansion.reserve(fseries.nops());
1203  for (size_t i=0; i<fseries.nops(); ++i) {
1204  ex currcoeff = ex_to<pseries>(fseries).coeffop(i);
1205  currcoeff = (currcoeff == Order(_ex1))
1206  ? currcoeff
1207  : integral(x, a.subs(r), b.subs(r), currcoeff);
1208  if (currcoeff != 0)
1209  fexpansion.emplace_back(
1210  expair(currcoeff, ex_to<pseries>(fseries).exponop(i)));
1211  }
1212 
1213  // Expanding lower boundary
1214  ex result = dynallocate<pseries>(r, std::move(fexpansion));
1215  ex aseries = (a-a.subs(r)).series(r, order, options);
1216  fseries = f.series(x == (a.subs(r)), order, options);
1217  for (size_t i=0; i<fseries.nops(); ++i) {
1218  ex currcoeff = ex_to<pseries>(fseries).coeffop(i);
1219  if (is_order_function(currcoeff))
1220  break;
1221  ex currexpon = ex_to<pseries>(fseries).exponop(i);
1222  int orderforf = order-ex_to<numeric>(currexpon).to_int()-1;
1223  currcoeff = currcoeff.series(r, orderforf);
1224  ex term = ex_to<pseries>(aseries).power_const(ex_to<numeric>(currexpon+1),order);
1225  term = ex_to<pseries>(term).mul_const(ex_to<numeric>(-1/(currexpon+1)));
1226  term = ex_to<pseries>(term).mul_series(ex_to<pseries>(currcoeff));
1227  result = ex_to<pseries>(result).add_series(ex_to<pseries>(term));
1228  }
1229 
1230  // Expanding upper boundary
1231  ex bseries = (b-b.subs(r)).series(r, order, options);
1232  fseries = f.series(x == (b.subs(r)), order, options);
1233  for (size_t i=0; i<fseries.nops(); ++i) {
1234  ex currcoeff = ex_to<pseries>(fseries).coeffop(i);
1235  if (is_order_function(currcoeff))
1236  break;
1237  ex currexpon = ex_to<pseries>(fseries).exponop(i);
1238  int orderforf = order-ex_to<numeric>(currexpon).to_int()-1;
1239  currcoeff = currcoeff.series(r, orderforf);
1240  ex term = ex_to<pseries>(bseries).power_const(ex_to<numeric>(currexpon+1),order);
1241  term = ex_to<pseries>(term).mul_const(ex_to<numeric>(1/(currexpon+1)));
1242  term = ex_to<pseries>(term).mul_series(ex_to<pseries>(currcoeff));
1243  result = ex_to<pseries>(result).add_series(ex_to<pseries>(term));
1244  }
1245 
1246  return result;
1247 }
1248 
1249 
1259 ex ex::series(const ex & r, int order, unsigned options) const
1260 {
1261  ex e;
1262  relational rel_;
1263 
1264  if (is_a<relational>(r))
1265  rel_ = ex_to<relational>(r);
1266  else if (is_a<symbol>(r))
1267  rel_ = relational(r,_ex0);
1268  else
1269  throw (std::logic_error("ex::series(): expansion point has unknown type"));
1270 
1271  e = bp->series(rel_, order, options);
1272  return e;
1273 }
1274 
1276 
1277 } // namespace GiNaC
inifcns.h
Interface to GiNaC's initially known functions.
GiNaC::conjugateepvector
epvector * conjugateepvector(const epvector &)
Complex conjugate every element of an epvector.
GiNaC::print_python_repr
Context for python-parsable output.
Definition: print.h:139
GiNaC::epvector
std::vector< expair > epvector
expair-vector
Definition: expairseq.h:33
GiNaC::integral::integral
integral(const ex &x_, const ex &a_, const ex &b_, const ex &f_)
Definition: integral.cpp:61
GiNaC::ex::expand
ex expand(unsigned options=0) const
Definition: ex.cpp:73
GiNaC::info_flags::real
@ real
Definition: flags.h:221
GiNaC::pseries::do_print_python
void do_print_python(const print_python &c, unsigned level) const
Definition: pseries.cpp:222
GiNaC::pseries::conjugate
ex conjugate() const override
Definition: pseries.cpp:412
GiNaC::pseries::do_print_python_repr
void do_print_python_repr(const print_python_repr &c, unsigned level) const
Definition: pseries.cpp:242
GiNaC::integral::a
ex a
Definition: integral.h:78
GiNaC::pseries::is_terminating
bool is_terminating() const
Returns true if there is no order term, i.e.
Definition: pseries.cpp:586
GiNaC::GINAC_IMPLEMENT_REGISTERED_CLASS_OPT
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(add, expairseq, print_func< print_context >(&add::do_print). print_func< print_latex >(&add::do_print_latex). print_func< print_csrc >(&add::do_print_csrc). print_func< print_tree >(&add::do_print_tree). print_func< print_python_repr >(&add::do_print_python_repr)) add
Definition: add.cpp:40
GiNaC::info_flags::integer
@ integer
Definition: flags.h:223
GiNaC::pseries::collect
ex collect(const ex &s, bool distributed=false) const override
Does nothing.
Definition: pseries.cpp:389
r
size_t r
Definition: factor.cpp:770
GiNaC::pseries::do_print
void do_print(const print_context &c, unsigned level) const
Definition: pseries.cpp:212
GiNaC::info_flags::negative
@ negative
Definition: flags.h:227
mul.h
Interface to GiNaC's products of expressions.
GiNaC::pseries
This class holds a extended truncated power series (positive and negative integer powers).
Definition: pseries.h:36
GiNaC::pseries::pseries
pseries(const ex &rel_, const epvector &ops_)
Construct pseries from a vector of coefficients and powers.
Definition: pseries.cpp:71
GiNaC::basic::hashvalue
unsigned hashvalue
hash value
Definition: basic.h:303
GiNaC::ex::coeff
ex coeff(const ex &s, int n=1) const
Definition: ex.h:175
GiNaC::status_flags::expanded
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition: flags.h:204
GiNaC::pseries::exponop
ex exponop(size_t i) const
Definition: pseries.cpp:598
GiNaC::_ex0
const ex _ex0
Definition: utils.cpp:177
GiNaC::relational
This class holds a relation consisting of two expressions and a logical relation between them.
Definition: relational.h:35
GiNaC::ex::compare
int compare(const ex &other) const
Definition: ex.h:322
GiNaC::ex::subs
ex subs(const exmap &m, unsigned options=0) const
Definition: ex.h:826
GiNaC::print_context
Base class for print_contexts.
Definition: print.h:103
GiNaC::pseries::real_part
ex real_part() const override
Definition: pseries.cpp:427
GiNaC::pseries::do_print_latex
void do_print_latex(const print_latex &c, unsigned level) const
Definition: pseries.cpp:217
add.h
Interface to GiNaC's sums of expressions.
GiNaC::pseries::derivative
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a power series.
Definition: pseries.cpp:540
GiNaC::pseries::convert_to_poly
ex convert_to_poly(bool no_order=false) const
Convert the pseries object to an ordinary polynomial.
Definition: pseries.cpp:573
GiNaC::ex::conjugate
ex conjugate() const
Definition: ex.h:146
power.h
Interface to GiNaC's symbolic exponentiation (basis^exponent).
GiNaC::exvector
std::vector< ex > exvector
Definition: basic.h:46
GiNaC::ex::nops
size_t nops() const
Definition: ex.h:135
GiNaC::status_flags::evaluated
@ evaluated
.eval() has already done its job
Definition: flags.h:203
GiNaC::is_order_function
bool is_order_function(const ex &e)
Check whether a function is the Order (O(n)) function.
Definition: inifcns.h:229
GiNaC::integral::x
ex x
Definition: integral.h:77
GiNaC::pseries::print_series
void print_series(const print_context &c, const char *openbrace, const char *closebrace, const char *mul_sym, const char *pow_sym, unsigned level) const
Definition: pseries.cpp:153
GiNaC::power::exponent
ex exponent
Definition: power.h:106
GiNaC::archive_node
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
Definition: archive.h:49
GiNaC::_ex1
const ex _ex1
Definition: utils.cpp:193
GiNaC::pseries::subs
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
Definition: pseries.cpp:508
relational.h
Interface to relations between expressions.
GiNaC::info_flags::positive
@ positive
Definition: flags.h:226
options
unsigned options
Definition: factor.cpp:2480
GiNaC::ex::is_equal
bool is_equal(const ex &other) const
Definition: ex.h:345
GiNaC::pseries::shift_exponents
pseries shift_exponents(int deg) const
Return a new pseries object with the powers shifted by deg.
Definition: pseries.cpp:1061
m
mvec m
Definition: factor.cpp:771
GiNaC::GINAC_BIND_UNARCHIVER
GINAC_BIND_UNARCHIVER(add)
GiNaC::pseries::read_archive
void read_archive(const archive_node &n, lst &syms) override
Read (a.k.a.
Definition: pseries.cpp:119
GiNaC
Definition: add.cpp:38
GiNaC::pseries::mul_const
ex mul_const(const numeric &other) const
Multiply a pseries object with a numeric constant, producing a pseries object that represents the pro...
Definition: pseries.cpp:779
GiNaC::are_ex_trivially_equal
bool are_ex_trivially_equal(const ex &e1, const ex &e2)
Compare two objects of class quickly without doing a deep tree traversal.
Definition: ex.h:684
GiNaC::numeric::is_negative
bool is_negative() const
True if object is not complex and less than zero.
Definition: numeric.cpp:1145
GiNaC::ex::info
bool info(unsigned inf) const
Definition: ex.h:132
utils.h
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...
GiNaC::integral::f
ex f
Definition: integral.h:80
GiNaC::ex
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
lst.h
Definition of GiNaC's lst.
GiNaC::numeric::is_zero
bool is_zero() const
True if object is zero.
Definition: numeric.cpp:1129
GiNaC::basic::compare_same_type
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition: basic.cpp:719
GiNaC::print_python
Context for python pretty-print output.
Definition: print.h:131
GiNaC::pseries::point
ex point
Expansion point.
Definition: pseries.h:121
GiNaC::pseries::degree
int degree(const ex &s) const override
Return degree of highest power of the series.
Definition: pseries.cpp:315
integral.h
Interface to GiNaC's symbolic integral.
GiNaC::ex::eval_integ
ex eval_integ() const
Definition: ex.h:124
GiNaC::ex::find
bool find(const ex &pattern, exset &found) const
Find all occurrences of a pattern.
Definition: ex.cpp:105
GiNaC::exp
const numeric exp(const numeric &x)
Exponential function.
Definition: numeric.cpp:1439
GiNaC::add::series
ex series(const relational &r, int order, unsigned options=0) const override
Implementation of ex::series() for sums.
Definition: pseries.cpp:750
GiNaC::ex::diff
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition: ex.cpp:86
GiNaC::symbol::is_equal_same_type
bool is_equal_same_type(const basic &other) const override
Returns true if two objects of same type are equal.
Definition: symbol.cpp:271
GiNaC::power::series
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for powers.
Definition: pseries.cpp:1073
GiNaC::pseries::is_zero
bool is_zero() const
Check whether series has the value zero.
Definition: pseries.h:89
GiNaC::basic::has
virtual bool has(const ex &other, unsigned options=0) const
Test for occurrence of a pattern.
Definition: basic.cpp:280
GiNaC::ex::ldegree
int ldegree(const ex &s) const
Definition: ex.h:174
GiNaC::basic::hold
const basic & hold() const
Stop further evaluation.
Definition: basic.cpp:887
GiNaC::expairseq::seq
epvector seq
Definition: expairseq.h:127
GiNaC::ex::evalm
ex evalm() const
Definition: ex.h:122
GiNaC::pseries::add_series
ex add_series(const pseries &other) const
Add one series object to another, producing a pseries object that represents the sum.
Definition: pseries.cpp:681
GiNaC::print_latex
Context for latex-parsable output.
Definition: print.h:123
GiNaC::basic::coeff
virtual ex coeff(const ex &s, int n=1) const
Return coefficient of degree n in object s.
Definition: basic.cpp:337
symbol.h
Interface to GiNaC's symbolic objects.
GiNaC::ex::print
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition: ex.cpp:56
GiNaC::ex::real_part
ex real_part() const
Definition: ex.h:147
GiNaC::pseries::mul_series
ex mul_series(const pseries &other) const
Multiply one pseries object to another, producing a pseries object that represents the product.
Definition: pseries.cpp:799
GiNaC::print_tree
Context for tree-like output for debugging.
Definition: print.h:147
GiNaC::pseries::imag_part
ex imag_part() const override
Definition: pseries.cpp:442
GiNaC::ex::rhs
ex rhs() const
Right hand side of relational expression.
Definition: ex.cpp:233
GiNaC::pseries::series
ex series(const relational &r, int order, unsigned options=0) const override
Re-expansion of a pseries object.
Definition: pseries.cpp:1169
GiNaC::info_flags::numeric
@ numeric
Definition: flags.h:220
GiNaC::integral::b
ex b
Definition: integral.h:79
GiNaC::pseries::seq
epvector seq
Vector of {coefficient, power} pairs.
Definition: pseries.h:115
GiNaC::container
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
GiNaC::pseries::nops
size_t nops() const override
Return the number of operands including a possible order term.
Definition: pseries.cpp:296
GiNaC::pseries::precedence
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition: pseries.h:46
GiNaC::subs_options::no_pattern
@ no_pattern
disable pattern matching
Definition: flags.h:51
GiNaC::pseries::ldegree
int ldegree(const ex &s) const override
Return degree of lowest power of the series.
Definition: pseries.cpp:335
GiNaC::pseries::expand
ex expand(unsigned options=0) const override
Implementation of ex::expand() for a power series.
Definition: pseries.cpp:527
GiNaC::pole_error
Exception class thrown when a singularity is encountered.
Definition: numeric.h:70
c
size_t c
Definition: factor.cpp:770
GiNaC::exmap
std::map< ex, ex, ex_is_less > exmap
Definition: basic.h:50
GiNaC::basic::series
virtual ex series(const relational &r, int order, unsigned options=0) const
Default implementation of ex::series().
Definition: pseries.cpp:612
GiNaC::pseries::do_print_tree
void do_print_tree(const print_tree &c, unsigned level) const
Definition: pseries.cpp:227
GiNaC::ex::series
ex series(const ex &r, int order, unsigned options=0) const
Compute the truncated series expansion of an expression.
Definition: pseries.cpp:1259
GiNaC::factor
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition: factor.cpp:2581
GiNaC::expairseq::overall_coeff
ex overall_coeff
Definition: expairseq.h:128
GiNaC::symbol::series
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for symbols.
Definition: pseries.cpp:657
GiNaC::pseries::var
ex var
Series variable (holds a symbol)
Definition: pseries.h:118
archive.h
Archiving of GiNaC expressions.
std
Definition: ex.h:972
GiNaC::symbol
Basic CAS symbol.
Definition: symbol.h:39
n
size_t n
Definition: factor.cpp:1463
GiNaC::info_flags::rational_function
@ rational_function
Definition: flags.h:260
GiNaC::pow
const numeric pow(const numeric &x, const numeric &y)
Definition: numeric.h:251
GiNaC::to_int
int to_int(const numeric &x)
Definition: numeric.h:302
pseries.h
Interface to class for extended truncated power series.
GiNaC::pseries::eval
ex eval() const override
Perform coefficient-wise automatic term rewriting rules in this class.
Definition: pseries.cpp:395
GiNaC::basic
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition: basic.h:105
GiNaC::pseries::coeffop
ex coeffop(size_t i) const
Get coefficients and exponents.
Definition: pseries.cpp:591
GiNaC::expair
A pair of expressions.
Definition: expair.h:38
GiNaC::info_flags::negint
@ negint
Definition: flags.h:230
GiNaC::power::basis
ex basis
Definition: power.h:105
GiNaC::numeric::div
const numeric div(const numeric &other) const
Numerical division method.
Definition: numeric.cpp:890
GiNaC::ex::is_zero
bool is_zero() const
Definition: ex.h:213
GiNaC::expairseq::op
ex op(size_t i) const override
Return operand/member at position i.
GiNaC::pseries::eval_integ
ex eval_integ() const override
Evaluate integrals, if result is known.
Definition: pseries.cpp:457
GiNaC::mul::recombine_pair_to_ex
ex recombine_pair_to_ex(const expair &p) const override
Definition: mul.cpp:999
GiNaC::log
const numeric log(const numeric &x)
Natural logarithm.
Definition: numeric.cpp:1450
GiNaC::integral::series
ex series(const relational &r, int order, unsigned options=0) const override
Default implementation of ex::series().
Definition: pseries.cpp:1194
GiNaC::pseries::is_compatible_to
bool is_compatible_to(const pseries &other) const
Check whether series is compatible to another series (expansion variable and point are the same.
Definition: pseries.h:86
GiNaC::mul::series
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for product.
Definition: pseries.cpp:864
GiNaC::numeric::real
const numeric real() const
Real part of a number.
Definition: numeric.cpp:1339
GiNaC::is_integer
bool is_integer(const numeric &x)
Definition: numeric.h:272
GiNaC::numeric::coeff
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition: numeric.cpp:743
GiNaC::pseries::evalm
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
Definition: pseries.cpp:481
GiNaC::pseries::coeff
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in power series if s is the expansion variable.
Definition: pseries.cpp:357
GiNaC::basic::flags
unsigned flags
of type status_flags
Definition: basic.h:302
GiNaC::basic::print
virtual void print(const print_context &c, unsigned level=0) const
Output to stream.
Definition: basic.cpp:116
GiNaC::print_func< print_context >
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition: idx.cpp:45
GiNaC::pseries::power_const
ex power_const(const numeric &p, int deg) const
Compute the p-th power of a series.
Definition: pseries.cpp:976
GiNaC::ex::bp
ptr< basic > bp
pointer to basic object managed by this
Definition: ex.h:251
order
int order
Definition: integration_kernel.cpp:248
operators.h
Interface to GiNaC's overloaded operators.
GiNaC::numeric
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition: numeric.h:82
GINAC_ASSERT
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition: assertion.h:33
GiNaC::pseries::evalf
ex evalf() const override
Evaluate coefficients numerically.
Definition: pseries.cpp:401
GiNaC::ex::lhs
ex lhs() const
Left hand side of relational expression.
Definition: ex.cpp:225
GiNaC::pseries::op
ex op(size_t i) const override
Return the ith term in the series when represented as a sum.
Definition: pseries.cpp:302
GiNaC::pseries::archive
void archive(archive_node &n) const override
Save (a.k.a.
Definition: pseries.cpp:137

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.