/***************************************************************************
operands.cpp - description
-------------------
begin : Wed Jun 26 2002
copyright : (C) 2002 by Jan Rheinlaender
email : jrheinlaender@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
//#include "../config/config.h" // *** added in 1.3.1
#include <sstream>
#include "operands.h"
#include "printing.h"
#include "msgdriver.h" // *** added in 1.3.1
#include "equation.h" // *** added in 1.2
#include "ncsymbol.h" // *** added in 1.4.3
exrec::exrec (const expression &exp, const operands &op1, const operands &op2)
: e(exp), o1(op1), o2(op2), hits(0) {};
exrec::~exrec() {
MSG_INFO(0) << hits << " hits for " << e << endline;
} // ~exrec()
ex mul_ops(const ex &op1, const ex &op2) {
return (op1 * op2);
} //mul_ops()
ex add_ops(const ex &op1, const ex &op2) {
return (op1 + op2);
} //add_ops()
operands::operands(const int ops_type) throw(std::invalid_argument) {
// *** added matrices in 1.0, integrals in 1.3.1
if ((ops_type != GINAC_ADD) && (ops_type != GINAC_MUL))
throw std::invalid_argument("operands::operands(): Type must be ADD or MUL");
symbols = constants = units = functions = integrals = adds = muls = powers = matrices = others = coefficient = ops_type;
oper = ((ops_type == GINAC_ADD) ? &add_ops : &mul_ops);
type = ops_type;
} //operands()
operands::~operands() {}
void operands::split_ex(const expression &e, operands &o1, operands &o2) throw(std::runtime_error) {
// Split the ex into different types of operands (symbols, functions etc.)
// *** changed ex& to expression& in 0.9
// *** removed ex_to<> in argument of include() in 1.0
// *** added caching of split_ex() results in 1.0
MSG_INFO(3) << "Splitting expression " << e <<
", number of operands: " << e.nops() << endline;
unsigned hash = e.gethash();
if ((remember_split[hash] != NULL) && (remember_split[hash]->e.is_equal(e))) {
o1 = remember_split[hash]->o1;
o2 = remember_split[hash]->o2;
remember_split[hash]->hits++;
MSG_INFO(3) << "split_ex: Cache hit for " << e << endline;
return;
}
if (is_a<mul>(e))
for (const_iterator i = e.begin(); i != e.end(); i++) {
// *** changed to const_iterator in 0.7
if (is_negpower(*i))
o2.include(pow(*i, -1));
else if (is_a<numeric>(*i)) // *** changed in 1.2, separating numerator and denominator make no sense
o1.include(*i);
else
o1.include(*i);
}
else if (is_a<add>(e))
for (const_iterator i = e.begin(); i != e.end(); i++) {
// *** changed to const_iterator in 0.7
if (is_negex(*i))
o2.include(-*i);
else
o1.include(*i);
}
else if (is_negpower(e))
o2.include(pow(e, -1));
else if (is_a<power>(e))
o1.include(e);
else if (is_a<numeric>(e)) // *** changed in 1.2, separating numerator and denominator make no sense
o1.include(e);
else if (is_a<constant>(e)) // Pi etc.
o1.include(e); // *** added in 1.2
else if (is_a<function>(e))
o1.include(e); // *** added in 0.6
else if (is_a<func>(e))
o1.include(e); // *** added in 0.6
else if (is_a<integral>(e))
o1.include(e); // *** added in 1.3.1
else if (is_a<matrix>(e))
o1.include(e); // *** added in 1.0
else if (e.nops() == 0)
o1.include(e);
else // *** changed in 0.6 because throwing an exception makes no sense
msg::error(0) << "Internal error: Unexpected expression type in split_ex()" << endline;
if (msg::info().checkprio(4)) {
std::ostringstream os;
o1.print(os);
o2.print(os);
msg::info() << os.str();
}
// *** added in 1.0
remember_split[hash] = new exrec(e, o1, o2);
MSG_INFO(3) << "split_ex: Cached result for " << e << endline;
} // split_ex()
void operands::include(const ex &what) {
// Find the type of what and include it in the receiver
if (is_a<symbol>(what) || is_a<ncsymbol>(what)) symbols = oper(symbols, what);
else if (is_a<constant>(what)) constants = oper(constants, what); // *** added in 1.2
else if (is_a<Unit>(what)) units = oper(units, what);
else if (is_a<func>(what)) functions = oper(functions, what); // *** added in 0.5
else if (is_a<function>(what)) functions = oper(functions, what);
else if (is_a<integral>(what)) integrals = oper(integrals, what); // *** added in 1.3.1
else if (is_a<add>(what)) adds = oper(adds, what);
else if (is_a<mul>(what)) muls = oper(muls, what);
else if (is_a<matrix>(what)) matrices = oper(matrices, what); // *** added in 1.0
else if (is_a<power>(what)) {
power pow = ex_to<power>(what);
ex base = get_basis(pow); // *** changed to get_.. in 1.2
ex exponent = get_exp(pow);
if (is_a<numeric>(exponent) && (is_a<Unit>(base))) {
units = oper(units, what);
} else if (is_a<numeric>(exponent) && (is_a<symbol>(base) || is_a<ncsymbol>(base))) { // *** added in 1.2
symbols = oper(symbols, what);
} else if (is_a<numeric>(exponent) && (is_a<constant>(base))) { // *** added in 1.2
constants = oper(constants, what);
} else {
powers = oper(powers, what);
}
} else if (is_a<numeric>(what)) {
if (what == I)
others = oper(others, I);
else if (what == -I) {
coefficient = ex_to<numeric>(oper(coefficient, -1));
others = oper(others, I);
} else
coefficient = ex_to<numeric>(oper(coefficient, what));
} else others = oper(others, what);
MSG_INFO(6) << "Included expression " << what << endline;
} //operands::include()
void operands::exclude(const ex &what) { // *** added in 1.2
// Find the type of what and include it in the receiver
if (is_a<symbol>(what) || is_a<ncsymbol>(what)) symbols = oper(symbols, 1 / what);
else if (is_a<constant>(what)) constants = oper(constants, 1 / what);
else if (is_a<Unit>(what)) units = oper(units, 1 / what);
else if (is_a<func>(what)) functions = oper(functions, 1 / what); // *** added in 0.5
else if (is_a<function>(what)) functions = oper(functions, 1 / what);
else if (is_a<integral>(what)) integrals = oper(integrals, 1 / what); // *** added in 1.3.1
else if (is_a<add>(what)) adds = oper(adds, 1 / what);
else if (is_a<mul>(what)) muls = oper(muls, 1 / what);
else if (is_a<matrix>(what)) matrices = oper(matrices, 1 / what); // *** added in 1.0
else if (is_a<power>(what)) {
power pow = ex_to<power>(what);
ex base = get_basis(pow); // *** changed to get_.. in 1.2
ex exponent = get_exp(pow);
if (is_a<numeric>(exponent) && (is_a<Unit>(base))) {
units = oper(units, 1 / what);
} else if (is_a<numeric>(exponent) && (is_a<symbol>(base) || is_a<ncsymbol>(base))) {
symbols = oper(symbols, 1 / what);
} else if (is_a<numeric>(exponent) && (is_a<constant>(base))) {
constants = oper(constants, 1 / what);
} else {
powers = oper(powers, 1 / what);
}
} else if (is_a<numeric>(what))
coefficient = ex_to<numeric>(oper(coefficient, 1 / what));
else others = oper(others, 1 / what);
} //operands::exclude()
void operands::exclude_all(const ex &what) {
if ((is_a<mul>(what) && (type == GINAC_MUL)) || (is_a<add>(what) && (type == GINAC_ADD))) {
for (const_iterator i = what.begin(); i != what.end(); i++) {
exclude(*i);
}
} else {
exclude(what);
}
} // operands::exclude_all()
bool checkmatrix(const matrix &m) { // *** added in 1.0
for (unsigned i = 0; i < m.nops(); i++) {
if (is_a<matrix>(m.op(i))) {
if (!checkmatrix(ex_to<matrix>(m.op(i))))
return false;
} else {
if (!m.op(i).info(info_flags::numeric))
return false;
}
}
return true;
} // checkmatrix()
// TODO: Store the result of these queries for the next time!
const bool operands::is_quantity() const {
// *** added integrals in 1.3.1
return ((check_symbols(type)) && (constants == type) && (functions == type) && (integrals == type) && (adds == type) &&
(muls == type) && (powers == type) && (others == type) && check_matrices(type));
} // operands::is_quantity()
const bool operands::is_number() const {
return (this->is_quantity() && (units == type));
} // operands::is_number()
const bool operands::is_trivial() const {
return (this->is_number() && (abs(coefficient) == type));
} // operands::is_trivial()
const bool operands::is_symbol() const { // *** added in 1.2, added integrals in 1.3.1
return ((coefficient == type) && (!check_symbols(type)) && (constants == type) && (functions == type) && (adds == type) &&
(muls == type) && (powers == type) && (check_matrices(type)) && (others == type) && (integrals == type));
} // operands::is_symbol()
const bool operands::is_add() const {
return (type == GINAC_ADD);
} // operands::is_add()
const bool operands::is_mul() const {
return (type == GINAC_MUL);
} // operands::is_mul()
void checksplit(const bool toplevel, const int opnum, std::ostream &os) {
if (toplevel) {
if (opnum == optstack::options->get(o_eqsplit).integer) {
MSG_INFO(1) << "Splitting equation at operand " << opnum << endline;
MSG_INFO(2) << "Interjected text: " << *optstack::options->get(o_eqsplittext).str << endline;
if (optstack::options->get(o_eqalign).align == onlyleft) {
os << "\\\\" << std::endl;
if (*optstack::options->get(o_eqsplittext).str == "") {
os << "&\\quad\\,\\,";
} else {
os << *optstack::options->get(o_eqsplittext).str;
}
} else if (optstack::options->get(o_eqalign).align == both) {
os << "\\nonumber\\\\" << std::endl;
if (*optstack::options->get(o_eqsplittext).str == "") {
os << "&&";
} else {
os << *optstack::options->get(o_eqsplittext).str;
}
} else {
os << "\\\\" << std::endl << *optstack::options->get(o_eqsplittext).str;
}
}
}
} // operands::checksplit()
const bool operands::check_matrices(const unsigned type) const {
if (matrices.info(info_flags::numeric)) {
return (matrices == type);
} else {
return (false);
}
}
const bool operands::check_symbols(const unsigned type) const {
if (symbols.info(info_flags::numeric)) {
return (symbols == type);
} else {
return (false);
}
}
void print_ltx_ops (const ex &e, const std::string &sym, std::ostream &os, const bool toplevel, int &opnum) {
// *** replaced first with opnum in 1.2
if (opnum > 0) {
os << sym;
checksplit(toplevel, opnum, os); // *** added in 1.2
}
if (is_a<symbol>(e))
print_ltx(ex_to<symbol>(e), os);
else if (is_a<ncsymbol>(e))
print_ltx(ex_to<ncsymbol>(e), os);
else if (is_a<power>(e))
print_ltx(ex_to<power>(e), os);
else if (is_a<Unit>(e))
print_ltx(ex_to<Unit>(e), os);
else if (is_a<func>(e))
print_ltx(ex_to<func>(e), os); // *** added in 0.5
else if (is_a<function>(e))
print_ltx(ex_to<function>(e), os);
else if (is_a<integral>(e))
print_ltx(ex_to<integral>(e), os); // *** added in 1.3.1
else if (is_a<matrix>(e)) {
print_ltx(ex_to<matrix>(e), os); // *** added in 1.0
} else if (is_a<add>(e)) {
for (const_iterator i = e.begin(); i != e.end(); i++) {
// *** changed to const_iterator in 0.7
if (i != e.begin()) checksplit(toplevel, opnum, os);
if (is_a<Unit>(*i)) {
os << "\\unit{1}{"; // *** added in 1.2, toplevel has a new meaning now
print_ltx(ex_to<Unit>(*i), os);
os << "}";
} else
print_ltx(*i, os);
if ((i != e.end()-1) && !is_negex(*(i+1)))
os << sym;
opnum++;
}
return; // Don't increment opnum again!
} else if (is_a<mul>(e)) {
for (const_iterator i = e.end(); i != e.begin();) { // *** changed to const_iterator in 0.7
if (i != e.end()) checksplit(toplevel, opnum, os);
i--;
if (is_a<add>(*i)) {
os << "\\left(";
print_ltx(ex_to<add>(*i), os, false, 0);
os << "\\right)";
} else {
print_ltx(*i, os);
}
if (i != e.begin()) os << sym;
opnum++;
//std::cout << "Incremented opnum after printing " << *i << ", value: " << opnum << std::endl;
}
return;
} else
os << latex << e << dflt; // *** changed print to << in 0.8
opnum++;
} // print_ltx_ops()
void operands::print_ltx_mul(std::ostream &os, const bool toplevel, const int ops) const throw(std::invalid_argument) {
if (!type == GINAC_MUL)
throw std::invalid_argument("Receiver must be of type GINAC_MUL");
if (msg::info().checkprio(5)) {
msg::info() << "Printing Latex mul ";
std::ostringstream os;
this->print(os);
msg::info() << os.str();
}
// Print the coefficient
//bool first = true; // *** changed in 1.2
int opnum = ops;
if (!is_equal_one(coefficient) || is_trivial()) { // *** changed to is_equal_one() in 1.0
//std::cout << "Printing coefficient " << coefficient << std::endl;
if (coefficient.is_real())
print_ltx(coefficient, os);
else {
os << "\\left(";
print_ltx(coefficient, os);
os << "\\right)";
}
opnum++;
}
const std::string separator = "\\,"; // *** added in 1.0
// Print powers of numerics *** added in 1.2
ex restpowers = 1;
if (is_a<mul>(powers)) {
for (const_iterator i = powers.begin(); i != powers.end(); i++) {
if (is_a<numeric>(get_basis(ex_to<power>(*i))) && is_a<numeric>(get_exp(ex_to<power>(*i)))) {
print_ltx_ops(*i, separator, os, toplevel, opnum);
} else {
restpowers = restpowers * *i;
}
}
} else if (powers != 1) {
if (is_a<numeric>(get_basis(ex_to<power>(powers))) && is_a<numeric>(get_exp(ex_to<power>(powers)))) {
print_ltx_ops(powers, separator, os, toplevel, opnum);
} else {
restpowers = powers;
}
}
// Functions must be printed last to avoid ambiguities like tan xa -> tan (x*a) or tan (x) * a ?
// TODO: Print constants right after that!
if (units != 1) // *** moved here in 1.2
print_ltx_ops(units, separator, os, toplevel, opnum);
if (constants != 1)
print_ltx_ops(constants, separator, os, toplevel, opnum);
if (!check_symbols(1))
print_ltx_ops(symbols, separator, os, toplevel, opnum);
if (restpowers != 1)
print_ltx_ops(restpowers, separator, os, toplevel, opnum);
if (adds != 1) { // *** changed in 0.6 to avoid unnecessary brackets
if (opnum > 0) os << separator;
if (is_a<mul>(adds)) { // There are several adds in this mul
opnum++; // suppress op_symbol here!
print_ltx_ops(adds, separator, os, toplevel, opnum);
opnum--; // correct operator count
} else {
if ((opnum == 0) && (others == 1) && (functions == 1) &&
(muls == 1) && (integrals == 1) && check_matrices(1)) {
// *** added in 0.6, added muls in 0.9, added matrices in 1.0, integrals in 1.3.1
// *** removed units in 1.2
// In other words, if there is only this one add in the mul
print_ltx(ex_to<add>(adds), os, toplevel, opnum);
} else {
os << "\\left(";
print_ltx(ex_to<add>(adds), os, false, 0);
os << "\\right) ";
}
checksplit(toplevel, opnum, os);
}
}
// Warning: The preceding code depends on these statements following AFTER it!
if (muls != 1) { // *** added in 0.9
print_ltx(ex_to<mul>(muls), os, toplevel, opnum);
opnum += muls.nops();
}
if (!check_matrices(1)) {// *** added in 1.0
// Matrices cannot be compared to a numeric! Because of non-commutativity.
print_ltx_ops(matrices, separator, os, toplevel, opnum);
}
if (others != 1)
print_ltx_ops(others, separator, os, toplevel, opnum);
if (functions != 1)
print_ltx_ops(functions, separator, os, toplevel, opnum);
if (integrals != 1) // *** added in 1.3.1
print_ltx_ops(integrals, separator, os, toplevel, opnum);
os << ' ';
} // operands::print_ltx_mul()
void operands::print_ltx_add(const operands &neg, std::ostream &os, const bool toplevel, const int ops) const throw(std::invalid_argument) {
// *** added opnum in 1.2, replaces first
if (!type == GINAC_ADD)
throw std::invalid_argument("Receiver must be of type GINAC_ADD");
// *** added integrals in 1.3.1
bool coefficient_later = false, units_later = false, symbols_later = false, constants_later = false, muls_later = false,
powers_later = false, adds_later = false, matrices_later = false, others_later = false, functions_later = false, integrals_later = false;
int opnum = ops; // *** added in 1.2
checksplit(toplevel, opnum, os); // *** added in 1.2
if (!coefficient.is_zero()) {
print_ltx(coefficient, os);
opnum++;
}
if (!neg.get_coefficient().is_zero()) {
if (opnum == 0) { // *** added code to always print something with a posivite sign first in 1.2
coefficient_later = true;
} else {
os << "-";
checksplit(toplevel, opnum, os);
print_ltx(neg.get_coefficient(), os);
opnum++;
}
}
std::string addsym = "+"; // *** added in 1.0
std::string subsym = "-";
if (units != 0) { // *** moved here in 1.2
os << "\\unit{1}{"; // *** changed in 1.2, toplevel has a new meaning now
print_ltx_ops(units, addsym, os, toplevel, opnum); // *** changed first to opnum in 1.2
os << "}";
}
if (neg.get_units() != 0) { // *** moved here in 1.2
if (opnum == 0) { // *** changed first to opnum == 0
units_later = true;
} else {
os << "\\unit{1}{"; // *** added in 1.2 instead of first = false
print_ltx_ops(neg.get_units(), subsym, os, toplevel, opnum);
os << "}";
}
}
if (constants != 0)
print_ltx_ops(constants, addsym, os, toplevel, opnum);
if (neg.get_constants() != 0) {
if (opnum == 0) {
constants_later = true;
} else {
print_ltx_ops(neg.get_constants(), subsym, os, toplevel, opnum);
}
}
if (!check_symbols(0))
print_ltx_ops(symbols, addsym, os, toplevel, opnum);
if (!neg.check_symbols(0)) {
if (opnum == 0) {
symbols_later = true;
} else {
print_ltx_ops(neg.get_symbols(), subsym, os, toplevel, opnum);
}
}
if (powers != 0)
print_ltx_ops(powers, addsym, os, toplevel, opnum);
if (neg.get_powers() != 0) {
if (opnum == 0) {
powers_later = true;
} else {
print_ltx_ops(neg.get_powers(), subsym, os, toplevel, opnum);
}
}
if (muls != 0) {
if (is_a<add>(muls)) { // There are several muls in this add
print_ltx_ops(muls, addsym, os, toplevel, opnum);
} else { // There is only one mul
if (opnum > 0) {
os << addsym;
checksplit(toplevel, opnum, os);
}
print_ltx(ex_to<mul>(muls), os, false, 0);
opnum++;
}
}
if (neg.get_muls() != 0) {
if (opnum == 0) {
muls_later = true;
} else {
if (is_a<add>(neg.get_muls())) {
print_ltx_ops(neg.get_muls(), subsym, os, toplevel, opnum);
} else {
checksplit(toplevel, opnum, os);
print_ltx(ex_to<mul>(-neg.get_muls()), os, false, 0);
opnum++;
}
}
}
if (adds != 0) { // *** added in 0.9
print_ltx(ex_to<add>(adds), os, toplevel, opnum);
opnum += adds.nops();
}
if (neg.get_adds() != 0) { // *** added in 0.9
if (opnum == 0) {
adds_later = true;
} else {
print_ltx(ex_to<add>(neg.get_adds()), os, toplevel, opnum);
opnum += adds.nops();
}
}
if (!check_matrices(0)) // *** added in 1.0
print_ltx_ops(matrices, addsym, os, toplevel, opnum);
ex negmatrices = neg.get_matrices();
if (is_a<matrix>(negmatrices) || is_a<add>(negmatrices)) { // *** added in 1.0
if (opnum == 0) {
matrices_later = true;
} else {
print_ltx_ops(neg.get_matrices(), subsym, os, toplevel, opnum);
}
}
if (others != 0)
print_ltx_ops(others, addsym, os, toplevel, opnum);
if (neg.get_others()!= 0) {
if (opnum == 0) {
others_later = true;
} else {
print_ltx_ops(neg.get_others(), subsym, os, toplevel, opnum);
}
}
if (functions != 0)
print_ltx_ops(functions, addsym, os, toplevel, opnum);
if (neg.get_functions() != 0) {
if (opnum == 0) {
functions_later = true;
} else {
print_ltx_ops(neg.get_functions(), subsym, os, toplevel, opnum);
}
}
if (integrals != 0) // *** added in 1.3.1
print_ltx_ops(integrals, addsym, os, toplevel, opnum);
if (neg.get_integrals() != 0) {
if (opnum == 0) {
integrals_later = true;
} else {
print_ltx_ops(neg.get_integrals(), subsym, os, toplevel, opnum);
}
}
if (coefficient_later) {
if (opnum != 0) checksplit(toplevel, opnum, os);
os << subsym;
print_ltx(neg.get_coefficient(), os);
opnum++;
} else if (opnum == 0) {
os << subsym;
}
if (units_later) { // TODO: Does this ever occur? *** removed unit{1}{... in 1.2
//os << "\\unit{1}{"; // *** changed in 1.2, toplevel has a new meaning now
print_ltx_ops(neg.get_units(), subsym, os, toplevel, opnum);
//os << "}";
}
if (constants_later)
print_ltx_ops(neg.get_constants(), subsym, os, toplevel, opnum);
if (symbols_later)
print_ltx_ops(neg.get_symbols(), subsym, os, toplevel, opnum);
if (muls_later) {
if (is_a<add>(neg.get_muls())) {
print_ltx_ops(neg.get_muls(), subsym, os, toplevel, opnum);
} else {
if (opnum != 0) {
checksplit(toplevel, opnum, os);
os << subsym;
}
print_ltx(ex_to<mul>(neg.get_muls()), os);
opnum++;
}
}
if (powers_later)
print_ltx_ops(neg.get_powers(), subsym, os, toplevel, opnum);
if (adds_later) { // *** changed neg to -neg in 1.2
print_ltx(ex_to<add>(-neg.get_adds()), os, toplevel, opnum);
opnum += adds.nops();
}
if (matrices_later)
print_ltx_ops(neg.get_matrices(), subsym, os, toplevel, opnum);
if (others_later)
print_ltx_ops(neg.get_others(), subsym, os, toplevel, opnum);
if (functions_later)
print_ltx_ops(neg.get_functions(), subsym, os, toplevel, opnum);
if (integrals_later) // *** added in 1.3.1
print_ltx_ops(neg.get_integrals(), subsym, os, toplevel, opnum);
os << " ";
} // print_ltx_add()
void operands::print(std::ostream &os) const {
os << "Symbols: " << symbols << std::endl;
os << "Constants: " << constants << std::endl;
os << "Units: " << units << std::endl;
os << "Functions: " << functions << std::endl;
os << "Adds: " << adds << std::endl;
os << "Muls: " << muls << std::endl;
os << "Powers: " << powers << std::endl;
os << "Numerics: " << ex(coefficient) << std::endl;
os << "Matrices: " << matrices << std::endl; // *** added in 1.3.0
os << "Integrals: " << integrals << std::endl; // *** added in 1.3.1
os << "Others: " << others << std::endl;
os << "Quantity: " << (is_quantity() ? "true" : "false") << std::endl;
os << "Number: " << (is_number() ? "true" : "false") << std::endl;
os << "Trivial: " << (is_trivial() ? "true" : "false") << std::endl;
} //operands::print()
/*void operands::print(message &ms) const {
ms << "Symbols: " << symbols << endline;
ms << "Constants: " << constants << endline;
ms << "Units: " << units << endline;
ms << "Functions: " << functions << endline;
ms << "Adds: " << adds << endline;
ms << "Muls: " << muls << endline;
ms << "Powers: " << powers << endline;
ms << "Numerics: " << ex(coefficient) << endline;
ms << "Matrices: " << matrices << endline; // *** added in 1.3.0
ms << "Integrals: " << integrals << endline; // *** added in 1.3.1
ms << "Others: " << others << endline;
ms << "Quantity: " << (is_quantity() ? "true" : "false") << endline;
ms << "Number: " << (is_number() ? "true" : "false") << endline;
ms << "Trivial: " << (is_trivial() ? "true" : "false") << endline;
} //operands::print()
*/