Expression Expression::operator-() const { // checkWellFormed(); if (kindIs("constant")) { return -value; } else if (kindIs("*/") && name == "*" && arg1->kindIs("constant")) { return (-arg1->value) * *arg2; } else if (kindIs("*/") && name == "/" && arg1->kindIs("constant")) { return (-arg1->value) / *arg2; } else if (kindIs("*/") && name == "*" && arg2->kindIs("constant")) { return *arg1 * (-arg2->value); } else if (kindIs("*/") && name == "/" && arg2->kindIs("constant")) { return *arg1 / (-arg2->value); //} else if (kindIs("+-") && name == "+") { // return (-*arg1) + (-*arg2); } else if (kindIs("unary") && name == "-") { return *arg1; } Expression out; out.name = "-"; out.kind = "unary"; out.type = type; out.arg1 = new Expression(*this); out.SetDepth(); // out.checkWellFormed(); return out; }
Expression Expression::method(const std::string n) const { Expression out; out.kind = "method"; out.name = "." + n + "("; out.arg1 = new Expression(*this); out.type = type; // default to methods not changing types out.SetDepth(); return out; }
Expression Expression::operator()(const Expression &e) const { Expression out; out.name = "("; out.kind = "method"; out.arg1 = new Expression(*this); out.arg2 = new Expression(e); out.SetDepth(); return out; }
Expression linearfunexprgd(const char *n, const char *type, const Expression &arg) { if (arg.kindIs("constant") && arg.value == 0) return Expression(0); // Nice optimization! :) Expression newarg(arg); Expression prefactor = newarg.ScalarFactor(); Expression out = funexpr(n, newarg); out.kind = "linear function"; out.name = std::string(n) + "(gd, "; out.unlazy = true; out.type = type; out.SetDepth(); return prefactor*out; }
Expression Expression::operator+(const Expression &e) const { if (kindIs("constant") && value == 0) { return e; } else if (e.kindIs("constant") && e.value == 0) { return *this; } else if (e.kindIs("constant") && kindIs("constant")) { return Expression(value+e.value); } Expression thispost(*this), epost(e); Expression thispre = thispost.ScalarFactor(), epre = epost.ScalarFactor(); if (thispost.kindIs("linear function") && epost.kindIs("linear function") && thispost.name == epost.name) { if (thispre == epre) { Expression out = linearfunexprgd("oops", thispost.type, *thispost.arg1 + *epost.arg1); out.name = thispost.name; return epre*out; } if (thispre == -epre && thispre != Expression(1)) { Expression out = linearfunexprgd("oops", thispost.type, *thispost.arg1 - *epost.arg1); out.name = thispost.name; return thispre*out; } Expression out = linearfunexprgd("oops", thispost.type, thispre * *thispost.arg1 + epre * *epost.arg1); out.name = thispost.name; return out; } Expression out; if (typeIs("ReciprocalGrid")) { assert(!e.typeIs("Grid")); out.type = "ReciprocalGrid"; } else if (typeIs("Grid")) { assert(!e.typeIs("ReciprocalGrid")); } else if (e.typeIs("double")) { out.type = "double"; } else if (e.typeIs("ReciprocalGrid")) { out.type = "ReciprocalGrid"; } out.name = "+"; out.kind = "+-"; out.arg1 = new Expression(*this); out.arg2 = new Expression(e); out.SetDepth(); return out; }
Expression Expression::operator/(const Expression &e) const { // First, let's make a few optimizations... if (kindIs("constant") && value == 0) { return *this; } else if (e.kindIs("constant") && e.value == 1) { return *this; } else if (e.kindIs("constant") && e.value == -1) { return - *this; } else if (e.kindIs("constant") && kindIs("constant")) { return Expression(value/e.value); } else if (e.kindIs("*/") && e.name == "/") { return *this * *e.arg2 / *e.arg1; // inverse of inverse } //Expression postfactor = e; //Expression prefactor = postfactor.ScalarFactor(); //if (postfactor.kindIs("*/") && postfactor.name == "/") { // return (*this / prefactor) * *postfactor.arg2 / *postfactor.arg1; //} Expression out; if (typeIs("ReciprocalGrid")) { assert(!e.typeIs("Grid")); out.type = "ReciprocalGrid"; } else if (typeIs("Grid")) { assert(!e.typeIs("ReciprocalGrid")); } else if (typeIs("ReciprocalGrid")) { out.type = "ReciprocalGrid"; } else if (e.typeIs("double") && typeIs("double")) { out.type = "double"; } else if (e.typeIs("ReciprocalGrid")) { out.type = "ReciprocalGrid"; } out.name = "/"; out.kind = "*/"; out.arg1 = new Expression(*this); out.arg2 = new Expression(e); out.SetDepth(); return out; }
Expression Expression::operator*(const Expression &e) const { // checkWellFormed(); // e.checkWellFormed(); if (kindIs("constant") && e.kindIs("constant")) { return Expression(value*e.value); } else if (e.kindIs("constant")) { // prefer to have scalar on left. return e*(*this); } // First, let's make a few optimizations... if (kindIs("constant") && value == 1) { return e; } else if (kindIs("constant") && value == -1) { return -e; } else if (kindIs("constant") && value == 0) { return *this; } else if (e.kindIs("unary") && e.name == "-") { return - (*this * *e.arg1); } Expression out; if (e.typeIs("ReciprocalGrid")) { assert(!typeIs("Grid")); out.type = "ReciprocalGrid"; } else if (typeIs("ReciprocalGrid")) { out.type = "ReciprocalGrid"; } else if (e.typeIs("Grid")) { assert(!e.typeIs("ReciprocalGrid")); } else if (e.typeIs("double") && typeIs("double")) { out.type = "double"; } out.name = "*"; out.kind = "*/"; out.arg1 = new Expression(*this); out.arg2 = new Expression(e); out.SetDepth(); return out; }
Expression Expression::method(const char *n, const Expression &a) const { Expression out = method(n); out.arg2 = new Expression(a); out.SetDepth(); return out; }
Expression funexpr(const char *n, const Expression &arg, const Expression &a2, const Expression &a3) { Expression out = funexpr(n, arg, a2); out.arg3 = new Expression(a3); out.SetDepth(); return out; }
Expression funexpr(const char *n, const Expression &arg) { Expression out = funexpr(n); out.arg1 = new Expression(arg); out.SetDepth(); return out; }
Expression Expression::method(const char *n, const Expression &a, const Expression &b) const { Expression out = method(n, a); out.arg3 = new Expression(b); out.SetDepth(); return out; }