-ex basic::subs(ex const & e) const
-{
- // accept 2 types of replacement expressions:
- // - symbol==ex
- // - lst(symbol1==ex1,symbol2==ex2,...)
- // convert to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...))
- // additionally, idx can be used instead of symbol
- if (e.info(info_flags::relation_equal)) {
- return subs(lst(e));
- }
- if (!e.info(info_flags::list)) {
- throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
- }
- lst ls;
- lst lr;
- for (int i=0; i<e.nops(); i++) {
- if (!e.op(i).info(info_flags::relation_equal)) {
- throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
- }
- if (!e.op(i).op(0).info(info_flags::symbol)) {
- if (!e.op(i).op(0).info(info_flags::idx)) {
- throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
- }
- }
- ls.append(e.op(i).op(0));
- lr.append(e.op(i).op(1));
- }
- return subs(ls,lr);
-}
-
-// compare functions to sort expressions canonically
-// all compare functions return: -1 for *this less than other, 0 equal, 1 greater
-
-/*
-int basic::compare(basic const & other) const
-{
- const type_info & typeid_this = typeid(*this);
- const type_info & typeid_other = typeid(other);
-
- if (typeid_this==typeid_other) {
- return compare_same_type(other);
- }
-
- // special rule: sort numeric() to end
- if (typeid_this==typeid_numeric) return 1;
- if (typeid_other==typeid_numeric) return -1;
-
- // otherwise: sort according to type_info order (arbitrary, but well defined)
- return typeid_this.before(typeid_other) ? -1 : 1;
-}
-*/
-
-int basic::compare(basic const & other) const
-{
- unsigned hash_this = gethash();
- unsigned hash_other = other.gethash();
-
- if (hash_this<hash_other) return -1;
- if (hash_this>hash_other) return 1;
-
- unsigned typeid_this = tinfo();
- unsigned typeid_other = other.tinfo();
-
- if (typeid_this<typeid_other) {
- /*
- cout << "hash collision, different types: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- return -1;
- }
- if (typeid_this>typeid_other) {
- /*
- cout << "hash collision, different types: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- return 1;
- }
-
- ASSERT(typeid(*this)==typeid(other));
-
- int cmpval=compare_same_type(other);
- if ((cmpval!=0)&&(hash_this<0x80000000U)) {
- /*
- cout << "hash collision, same type: "
- << *this << " and " << other << endl;
- this->printraw(cout);
- cout << " and ";
- other.printraw(cout);
- cout << endl;
- */
- }
- return cmpval;
-}
-
-bool basic::is_equal(basic const & other) const
-{
- unsigned hash_this = gethash();
- unsigned hash_other = other.gethash();
-
- if (hash_this!=hash_other) return false;
-
- unsigned typeid_this = tinfo();
- unsigned typeid_other = other.tinfo();
-
- if (typeid_this!=typeid_other) return false;
-
- ASSERT(typeid(*this)==typeid(other));
-
- return is_equal_same_type(other);
+/** Substitute symbols in expression and return the result as a new expression.
+ * There are two valid types of replacement arguments: 1) a relational like
+ * symbol==ex and 2) a list of relationals lst(symbol1==ex1,symbol2==ex2,...),
+ * which is converted to subs(lst(symbol1,symbol2,...),lst(ex1,ex2,...)).
+ * In addition, an object of class idx can be used instead of a symbol. */
+ex basic::subs(const ex & e) const
+{
+ if (e.info(info_flags::relation_equal)) {
+ return subs(lst(e));
+ }
+ if (!e.info(info_flags::list)) {
+ throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
+ }
+ lst ls;
+ lst lr;
+ for (unsigned i=0; i<e.nops(); i++) {
+ if (!e.op(i).info(info_flags::relation_equal)) {
+ throw(std::invalid_argument("basic::subs(ex): argument must be a list or equations"));
+ }
+ if (!e.op(i).op(0).info(info_flags::symbol)) {
+ if (!e.op(i).op(0).info(info_flags::idx)) {
+ throw(std::invalid_argument("basic::subs(ex): lhs must be a symbol or an idx"));
+ }
+ }
+ ls.append(e.op(i).op(0));
+ lr.append(e.op(i).op(1));
+ }
+ return subs(ls,lr);
+}
+
+/** Compare objects to establish canonical order.
+ * All compare functions return: -1 for *this less than other, 0 equal,
+ * 1 greater. */
+int basic::compare(const basic & other) const
+{
+ unsigned hash_this = gethash();
+ unsigned hash_other = other.gethash();
+
+ if (hash_this<hash_other) return -1;
+ if (hash_this>hash_other) return 1;
+
+ unsigned typeid_this = tinfo();
+ unsigned typeid_other = other.tinfo();
+
+ if (typeid_this<typeid_other) {
+ /*
+ cout << "hash collision, different types: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ return -1;
+ }
+ if (typeid_this>typeid_other) {
+ /*
+ cout << "hash collision, different types: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ return 1;
+ }
+
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+
+ int cmpval=compare_same_type(other);
+ if ((cmpval!=0)&&(hash_this<0x80000000U)) {
+ /*
+ cout << "hash collision, same type: "
+ << *this << " and " << other << endl;
+ this->printraw(cout);
+ cout << " and ";
+ other.printraw(cout);
+ cout << endl;
+ */
+ }
+ return cmpval;
+}
+
+/** Test for equality. */
+bool basic::is_equal(const basic & other) const
+{
+ unsigned hash_this = gethash();
+ unsigned hash_other = other.gethash();
+
+ if (hash_this!=hash_other) return false;
+
+ unsigned typeid_this = tinfo();
+ unsigned typeid_other = other.tinfo();
+
+ if (typeid_this!=typeid_other) return false;
+
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+
+ return is_equal_same_type(other);