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