GiNaC 1.8.6
pseries.cpp
Go to the documentation of this file.
1
6/*
7 * GiNaC Copyright (C) 1999-2023 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
41namespace 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
56
57
58/*
59 * Other ctors
60 */
61
71pseries::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}
92pseries::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())
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
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
153void 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
212void pseries::do_print(const print_context & c, unsigned level) const
213{
214 print_series(c, "", "", "*", "^", level);
215}
216
217void pseries::do_print_latex(const print_latex & c, unsigned level) const
218{
219 print_series(c, "{", "}", " ", "^", level);
220}
221
222void pseries::do_print_python(const print_python & c, unsigned level) const
223{
224 print_series(c, "", "", "*", "**", level);
225}
226
227void 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
242void 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
262int 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
296size_t pseries::nops() const
297{
298 return seq.size();
299}
300
302ex 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
315int 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
335int 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
357ex 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
389ex 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
508ex 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
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
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
573ex 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
591ex 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
598ex 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
612ex 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
657ex 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
681ex 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
750ex 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
779ex 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
799ex 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
864ex 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
976ex 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
1073ex 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
1169ex 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
1194ex 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
1259ex 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:841
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.
Definition: expairseq.cpp:210
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
Form an ex out of an expair, using the corresponding semantics.
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:2475
size_t n
Definition: factor.cpp:1432
size_t c
Definition: factor.cpp:757
size_t r
Definition: factor.cpp:757
mvec m
Definition: factor.cpp:758
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
epvector * conjugateepvector(const epvector &epv)
Complex conjugate every element of an epvector.
Definition: expairseq.cpp:252
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:699
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
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:2576
int to_int(const numeric &x)
Definition: numeric.h:302
bool is_integer(const numeric &x)
Definition: numeric.h:272
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
const ex _ex0
Definition: utils.cpp:369
std::vector< ex > exvector
Definition: basic.h:48
bool is_order_function(const ex &e)
Check whether a function is the Order (O(n)) function.
Definition: inifcns.h:229
Definition: ex.h:987
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.