+/** Substitute a set of objects by arbitrary expressions. The ex returned
+ * will already be evaluated. */
+ex basic::subs(const exmap & m, unsigned options) const
+{
+ size_t num = nops();
+ if (num) {
+
+ // Substitute in subexpressions
+ for (size_t i=0; i<num; i++) {
+ const ex & orig_op = op(i);
+ const ex & subsed_op = orig_op.subs(m, options);
+ if (!are_ex_trivially_equal(orig_op, subsed_op)) {
+
+ // Something changed, clone the object
+ basic *copy = duplicate();
+ copy->setflag(status_flags::dynallocated);
+ copy->clearflag(status_flags::hash_calculated | status_flags::expanded);
+
+ // Substitute the changed operand
+ copy->let_op(i++) = subsed_op;
+
+ // Substitute the other operands
+ for (; i<num; i++)
+ copy->let_op(i) = op(i).subs(m, options);
+
+ // Perform substitutions on the new object as a whole
+ return copy->subs_one_level(m, options);
+ }
+ }
+ }
+
+ // Nothing changed or no subexpressions
+ return subs_one_level(m, options);
+}
+