|
@@ -115,11 +115,48 @@ namespace mnd
|
|
return { newa, newb };
|
|
return { newa, newb };
|
|
}
|
|
}
|
|
|
|
|
|
- NodePair operator() (const Division& mul)
|
|
|
|
|
|
+ NodePair operator() (const Division& div)
|
|
{
|
|
{
|
|
- // TODO implement
|
|
|
|
- throw "unimplemented";
|
|
|
|
- return { nullptr, nullptr };
|
|
|
|
|
|
+ auto [a, b] = std::visit(*this, *div.left);
|
|
|
|
+ auto [c, d] = std::visit(*this, *div.right);
|
|
|
|
+
|
|
|
|
+ return division(a, b, c, d);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ NodePair division(Node* a, Node* b, Node* c, Node* d)
|
|
|
|
+ {
|
|
|
|
+ Node* ac = arena.allocate(ir::Multiplication{ a, c });
|
|
|
|
+ Node* bd = arena.allocate(ir::Multiplication{ b, d });
|
|
|
|
+ Node* bc = arena.allocate(ir::Multiplication{ b, c });
|
|
|
|
+ Node* ad = arena.allocate(ir::Multiplication{ a, d });
|
|
|
|
+
|
|
|
|
+ Node* cc = arena.allocate(ir::Multiplication{ c, c });
|
|
|
|
+ Node* dd = arena.allocate(ir::Multiplication{ d, d });
|
|
|
|
+
|
|
|
|
+ Node* ac_bd = arena.allocate(ir::Addition{ ac, bd });
|
|
|
|
+ Node* bc_ad = arena.allocate(ir::Subtraction{ bc, ad });
|
|
|
|
+
|
|
|
|
+ Node* den = arena.allocate(ir::Addition{ cc, dd });
|
|
|
|
+ Node* factor = arena.allocate(ir::Division{ one, den });
|
|
|
|
+
|
|
|
|
+ Node* re = arena.allocate(ir::Multiplication{ factor, ac_bd });
|
|
|
|
+ Node* im = arena.allocate(ir::Multiplication{ factor, bc_ad });
|
|
|
|
+
|
|
|
|
+ return { re, im };
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ NodePair oneOver(Node* a, Node* b)
|
|
|
|
+ {
|
|
|
|
+ Node* cc = arena.allocate(ir::Multiplication{ a, a });
|
|
|
|
+ Node* dd = arena.allocate(ir::Multiplication{ b, b });
|
|
|
|
+
|
|
|
|
+ Node* den = arena.allocate(ir::Addition{ cc, dd });
|
|
|
|
+ Node* factor = arena.allocate(ir::Division{ one, den });
|
|
|
|
+
|
|
|
|
+ Node* re = arena.allocate(ir::Multiplication{ factor, a });
|
|
|
|
+ Node* im = arena.allocate(ir::Negation{ arena.allocate(ir::Multiplication{ factor, b }) });
|
|
|
|
+
|
|
|
|
+ return { re, im };
|
|
}
|
|
}
|
|
|
|
|
|
NodePair operator() (const Pow& p)
|
|
NodePair operator() (const Pow& p)
|
|
@@ -170,9 +207,8 @@ namespace mnd
|
|
auto [a, b] = val;
|
|
auto [a, b] = val;
|
|
|
|
|
|
if (exponent < 0) {
|
|
if (exponent < 0) {
|
|
- // TODO implement
|
|
|
|
- exponent = 0;
|
|
|
|
- //return arena.allocate(ir::Division{ one });
|
|
|
|
|
|
+ auto [inva, invb] = intPow(val, -exponent);
|
|
|
|
+ return oneOver(inva, invb);
|
|
}
|
|
}
|
|
|
|
|
|
if (exponent == 0)
|
|
if (exponent == 0)
|
|
@@ -232,67 +268,130 @@ namespace mnd
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-std::string mnd::ir::Formula::toString(void) const
|
|
|
|
|
|
+using namespace std::string_literals;
|
|
|
|
+struct ToStringVisitor
|
|
{
|
|
{
|
|
- struct ToStringVisitor
|
|
|
|
- {
|
|
|
|
- std::string operator()(const ir::Constant& c) {
|
|
|
|
- return mnd::toString(c.value);
|
|
|
|
- }
|
|
|
|
|
|
+ // return string and precedence
|
|
|
|
+ using Ret = std::pair<std::string, int>;
|
|
|
|
|
|
- std::string operator()(const ir::Variable& v) {
|
|
|
|
- return v.name;
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Constant& c) {
|
|
|
|
+ return { mnd::toString(c.value), 0 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Negation& n) {
|
|
|
|
- return "-(" + std::visit(*this, *n.value) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Variable& v) {
|
|
|
|
+ return { v.name, 0 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Addition& n) {
|
|
|
|
- return "(" + std::visit(*this, *n.left) + ") + (" + std::visit(*this, *n.right) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Negation& n) {
|
|
|
|
+ auto [str, prec] = std::visit(*this, *n.value);
|
|
|
|
+ if (prec > 0)
|
|
|
|
+ return { "-("s + str + ")", 2 };
|
|
|
|
+ else
|
|
|
|
+ return { "-"s + str, 2 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Subtraction& n) {
|
|
|
|
- return "(" + std::visit(*this, *n.left) + ") - (" + std::visit(*this, *n.right) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Addition& n) {
|
|
|
|
+ auto [strl, precl] = std::visit(*this, *n.left);
|
|
|
|
+ auto [strr, precr] = std::visit(*this, *n.right);
|
|
|
|
+ std::string ret;
|
|
|
|
+ if (precl > 4)
|
|
|
|
+ ret += strl + " + ";
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strl + ") + ";
|
|
|
|
+ if (precr > 4)
|
|
|
|
+ ret += strr;
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strr + ")";
|
|
|
|
+ return { ret, 4 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Multiplication& n) {
|
|
|
|
- return "(" + std::visit(*this, *n.left) + ") * (" + std::visit(*this, *n.right) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Subtraction& n) {
|
|
|
|
+ auto [strl, precl] = std::visit(*this, *n.left);
|
|
|
|
+ auto [strr, precr] = std::visit(*this, *n.right);
|
|
|
|
+ std::string ret;
|
|
|
|
+ if (precl > 4)
|
|
|
|
+ ret += strl + " - ";
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strl + ") - ";
|
|
|
|
+ if (precr >= 4)
|
|
|
|
+ ret += strr;
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strr + ")";
|
|
|
|
+ return { ret, 4 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Division& n) {
|
|
|
|
- return "(" + std::visit(*this, *n.left) + ") / (" + std::visit(*this, *n.right) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Multiplication& n) {
|
|
|
|
+ auto [strl, precl] = std::visit(*this, *n.left);
|
|
|
|
+ auto [strr, precr] = std::visit(*this, *n.right);
|
|
|
|
+ std::string ret;
|
|
|
|
+ if (precl > 3)
|
|
|
|
+ ret += strl + " * ";
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strl + ") * ";
|
|
|
|
+ if (precr > 3)
|
|
|
|
+ ret += strr;
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strr + ")";
|
|
|
|
+ return { ret, 3 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Atan2& n) {
|
|
|
|
- return "atan2(" + std::visit(*this, *n.left) + ", " + std::visit(*this, *n.right) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Division& n) {
|
|
|
|
+ auto [strl, precl] = std::visit(*this, *n.left);
|
|
|
|
+ auto [strr, precr] = std::visit(*this, *n.right);
|
|
|
|
+ std::string ret;
|
|
|
|
+ if (precl > 3)
|
|
|
|
+ ret += strl + " / ";
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strl + ") / ";
|
|
|
|
+ if (precr >= 3)
|
|
|
|
+ ret += strr;
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strr + ")";
|
|
|
|
+ return { ret, 3 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Pow& n) {
|
|
|
|
- return std::visit(*this, *n.left) + " ^ " + std::visit(*this, *n.right);
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Atan2& n) {
|
|
|
|
+ return { "atan2(" + std::visit(*this, *n.left).first + ", " + std::visit(*this, *n.right).first + ")", 1 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Cos& n) {
|
|
|
|
- return "cos(" + std::visit(*this, *n.value) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Pow& n) {
|
|
|
|
+ auto [strl, precl] = std::visit(*this, *n.left);
|
|
|
|
+ auto [strr, precr] = std::visit(*this, *n.right);
|
|
|
|
+ std::string ret;
|
|
|
|
+ if (precl >= 2)
|
|
|
|
+ ret += strl + " ^ ";
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strl + ") ^ ";
|
|
|
|
+ if (precr > 2)
|
|
|
|
+ ret += strr;
|
|
|
|
+ else
|
|
|
|
+ ret += "(" + strr + ")";
|
|
|
|
+ return { ret, 2 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Sin& n) {
|
|
|
|
- return "sin(" + std::visit(*this, *n.value) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Cos& n) {
|
|
|
|
+ return { "cos(" + std::visit(*this, *n.value).first + ")", 1 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Exp& n) {
|
|
|
|
- return "exp(" + std::visit(*this, *n.value) + ")";
|
|
|
|
- }
|
|
|
|
|
|
+ Ret operator()(const ir::Sin& n) {
|
|
|
|
+ return { "sin(" + std::visit(*this, *n.value).first + ")", 1 };
|
|
|
|
+ }
|
|
|
|
|
|
- std::string operator()(const ir::Ln& n) {
|
|
|
|
- return "ln(" + std::visit(*this, *n.value) + ")";
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ Ret operator()(const ir::Exp& n) {
|
|
|
|
+ return { "exp(" + std::visit(*this, *n.value).first + ")", 1 };
|
|
|
|
+ }
|
|
|
|
|
|
- return std::string("a = ") + std::visit(ToStringVisitor{}, *this->newA) +
|
|
|
|
- "\nb = " + std::visit(ToStringVisitor{}, *this->newB) +
|
|
|
|
- "\nx = " + std::visit(ToStringVisitor{}, *this->startA) +
|
|
|
|
- "\ny = " + std::visit(ToStringVisitor{}, *this->startB);
|
|
|
|
|
|
+ Ret operator()(const ir::Ln& n) {
|
|
|
|
+ return { "ln(" + std::visit(*this, *n.value).first + ")", 1 };
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+std::string mnd::ir::Formula::toString(void) const
|
|
|
|
+{
|
|
|
|
+ return std::string("a = ") + std::visit(ToStringVisitor{}, *this->newA).first +
|
|
|
|
+ "\nb = " + std::visit(ToStringVisitor{}, *this->newB).first +
|
|
|
|
+ "\nx = " + std::visit(ToStringVisitor{}, *this->startA).first +
|
|
|
|
+ "\ny = " + std::visit(ToStringVisitor{}, *this->startB).first;
|
|
}
|
|
}
|
|
|
|
|
|
struct ConstantPropagator
|
|
struct ConstantPropagator
|
|
@@ -398,23 +497,42 @@ struct ConstantPropagator
|
|
MaybeNode operator()(ir::Multiplication& n) {
|
|
MaybeNode operator()(ir::Multiplication& n) {
|
|
visitNode(n.left);
|
|
visitNode(n.left);
|
|
visitNode(n.right);
|
|
visitNode(n.right);
|
|
|
|
+ printf("simpifying mul: %s * %s\n", std::visit(ToStringVisitor{}, *n.left).first.c_str(), std::visit(ToStringVisitor{}, *n.right).first.c_str());
|
|
auto* ca = getIfConstant(n.left);
|
|
auto* ca = getIfConstant(n.left);
|
|
auto* cb = getIfConstant(n.right);
|
|
auto* cb = getIfConstant(n.right);
|
|
if (ca && cb) {
|
|
if (ca && cb) {
|
|
return ir::Constant{ ca->value * cb->value };
|
|
return ir::Constant{ ca->value * cb->value };
|
|
}
|
|
}
|
|
- else if (ca && ca->value == 0) {
|
|
|
|
|
|
+ if (ca && ca->value == 0) {
|
|
return ir::Constant{ 0 };
|
|
return ir::Constant{ 0 };
|
|
}
|
|
}
|
|
- else if (cb && cb->value == 0) {
|
|
|
|
|
|
+ if (cb && cb->value == 0) {
|
|
return ir::Constant{ 0 };
|
|
return ir::Constant{ 0 };
|
|
}
|
|
}
|
|
- else if (ca && ca->value == 1) {
|
|
|
|
|
|
+ if (ca && ca->value == 1) {
|
|
return *n.right;
|
|
return *n.right;
|
|
}
|
|
}
|
|
- else if (cb && cb->value == 1) {
|
|
|
|
|
|
+ if (cb && cb->value == 1) {
|
|
return *n.left;
|
|
return *n.left;
|
|
}
|
|
}
|
|
|
|
+ if (ca) {
|
|
|
|
+ auto* rightMul = std::get_if<ir::Multiplication>(n.right);
|
|
|
|
+ if (rightMul) {
|
|
|
|
+ auto* clr = getIfConstant(rightMul->left);
|
|
|
|
+ if (clr) {
|
|
|
|
+ printf("left %s, right %s\n", mnd::toString(ca->value).c_str(), mnd::toString(clr->value).c_str());
|
|
|
|
+ //ca->value *= clr->value;
|
|
|
|
+ n.right = rightMul->right;
|
|
|
|
+ auto mul = ir::Multiplication{ arena.allocate(ir::Constant{ ca->value * clr->value }), rightMul->right };//
|
|
|
|
+ auto maybeBetter = this->operator()(mul);
|
|
|
|
+ return maybeBetter.value_or(mul);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (cb) {
|
|
|
|
+ // move constants to the left
|
|
|
|
+ std::swap(n.left, n.right);
|
|
|
|
+ }
|
|
return std::nullopt;
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
|