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