+/** Function object to be applied by basic::derivative(). */
+struct derivative_map_function : public map_function {
+ const symbol &s;
+ derivative_map_function(const symbol &sym) : s(sym) {}
+ ex operator()(const ex & e) { return diff(e, s); }
+};
+
+/** Default implementation of ex::diff(). It maps the operation on the
+ * operands (or returns 0 when the object has no operands).
+ *
+ * @see ex::diff */
+ex basic::derivative(const symbol & s) const
+{
+ if (nops() == 0)
+ return _ex0;
+ else {
+ derivative_map_function map_derivative(s);
+ return map(map_derivative);
+ }
+}
+
+/** Returns order relation between two objects of same type. This needs to be
+ * implemented by each class. It may never return anything else than 0,
+ * signalling equality, or +1 and -1 signalling inequality and determining
+ * the canonical ordering. (Perl hackers will wonder why C++ doesn't feature
+ * the spaceship operator <=> for denoting just this.) */
+int basic::compare_same_type(const basic & other) const
+{
+ return compare_pointers(this, &other);
+}
+
+/** Returns true if two objects of same type are equal. Normally needs
+ * not be reimplemented as long as it wasn't overwritten by some parent
+ * class, since it just calls compare_same_type(). The reason why this
+ * function exists is that sometimes it is easier to determine equality
+ * than an order relation and then it can be overridden. */
+bool basic::is_equal_same_type(const basic & other) const
+{
+ return compare_same_type(other)==0;
+}
+
+/** Returns true if the attributes of two objects are similar enough for
+ * a match. This function must not match subexpressions (this is already
+ * done by basic::match()). Only attributes not accessible by op() should
+ * be compared. This is also the reason why this function doesn't take the
+ * wildcard replacement list from match() as an argument: only subexpressions
+ * are subject to wildcard matches. Also, this function only needs to be
+ * implemented for container classes because is_equal_same_type() is
+ * automatically used instead of match_same_type() if nops() == 0.
+ *
+ * @see basic::match */
+bool basic::match_same_type(const basic & other) const
+{
+ // The default is to only consider subexpressions, but not any other
+ // attributes
+ return true;
+}
+
+unsigned basic::return_type() const
+{
+ return return_types::commutative;
+}
+
+unsigned basic::return_type_tinfo() const
+{
+ return tinfo();
+}
+
+/** Compute the hash value of an object and if it makes sense to store it in
+ * the objects status_flags, do so. The method inherited from class basic
+ * computes a hash value based on the type and hash values of possible
+ * members. For this reason it is well suited for container classes but
+ * atomic classes should override this implementation because otherwise they
+ * would all end up with the same hashvalue. */
+unsigned basic::calchash() const
+{
+ unsigned v = golden_ratio_hash(tinfo());
+ for (size_t i=0; i<nops(); i++) {
+ v = rotate_left(v);
+ v ^= this->op(i).gethash();
+ }
+
+ // store calculated hash value only if object is already evaluated
+ if (flags & status_flags::evaluated) {
+ setflag(status_flags::hash_calculated);
+ hashvalue = v;
+ }
+
+ return v;
+}
+
+/** Function object to be applied by basic::expand(). */
+struct expand_map_function : public map_function {
+ unsigned options;
+ expand_map_function(unsigned o) : options(o) {}
+ ex operator()(const ex & e) { return e.expand(options); }
+};
+
+/** Expand expression, i.e. multiply it out and return the result as a new
+ * expression. */
+ex basic::expand(unsigned options) const
+{
+ if (nops() == 0)
+ return (options == 0) ? setflag(status_flags::expanded) : *this;
+ else {
+ expand_map_function map_expand(options);
+ return ex_to<basic>(map(map_expand)).setflag(options == 0 ? status_flags::expanded : 0);
+ }
+}
+