+/** Test for occurrence of a pattern. An object 'has' a pattern if it matches
+ * the pattern itself or one of the children 'has' it. As a consequence
+ * (according to the definition of children) given e=x+y+z, e.has(x) is true
+ * but e.has(x+y) is false. */
+bool basic::has(const ex & pattern) const
+{
+ lst repl_lst;
+ if (match(pattern, repl_lst))
+ return true;
+ for (unsigned i=0; i<nops(); i++)
+ if (op(i).has(pattern))
+ return true;
+
+ return false;
+}
+
+/** Construct new expression by applying the specified function to all
+ * sub-expressions (one level only, not recursively). */
+ex basic::map(map_function & f) const
+{
+ unsigned num = nops();
+ if (num == 0)
+ return *this;
+
+ basic *copy = duplicate();
+ copy->setflag(status_flags::dynallocated);
+ copy->clearflag(status_flags::hash_calculated | status_flags::expanded);
+ ex e(*copy);
+ for (unsigned i=0; i<num; i++)
+ e.let_op(i) = f(e.op(i));
+ return e.eval();
+}
+
+/** Return degree of highest power in object s. */
+int basic::degree(const ex & s) const
+{
+ return is_equal(ex_to<basic>(s)) ? 1 : 0;
+}
+
+/** Return degree of lowest power in object s. */
+int basic::ldegree(const ex & s) const
+{
+ return is_equal(ex_to<basic>(s)) ? 1 : 0;
+}
+
+/** Return coefficient of degree n in object s. */
+ex basic::coeff(const ex & s, int n) const
+{
+ if (is_equal(ex_to<basic>(s)))
+ return n==1 ? _ex1 : _ex0;
+ else
+ return n==0 ? *this : _ex0;
+}
+
+/** Sort expanded expression in terms of powers of some object(s).
+ * @param s object(s) to sort in
+ * @param distributed recursive or distributed form (only used when s is a list) */
+ex basic::collect(const ex & s, bool distributed) const
+{
+ ex x;
+ if (is_a<lst>(s)) {
+
+ // List of objects specified
+ if (s.nops() == 0)
+ return *this;
+ if (s.nops() == 1)
+ return collect(s.op(0));
+
+ else if (distributed) {
+
+ // Get lower/upper degree of all symbols in list
+ int num = s.nops();
+ struct sym_info {
+ ex sym;
+ int ldeg, deg;
+ int cnt; // current degree, 'counter'
+ ex coeff; // coefficient for degree 'cnt'
+ };
+ sym_info *si = new sym_info[num];
+ ex c = *this;
+ for (int i=0; i<num; i++) {
+ si[i].sym = s.op(i);
+ si[i].ldeg = si[i].cnt = this->ldegree(si[i].sym);
+ si[i].deg = this->degree(si[i].sym);
+ c = si[i].coeff = c.coeff(si[i].sym, si[i].cnt);
+ }
+
+ while (true) {
+
+ // Calculate coeff*x1^c1*...*xn^cn
+ ex y = _ex1;
+ for (int i=0; i<num; i++) {
+ int cnt = si[i].cnt;
+ y *= power(si[i].sym, cnt);
+ }
+ x += y * si[num - 1].coeff;
+
+ // Increment counters
+ int n = num - 1;
+ while (true) {
+ ++si[n].cnt;
+ if (si[n].cnt <= si[n].deg) {
+ // Update coefficients
+ ex c;
+ if (n == 0)
+ c = *this;
+ else
+ c = si[n - 1].coeff;
+ for (int i=n; i<num; i++)
+ c = si[i].coeff = c.coeff(si[i].sym, si[i].cnt);
+ break;
+ }
+ if (n == 0)
+ goto done;
+ si[n].cnt = si[n].ldeg;
+ n--;
+ }
+ }
+
+done: delete[] si;
+
+ } else {
+
+ // Recursive form
+ x = *this;
+ for (int n=s.nops()-1; n>=0; n--)
+ x = x.collect(s[n]);
+ }
+
+ } else {
+
+ // Only one object specified
+ for (int n=this->ldegree(s); n<=this->degree(s); ++n)
+ x += this->coeff(s,n)*power(s,n);
+ }
+
+ // correct for lost fractional arguments and return
+ return x + (*this - x).expand();
+}
+
+/** Perform automatic non-interruptive term rewriting rules. */
+ex basic::eval(int level) const