GiNaC  1.8.3
pseries.cpp
Go to the documentation of this file.
1 
6 /*
7  * GiNaC Copyright (C) 1999-2022 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
Interface to GiNaC's sums of expressions.
Archiving of GiNaC expressions.
#define GINAC_ASSERT(X)
Assertion macro for checking invariances.
Definition: assertion.h:33
ex series(const relational &r, int order, unsigned options=0) const override
Implementation of ex::series() for sums.
Definition: pseries.cpp:750
This class stores all properties needed to record/retrieve the state of one object of class basic (or...
Definition: archive.h:49
This class is the ABC (abstract base class) of GiNaC's class hierarchy.
Definition: basic.h:105
unsigned hashvalue
hash value
Definition: basic.h:303
virtual bool has(const ex &other, unsigned options=0) const
Test for occurrence of a pattern.
Definition: basic.cpp:280
unsigned flags
of type status_flags
Definition: basic.h:302
virtual void print(const print_context &c, unsigned level=0) const
Output to stream.
Definition: basic.cpp:116
const basic & hold() const
Stop further evaluation.
Definition: basic.cpp:887
virtual ex series(const relational &r, int order, unsigned options=0) const
Default implementation of ex::series().
Definition: pseries.cpp:612
virtual int compare_same_type(const basic &other) const
Returns order relation between two objects of same type.
Definition: basic.cpp:719
virtual ex coeff(const ex &s, int n=1) const
Return coefficient of degree n in object s.
Definition: basic.cpp:337
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
ex eval_integ() const
Definition: ex.h:124
bool find(const ex &pattern, exset &found) const
Find all occurrences of a pattern.
Definition: ex.cpp:105
ex diff(const symbol &s, unsigned nth=1) const
Compute partial derivative of an expression.
Definition: ex.cpp:86
ex expand(unsigned options=0) const
Definition: ex.cpp:73
bool is_equal(const ex &other) const
Definition: ex.h:345
ptr< basic > bp
pointer to basic object managed by this
Definition: ex.h:251
ex conjugate() const
Definition: ex.h:146
size_t nops() const
Definition: ex.h:135
ex series(const ex &r, int order, unsigned options=0) const
Compute the truncated series expansion of an expression.
Definition: pseries.cpp:1259
ex subs(const exmap &m, unsigned options=0) const
Definition: ex.h:826
bool info(unsigned inf) const
Definition: ex.h:132
int compare(const ex &other) const
Definition: ex.h:322
ex lhs() const
Left hand side of relational expression.
Definition: ex.cpp:225
bool is_zero() const
Definition: ex.h:213
void print(const print_context &c, unsigned level=0) const
Print expression to stream.
Definition: ex.cpp:56
int ldegree(const ex &s) const
Definition: ex.h:174
ex rhs() const
Right hand side of relational expression.
Definition: ex.cpp:233
ex real_part() const
Definition: ex.h:147
ex evalm() const
Definition: ex.h:122
ex coeff(const ex &s, int n=1) const
Definition: ex.h:175
A pair of expressions.
Definition: expair.h:38
epvector seq
Definition: expairseq.h:127
ex op(size_t i) const override
Return operand/member at position i.
integral(const ex &x_, const ex &a_, const ex &b_, const ex &f_)
Definition: integral.cpp:61
ex series(const relational &r, int order, unsigned options=0) const override
Default implementation of ex::series().
Definition: pseries.cpp:1194
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for product.
Definition: pseries.cpp:864
ex recombine_pair_to_ex(const expair &p) const override
Definition: mul.cpp:999
This class is a wrapper around CLN-numbers within the GiNaC class hierarchy.
Definition: numeric.h:82
const numeric real() const
Real part of a number.
Definition: numeric.cpp:1339
ex coeff(const ex &s, int n=1) const override
Return coefficient of degree n in object s.
Definition: numeric.cpp:743
bool is_negative() const
True if object is not complex and less than zero.
Definition: numeric.cpp:1145
bool is_zero() const
True if object is zero.
Definition: numeric.cpp:1129
const numeric div(const numeric &other) const
Numerical division method.
Definition: numeric.cpp:890
Exception class thrown when a singularity is encountered.
Definition: numeric.h:70
ex basis
Definition: power.h:105
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for powers.
Definition: pseries.cpp:1073
ex exponent
Definition: power.h:106
Base class for print_contexts.
Definition: print.h:103
Context for latex-parsable output.
Definition: print.h:123
Context for python-parsable output.
Definition: print.h:139
Context for python pretty-print output.
Definition: print.h:131
Context for tree-like output for debugging.
Definition: print.h:147
This class holds a extended truncated power series (positive and negative integer powers).
Definition: pseries.h:36
int ldegree(const ex &s) const override
Return degree of lowest power of the series.
Definition: pseries.cpp:335
ex evalf() const override
Evaluate coefficients numerically.
Definition: pseries.cpp:401
ex var
Series variable (holds a symbol)
Definition: pseries.h:118
bool is_zero() const
Check whether series has the value zero.
Definition: pseries.h:89
pseries shift_exponents(int deg) const
Return a new pseries object with the powers shifted by deg.
Definition: pseries.cpp:1061
void do_print(const print_context &c, unsigned level) const
Definition: pseries.cpp:212
ex op(size_t i) const override
Return the ith term in the series when represented as a sum.
Definition: pseries.cpp:302
unsigned precedence() const override
Return relative operator precedence (for parenthezing output).
Definition: pseries.h:46
void do_print_latex(const print_latex &c, unsigned level) const
Definition: pseries.cpp:217
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
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
void do_print_tree(const print_tree &c, unsigned level) const
Definition: pseries.cpp:227
ex convert_to_poly(bool no_order=false) const
Convert the pseries object to an ordinary polynomial.
Definition: pseries.cpp:573
size_t nops() const override
Return the number of operands including a possible order term.
Definition: pseries.cpp:296
void read_archive(const archive_node &n, lst &syms) override
Read (a.k.a.
Definition: pseries.cpp:119
ex subs(const exmap &m, unsigned options=0) const override
Substitute a set of objects by arbitrary expressions.
Definition: pseries.cpp:508
pseries(const ex &rel_, const epvector &ops_)
Construct pseries from a vector of coefficients and powers.
Definition: pseries.cpp:71
ex eval_integ() const override
Evaluate integrals, if result is known.
Definition: pseries.cpp:457
ex expand(unsigned options=0) const override
Implementation of ex::expand() for a power series.
Definition: pseries.cpp:527
ex derivative(const symbol &s) const override
Implementation of ex::diff() for a power series.
Definition: pseries.cpp:540
ex real_part() const override
Definition: pseries.cpp:427
ex evalm() const override
Evaluate sums, products and integer powers of matrices.
Definition: pseries.cpp:481
epvector seq
Vector of {coefficient, power} pairs.
Definition: pseries.h:115
ex point
Expansion point.
Definition: pseries.h:121
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
ex exponop(size_t i) const
Definition: pseries.cpp:598
ex coeffop(size_t i) const
Get coefficients and exponents.
Definition: pseries.cpp:591
void archive(archive_node &n) const override
Save (a.k.a.
Definition: pseries.cpp:137
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
ex series(const relational &r, int order, unsigned options=0) const override
Re-expansion of a pseries object.
Definition: pseries.cpp:1169
void do_print_python(const print_python &c, unsigned level) const
Definition: pseries.cpp:222
ex imag_part() const override
Definition: pseries.cpp:442
void do_print_python_repr(const print_python_repr &c, unsigned level) const
Definition: pseries.cpp:242
bool is_terminating() const
Returns true if there is no order term, i.e.
Definition: pseries.cpp:586
ex conjugate() const override
Definition: pseries.cpp:412
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
ex power_const(const numeric &p, int deg) const
Compute the p-th power of a series.
Definition: pseries.cpp:976
int degree(const ex &s) const override
Return degree of highest power of the series.
Definition: pseries.cpp:315
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
ex collect(const ex &s, bool distributed=false) const override
Does nothing.
Definition: pseries.cpp:389
ex eval() const override
Perform coefficient-wise automatic term rewriting rules in this class.
Definition: pseries.cpp:395
This class holds a relation consisting of two expressions and a logical relation between them.
Definition: relational.h:35
@ expanded
.expand(0) has already done its job (other expand() options ignore this flag)
Definition: flags.h:204
@ evaluated
.eval() has already done its job
Definition: flags.h:203
@ no_pattern
disable pattern matching
Definition: flags.h:51
Basic CAS symbol.
Definition: symbol.h:39
bool is_equal_same_type(const basic &other) const override
Returns true if two objects of same type are equal.
Definition: symbol.cpp:271
ex series(const relational &s, int order, unsigned options=0) const override
Implementation of ex::series() for symbols.
Definition: pseries.cpp:657
unsigned options
Definition: factor.cpp:2480
size_t n
Definition: factor.cpp:1463
size_t c
Definition: factor.cpp:770
size_t r
Definition: factor.cpp:770
mvec m
Definition: factor.cpp:771
Interface to GiNaC's initially known functions.
Interface to GiNaC's symbolic integral.
int order
Definition of GiNaC's lst.
Interface to GiNaC's products of expressions.
Definition: add.cpp:38
const numeric pow(const numeric &x, const numeric &y)
Definition: numeric.h:251
std::map< ex, ex, ex_is_less > exmap
Definition: basic.h:50
std::vector< expair > epvector
expair-vector
Definition: expairseq.h:33
const ex _ex1
Definition: utils.cpp:385
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
const numeric exp(const numeric &x)
Exponential function.
Definition: numeric.cpp:1439
print_func< print_context >(&varidx::do_print). print_func< print_latex >(&varidx
Definition: idx.cpp:45
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_IMPLEMENT_REGISTERED_CLASS_OPT_T(lst, basic, print_func< print_context >(&lst::do_print). print_func< print_tree >(&lst::do_print_tree)) template<> bool lst GINAC_BIND_UNARCHIVER(lst)
Specialization of container::info() for lst.
Definition: lst.cpp:42
epvector * conjugateepvector(const epvector &)
Complex conjugate every element of an epvector.
const numeric log(const numeric &x)
Natural logarithm.
Definition: numeric.cpp:1450
ex factor(const ex &poly, unsigned options)
Interface function to the outside world.
Definition: factor.cpp:2581
int to_int(const numeric &x)
Definition: numeric.h:302
bool is_integer(const numeric &x)
Definition: numeric.h:272
const ex _ex0
Definition: utils.cpp:369
std::vector< ex > exvector
Definition: basic.h:46
bool is_order_function(const ex &e)
Check whether a function is the Order (O(n)) function.
Definition: inifcns.h:229
Definition: ex.h:972
Interface to GiNaC's overloaded operators.
Interface to GiNaC's symbolic exponentiation (basis^exponent).
Interface to class for extended truncated power series.
Interface to relations between expressions.
Interface to GiNaC's symbolic objects.
Interface to several small and furry utilities needed within GiNaC but not of any interest to the use...

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