Skip to content

Commit

Permalink
Beautiful output for DivExpression(Rational * Expression)
Browse files Browse the repository at this point in the history
  • Loading branch information
fintarin committed Jul 11, 2023
1 parent 149009d commit 084325f
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace fintamath {

class IPolynomExpression : public IExpression {
public:
std::string toString() const final;
std::string toString() const override;

std::shared_ptr<IFunction> getFunction() const final;

Expand Down
28 changes: 28 additions & 0 deletions src/fintamath/expressions/polynomial/MulExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,41 @@
#include "fintamath/functions/powers/Pow.hpp"
#include "fintamath/literals/constants/IConstant.hpp"
#include "fintamath/numbers/Integer.hpp"
#include "fintamath/numbers/IntegerFunctions.hpp"
#include "fintamath/numbers/Rational.hpp"

namespace fintamath {

MulExpression::MulExpression(const ArgumentsPtrVector &inChildren) : IPolynomExpressionCRTP(Mul(), inChildren) {
}

std::string MulExpression::toString() const {
if (const auto firstChildRat = cast<Rational>(children.front())) {
ArgumentsPtrVector numeratorChildren = children;

if (const Integer firstChildNumeratorAbs = abs(firstChildRat->numerator()); firstChildNumeratorAbs != 1) {
numeratorChildren.front() = firstChildNumeratorAbs.clone();
}
else {
numeratorChildren.erase(numeratorChildren.begin());
}

ArgumentPtr numerator =
numeratorChildren.size() > 1 ? makeExpr(Mul(), numeratorChildren) : numeratorChildren.front();
ArgumentPtr denominator = firstChildRat->denominator().clone();
ArgumentPtr res = makeExpr(Div(), numerator, denominator);

std::string resStr = res->toString();
if (firstChildRat->numerator() < Integer(0)) {
resStr.insert(0, Neg().toString());
}

return resStr;
}

return IPolynomExpression::toString();
}

std::string MulExpression::operatorChildToString(const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const {
if (!prevChild && *inChild == Integer(-1)) {
return Neg().toString();
Expand Down
2 changes: 2 additions & 0 deletions src/fintamath/expressions/polynomial/MulExpression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class MulExpression : public IPolynomExpressionCRTP<MulExpression> {
public:
explicit MulExpression(const ArgumentsPtrVector &inChildren);

std::string toString() const override;

static MathObjectTypeId getTypeIdStatic() {
return MathObjectTypeId(MathObjectType::MulExpression);
}
Expand Down
28 changes: 13 additions & 15 deletions tests/src/expressions/ExpressionFunctionsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,27 +144,27 @@ TEST(ExpressionFunctionsTests, lgTest) {
}

TEST(ExpressionFunctionsTests, sinTest) {
EXPECT_EQ(sin(Expression("5*Pi")).toString(), "sin(5 Pi)"); // TODO trigonometry
EXPECT_EQ(sin(Expression("Pi/2")).toString(), "sin(1/2 Pi)"); // TODO trigonometry
EXPECT_EQ(sin(Expression("5*Pi")).toString(), "sin(5 Pi)"); // TODO trigonometry
EXPECT_EQ(sin(Expression("Pi/2")).toString(), "sin(Pi/2)"); // TODO trigonometry
EXPECT_EQ(sin(Expression("a+b")).toString(), "sin(a + b)");
}

TEST(ExpressionFunctionsTests, cosTest) {
EXPECT_EQ(cos(Expression("5*Pi")).toString(), "cos(5 Pi)"); // TODO trigonometry
EXPECT_EQ(cos(Expression("3*Pi/2")).toString(), "cos(3/2 Pi)"); // TODO trigonometry
EXPECT_EQ(cos(Expression("5*Pi")).toString(), "cos(5 Pi)"); // TODO trigonometry
EXPECT_EQ(cos(Expression("3*Pi/2")).toString(), "cos((3 Pi)/2)"); // TODO trigonometry
EXPECT_EQ(cos(Expression("8*a")).toString(), "cos(8 a)");
}

TEST(ExpressionFunctionsTests, tanTest) {
EXPECT_EQ(tan(Expression("0")).toString(), "0");
EXPECT_EQ(tan(Expression("3*Pi/4")).toString(), "tan(3/4 Pi)"); // TODO trigonometry
EXPECT_EQ(tan(Expression("3*Pi/4")).toString(), "tan((3 Pi)/4)"); // TODO trigonometry
EXPECT_EQ(tan(Expression("a^3")).toString(), "tan(a^3)");
}

TEST(ExpressionFunctionsTests, cotTest) {
EXPECT_EQ(cot(Expression("Pi/4")).toString(), "cot(1/4 Pi)"); // TODO trigonometry
EXPECT_EQ(cot(Expression("Pi/2")).toString(), "cot(1/2 Pi)"); // TODO trigonometry
EXPECT_EQ(cot(Expression("a/5")).toString(), "cot(1/5 a)");
EXPECT_EQ(cot(Expression("Pi/4")).toString(), "cot(Pi/4)"); // TODO trigonometry
EXPECT_EQ(cot(Expression("Pi/2")).toString(), "cot(Pi/2)"); // TODO trigonometry
EXPECT_EQ(cot(Expression("a/5")).toString(), "cot(a/5)");
}

TEST(ExpressionFunctionsTests, asinTest) {
Expand All @@ -188,7 +188,7 @@ TEST(ExpressionFunctionsTests, atanTest) {
TEST(ExpressionFunctionsTests, acotTest) {
EXPECT_EQ(acot(Expression("1")).toString(), "acot(1)"); // TODO trigonometry
EXPECT_EQ(acot(Expression("0")).toString(), "acot(0)"); // TODO trigonometry
EXPECT_EQ(acot(Expression("a/5")).toString(), "acot(1/5 a)");
EXPECT_EQ(acot(Expression("a/5")).toString(), "acot(a/5)");
}

TEST(ExpressionFunctionsTests, derivativeTest) {
Expand Down Expand Up @@ -231,13 +231,11 @@ TEST(ExpressionFunctionsTests, solveTest) {
EXPECT_EQ(solve(Expression("15 - 2x - x^2 = 0")).toString(), "x = -5 | x = 3");
EXPECT_EQ(solve(Expression("x^2 + 12x + 36 = 0")).toString(), "x = -6");
EXPECT_EQ(solve(Expression("x^2 + 12x = 0")).toString(), "x = -12 | x = 0");
EXPECT_EQ(solve(Expression("x^2 - 23x - 3 = 0")).toString(), "x = -1/2 sqrt(541) + 23/2 | x = 1/2 sqrt(541) + 23/2");
// TODO! x = -sqrt(1969)/24 - 23/24 | x = sqrt(1969)/24 - 23/24
EXPECT_EQ(solve(Expression("x^2 - 23x - 3 = 0")).toString(), "x = -sqrt(541)/2 + 23/2 | x = sqrt(541)/2 + 23/2");
EXPECT_EQ(solve(Expression("-12x^2 - 23x + 30 = 0")).toString(),
"x = -1/24 sqrt(1969) - 23/24 | x = 1/24 sqrt(1969) - 23/24");
"x = -sqrt(1969)/24 - 23/24 | x = sqrt(1969)/24 - 23/24");
EXPECT_EQ(solve(Expression("-33x^2 - x + 34 = 0")).toString(), "x = -34/33 | x = 1");
EXPECT_EQ(solve(Expression("2x^2 + 2sqrt(2)x + 1 = 0")).toString(),
"x = -1/sqrt(2)"); // TODO! x = -sqrt(2)/2
EXPECT_EQ(solve(Expression("2x^2 + 2sqrt(2)x + 1 = 0")).toString(), "x = -1/sqrt(2)");

// TODO: implement cubic equations
EXPECT_EQ(solve(Expression("x^3 - 3x^2 + 3x - 1 = 0")).toString(), "x^3 - 3 x^2 + 3 x - 1 = 0"); // TODO: x = 1
Expand All @@ -260,7 +258,7 @@ TEST(ExpressionFunctionsTests, solveTest) {
// TODO: implement quadric inequalities
EXPECT_EQ(solve(Expression("x^2 + 2 x - 1 < 0")).toString(), "x^2 + 2 x - 1 < 0");

EXPECT_EQ(solve(Expression("15x^2 + sin(25)x - 10% = Ey")).toString(), "x^2 + 1/15 sin(25) x - 1/15 E y - 1/150 = 0");
EXPECT_EQ(solve(Expression("15x^2 + sin(25)x - 10% = Ey")).toString(), "x^2 + (sin(25) x)/15 - (E y)/15 - 1/150 = 0");
EXPECT_EQ(solve(Expression("x + x_1 + x_2 + y + y_1 = 0")).toString(), "x + x_1 + x_2 + y + y_1 = 0");
EXPECT_EQ(solve(Expression("-x^a = 0")).toString(), "x^a = 0");
EXPECT_EQ(solve(Expression("sin(x) = 0")).toString(), "sin(x) = 0");
Expand Down
29 changes: 14 additions & 15 deletions tests/src/expressions/ExpressionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("2^(2/3) 1/7^(2/3) 3^(3/4)").toString(),
"(root(27, 4) root(4, 3))/root(49, 3)"); // TODO! root(27, 4) root(4/49, 3)

EXPECT_EQ(Expression("Deg").toString(), "1/180 Pi");
EXPECT_EQ(Expression("60Deg").toString(), "1/3 Pi");
EXPECT_EQ(Expression("Deg").toString(), "Pi/180");
EXPECT_EQ(Expression("60Deg").toString(), "Pi/3");
EXPECT_EQ(Expression("E").toString(), "E");
EXPECT_EQ(Expression("Pi").toString(), "Pi");
EXPECT_EQ(Expression("E^101-E^101").toString(), "0");
Expand Down Expand Up @@ -182,18 +182,17 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("sin1^2").toString(), "sin(1)^2");
EXPECT_EQ(Expression("sin(10^30)").toString(), "sin(1000000000000000000000000000000)");
EXPECT_EQ(Expression("sin(1)^2+cos(1)^2").toString(), "cos(1)^2 + sin(1)^2");
EXPECT_EQ(Expression("sin(Pi/3)").toString(), "sin(1/3 Pi)");
EXPECT_EQ(Expression("cos(Pi/3)").toString(), "cos(1/3 Pi)");
EXPECT_EQ(Expression("sin(Pi/3)").toString(), "sin(Pi/3)");
EXPECT_EQ(Expression("cos(Pi/3)").toString(), "cos(Pi/3)");
EXPECT_EQ(Expression("2!*E").toString(), "2 E");
EXPECT_EQ(Expression("E*2!").toString(), "2 E");
EXPECT_EQ(Expression("sqrt((1-cos(2*(Pi/3)))/2)").toString(), "sqrt(-1/2 cos(2/3 Pi) + 1/2)");
EXPECT_EQ(Expression("2*sqrt((1-cos(2*(Pi/3)))/2)*cos(Pi/3)").toString(),
"2 sqrt(-1/2 cos(2/3 Pi) + 1/2) cos(1/3 Pi)");
EXPECT_EQ(Expression("sqrt((1-cos(2*(Pi/3)))/2)").toString(), "sqrt(-cos((2 Pi)/3)/2 + 1/2)");
EXPECT_EQ(Expression("2*sqrt((1-cos(2*(Pi/3)))/2)*cos(Pi/3)").toString(), "2 sqrt(-cos((2 Pi)/3)/2 + 1/2) cos(Pi/3)");
EXPECT_EQ(Expression("-sin(2)").toString(), "-sin(2)");
EXPECT_EQ(Expression("sqrt(26)").toString(), "sqrt(26)");
EXPECT_EQ(Expression("sqrt(145/26)").toString(), "sqrt(145)/sqrt(26)");
EXPECT_EQ(Expression("sqrt(169/3)").toString(), "13/sqrt(3)");
EXPECT_EQ(Expression("sqrt(168/25)").toString(), "2/5 sqrt(42)");
EXPECT_EQ(Expression("sqrt(168/25)").toString(), "(2 sqrt(42))/5");
EXPECT_EQ(Expression("log(2, 256)").toString(), "8");
EXPECT_EQ(Expression("2^(3/2)").toString(), "2 sqrt(2)");
EXPECT_EQ(Expression("sqrt(sqrt5)").toString(), "root(5, 4)");
Expand All @@ -216,7 +215,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("(a b)^-1").toString(), "1/(a b)");
EXPECT_EQ(Expression("(a b)^-2").toString(), "1/(a^2 b^2)");

EXPECT_EQ(Expression("2%a").toString(), "1/50 a");
EXPECT_EQ(Expression("2%a").toString(), "a/50");
EXPECT_EQ(Expression("2!!!!a!!!").toString(), "2 a!!!");
EXPECT_EQ(Expression("sin a").toString(), "sin(a)");
EXPECT_EQ(Expression("s i n a").toString(), "a i n s");
Expand All @@ -232,7 +231,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("ln cos sin a").toString(), "ln(cos(sin(a)))");

EXPECT_EQ(Expression("2.a").toString(), "2 a");
EXPECT_EQ(Expression("a.2").toString(), "1/5 a");
EXPECT_EQ(Expression("a.2").toString(), "a/5");
EXPECT_EQ(Expression("a+a").toString(), "2 a");
EXPECT_EQ(Expression("a-a").toString(), "0");
EXPECT_EQ(Expression("-a").toString(), "-a");
Expand Down Expand Up @@ -325,7 +324,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("5/(a+b) + 5/(2a+b) + 5/(a+b)").toString(), "5/(2 a + b) + 10/(a + b)");
EXPECT_EQ(Expression("(x+y)/(a+b) + 5/(2a+b) + (x+2y)/(a+b)").toString(), "(2 x + 3 y)/(a + b) + 5/(2 a + b)");
EXPECT_EQ(Expression("(a/b)(c/d)").toString(), "(a c)/(b d)");
EXPECT_EQ(Expression("(ab/2)(ad/3)").toString(), "1/6 a^2 b d");
EXPECT_EQ(Expression("(ab/2)(ad/3)").toString(), "(a^2 b d)/6");
EXPECT_EQ(Expression("(-a)(-b)").toString(), "a b");
EXPECT_EQ(Expression("(a)(-b)").toString(), "-a b");
EXPECT_EQ(Expression("(-a)(b)").toString(), "-a b");
Expand All @@ -334,7 +333,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("(a b)/(a b)").toString(), "1");
EXPECT_EQ(Expression("(a b)/1").toString(), "a b");
EXPECT_EQ(Expression("(a b)/-1").toString(), "-a b");
EXPECT_EQ(Expression("(a b)/-2").toString(), "-1/2 a b");
EXPECT_EQ(Expression("(a b)/-2").toString(), "-(a b)/2");
EXPECT_EQ(Expression("(a b)/(-a - b)").toString(), "-b + b^2/(a + b)");
EXPECT_EQ(Expression("(x^5)/(x - y)").toString(), "x^4 + x^3 y + x^2 y^2 + x y^3 + y^4 + y^5/(x - y)");
EXPECT_EQ(Expression("(3 x + 5/9)/(2y - 9/x + 3/2 x + 1/2 + 2 y / x)").toString(),
Expand Down Expand Up @@ -389,7 +388,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("tan(4 a_1^3 b) + cot(sin(4 a_1 b^3)) + b^4 + asin(sin(a_1^4)) + cos(6 a_1^2 b^2)").toString(),
"b^4 + asin(sin(a_1^4)) + tan(4 a_1^3 b) + cos(6 a_1^2 b^2) + cot(sin(4 a_1 b^3))");
EXPECT_EQ(Expression("a!!!!!!!!!!").toString(), "a!!!!!!!!!!");
EXPECT_EQ(Expression("a% * a!!! * a! * a!!").toString(), "1/100 a a! a!! a!!!");
EXPECT_EQ(Expression("a% * a!!! * a! * a!!").toString(), "(a a! a!! a!!!)/100");
EXPECT_EQ(Expression("a! sin(a)").toString(), "a! sin(a)");
EXPECT_EQ(Expression("sin(a) a!").toString(), "a! sin(a)");
EXPECT_EQ(Expression("sin(a) a").toString(), "a sin(a)");
Expand Down Expand Up @@ -442,9 +441,9 @@ TEST(ExpressionTests, stringConstructorTest) {
// EXPECT_EQ(Expression("derivative(5, a^2)").toString(), "0");
// EXPECT_EQ(Expression("derivative(a, a^2)").toString(), "derivative(a, a^2)");

EXPECT_EQ(Expression("integral(a, a)").toString(), "1/2 a^2");
EXPECT_EQ(Expression("integral(a, a)").toString(), "a^2/2");
EXPECT_EQ(Expression("integral(a+a, a)").toString(), "integral(2 a, a)");
EXPECT_EQ(Expression("integral(a, a) + integral(b, b)").toString(), "1/2 a^2 + 1/2 b^2");
EXPECT_EQ(Expression("integral(a, a) + integral(b, b)").toString(), "a^2/2 + b^2/2");
// TODO: integral
// EXPECT_EQ(Expression("integral(5, a^2)").toString(), "???");
// EXPECT_EQ(Expression("integral(a, a^2)").toString(), "???");
Expand Down
2 changes: 1 addition & 1 deletion tests/src/functions/calculus/IntegralTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TEST(IntegralTests, getFunctionTypeTest) {
}

TEST(IntegralTests, callTest) {
EXPECT_EQ(f(Variable("a"), Variable("a"))->toString(), "1/2 a^2");
EXPECT_EQ(f(Variable("a"), Variable("a"))->toString(), "a^2/2");
EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "integral(a, b)");
EXPECT_EQ(f(Expression("a+a"), Variable("a"))->toString(), "integral(2 a, a)"); // TODO: integral
EXPECT_EQ(f(Integer(5), Variable("a"))->toString(), "5 a");
Expand Down
2 changes: 1 addition & 1 deletion tests/src/functions/other/PercentTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ TEST(PercentTests, callTest) {
EXPECT_EQ(f(Integer(-10))->toString(), "-1/10");
EXPECT_EQ(f(Rational(1, 10))->toString(), "1/1000");

EXPECT_EQ(f(Variable("a"))->toString(), "1/100 a");
EXPECT_EQ(f(Variable("a"))->toString(), "a/100");

EXPECT_THROW(f(), InvalidInputFunctionException);
EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException);
Expand Down
2 changes: 1 addition & 1 deletion tests/src/functions/powers/SqrtTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TEST(SqrtTests, callTest) {
EXPECT_EQ(f(Rational("1.44"))->toString(), "6/5");
EXPECT_EQ(f(Rational(1, 10))->toString(), "1/sqrt(10)");
EXPECT_EQ(f(Rational(25, 48))->toString(), "5/(4 sqrt(3))");
EXPECT_EQ(f(Rational(26, 49))->toString(), "1/7 sqrt(26)");
EXPECT_EQ(f(Rational(26, 49))->toString(), "sqrt(26)/7");
EXPECT_EQ(f(Rational(45, 67))->toString(), "(3 sqrt(5))/sqrt(67)"); // TODO! 3 sqrt(5/67)
EXPECT_EQ(f(Rational("68732648273642987365932706179432649827364.144"))->toString(),
"sqrt(8591581034205373420741588272429081228420518)/(5 sqrt(5))");
Expand Down

0 comments on commit 084325f

Please sign in to comment.