Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug fix #126

Merged
merged 6 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/fintamath/expressions/ExpressionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ std::string prefixUnaryOperatorToString(const IOperator &oper, const ArgumentPtr
std::string result = oper.toString();

if (const auto child = cast<IExpression>(rhs)) {
if (is<IOperator>(child->getFunction())) {
if (is<IOperator>(child->getOutputFunction())) {
return result + putInBrackets(rhs->toString());
}
}
Expand All @@ -96,7 +96,7 @@ std::string postfixUnaryOperatorToString(const IOperator &oper, const ArgumentPt
std::string result = rhs->toString();

if (const auto child = cast<IExpression>(rhs)) {
if (is<IOperator>(child->getFunction())) {
if (is<IOperator>(child->getOutputFunction())) {
return putInBrackets(result) + oper.toString();
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/fintamath/expressions/binary/CompExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ ArgumentPtr CompExpression::coeffSimplify(const IFunction &func, const ArgumentP
}
}

if (dividerNum) {
if (dividerNum && hasVariables(lhsExpr)) {
for (auto &child : dividendPolynom) {
child = makeExpr(Div(), child, dividerNum);
}
Expand All @@ -133,6 +133,7 @@ ArgumentPtr CompExpression::coeffSimplify(const IFunction &func, const ArgumentP
return makeExpr(func, newLhs, rhs);
}
}

return {};
}

Expand Down
9 changes: 9 additions & 0 deletions src/fintamath/expressions/binary/DivExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ DivExpression::DivExpression(const ArgumentPtr &inLhsChild, const ArgumentPtr &i
: IBinaryExpressionCRTP(Div(), inLhsChild, inRhsChild) {
}

std::string DivExpression::toString() const {
if (auto lhsChildExpr = cast<IExpression>(lhsChild); lhsChildExpr && is<Neg>(lhsChildExpr->getFunction())) {
ArgumentPtr innerDiv = makeExpr(Div(), lhsChildExpr->getChildren().front(), rhsChild);
return makeExpr(Neg(), innerDiv)->toString();
}

return IBinaryExpression::toString();
}

DivExpression::SimplifyFunctionsVector DivExpression::getFunctionsForPreSimplify() const {
static const DivExpression::SimplifyFunctionsVector simplifyFunctions = {
&DivExpression::zeroSimplify, //
Expand Down
2 changes: 2 additions & 0 deletions src/fintamath/expressions/binary/DivExpression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class DivExpression : public IBinaryExpressionCRTP<DivExpression> {
public:
explicit DivExpression(const ArgumentPtr &inLhsChild, const ArgumentPtr &inRhsChild);

std::string toString() const override;

static MathObjectTypeId getTypeIdStatic() {
return MathObjectTypeId(MathObjectType::DivExpression);
}
Expand Down
1 change: 1 addition & 0 deletions src/fintamath/expressions/binary/LogExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ LogExpression::SimplifyFunctionsVector LogExpression::getFunctionsForPreSimplify
static const LogExpression::SimplifyFunctionsVector simplifyFunctions = {
&LogExpression::numSimplify, //
&LogExpression::equalSimplify, //
&LogExpression::powSimplify, //
};
return simplifyFunctions;
}
Expand Down
10 changes: 5 additions & 5 deletions src/fintamath/expressions/binary/PowExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,17 +217,17 @@ ArgumentPtr PowExpression::numSimplify(const IFunction & /*func*/, const Argumen
ArgumentPtr res = makeExpr(Div(), std::make_shared<Integer>(1), lhs);
return res;
}

if (*rhsInt < 0) {
ArgumentPtr res = makeExpr(Div(), std::make_shared<Integer>(1), makeExpr(Pow(), lhs, makeExpr(Neg(), rhsInt)));
return res;
}
}

if (lhsInt && *lhsInt == 0) {
return lhs;
}

if (const auto rhsComp = cast<IComparable>(rhs); rhsComp && *rhsComp < Integer(0)) {
ArgumentPtr res = makeExpr(Div(), std::make_shared<Integer>(1), makeExpr(Pow(), lhs, makeExpr(Neg(), rhs)));
return res;
}

return {};
}

Expand Down
53 changes: 45 additions & 8 deletions src/fintamath/expressions/interfaces/IPolynomExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,29 +318,66 @@ int IPolynomExpression::comparatorPolynomAndNonPolynom(const std::shared_ptr<con
int IPolynomExpression::comparatorExpressionAndNonExpression(const std::shared_ptr<const IExpression> &lhs,
const ArgumentPtr &rhs) const {

if (auto oper = cast<IOperator>(lhs->getFunction());
oper && oper->getOperatorPriority() <= IOperator::Priority::PrefixUnary) {

if (int res = comparator(lhs->getChildren().front(), rhs); res != 0) {
return res;
}

return 1;
if (!is<Variable>(rhs)) {
return !isTermsOrderInversed() ? -1 : 1;
}

if (auto res = comparatorVariables(lhs, rhs, isTermsOrderInversed()); res != 0) {
return res;
}

if (auto lhsOper = cast<IOperator>(lhs->getFunction())) {
auto lhsOperPriority = lhsOper->getOperatorPriority();

switch (lhsOperPriority) {
case IOperator::Priority::PostfixUnary:
case IOperator::Priority::PrefixUnary: {
if (int res = comparator(lhs->getChildren().front(), rhs); res != 0) {
return res;
}

return 1;
}
case IOperator::Priority::Exponentiation:
case IOperator::Priority::Multiplication: {
static const ArgumentPtr one = Integer(1).clone();
ArgumentPtr rhsExpr = makeExpr(*lhsOper, rhs, one);
int comp = comparator(lhs, rhsExpr);
return isTermsOrderInversed() ? comp * -1 : comp;
}
default:
break;
}
}

return !isTermsOrderInversed() ? -1 : 1;
}

int IPolynomExpression::comparatorExpressions(const std::shared_ptr<const IExpression> &lhs,
const std::shared_ptr<const IExpression> &rhs) const {

auto lhsOper = cast<IOperator>(lhs->getFunction());
auto rhsOper = cast<IOperator>(rhs->getFunction());

ArgumentsPtrVector lhsChildren = lhs->getChildren();
ArgumentsPtrVector rhsChildren = rhs->getChildren();

if (lhsOper && lhsOper->getOperatorPriority() == IOperator::Priority::PrefixUnary &&
(!rhsOper || rhsOper->getOperatorPriority() != IOperator::Priority::PrefixUnary)) {

if (int res = comparator(lhsChildren.front(), rhs); res != 0) {
return res;
}
}

if (rhsOper && rhsOper->getOperatorPriority() == IOperator::Priority::PrefixUnary &&
(!lhsOper || lhsOper->getOperatorPriority() != IOperator::Priority::PrefixUnary)) {

if (int res = comparator(lhs, rhsChildren.front()); res != 0) {
return res;
}
}

ChildrenComparatorResult childrenComp = comparatorChildren(lhs->getChildren(), rhs->getChildren());

if (childrenComp.prefixVariables != 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/fintamath/expressions/polynomial/AddExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ ArgumentPtr AddExpression::simplifyMulLogarithms(const IFunction & /*func*/, con
mulExpr = lhsExpr;
logExpr = rhsExpr;
}
else if (is<Mul>(rhsExpr->getFunction()) && is<Log>(lhsExpr->getFunction())) {
else if (is<Log>(lhsExpr->getFunction()) && is<Mul>(rhsExpr->getFunction())) {
mulExpr = rhsExpr;
logExpr = lhsExpr;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/src/FintamathTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ TEST(FintamathTests, fintamathTests) {
EXPECT_EQ(expr.toString(), "x^3 y + 10 x");

expr = x + 10 * x / 10 + (sqrt(x) * 2);
EXPECT_EQ(expr.toString(), "2 sqrt(x) + 2 x");
EXPECT_EQ(expr.toString(), "2 x + 2 sqrt(x)");

expr = eqv(x * x + y * y * y, x * y);
EXPECT_EQ(expr.toString(), "x^2 - x y + y^3 = 0");
Expand Down
3 changes: 1 addition & 2 deletions tests/src/expressions/ExpressionFunctionsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,5 @@ TEST(ExpressionFunctionsTests, solveTest) {

EXPECT_EQ(solve(Expression("E >= Ey")).toString(), "E y - E <= 0");
EXPECT_EQ(solve(Expression("x >= x sqrt(x)")).toString(), "x^(3/2) - x <= 0");
EXPECT_EQ(solve(Expression("x >= x^(1/100)")).toString(), "root(x, 100) - x <= 0");
EXPECT_EQ(solve(Expression("E^Pi > Pi^E")).toString(), "E^Pi - Pi^E > 0");
EXPECT_EQ(solve(Expression("x >= x^(1/100)")).toString(), "x - root(x, 100) >= 0");
}
38 changes: 25 additions & 13 deletions tests/src/expressions/ExpressionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,16 +352,23 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("(x/y)^2").toString(), "(x^2)/(y^2)");
EXPECT_EQ(Expression("(x/y)^(1/2)").toString(), "sqrt(x)/sqrt(y)");
EXPECT_EQ(Expression("(x/y)^(1/3)").toString(), "root(x, 3)/root(y, 3)");
EXPECT_EQ(Expression("(x/y)^(-1/2)").toString(), "sqrt(y)/sqrt(x)");
EXPECT_EQ(Expression("(x/y)^(-1/3)").toString(), "root(y, 3)/root(x, 3)");
EXPECT_EQ(Expression("(x/y)^x").toString(), "(x^x)/(y^x)");
EXPECT_EQ(Expression("(x/y)^(1/x)").toString(), "root(x, x)/root(y, x)");

// TODO! fix
// EXPECT_EQ(Expression("x/(2 sqrt(x) - x)").toString(), "TODO");
// EXPECT_EQ(Expression("(x-1)/(sqrt(x) - x)").toString(), "TODO");
// EXPECT_EQ(Expression("(x-1)/(2 sqrt(x) - x)").toString(), "TODO");
// EXPECT_EQ(Expression("(x-1)/(sqrt(x)/2 - x)").toString(), "TODO");
// EXPECT_EQ(Expression("(x-1)/(2 root(x, 3) - x)").toString(), "TODO");
// EXPECT_EQ(Expression("(x-1)/(2 x^(4/3) - x)").toString(), "TODO");

EXPECT_EQ(Expression("sqrt(x) + x").toString(), "x + sqrt(x)");
EXPECT_EQ(Expression("sqrt(x) - x").toString(), "-x + sqrt(x)");
EXPECT_EQ(Expression("x/(sqrt(x) - x)").toString(), "-1 - (sqrt(x)/(x - sqrt(x)))");
EXPECT_EQ(Expression("x/(2 sqrt(x) - x)").toString(), "-1 + (-2 sqrt(x))/(x - 2 sqrt(x))");
EXPECT_EQ(Expression("(x-1)/(sqrt(x) - x)").toString(), "-1 - 1/sqrt(x)");
EXPECT_EQ(Expression("(x-1)/(2 sqrt(x) - x)").toString(), "-1 + (-2 sqrt(x) + 1)/(x - 2 sqrt(x))");
EXPECT_EQ(Expression("(x-1)/(sqrt(x)/2 - x)").toString(), "-1 + (sqrt(x) - 2)/(-2 x + sqrt(x))");
EXPECT_EQ(Expression("(x-1)/(root(x, 3) - x)").toString(), "-1 + (-root(x, 3) + 1)/(x - root(x, 3))");
EXPECT_EQ(Expression("(x-1)/(2 root(x, 3) - x)").toString(), "-1 + (-2 root(x, 3) + 1)/(x - 2 root(x, 3))");
EXPECT_EQ(Expression("(x-1)/(root(x, 3)/2 - x)").toString(), "-1 + (root(x, 3) - 2)/(-2 x + root(x, 3))");
EXPECT_EQ(Expression("(x-1)/(x^(4/3) - x)").toString(), "(x - 1)/(x^(4/3) - x)");
EXPECT_EQ(Expression("(x-1)/(2 x^(4/3) - x)").toString(), "(x - 1)/(2 x^(4/3) - x)");

// TODO! implement this
// EXPECT_EQ(Expression("sqrt(x^2)").toString(), "abs(x)");
Expand Down Expand Up @@ -445,6 +452,9 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("log(E,5)>ln(5)").toString(), "False");
EXPECT_EQ(Expression("log(E,5)<=ln(5)").toString(), "True");
EXPECT_EQ(Expression("log(E,5)>=ln(5)").toString(), "True");
EXPECT_EQ(Expression("log(Deg, Deg^Deg) = Deg").toString(), "True");
EXPECT_EQ(Expression("E^Pi > Pi^E").toString(), "-Pi^E + E^Pi > 0"); // TODO: True
EXPECT_EQ(Expression("Pi^E < E^Pi").toString(), "Pi^E - E^Pi < 0"); // TODO: True

EXPECT_EQ(Expression("derivative(a, a)").toString(), "1");
EXPECT_EQ(Expression("derivative(a+a, a)").toString(), "derivative(2 a, a)");
Expand Down Expand Up @@ -484,6 +494,7 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("((1=2) -> (1=2) & ~(1=1)) !<-> ((1=1) <-> ~((1=2) | (1=1)))").toString(), "True");
EXPECT_EQ(Expression("False|1=1").toString(), "True");
EXPECT_EQ(Expression("1=1|False").toString(), "True");
EXPECT_EQ(Expression("a>b|a").toString(), "a - b > 0 | a");

EXPECT_EQ(Expression("~(x = 1)").toString(), "x - 1 != 0");
EXPECT_EQ(Expression("~(x != 1)").toString(), "x - 1 = 0");
Expand Down Expand Up @@ -619,16 +630,17 @@ TEST(ExpressionTests, stringConstructorTest) {
EXPECT_EQ(Expression("ln((E)/(20000.1EE)) + ln(20000.1E)").toString(), "0");
EXPECT_EQ(Expression("ln((10 E)^2) - ln(10 E 10 E)").toString(), "0");
EXPECT_EQ(Expression("ln((10 E)^2) - 2 ln(10 E)").toString(), "0");
EXPECT_EQ(Expression("3 ln((10 E)^2) - 2 ln(10 E)").toString(), "ln(10000 E^4)");
EXPECT_EQ(Expression("ln((10 E)^(2ab)) - 2 a ln(10 E) b").toString(),
"ln(10^(2 a b) E^(2 a b) 10^(-2 a b) E^(-2 a b))"); // TODO! 0
EXPECT_EQ(Expression("ln((10 E)^(2 ln(2))) - 2 ln(2) ln(10 E)").toString(),
"ln(10^(2 ln(2)) E^(2 ln(2)) 10^(-2 ln(2)) E^(-2 ln(2)))"); // TODO! 0
EXPECT_EQ(Expression("3 ln((10 E)^2) - 2 ln(10 E)").toString(), "4 ln(10 E)");
EXPECT_EQ(Expression("ln((10 E)^(2ab)) - 2 a ln(10 E) b").toString(), "0");
EXPECT_EQ(Expression("ln((10 E)^(2 ln(2))) - 2 ln(2) ln(10 E)").toString(), "0");
EXPECT_EQ(Expression("log(2.3,(E)/(20000.1EE)) + log(2.3,20000.1E)").toString(), "0");
EXPECT_EQ(Expression("log(2, 3) + log(3, 4)").toString(), "log(3, 4) + log(2, 3)");
EXPECT_EQ(Expression("x log(2, 3) + log(2, 5)").toString(), "log(2, 5 3^x)");
EXPECT_EQ(Expression("x log(2, 3) + log(2, 5a)").toString(), "log(2, 5 a 3^x)");
EXPECT_EQ(Expression("log(2, 3) + 3log(3, 4)").toString(), "3 log(3, 4) + log(2, 3)");
EXPECT_EQ(Expression("3log(2x, 3) + log(3, 4)").toString(), "3 log(2 x, 3) + log(3, 4)");
EXPECT_EQ(Expression("3log(2x, 3) + 4log(3, 4)").toString(), "3 log(2 x, 3) + 4 log(3, 4)");
EXPECT_EQ(Expression("3log(2x, 3) + 5log(2x, 4)").toString(), "log(2 x, 27648)");

EXPECT_EQ(Expression("sin(asin(x))").toString(), "x");
EXPECT_EQ(Expression("cos(acos(x))").toString(), "x");
Expand Down