-basic *pseries::duplicate() const
-{
- debugmsg("pseries duplicate", LOGLEVEL_DUPLICATE);
- return new pseries(*this);
-}
-
-void pseries::print(ostream &os, unsigned upper_precedence) const
-{
- debugmsg("pseries print", LOGLEVEL_PRINT);
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); i++) {
- // print a sign, if needed
- if (i!=seq.begin())
- os << '+';
- if (!is_order_function(i->rest)) {
- // print 'rest', i.e. the expansion coefficient
- if (i->rest.info(info_flags::numeric) &&
- i->rest.info(info_flags::positive)) {
- os << i->rest;
- } else
- os << "(" << i->rest << ')';
- // print 'coeff', something like (x-1)^42
- if (!i->coeff.is_zero()) {
- os << '*';
- if (!point.is_zero())
- os << '(' << var-point << ')';
- else
- os << var;
- if (i->coeff.compare(_ex1())) {
- os << '^';
- if (i->coeff.info(info_flags::negative))
- os << '(' << i->coeff << ')';
- else
- os << i->coeff;
- }
- }
- } else {
- os << Order(power(var-point,i->coeff));
- }
- }
-}
-
-void pseries::printraw(ostream &os) const
-{
- debugmsg("pseries printraw", LOGLEVEL_PRINT);
- os << "pseries(" << var << ";" << point << ";";
- for (epvector::const_iterator i=seq.begin(); i!=seq.end(); i++) {
- os << "(" << (*i).rest << "," << (*i).coeff << "),";
- }
- os << ")";
-}
-
-void pseries::printtree(ostream & os, unsigned indent) const
-{
- debugmsg("pseries printtree",LOGLEVEL_PRINT);
- os << string(indent,' ') << "pseries "
- << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
- << ", flags=" << flags << endl;
- for (unsigned i=0; i<seq.size(); ++i) {
- seq[i].rest.printtree(os,indent+delta_indent);
- seq[i].coeff.printtree(os,indent+delta_indent);
- if (i!=seq.size()-1) {
- os << string(indent+delta_indent,' ') << "-----" << endl;
- }
- }
- var.printtree(os, indent+delta_indent);
- point.printtree(os, indent+delta_indent);
-}
-
-unsigned pseries::nops(void) const
-{
- return seq.size();
-}
-
-ex pseries::op(int i) const
-{
- if (i < 0 || unsigned(i) >= seq.size())
- throw (std::out_of_range("op() out of range"));
- return seq[i].rest * power(var - point, seq[i].coeff);
-}
-
-ex &pseries::let_op(int i)
-{
- throw (std::logic_error("let_op not defined for pseries"));
-}
-
-int pseries::degree(const symbol &s) const
-{
- if (var.is_equal(s)) {
- // Return last exponent
- if (seq.size())
- return ex_to_numeric((*(seq.end() - 1)).coeff).to_int();
- else
- return 0;
- } else {
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- if (it == itend)
- return 0;
- int max_pow = INT_MIN;
- while (it != itend) {
- int pow = it->rest.degree(s);
- if (pow > max_pow)
- max_pow = pow;
- it++;
- }
- return max_pow;
- }
-}
-
-int pseries::ldegree(const symbol &s) const
-{
- if (var.is_equal(s)) {
- // Return first exponent
- if (seq.size())
- return ex_to_numeric((*(seq.begin())).coeff).to_int();
- else
- return 0;
- } else {
- epvector::const_iterator it = seq.begin(), itend = seq.end();
- if (it == itend)
- return 0;
- int min_pow = INT_MAX;
- while (it != itend) {
- int pow = it->rest.ldegree(s);
- if (pow < min_pow)
- min_pow = pow;
- it++;
- }
- return min_pow;
- }
-}
-
-ex pseries::coeff(const symbol &s, int n) const
-{
- if (var.is_equal(s)) {
- if (seq.size() == 0)
- return _ex0();
-
- // Binary search in sequence for given power
- numeric looking_for = numeric(n);
- int lo = 0, hi = seq.size() - 1;
- while (lo <= hi) {
- int mid = (lo + hi) / 2;
- GINAC_ASSERT(is_ex_exactly_of_type(seq[mid].coeff, numeric));
- int cmp = ex_to_numeric(seq[mid].coeff).compare(looking_for);
- switch (cmp) {
- case -1:
- lo = mid + 1;
- break;
- case 0:
- return seq[mid].rest;
- case 1:
- hi = mid - 1;
- break;
- default:
- throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
- }
- }
- return _ex0();
- } else
- return convert_to_poly().coeff(s, n);
-}
-
-ex pseries::collect(const symbol &s) const
-{
- return *this;
-}
-
-/** Evaluate coefficients. */
+void pseries::print_series(const print_context & c, const char *openbrace, const char *closebrace, const char *mul_sym, const char *pow_sym, unsigned level) const
+{
+ if (precedence() <= level)
+ c.s << '(';
+
+ // objects of type pseries must not have any zero entries, so the
+ // trivial (zero) pseries needs a special treatment here:
+ if (seq.empty())
+ c.s << '0';
+
+ epvector::const_iterator i = seq.begin(), end = seq.end();
+ while (i != end) {
+
+ // print a sign, if needed
+ if (i != seq.begin())
+ c.s << '+';
+
+ if (!is_order_function(i->rest)) {
+
+ // print 'rest', i.e. the expansion coefficient
+ if (i->rest.info(info_flags::numeric) &&
+ i->rest.info(info_flags::positive)) {
+ i->rest.print(c);
+ } else {
+ c.s << openbrace << '(';
+ i->rest.print(c);
+ c.s << ')' << closebrace;
+ }
+
+ // print 'coeff', something like (x-1)^42
+ if (!i->coeff.is_zero()) {
+ c.s << mul_sym;
+ if (!point.is_zero()) {
+ c.s << openbrace << '(';
+ (var-point).print(c);
+ c.s << ')' << closebrace;
+ } else
+ var.print(c);
+ if (i->coeff.compare(_ex1)) {
+ c.s << pow_sym;
+ c.s << openbrace;
+ if (i->coeff.info(info_flags::negative)) {
+ c.s << '(';
+ i->coeff.print(c);
+ c.s << ')';
+ } else
+ i->coeff.print(c);
+ c.s << closebrace;
+ }
+ }
+ } else
+ Order(power(var-point,i->coeff)).print(c);
+ ++i;
+ }
+
+ if (precedence() <= level)
+ c.s << ')';
+}
+
+void pseries::do_print(const print_context & c, unsigned level) const
+{
+ print_series(c, "", "", "*", "^", level);
+}
+
+void pseries::do_print_latex(const print_latex & c, unsigned level) const
+{
+ print_series(c, "{", "}", " ", "^", level);
+}
+
+void pseries::do_print_python(const print_python & c, unsigned level) const
+{
+ print_series(c, "", "", "*", "**", level);
+}
+
+void pseries::do_print_tree(const print_tree & c, unsigned level) const
+{
+ c.s << std::string(level, ' ') << class_name()
+ << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+ << std::endl;
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i) {
+ seq[i].rest.print(c, level + c.delta_indent);
+ seq[i].coeff.print(c, level + c.delta_indent);
+ c.s << std::string(level + c.delta_indent, ' ') << "-----" << std::endl;
+ }
+ var.print(c, level + c.delta_indent);
+ point.print(c, level + c.delta_indent);
+}
+
+void pseries::do_print_python_repr(const print_python_repr & c, unsigned level) const
+{
+ c.s << class_name() << "(relational(";
+ var.print(c);
+ c.s << ',';
+ point.print(c);
+ c.s << "),[";
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i) {
+ if (i)
+ c.s << ',';
+ c.s << '(';
+ seq[i].rest.print(c);
+ c.s << ',';
+ seq[i].coeff.print(c);
+ c.s << ')';
+ }
+ c.s << "])";
+}
+
+int pseries::compare_same_type(const basic & other) const
+{
+ GINAC_ASSERT(is_a<pseries>(other));
+ const pseries &o = static_cast<const pseries &>(other);
+
+ // first compare the lengths of the series...
+ if (seq.size()>o.seq.size())
+ return 1;
+ if (seq.size()<o.seq.size())
+ return -1;
+
+ // ...then the expansion point...
+ int cmpval = var.compare(o.var);
+ if (cmpval)
+ return cmpval;
+ cmpval = point.compare(o.point);
+ if (cmpval)
+ return cmpval;
+
+ // ...and if that failed the individual elements
+ epvector::const_iterator it = seq.begin(), o_it = o.seq.begin();
+ while (it!=seq.end() && o_it!=o.seq.end()) {
+ cmpval = it->compare(*o_it);
+ if (cmpval)
+ return cmpval;
+ ++it;
+ ++o_it;
+ }
+
+ // so they are equal.
+ return 0;
+}
+
+/** Return the number of operands including a possible order term. */
+size_t pseries::nops() const
+{
+ return seq.size();
+}
+
+/** Return the ith term in the series when represented as a sum. */
+ex pseries::op(size_t i) const
+{
+ if (i >= seq.size())
+ throw (std::out_of_range("op() out of range"));
+
+ return seq[i].rest * power(var - point, seq[i].coeff);
+}
+
+/** Return degree of highest power of the series. This is usually the exponent
+ * of the Order term. If s is not the expansion variable of the series, the
+ * series is examined termwise. */
+int pseries::degree(const ex &s) const
+{
+ if (var.is_equal(s)) {
+ // Return last exponent
+ if (seq.size())
+ return ex_to<numeric>((seq.end()-1)->coeff).to_int();
+ else
+ return 0;
+ } else {
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ if (it == itend)
+ return 0;
+ int max_pow = INT_MIN;
+ while (it != itend) {
+ int pow = it->rest.degree(s);
+ if (pow > max_pow)
+ max_pow = pow;
+ ++it;
+ }
+ return max_pow;
+ }
+}
+
+/** Return degree of lowest power of the series. This is usually the exponent
+ * of the leading term. If s is not the expansion variable of the series, the
+ * series is examined termwise. If s is the expansion variable but the
+ * expansion point is not zero the series is not expanded to find the degree.
+ * I.e.: (1-x) + (1-x)^2 + Order((1-x)^3) has ldegree(x) 1, not 0. */
+int pseries::ldegree(const ex &s) const
+{
+ if (var.is_equal(s)) {
+ // Return first exponent
+ if (seq.size())
+ return ex_to<numeric>((seq.begin())->coeff).to_int();
+ else
+ return 0;
+ } else {
+ epvector::const_iterator it = seq.begin(), itend = seq.end();
+ if (it == itend)
+ return 0;
+ int min_pow = INT_MAX;
+ while (it != itend) {
+ int pow = it->rest.ldegree(s);
+ if (pow < min_pow)
+ min_pow = pow;
+ ++it;
+ }
+ return min_pow;
+ }
+}
+
+/** Return coefficient of degree n in power series if s is the expansion
+ * variable. If the expansion point is nonzero, by definition the n=1
+ * coefficient in s of a+b*(s-z)+c*(s-z)^2+Order((s-z)^3) is b (assuming
+ * the expansion took place in the s in the first place).
+ * If s is not the expansion variable, an attempt is made to convert the
+ * series to a polynomial and return the corresponding coefficient from
+ * there. */
+ex pseries::coeff(const ex &s, int n) const
+{
+ if (var.is_equal(s)) {
+ if (seq.empty())
+ return _ex0;
+
+ // Binary search in sequence for given power
+ numeric looking_for = numeric(n);
+ int lo = 0, hi = seq.size() - 1;
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ GINAC_ASSERT(is_exactly_a<numeric>(seq[mid].coeff));
+ int cmp = ex_to<numeric>(seq[mid].coeff).compare(looking_for);
+ switch (cmp) {
+ case -1:
+ lo = mid + 1;
+ break;
+ case 0:
+ return seq[mid].rest;
+ case 1:
+ hi = mid - 1;
+ break;
+ default:
+ throw(std::logic_error("pseries::coeff: compare() didn't return -1, 0 or 1"));
+ }
+ }
+ return _ex0;
+ } else
+ return convert_to_poly().coeff(s, n);
+}
+
+/** Does nothing. */
+ex pseries::collect(const ex &s, bool distributed) const
+{
+ return *this;
+}
+
+/** Perform coefficient-wise automatic term rewriting rules in this class. */