+// public
+
+/** Compare objects syntactically to establish canonical ordering.
+ * All compare functions return: -1 for *this less than other, 0 equal,
+ * 1 greater. */
+int basic::compare(const basic & other) const
+{
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.total_basic_compares++;
+#endif
+ const unsigned hash_this = gethash();
+ const unsigned hash_other = other.gethash();
+ if (hash_this<hash_other) return -1;
+ if (hash_this>hash_other) return 1;
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.compare_same_hashvalue++;
+#endif
+
+ const unsigned typeid_this = tinfo();
+ const unsigned typeid_other = other.tinfo();
+ if (typeid_this==typeid_other) {
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+// int cmpval = compare_same_type(other);
+// if (cmpval!=0) {
+// std::cout << "hash collision, same type: "
+// << *this << " and " << other << std::endl;
+// this->print(print_tree(std::cout));
+// std::cout << " and ";
+// other.print(print_tree(std::cout));
+// std::cout << std::endl;
+// }
+// return cmpval;
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.compare_same_type++;
+#endif
+ return compare_same_type(other);
+ } else {
+// std::cout << "hash collision, different types: "
+// << *this << " and " << other << std::endl;
+// this->print(print_tree(std::cout));
+// std::cout << " and ";
+// other.print(print_tree(std::cout));
+// std::cout << std::endl;
+ return (typeid_this<typeid_other ? -1 : 1);
+ }
+}
+
+/** Test for syntactic equality.
+ * This is only a quick test, meaning objects should be in the same domain.
+ * You might have to .expand(), .normal() objects first, depending on the
+ * domain of your computation, to get a more reliable answer.
+ *
+ * @see is_equal_same_type */
+bool basic::is_equal(const basic & other) const
+{
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.total_basic_is_equals++;
+#endif
+ if (this->gethash()!=other.gethash())
+ return false;
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.is_equal_same_hashvalue++;
+#endif
+ if (this->tinfo()!=other.tinfo())
+ return false;
+
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+
+#ifdef GINAC_COMPARE_STATISTICS
+ compare_statistics.is_equal_same_type++;
+#endif
+ return is_equal_same_type(other);
+}
+
+// protected
+
+/** Stop further evaluation.
+ *
+ * @see basic::eval */
+const basic & basic::hold() const
+{
+ return setflag(status_flags::evaluated);
+}
+
+/** Ensure the object may be modified without hurting others, throws if this
+ * is not the case. */
+void basic::ensure_if_modifiable() const
+{
+ if (get_refcount() > 1)
+ throw(std::runtime_error("cannot modify multiply referenced object"));
+ clearflag(status_flags::hash_calculated | status_flags::evaluated);
+}