From ae0f959be64a29a30657ae698775cc40ab4cff0b Mon Sep 17 00:00:00 2001 From: fintarin Date: Fri, 5 Apr 2024 16:09:09 +0400 Subject: [PATCH] Add new functions and rework operators --- include/fintamath/expressions/Expression.hpp | 9 +- .../fintamath/expressions/ExpressionUtils.hpp | 4 +- .../interfaces/IPolynomExpression.hpp | 5 +- include/fintamath/functions/FunctionUtils.hpp | 2 - include/fintamath/functions/IFunction.hpp | 2 - include/fintamath/functions/IFunctionCRTP.hpp | 25 +- .../fintamath/functions/arithmetic/Add.hpp | 12 +- .../functions/arithmetic/AddOper.hpp | 33 +++ .../fintamath/functions/arithmetic/Mul.hpp | 12 +- .../functions/arithmetic/MulOper.hpp | 33 +++ include/fintamath/functions/logic/And.hpp | 11 +- include/fintamath/functions/logic/AndOper.hpp | 33 +++ include/fintamath/functions/logic/Or.hpp | 12 +- include/fintamath/functions/logic/OrOper.hpp | 35 +++ include/fintamath/functions/powers/Pow.hpp | 8 +- .../powers/{PowFunction.hpp => PowOper.hpp} | 15 +- src/fintamath/config/ExpressionConfig.cpp | 34 ++- src/fintamath/config/TypeConfig.cpp | 65 +++--- src/fintamath/expressions/Expression.cpp | 10 +- .../expressions/ExpressionComparator.cpp | 213 +++++++----------- src/fintamath/expressions/ExpressionUtils.cpp | 59 +++-- .../expressions/FunctionExpression.cpp | 21 +- .../expressions/FunctionExpression.hpp | 3 + src/fintamath/expressions/IExpression.cpp | 7 +- src/fintamath/expressions/binary/CompExpr.cpp | 6 +- .../expressions/binary/DerivativeExpr.cpp | 4 +- src/fintamath/expressions/binary/DivExpr.cpp | 24 +- src/fintamath/expressions/binary/PowExpr.cpp | 43 ++-- src/fintamath/expressions/binary/PowExpr.hpp | 4 +- .../interfaces/IBinaryExpression.cpp | 9 +- .../interfaces/IPolynomExpression.cpp | 48 ++-- .../interfaces/IUnaryExpression.cpp | 15 +- .../expressions/polynomial/AddExpr.cpp | 8 +- .../expressions/polynomial/AddExpr.hpp | 11 +- .../expressions/polynomial/AndExpr.cpp | 14 +- .../expressions/polynomial/AndExpr.hpp | 2 + .../expressions/polynomial/MulExpr.cpp | 16 +- .../expressions/polynomial/MulExpr.hpp | 3 + .../expressions/polynomial/OrExpr.cpp | 68 ++---- .../expressions/polynomial/OrExpr.hpp | 6 +- .../expressions/unary/InvTrigExpr.cpp | 13 +- .../expressions/unary/InvTrigExpr.hpp | 2 +- src/fintamath/expressions/unary/TrigExpr.cpp | 16 +- src/fintamath/expressions/unary/TrigExpr.hpp | 6 +- src/fintamath/functions/IFunction.cpp | 14 -- src/fintamath/functions/arithmetic/Add.cpp | 9 +- .../functions/arithmetic/AddOper.cpp | 15 ++ src/fintamath/functions/arithmetic/Mul.cpp | 9 +- .../functions/arithmetic/MulOper.cpp | 15 ++ src/fintamath/functions/logic/And.cpp | 9 +- src/fintamath/functions/logic/AndOper.cpp | 15 ++ src/fintamath/functions/logic/Or.cpp | 9 +- src/fintamath/functions/logic/OrOper.cpp | 15 ++ .../powers/{PowFunction.cpp => PowOper.cpp} | 4 +- tests/src/FintamathTests.cpp | 2 +- tests/src/core/ParserTests.cpp | 4 +- .../expressions/ExpressionComparatorTests.cpp | 29 ++- .../expressions/ExpressionFunctionsTests.cpp | 2 +- .../src/expressions/ExpressionUtilsTests.cpp | 4 - .../interfaces/IBinaryExpressionTests.cpp | 4 +- .../interfaces/IPolynomExpressionTests.cpp | 6 +- tests/src/functions/FunctionUtilsTests.cpp | 18 +- tests/src/functions/IFunctionTests.cpp | 72 +++--- tests/src/functions/IOperatorTests.cpp | 15 +- .../src/functions/arithmetic/AddOperTests.cpp | 60 +++++ tests/src/functions/arithmetic/AddTests.cpp | 24 +- .../src/functions/arithmetic/MulOperTests.cpp | 58 +++++ tests/src/functions/arithmetic/MulTests.cpp | 24 +- tests/src/functions/logic/AndOperTests.cpp | 57 +++++ tests/src/functions/logic/AndTests.cpp | 22 +- tests/src/functions/logic/EquivTests.cpp | 2 +- tests/src/functions/logic/NequivTests.cpp | 2 +- tests/src/functions/logic/OrOperTests.cpp | 57 +++++ tests/src/functions/logic/OrTests.cpp | 22 +- .../src/functions/powers/PowFunctionTests.cpp | 51 ----- tests/src/functions/powers/PowOperTests.cpp | 60 +++++ tests/src/functions/powers/PowTests.cpp | 12 +- .../simplify/SimplifyDerivativeTests.cpp | 22 +- .../overall/simplify/SimplifyLogicTests.cpp | 44 ++-- tests/src/overall/simplify/SimplifyTests.cpp | 14 +- .../simplify/SimplifyTrigonometryTests.cpp | 2 +- tests/src/overall/solve/SolveTests.cpp | 2 +- 82 files changed, 1089 insertions(+), 697 deletions(-) create mode 100644 include/fintamath/functions/arithmetic/AddOper.hpp create mode 100644 include/fintamath/functions/arithmetic/MulOper.hpp create mode 100644 include/fintamath/functions/logic/AndOper.hpp create mode 100644 include/fintamath/functions/logic/OrOper.hpp rename include/fintamath/functions/powers/{PowFunction.hpp => PowOper.hpp} (57%) create mode 100644 src/fintamath/functions/arithmetic/AddOper.cpp create mode 100644 src/fintamath/functions/arithmetic/MulOper.cpp create mode 100644 src/fintamath/functions/logic/AndOper.cpp create mode 100644 src/fintamath/functions/logic/OrOper.cpp rename src/fintamath/functions/powers/{PowFunction.cpp => PowOper.cpp} (60%) create mode 100644 tests/src/functions/arithmetic/AddOperTests.cpp create mode 100644 tests/src/functions/arithmetic/MulOperTests.cpp create mode 100644 tests/src/functions/logic/AndOperTests.cpp create mode 100644 tests/src/functions/logic/OrOperTests.cpp delete mode 100644 tests/src/functions/powers/PowFunctionTests.cpp create mode 100644 tests/src/functions/powers/PowOperTests.cpp diff --git a/include/fintamath/expressions/Expression.hpp b/include/fintamath/expressions/Expression.hpp index c8e4de64f..f47e34cda 100644 --- a/include/fintamath/expressions/Expression.hpp +++ b/include/fintamath/expressions/Expression.hpp @@ -90,7 +90,7 @@ class Expression final : public IExpressionCRTP { void setVariable(const Variable &var, const Expression &val); - template + template static void registerExpressionConstructor(ExpressionConstructor constructor); protected: @@ -159,7 +159,7 @@ class Expression final : public IExpressionCRTP { mutable bool isSimplified = false; }; -template +template void Expression::registerExpressionConstructor(ExpressionConstructor constructor) { getExpressionMaker()[Function::getClassStatic()] = [maker = std::move(constructor)](ArgumentPtrVector &&args) { static const size_t funcArgSize = Function{}.getArgumentClasses().size(); @@ -169,11 +169,6 @@ void Expression::registerExpressionConstructor(ExpressionConstructor constructor if constexpr (Function::isVariadicStatic()) { res = maker(std::move(args)); } - else if constexpr (isPolynomial) { - if (funcArgSize <= args.size()) { - res = maker(std::move(args)); - } - } else { if (funcArgSize == args.size()) { res = maker(std::move(args)); diff --git a/include/fintamath/expressions/ExpressionUtils.hpp b/include/fintamath/expressions/ExpressionUtils.hpp index 201571bb6..586dfa906 100644 --- a/include/fintamath/expressions/ExpressionUtils.hpp +++ b/include/fintamath/expressions/ExpressionUtils.hpp @@ -76,9 +76,7 @@ std::pair splitRational(const ArgumentPtr &arg); ArgumentPtr negate(const ArgumentPtr &arg); -ArgumentPtr makePolynom(const IFunction &func, ArgumentPtrVector &&args); - -ArgumentPtr makePolynom(const IFunction &func, const ArgumentPtrVector &args); +ArgumentPtr invert(const ArgumentPtr &arg); ArgumentPtrVector getPolynomChildren(const IFunction &func, const ArgumentPtr &arg); diff --git a/include/fintamath/expressions/interfaces/IPolynomExpression.hpp b/include/fintamath/expressions/interfaces/IPolynomExpression.hpp index daaf0739f..6784a9a7b 100644 --- a/include/fintamath/expressions/interfaces/IPolynomExpression.hpp +++ b/include/fintamath/expressions/interfaces/IPolynomExpression.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -41,8 +40,6 @@ class IPolynomExpression : public IExpression { virtual std::string childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const; - virtual std::strong_ordering compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const; - ArgumentPtr preSimplify() const override; ArgumentPtr postSimplify() const override; @@ -51,6 +48,8 @@ class IPolynomExpression : public IExpression { virtual bool isComparableOrderInversed() const; + virtual std::strong_ordering compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const; + private: void simplifyRec(bool isPostSimplify); diff --git a/include/fintamath/functions/FunctionUtils.hpp b/include/fintamath/functions/FunctionUtils.hpp index e7325e694..12ecbf895 100644 --- a/include/fintamath/functions/FunctionUtils.hpp +++ b/include/fintamath/functions/FunctionUtils.hpp @@ -17,8 +17,6 @@ class IFunction; namespace detail { -extern bool isExpression(const IMathObject &arg); - extern std::unique_ptr makeExpr(const IFunction &func, ArgumentPtrVector args); extern std::unique_ptr makeExpr(const IFunction &func, const ArgumentRefVector &args); diff --git a/include/fintamath/functions/IFunction.hpp b/include/fintamath/functions/IFunction.hpp index 4023997be..11b32f349 100644 --- a/include/fintamath/functions/IFunction.hpp +++ b/include/fintamath/functions/IFunction.hpp @@ -44,8 +44,6 @@ class IFunction : public IMathObject { protected: virtual std::unique_ptr callAbstract(const ArgumentRefVector &argVect) const = 0; - - virtual void validateArgsSize(const ArgumentRefVector &argVect) const; }; template diff --git a/include/fintamath/functions/IFunctionCRTP.hpp b/include/fintamath/functions/IFunctionCRTP.hpp index c523e6405..f5ff20abd 100644 --- a/include/fintamath/functions/IFunctionCRTP.hpp +++ b/include/fintamath/functions/IFunctionCRTP.hpp @@ -34,7 +34,7 @@ class IFunctionCRTP_ : public IFunction { bool doArgsMatch(const ArgumentRefVector &argVect) const override { if constexpr (Derived::isVariadicStatic()) { - return doAnyArgsMatch(argVect); + return doVariadicArgsMatch(argVect); } else { if (argVect.size() != getArgumentClassesStatic().size()) { @@ -65,8 +65,6 @@ class IFunctionCRTP_ : public IFunction { virtual std::unique_ptr call(const ArgumentRefVector &argVect) const = 0; std::unique_ptr callAbstract(const ArgumentRefVector &argVect) const override { - validateArgsSize(argVect); - if (doArgsMatch(argVect)) { try { if (auto res = call(argVect)) { @@ -85,8 +83,8 @@ class IFunctionCRTP_ : public IFunction { private: template - bool doArgsMatch(const ArgumentRefVector &argVect) const { - if (!is(argVect[i]) || detail::isExpression(argVect[i])) { + static bool doArgsMatch(const ArgumentRefVector &argVect) { + if (!doArgMatch(argVect[i])) { return false; } @@ -94,18 +92,27 @@ class IFunctionCRTP_ : public IFunction { } template - bool doArgsMatch(const ArgumentRefVector & /*unused*/) const { + static bool doArgsMatch(const ArgumentRefVector &) { return true; } - bool doAnyArgsMatch(const ArgumentRefVector &argVect) const { - using AnyArgsType = typename std::tuple_element_t<0, std::tuple>; + static bool doVariadicArgsMatch(const ArgumentRefVector &argVect) { + if (argVect.empty()) { + return false; + } + + using ExpectedArg = typename std::tuple_element_t<0, std::tuple>; return stdr::all_of(argVect, [](const auto &arg) { - return is(arg); + return doArgMatch(arg); }); } + template + static bool doArgMatch(const ArgumentRef &arg) { + return is(arg); + } + private: #if !defined(I_FUNCTION_CRTP) && !defined(NDEBUG) }; diff --git a/include/fintamath/functions/arithmetic/Add.hpp b/include/fintamath/functions/arithmetic/Add.hpp index 310593bbd..6f7764f88 100644 --- a/include/fintamath/functions/arithmetic/Add.hpp +++ b/include/fintamath/functions/arithmetic/Add.hpp @@ -8,26 +8,22 @@ #include "fintamath/core/MathObjectClass.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/FunctionUtils.hpp" -#include "fintamath/functions/IOperator.hpp" +#include "fintamath/functions/IFunction.hpp" namespace fintamath { -class Add final : public IOperatorCRTP { +class Add final : public IFunctionCRTP { FINTAMATH_CLASS_BODY(Add) public: std::string toString() const override { - return "+"; + return "add"; } - static constexpr bool isAssociativeStatic() { + static constexpr bool isVariadicStatic() { return true; } - static constexpr Priority getPriorityStatic() { - return Priority::Addition; - } - protected: std::unique_ptr call(const ArgumentRefVector &argVect) const override; }; diff --git a/include/fintamath/functions/arithmetic/AddOper.hpp b/include/fintamath/functions/arithmetic/AddOper.hpp new file mode 100644 index 000000000..d592152d8 --- /dev/null +++ b/include/fintamath/functions/arithmetic/AddOper.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "fintamath/core/IArithmetic.hpp" +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/IOperator.hpp" + +namespace fintamath { + +class AddOper final : public IOperatorCRTP { + FINTAMATH_CLASS_BODY(AddOper) + +public: + std::string toString() const override { + return "+"; + } + + static constexpr bool isAssociativeStatic() { + return true; + } + + static constexpr Priority getPriorityStatic() { + return Priority::Addition; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argVect) const override; +}; + +} diff --git a/include/fintamath/functions/arithmetic/Mul.hpp b/include/fintamath/functions/arithmetic/Mul.hpp index 6f9103d4f..399428792 100644 --- a/include/fintamath/functions/arithmetic/Mul.hpp +++ b/include/fintamath/functions/arithmetic/Mul.hpp @@ -8,26 +8,22 @@ #include "fintamath/core/MathObjectClass.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/FunctionUtils.hpp" -#include "fintamath/functions/IOperator.hpp" +#include "fintamath/functions/IFunction.hpp" namespace fintamath { -class Mul final : public IOperatorCRTP { +class Mul final : public IFunctionCRTP { FINTAMATH_CLASS_BODY(Mul) public: std::string toString() const override { - return "*"; + return "mul"; } - static constexpr bool isAssociativeStatic() { + static constexpr bool isVariadicStatic() { return true; } - static constexpr Priority getPriorityStatic() { - return Priority::Multiplication; - } - protected: std::unique_ptr call(const ArgumentRefVector &argVect) const override; }; diff --git a/include/fintamath/functions/arithmetic/MulOper.hpp b/include/fintamath/functions/arithmetic/MulOper.hpp new file mode 100644 index 000000000..0d8a9ee81 --- /dev/null +++ b/include/fintamath/functions/arithmetic/MulOper.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "fintamath/core/IArithmetic.hpp" +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/IOperator.hpp" + +namespace fintamath { + +class MulOper final : public IOperatorCRTP { + FINTAMATH_CLASS_BODY(MulOper) + +public: + std::string toString() const override { + return "*"; + } + + static constexpr bool isAssociativeStatic() { + return true; + } + + static constexpr Priority getPriorityStatic() { + return Priority::Multiplication; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argVect) const override; +}; + +} diff --git a/include/fintamath/functions/logic/And.hpp b/include/fintamath/functions/logic/And.hpp index 19670ded5..5c739c046 100644 --- a/include/fintamath/functions/logic/And.hpp +++ b/include/fintamath/functions/logic/And.hpp @@ -7,27 +7,24 @@ #include "fintamath/core/MathObjectClass.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/FunctionUtils.hpp" +#include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/IOperator.hpp" #include "fintamath/literals/Boolean.hpp" namespace fintamath { -class And final : public IOperatorCRTP { +class And final : public IFunctionCRTP { FINTAMATH_CLASS_BODY(And) public: std::string toString() const override { - return "&"; + return "and"; } - static constexpr bool isAssociativeStatic() { + static constexpr bool isVariadicStatic() { return true; } - static constexpr Priority getPriorityStatic() { - return Priority::Conjunction; - } - protected: std::unique_ptr call(const ArgumentRefVector &argVect) const override; }; diff --git a/include/fintamath/functions/logic/AndOper.hpp b/include/fintamath/functions/logic/AndOper.hpp new file mode 100644 index 000000000..2ab2817e0 --- /dev/null +++ b/include/fintamath/functions/logic/AndOper.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/IOperator.hpp" +#include "fintamath/literals/Boolean.hpp" + +namespace fintamath { + +class AndOper final : public IOperatorCRTP { + FINTAMATH_CLASS_BODY(AndOper) + +public: + std::string toString() const override { + return "&"; + } + + static constexpr bool isAssociativeStatic() { + return true; + } + + static constexpr Priority getPriorityStatic() { + return Priority::Conjunction; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argVect) const override; +}; + +} diff --git a/include/fintamath/functions/logic/Or.hpp b/include/fintamath/functions/logic/Or.hpp index d49a3b0eb..4148ff857 100644 --- a/include/fintamath/functions/logic/Or.hpp +++ b/include/fintamath/functions/logic/Or.hpp @@ -7,27 +7,23 @@ #include "fintamath/core/MathObjectClass.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/FunctionUtils.hpp" -#include "fintamath/functions/IOperator.hpp" +#include "fintamath/functions/IFunction.hpp" #include "fintamath/literals/Boolean.hpp" namespace fintamath { -class Or final : public IOperatorCRTP { +class Or final : public IFunctionCRTP { FINTAMATH_CLASS_BODY(Or) public: std::string toString() const override { - return "|"; + return "or"; } - static constexpr bool isAssociativeStatic() { + static constexpr bool isVariadicStatic() { return true; } - static constexpr Priority getPriorityStatic() { - return Priority::Disjunction; - } - protected: std::unique_ptr call(const ArgumentRefVector &argVect) const override; }; diff --git a/include/fintamath/functions/logic/OrOper.hpp b/include/fintamath/functions/logic/OrOper.hpp new file mode 100644 index 000000000..7fd66d496 --- /dev/null +++ b/include/fintamath/functions/logic/OrOper.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/FunctionUtils.hpp" +#include "fintamath/functions/IFunction.hpp" +#include "fintamath/functions/IOperator.hpp" +#include "fintamath/literals/Boolean.hpp" + +namespace fintamath { + +class OrOper final : public IOperatorCRTP { + FINTAMATH_CLASS_BODY(OrOper) + +public: + std::string toString() const override { + return "|"; + } + + static constexpr bool isAssociativeStatic() { + return true; + } + + static constexpr Priority getPriorityStatic() { + return Priority::Disjunction; + } + +protected: + std::unique_ptr call(const ArgumentRefVector &argVect) const override; +}; + +} diff --git a/include/fintamath/functions/powers/Pow.hpp b/include/fintamath/functions/powers/Pow.hpp index 9c34f396d..5fc4772ad 100644 --- a/include/fintamath/functions/powers/Pow.hpp +++ b/include/fintamath/functions/powers/Pow.hpp @@ -17,16 +17,12 @@ class Rational; class Real; class Complex; -class Pow final : public IOperatorCRTP { +class Pow final : public IFunctionCRTP { FINTAMATH_CLASS_BODY(Pow) public: std::string toString() const override { - return "^"; - } - - static constexpr Priority getPriorityStatic() { - return Priority::Exponentiation; + return "pow"; } protected: diff --git a/include/fintamath/functions/powers/PowFunction.hpp b/include/fintamath/functions/powers/PowOper.hpp similarity index 57% rename from include/fintamath/functions/powers/PowFunction.hpp rename to include/fintamath/functions/powers/PowOper.hpp index f071108e0..91b4cc4b3 100644 --- a/include/fintamath/functions/powers/PowFunction.hpp +++ b/include/fintamath/functions/powers/PowOper.hpp @@ -7,20 +7,25 @@ #include "fintamath/core/IMathObject.hpp" #include "fintamath/core/MathObjectClass.hpp" #include "fintamath/functions/FunctionArguments.hpp" -#include "fintamath/functions/IFunction.hpp" +#include "fintamath/functions/IOperator.hpp" +#include "fintamath/numbers/INumber.hpp" namespace fintamath { -class PowFunction final : public IFunctionCRTP { - FINTAMATH_CLASS_BODY(PowFunction) +class PowOper final : public IOperatorCRTP { + FINTAMATH_CLASS_BODY(PowOper) public: std::string toString() const override { - return "pow"; + return "^"; + } + + static constexpr Priority getPriorityStatic() { + return Priority::Exponentiation; } protected: std::unique_ptr call(const ArgumentRefVector &argVect) const override; }; -} +} \ No newline at end of file diff --git a/src/fintamath/config/ExpressionConfig.cpp b/src/fintamath/config/ExpressionConfig.cpp index bc98453b8..6474b7b2e 100644 --- a/src/fintamath/config/ExpressionConfig.cpp +++ b/src/fintamath/config/ExpressionConfig.cpp @@ -28,10 +28,12 @@ #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/arithmetic/Abs.hpp" #include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Frac.hpp" #include "fintamath/functions/arithmetic/FracMixed.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sign.hpp" #include "fintamath/functions/arithmetic/Sub.hpp" @@ -63,11 +65,13 @@ #include "fintamath/functions/logarithms/Ln.hpp" #include "fintamath/functions/logarithms/Log.hpp" #include "fintamath/functions/logic/And.hpp" +#include "fintamath/functions/logic/AndOper.hpp" #include "fintamath/functions/logic/Equiv.hpp" #include "fintamath/functions/logic/Impl.hpp" #include "fintamath/functions/logic/Nequiv.hpp" #include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/logic/Or.hpp" +#include "fintamath/functions/logic/OrOper.hpp" #include "fintamath/functions/ntheory/Ceil.hpp" #include "fintamath/functions/ntheory/Floor.hpp" #include "fintamath/functions/other/Deg.hpp" @@ -75,7 +79,7 @@ #include "fintamath/functions/other/Percent.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" -#include "fintamath/functions/powers/PowFunction.hpp" +#include "fintamath/functions/powers/PowOper.hpp" #include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqr.hpp" #include "fintamath/functions/powers/Sqrt.hpp" @@ -97,23 +101,31 @@ namespace fintamath::detail { ExpressionConfig::ExpressionConfig() { - Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { return AddExpr(std::move(args)).clone(); }); + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + return addExpr(std::move(args)); + }); + Expression::registerExpressionConstructor([](ArgumentPtrVector args) { ArgumentPtr lhs = std::move(args.front()); ArgumentPtr rhs = std::move(args.back()); ArgumentPtr negRhs = negExpr(std::move(rhs)); - return AddExpr({std::move(lhs), std::move(negRhs)}).clone(); + return addExpr(std::move(lhs), std::move(negRhs)); }); - Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { return MulExpr(std::move(args)).clone(); }); + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + return mulExpr(std::move(args)); + }); + Expression::registerExpressionConstructor
([](ArgumentPtrVector args) { return DivExpr(std::move(args.front()), std::move(args.back())).clone(); }); @@ -130,19 +142,27 @@ ExpressionConfig::ExpressionConfig() { return addExpr(std::move(integ), divExpr(std::move(numer), std::move(denom))); }); - Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { return AndExpr(std::move(args)).clone(); }); - Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + return andExpr(std::move(args)); + }); + + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { return OrExpr(std::move(args)).clone(); }); + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + return orExpr(std::move(args)); + }); + Expression::registerExpressionConstructor([](ArgumentPtrVector args) { return PowExpr(std::move(args.front()), std::move(args.back())).clone(); }); - Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { + Expression::registerExpressionConstructor([](ArgumentPtrVector &&args) { return powExpr(std::move(args)); }); diff --git a/src/fintamath/config/TypeConfig.cpp b/src/fintamath/config/TypeConfig.cpp index c59f312b4..d193e7064 100644 --- a/src/fintamath/config/TypeConfig.cpp +++ b/src/fintamath/config/TypeConfig.cpp @@ -32,10 +32,12 @@ #include "fintamath/functions/IOperator.hpp" #include "fintamath/functions/arithmetic/Abs.hpp" #include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Frac.hpp" #include "fintamath/functions/arithmetic/FracMixed.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sign.hpp" #include "fintamath/functions/arithmetic/Sub.hpp" @@ -67,11 +69,13 @@ #include "fintamath/functions/logarithms/Ln.hpp" #include "fintamath/functions/logarithms/Log.hpp" #include "fintamath/functions/logic/And.hpp" +#include "fintamath/functions/logic/AndOper.hpp" #include "fintamath/functions/logic/Equiv.hpp" #include "fintamath/functions/logic/Impl.hpp" #include "fintamath/functions/logic/Nequiv.hpp" #include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/logic/Or.hpp" +#include "fintamath/functions/logic/OrOper.hpp" #include "fintamath/functions/ntheory/Ceil.hpp" #include "fintamath/functions/ntheory/Floor.hpp" #include "fintamath/functions/ntheory/Mod.hpp" @@ -82,7 +86,7 @@ #include "fintamath/functions/other/Percent.hpp" #include "fintamath/functions/powers/Exp.hpp" #include "fintamath/functions/powers/Pow.hpp" -#include "fintamath/functions/powers/PowFunction.hpp" +#include "fintamath/functions/powers/PowOper.hpp" #include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqr.hpp" #include "fintamath/functions/powers/Sqrt.hpp" @@ -150,6 +154,36 @@ TypeConfig::TypeConfig() { IConstant::registerType(); IFunction::registerType(); + + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType
(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + IOperator::registerType(); + + IFunction::registerType(); + IFunction::registerType(); + IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); @@ -190,35 +224,10 @@ TypeConfig::TypeConfig() { IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); - IFunction::registerType(); IFunction::registerType(); IFunction::registerType(); - - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType
(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); - IOperator::registerType(); + IFunction::registerType(); + IFunction::registerType(); IExpression::registerType(); IExpression::registerType(); diff --git a/src/fintamath/expressions/Expression.cpp b/src/fintamath/expressions/Expression.cpp index 377f927c8..6ed8b35c7 100644 --- a/src/fintamath/expressions/Expression.cpp +++ b/src/fintamath/expressions/Expression.cpp @@ -28,6 +28,7 @@ #include "fintamath/functions/arithmetic/Add.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sub.hpp" #include "fintamath/functions/other/Comma.hpp" @@ -298,7 +299,7 @@ void Expression::moveFunctionTermsToOperands(OperandStack &operands, std::stack< } void Expression::insertMultiplications(TermVector &terms) { - static const ArgumentPtr mul = Mul{}.clone(); + static const ArgumentPtr mul = MulOper{}.clone(); for (size_t i = 1; i < terms.size(); i++) { if (canNextTermBeBinaryOperator(terms[i - 1]) && @@ -450,7 +451,7 @@ Expression::ExpressionMaker &Expression::getExpressionMaker() { void Expression::validateFunctionArgs(const IFunction &func, const ArgumentPtrVector &args) { const ArgumentTypeVector &expectedArgTypes = func.getArgumentClasses(); - if (args.empty() || (!func.isVariadic() && args.size() < expectedArgTypes.size())) { + if (args.empty() || (!func.isVariadic() && args.size() != expectedArgTypes.size())) { throw InvalidInputFunctionException(func.toString(), argumentVectorToStringVector(args)); } @@ -504,8 +505,13 @@ namespace detail { std::unique_ptr makeExpr(const IFunction &func, ArgumentPtrVector args) { stdr::transform(args, args.begin(), &Expression::compress); + Expression::validateFunctionArgs(func, args); + if (func.isVariadic() && args.size() == 1) { + return std::move(args.front())->clone(); + } + if (const auto strToConstr = Expression::getExpressionMaker().find(func.getClass()); strToConstr != Expression::getExpressionMaker().end()) { diff --git a/src/fintamath/expressions/ExpressionComparator.cpp b/src/fintamath/expressions/ExpressionComparator.cpp index d391c60a3..c0649953f 100644 --- a/src/fintamath/expressions/ExpressionComparator.cpp +++ b/src/fintamath/expressions/ExpressionComparator.cpp @@ -17,11 +17,12 @@ #include "fintamath/functions/FunctionUtils.hpp" #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" -#include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/literals/ILiteral.hpp" #include "fintamath/literals/Variable.hpp" +#include + namespace fintamath::detail { using Ordering = std::strong_ordering; @@ -36,28 +37,24 @@ using ExpressionTreePathStack = std::stack>; struct ChildrenComparatorResult final { Ordering postfix = Ordering::equal; - Ordering prefixFirst = Ordering::equal; - Ordering prefixLast = Ordering::equal; - Ordering unary = Ordering::equal; + Ordering prefix = Ordering::equal; Ordering literals = Ordering::equal; Ordering size = Ordering::equal; }; -Ordering compareNonExpressions(const ArgumentPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options); - -Ordering comparePolynoms(const PolynomPtr &lhs, const PolynomPtr &rhs, const ComparatorOptions &options); +Ordering compareNonExpressions(const ArgumentPtr &lhs, const ArgumentPtr &rhs, ComparatorOptions options); -Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, const ComparatorOptions &options); +Ordering comparePolynoms(const PolynomPtr &lhs, const PolynomPtr &rhs, ComparatorOptions options); -Ordering comparePolynomAndNonPolynom(const PolynomPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options); +Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, ComparatorOptions options); -Ordering compareExpressionAndNonExpression(const ExpressionPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options); +Ordering comparePolynomAndNonPolynom(const PolynomPtr &lhs, const ArgumentPtr &rhs, ComparatorOptions options); -Ordering compareFunctions(const FunctionPtr &lhs, const FunctionPtr &rhs, const ComparatorOptions &options); +Ordering compareExpressionAndNonExpression(const ExpressionPtr &lhs, const ArgumentPtr &rhs, ComparatorOptions options); -ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, const ArgumentPtrVector &rhsChildren, const ComparatorOptions &options); +Ordering compareFunctions(const FunctionPtr &lhs, const FunctionPtr &rhs); -bool unwrapUnaryExpression(ArgumentPtr &arg); +ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, const ArgumentPtrVector &rhsChildren, ComparatorOptions options); bool unwrapEmptyExpression(ArgumentPtr &arg); @@ -108,7 +105,7 @@ std::shared_ptr popNextTerm(ExpressionTreePathStack &stack) { } template -Ordering compareTerms(const ArgumentPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options) { +Ordering compareTerms(const ArgumentPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions options) { ExpressionTreePathStack lhsPath; ExpressionTreePathStack rhsPath; @@ -188,39 +185,58 @@ Ordering compare(ArgumentPtr lhs, ArgumentPtr rhs, const ComparatorOptions optio return compareExpressions(lhsExpr, rhsExpr, options); } -Ordering compareNonExpressions(const ArgumentPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options) { - if (is(lhs) && !is(rhs)) { - return !options.termOrderInversed ? Ordering::greater : Ordering::less; - } - if (!is(lhs) && is(rhs)) { - return options.termOrderInversed ? Ordering::greater : Ordering::less; +Ordering compareNonExpressions(const ArgumentPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions options) { + Ordering ordering = Ordering::equal; + + if (!lhs && !rhs) { + return ordering; } - if (is(lhs) && !is(rhs)) { - return !options.termOrderInversed ? Ordering::greater : Ordering::less; + if (lhs && !rhs) { + ordering = Ordering::greater; } - if (!is(lhs) && is(rhs)) { - return options.termOrderInversed ? Ordering::greater : Ordering::less; + else if (!lhs && rhs) { + ordering = Ordering::less; + } + else if (is(lhs) && !is(rhs)) { + ordering = Ordering::greater; + } + else if (!is(lhs) && is(rhs)) { + ordering = Ordering::less; + } + else if (is(lhs) && !is(rhs)) { + ordering = Ordering::greater; + } + else if (!is(lhs) && is(rhs)) { + ordering = Ordering::less; } - if (*lhs == *rhs) { - return Ordering::equal; + if (ordering != Ordering::equal || *lhs == *rhs) { + return options.termOrderInversed ? reverse(ordering) : ordering; } - if (const auto lhsComp = cast(lhs)) { - if (const auto rhsComp = cast(rhs)) { - if (options.comparableOrderInversed) { - return *lhsComp < *rhsComp ? Ordering::greater : Ordering::less; - } + const auto lhsComp = cast(lhs); + const auto rhsComp = cast(rhs); - return *lhsComp > *rhsComp ? Ordering::greater : Ordering::less; + if (lhsComp && rhsComp) { + ordering = *lhsComp < *rhsComp ? Ordering::less : Ordering::greater; + + if (options.comparableOrderInversed) { + ordering = reverse(ordering); } } + else { + ordering = lhs->toString() < rhs->toString() ? Ordering::greater : Ordering::less; + } - return lhs->toString() < rhs->toString() ? Ordering::greater : Ordering::less; + return ordering; } -Ordering comparePolynoms(const PolynomPtr &lhs, const PolynomPtr &rhs, const ComparatorOptions &options) { +Ordering comparePolynoms(const PolynomPtr &lhs, const PolynomPtr &rhs, const ComparatorOptions options) { + if (*lhs->getFunction() != *rhs->getFunction()) { + return compareFunctions(lhs->getFunction(), rhs->getFunction()); + } + const ChildrenComparatorResult childrenComp = compareChildren(lhs->getChildren(), rhs->getChildren(), options); if (childrenComp.postfix != Ordering::equal) { @@ -229,27 +245,29 @@ Ordering comparePolynoms(const PolynomPtr &lhs, const PolynomPtr &rhs, const Com if (childrenComp.size != Ordering::equal) { return childrenComp.size; } - if (childrenComp.unary != Ordering::equal) { - return childrenComp.unary; - } - if (childrenComp.prefixFirst != Ordering::equal) { - return childrenComp.prefixFirst; + if (childrenComp.prefix != Ordering::equal) { + return childrenComp.prefix; } - return compareFunctions(lhs->getFunction(), rhs->getFunction(), options); + return Ordering::equal; } -Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, const ComparatorOptions &options) { - const auto lhsOper = cast(lhs->getFunction()); - const auto rhsOper = cast(rhs->getFunction()); +Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, const ComparatorOptions options) { + if (*lhs->getFunction() != *rhs->getFunction()) { + return compareFunctions(lhs->getFunction(), rhs->getFunction()); + } + + ArgumentPtrVector lhsChildren = lhs->getChildren(); + ArgumentPtrVector rhsChildren = rhs->getChildren(); - if ((lhsOper != nullptr) != (rhsOper != nullptr)) { - return compareFunctions(lhs->getFunction(), rhs->getFunction(), options); + if (is(lhs->getFunction()) && is(rhs->getFunction())) { + stdr::reverse(lhsChildren); + stdr::reverse(rhsChildren); } ComparatorOptions childCompOptions = options; childCompOptions.termOrderInversed = false; - const ChildrenComparatorResult childrenComp = compareChildren(lhs->getChildren(), rhs->getChildren(), childCompOptions); + const ChildrenComparatorResult childrenComp = compareChildren(lhsChildren, rhsChildren, childCompOptions); if (childrenComp.literals != Ordering::equal) { return childrenComp.literals; @@ -260,32 +278,24 @@ Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, if (childrenComp.postfix != Ordering::equal) { return childrenComp.postfix; } - - if (is(lhs->getFunction()) && is(rhs->getFunction())) { - if (childrenComp.prefixLast != Ordering::equal) { - return childrenComp.prefixLast; - } - } - else { - if (childrenComp.prefixFirst != Ordering::equal) { - return childrenComp.prefixFirst; - } + if (childrenComp.prefix != Ordering::equal) { + return childrenComp.prefix; } - return compareFunctions(lhs->getFunction(), rhs->getFunction(), options); + return Ordering::equal; } -Ordering comparePolynomAndNonPolynom(const PolynomPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options) { +Ordering comparePolynomAndNonPolynom(const PolynomPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions options) { const ChildrenComparatorResult childrenComp = compareChildren(lhs->getChildren(), {rhs}, options); if (childrenComp.postfix != Ordering::equal) { return childrenComp.postfix; } - return childrenComp.prefixFirst; + return childrenComp.prefix; } -Ordering compareExpressionAndNonExpression(const ExpressionPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions &options) { +Ordering compareExpressionAndNonExpression(const ExpressionPtr &lhs, const ArgumentPtr &rhs, const ComparatorOptions options) { if (!is(rhs)) { return !options.termOrderInversed ? Ordering::greater : Ordering::less; } @@ -294,39 +304,17 @@ Ordering compareExpressionAndNonExpression(const ExpressionPtr &lhs, const Argum return res; } - if (!is(lhs->getFunction())) { - return !options.termOrderInversed ? Ordering::greater : Ordering::less; - } - - if (const auto res = compareTerms(lhs, rhs, options); res != Ordering::equal) { - return res; - } - - if (is(lhs->getFunction())) { - if (const Ordering res = compare(lhs->getChildren().front(), rhs); res != Ordering::equal) { - return res; - } + if ((is(lhs->getFunction()) || is(lhs->getFunction())) && + !is(lhs->getChildren().front())) { - return Ordering::less; - } - - if (is(lhs->getFunction()) || is(lhs->getFunction())) { const ArgumentPtr rhsExpr = makeExpr(*lhs->getFunction(), rhs, Integer(1).clone()); - const Ordering res = compare(lhs, rhsExpr); - return !options.termOrderInversed ? res : reverse(res); + return compare(lhs, rhsExpr, options); } return !options.termOrderInversed ? Ordering::greater : Ordering::less; } -Ordering compareFunctions(const FunctionPtr &lhs, const FunctionPtr &rhs, const ComparatorOptions &options) { - if (is(lhs) && !is(rhs)) { - return options.termOrderInversed ? Ordering::greater : Ordering::less; - } - if (!is(lhs) && is(rhs)) { - return !options.termOrderInversed ? Ordering::greater : Ordering::less; - } - +Ordering compareFunctions(const FunctionPtr &lhs, const FunctionPtr &rhs) { if (*lhs == *rhs) { return Ordering::equal; } @@ -338,7 +326,7 @@ Ordering compareFunctions(const FunctionPtr &lhs, const FunctionPtr &rhs, const return lhs->toString() < rhs->toString() ? Ordering::greater : Ordering::less; } -ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, const ArgumentPtrVector &rhsChildren, const ComparatorOptions &options) { +ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, const ArgumentPtrVector &rhsChildren, const ComparatorOptions options) { ChildrenComparatorResult result = {}; if (lhsChildren.size() != rhsChildren.size()) { @@ -351,50 +339,29 @@ ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, c std::min(lhsChildren.size(), rhsChildren.size())); for (const auto i : stdv::iota(0U, prefixSize)) { - const Ordering childrenComp = compare(lhsChildren[i], rhsChildren[i], options); - - if (childrenComp != Ordering::equal) { - result.prefixLast = childrenComp; - } - - if (result.prefixFirst == Ordering::equal) { - result.prefixFirst = childrenComp; + if (result.prefix == Ordering::equal) { + result.prefix = compare(lhsChildren[i], rhsChildren[i], options); } if (result.literals == Ordering::equal) { result.literals = compareTerms(lhsChildren[i], rhsChildren[i], {}); } - if (result.literals != Ordering::equal && result.prefixLast != Ordering::equal) { + if (result.prefix != Ordering::equal && result.literals != Ordering::equal) { break; } } for (size_t i = lhsPostfixStart, j = rhsPostfixStart; i < lhsChildren.size() && j < rhsChildren.size(); i++, j++) { - ArgumentPtr compLhs = lhsChildren[i]; - ArgumentPtr compRhs = rhsChildren[j]; - - const bool isLhsUnary = unwrapUnaryExpression(compLhs); - const bool isRhsUnary = unwrapUnaryExpression(compRhs); - - if (isLhsUnary && isRhsUnary) { - compLhs = lhsChildren[i]; - compRhs = rhsChildren[j]; + if (result.postfix == Ordering::equal) { + result.postfix = compare(lhsChildren[i], rhsChildren[j], options); } if (result.literals == Ordering::equal) { - result.literals = compareTerms(compLhs, compRhs, options); - } - - if (result.unary == Ordering::equal && isLhsUnary != isRhsUnary) { - result.unary = !isLhsUnary ? Ordering::greater : Ordering::less; + result.literals = compareTerms(lhsChildren[i], rhsChildren[j], options); } - if (result.postfix == Ordering::equal) { - result.postfix = compare(compLhs, compRhs, options); - } - - if (result.postfix != Ordering::equal) { + if (result.postfix != Ordering::equal && result.literals != Ordering::equal) { break; } } @@ -411,22 +378,10 @@ ChildrenComparatorResult compareChildren(const ArgumentPtrVector &lhsChildren, c return result; } -bool unwrapUnaryExpression(ArgumentPtr &arg) { - if (const auto expr = cast(arg); - expr && - expr->getFunction()->getArgumentClasses().size() == 1) { - - arg = expr->getChildren().front(); - return true; - } - - return false; -} - bool unwrapEmptyExpression(ArgumentPtr &arg) { if (const auto expr = cast(arg); - expr && - !expr->getFunction()) { + expr && + !expr->getFunction()) { arg = expr->getChildren().front(); return true; diff --git a/src/fintamath/expressions/ExpressionUtils.cpp b/src/fintamath/expressions/ExpressionUtils.cpp index 99ad079c3..d869c5a1a 100644 --- a/src/fintamath/expressions/ExpressionUtils.cpp +++ b/src/fintamath/expressions/ExpressionUtils.cpp @@ -17,8 +17,10 @@ #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/IOperator.hpp" #include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/literals/Variable.hpp" @@ -34,10 +36,6 @@ namespace fintamath::detail { const ArgumentPtr one = Integer(1).clone(); -bool isExpression(const IMathObject &arg) { - return is(arg); -} - bool isInfinity(const ArgumentPtr &arg) { return is(arg) || is(arg) || is(arg); } @@ -156,21 +154,18 @@ std::pair splitMulExpr(const ArgumentPtr &inChild, con } } - ArgumentPtr rate = makePolynom(Mul{}, - ArgumentPtrVector(mulExprChildren.begin(), - mulExprChildren.begin() + static_cast(i))); - ArgumentPtr value = makePolynom(Mul{}, - ArgumentPtrVector(mulExprChildren.begin() + static_cast(i), - mulExprChildren.end())); - - if (!rate) { - rate = one; + if (i == 0) { + return {one, inChild}; } - if (!value) { - value = checkVariables ? one : inChild; + if (i >= mulExprChildren.size()) { + return {inChild, one}; } + ArgumentPtr rate = mulExpr(ArgumentPtrVector(mulExprChildren.begin(), + mulExprChildren.begin() + static_cast(i))); + ArgumentPtr value = mulExpr(ArgumentPtrVector(mulExprChildren.begin() + static_cast(i), + mulExprChildren.end())); return {rate, value}; } @@ -231,19 +226,19 @@ ArgumentPtr negate(const ArgumentPtr &arg) { stdv::transform([](const ArgumentPtr &child) { return negate(child); }); - return makePolynom(Add{}, ArgumentPtrVector(negChildrenView.begin(), negChildrenView.end())); // TODO: use C++23 stdv::to + return addExpr(ArgumentPtrVector(negChildrenView.begin(), negChildrenView.end())); // TODO: use C++23 stdv::to } if (is(expr->getFunction())) { if (const auto firstChildNum = cast(expr->getChildren().front())) { if (*firstChildNum == Integer(-1)) { ArgumentPtrVector negChildren(expr->getChildren().begin() + 1, expr->getChildren().end()); - return makePolynom(Mul(), std::move(negChildren)); + return mulExpr(std::move(negChildren)); } ArgumentPtrVector negChildren = expr->getChildren(); negChildren.front() = (*firstChildNum) * Integer(-1); - return makePolynom(Mul(), std::move(negChildren)); + return mulExpr(std::move(negChildren)); } } } @@ -254,20 +249,20 @@ ArgumentPtr negate(const ArgumentPtr &arg) { return mulExpr(Integer(-1).clone(), arg); } -ArgumentPtr makePolynom(const IFunction &func, ArgumentPtrVector &&args) { - if (args.empty()) { - return {}; +ArgumentPtr invert(const ArgumentPtr &arg) { + if (const auto num = cast(arg)) { + return Integer(1) / (*num); } - if (args.size() == 1) { - return args.front(); - } + if (const auto expr = cast(arg); expr && is
(expr->getFunction())) { + if (*expr->getChildren().front() == Integer(1)) { + return expr->getChildren().back(); + } - return makeExpr(func, std::move(args)); -} + return divExpr(expr->getChildren().back(), expr->getChildren().front()); + } -ArgumentPtr makePolynom(const IFunction &func, const ArgumentPtrVector &args) { - return makePolynom(func, ArgumentPtrVector(args)); + return divExpr(Integer(1).clone(), arg); } ArgumentPtrVector getPolynomChildren(const IFunction &func, const ArgumentPtr &arg) { @@ -329,14 +324,14 @@ std::string operatorChildToString(const IOperator &oper, const ArgumentPtr &chil } else if (const auto childComplex = cast(child)) { if (childComplex->real() != Integer(0)) { - childOper = std::make_shared(); + childOper = std::make_shared(); } else if (childComplex->imag() != Integer(1)) { if (childComplex->imag() == Integer(-1)) { childOper = std::make_shared(); } else { - childOper = std::make_shared(); + childOper = std::make_shared(); } } } @@ -347,8 +342,8 @@ std::string operatorChildToString(const IOperator &oper, const ArgumentPtr &chil childOper = std::make_shared
(); } else if (is(child)) { - if (childStr.find(Mul{}.toString()) != std::string::npos) { - childOper = std::make_shared(); + if (childStr.find(MulOper{}.toString()) != std::string::npos) { + childOper = std::make_shared(); } } diff --git a/src/fintamath/expressions/FunctionExpression.cpp b/src/fintamath/expressions/FunctionExpression.cpp index 82a16c578..15c3e7811 100644 --- a/src/fintamath/expressions/FunctionExpression.cpp +++ b/src/fintamath/expressions/FunctionExpression.cpp @@ -47,21 +47,25 @@ const ArgumentPtrVector &FunctionExpression::getChildren() const { } ArgumentPtr FunctionExpression::preSimplify() const { - auto simpl = cast(clone()); - - for (auto &child : simpl->children) { - preSimplifyChild(child); - } - - return simpl; + return simplifyRec(false); } ArgumentPtr FunctionExpression::postSimplify() const { + return simplifyRec(true); +} + +ArgumentPtr FunctionExpression::simplifyRec(bool isPostSimplify) const { auto simpl = cast(clone()); ArgumentRefVector args; for (auto &child : simpl->children) { - postSimplifyChild(child); + if (isPostSimplify) { + postSimplifyChild(child); + } + else { + preSimplifyChild(child); + } + args.emplace_back(*child); } @@ -79,4 +83,5 @@ void FunctionExpression::setChildren(const ArgumentPtrVector &childVect) { children = childVect; } + } diff --git a/src/fintamath/expressions/FunctionExpression.hpp b/src/fintamath/expressions/FunctionExpression.hpp index 2e0640e0a..ea7c486a0 100644 --- a/src/fintamath/expressions/FunctionExpression.hpp +++ b/src/fintamath/expressions/FunctionExpression.hpp @@ -29,6 +29,9 @@ class FunctionExpression final : public IExpressionCRTP { ArgumentPtr postSimplify() const override; +private: + ArgumentPtr simplifyRec(bool isPostSimplify) const; + private: std::shared_ptr func; diff --git a/src/fintamath/expressions/IExpression.cpp b/src/fintamath/expressions/IExpression.cpp index 5a358a5d4..ab386d39e 100644 --- a/src/fintamath/expressions/IExpression.cpp +++ b/src/fintamath/expressions/IExpression.cpp @@ -11,6 +11,7 @@ #include "fintamath/core/IMathObject.hpp" #include "fintamath/core/MathObjectUtils.hpp" #include "fintamath/core/MultiMethod.hpp" +#include "fintamath/expressions/ExpressionComparator.hpp" #include "fintamath/expressions/ExpressionUtils.hpp" #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/IFunction.hpp" @@ -167,8 +168,8 @@ std::unique_ptr IExpression::convertToApproximated(const INumber &num) outMultiApproximate.add([](const Complex &inRhs) { return Complex( - *convert(inRhs.real()), - *convert(inRhs.imag())) + *convert(inRhs.real()), + *convert(inRhs.imag())) .clone(); }); @@ -340,7 +341,7 @@ ArgumentPtr IExpression::approximate() const { if (!containsVar && areNumberChilrenPrecise) { if (auto res = callFunction(*approxSimplExpr->getFunction(), convertToApproximatedNumbers(approxSimplExpr->getChildren())); - is(res)) { + is(res)) { return res; } diff --git a/src/fintamath/expressions/binary/CompExpr.cpp b/src/fintamath/expressions/binary/CompExpr.cpp index e7f16fc07..2d795f88b 100644 --- a/src/fintamath/expressions/binary/CompExpr.cpp +++ b/src/fintamath/expressions/binary/CompExpr.cpp @@ -51,7 +51,7 @@ std::string CompExpr::toString() const { if (is(solLhs)) { sumChildren.erase(sumChildren.begin()); - ArgumentPtr solRhs = detail::negate(makePolynom(Add{}, std::move(sumChildren))); + ArgumentPtr solRhs = negate(mulExpr(std::move(sumChildren))); return CompExpr(cast(*func), std::move(solLhs), std::move(solRhs)).toString(); } } @@ -223,10 +223,10 @@ ArgumentPtr CompExpr::rateSimplify(const IFunction &func, const ArgumentPtr &lhs { ArgumentPtrVector newChildren = firstChildMulExpr->getChildren(); newChildren.erase(newChildren.begin()); - children.front() = makePolynom(Mul{}, std::move(newChildren)); + children.front() = mulExpr(std::move(newChildren)); } - ArgumentPtr newLhs = makePolynom(Add{}, std::move(children)); + ArgumentPtr newLhs = addExpr(std::move(children)); simplifyChild(newLhs); approximateChild(rate); diff --git a/src/fintamath/expressions/binary/DerivativeExpr.cpp b/src/fintamath/expressions/binary/DerivativeExpr.cpp index 340e86e08..e005deee8 100644 --- a/src/fintamath/expressions/binary/DerivativeExpr.cpp +++ b/src/fintamath/expressions/binary/DerivativeExpr.cpp @@ -152,8 +152,8 @@ ArgumentPtr DerivativeExpr::mulSimplify(const ArgumentPtrVector &children, const auto lhsChildren = ArgumentPtrVector(children.begin(), children.begin() + childrenSizeDiv2); auto rhsChildren = ArgumentPtrVector(children.begin() + childrenSizeDiv2, children.end()); - const ArgumentPtr lhs = makePolynom(Mul{}, std::move(lhsChildren)); - const ArgumentPtr rhs = makePolynom(Mul{}, std::move(rhsChildren)); + const ArgumentPtr lhs = mulExpr(std::move(lhsChildren)); + const ArgumentPtr rhs = mulExpr(std::move(rhsChildren)); return addExpr( mulExpr(derivativeExpr(lhs, var), rhs), diff --git a/src/fintamath/expressions/binary/DivExpr.cpp b/src/fintamath/expressions/binary/DivExpr.cpp index 0c92896ff..030684b38 100644 --- a/src/fintamath/expressions/binary/DivExpr.cpp +++ b/src/fintamath/expressions/binary/DivExpr.cpp @@ -47,7 +47,7 @@ DivExpr::DivExpr(ArgumentPtr inLhsChild, ArgumentPtr inRhsChild) std::string DivExpr::toString() const { if (isNegated(lhsChild)) { - return negExpr(divExpr(detail::negate(lhsChild), rhsChild))->toString(); + return negExpr(divExpr(negate(lhsChild), rhsChild))->toString(); } return IBinaryExpression::toString(); @@ -145,8 +145,8 @@ ArgumentPtr DivExpr::divSimplify(const IFunction & /*func*/, const ArgumentPtr & return {}; } - ArgumentPtr numerator = makePolynom(Mul{}, std::move(numeratorChildren)); - ArgumentPtr denominator = makePolynom(Mul{}, std::move(denominatorChildren)); + ArgumentPtr numerator = mulExpr(std::move(numeratorChildren)); + ArgumentPtr denominator = mulExpr(std::move(denominatorChildren)); ArgumentPtr res = divExpr(std::move(numerator), std::move(denominator)); return res; @@ -211,13 +211,13 @@ ArgumentPtr DivExpr::mulSimplify(const SimplifyFunctionVector &simplFuncs, } } - ArgumentPtr numerator = makePolynom(Mul{}, lhsChildren); + ArgumentPtr numerator = mulExpr(lhsChildren); if (rhsChildren.empty()) { return numerator; } - ArgumentPtr denominator = makePolynom(Mul{}, rhsChildren); + ArgumentPtr denominator = mulExpr(rhsChildren); if (lhsChildren.size() != lhsChildrenSizeInitial || rhsChildren.size() != rhsChildrenSizeInitial) { ArgumentPtr res = divExpr(std::move(numerator), std::move(denominator)); @@ -303,7 +303,7 @@ std::pair DivExpr::sumSumSimplify(const ArgumentPtr &l return {}; } - ArgumentPtr result = makePolynom(Add{}, std::move(resultVect)); + ArgumentPtr result = addExpr(std::move(resultVect)); ArgumentPtr remainderAdd = addExpr(std::move(remainderVect)); ArgumentPtr remainder = divExpr(std::move(remainderAdd), rhs); simplifyChild(remainder); @@ -352,11 +352,11 @@ std::pair DivExpr::sumMulSimplify(const ArgumentPtr &l return {}; } - ArgumentPtr result = makePolynom(Add{}, std::move(resultChildren)); + ArgumentPtr result = addExpr(std::move(resultChildren)); ArgumentPtr remainder; if (!remainderChildren.empty()) { - ArgumentPtr remainderAdd = makePolynom(Add{}, std::move(remainderChildren)); + ArgumentPtr remainderAdd = addExpr(std::move(remainderChildren)); remainder = divExpr(std::move(remainderAdd), rhs); simplifyChild(remainder); } @@ -398,11 +398,11 @@ std::pair DivExpr::mulSumSimplify(const ArgumentPtr &l multiplicators.emplace_back(mulExpr(rhsChild, result)); } - ArgumentPtr remainderAdd = negExpr(makePolynom(Add{}, std::move(multiplicators))); + ArgumentPtr remainderAdd = negExpr(addExpr(std::move(multiplicators))); simplifyChild(remainderAdd); if (const ArgumentPtr remainderAddFirstChild = getPolynomChildren(Add{}, remainderAdd).front(); - compare(lhs, remainderAddFirstChild) != std::strong_ordering::greater) { + fintamath::compare(lhs, remainderAddFirstChild) != std::strong_ordering::greater) { return {}; } @@ -526,8 +526,8 @@ ArgumentPtr DivExpr::nestedNumeratorRationalSimplify(const ArgumentPtrVector &lh if (!denominatorChildren.empty()) { denominatorChildren.emplace_back(rhs); - ArgumentPtr numerator = makePolynom(Mul{}, std::move(numeratorChildren)); - ArgumentPtr denominator = makePolynom(Mul{}, std::move(denominatorChildren)); + ArgumentPtr numerator = mulExpr(std::move(numeratorChildren)); + ArgumentPtr denominator = mulExpr(std::move(denominatorChildren)); return divExpr(std::move(numerator), std::move(denominator)); } diff --git a/src/fintamath/expressions/binary/PowExpr.cpp b/src/fintamath/expressions/binary/PowExpr.cpp index 647f8bbe7..98ff6dde9 100644 --- a/src/fintamath/expressions/binary/PowExpr.cpp +++ b/src/fintamath/expressions/binary/PowExpr.cpp @@ -21,6 +21,7 @@ #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/comparison/MoreEqv.hpp" #include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/PowOper.hpp" #include "fintamath/functions/powers/Root.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/literals/Boolean.hpp" @@ -43,32 +44,8 @@ PowExpr::PowExpr(ArgumentPtr inLhsChild, ArgumentPtr inRhsChild) : IBinaryExpressionCRTP(Pow{}, std::move(inLhsChild), std::move(inRhsChild)) { } -std::string PowExpr::toString() const { - if (const auto rhsChildRat = cast(rhsChild)) { - const Integer &numerator = rhsChildRat->numerator(); - const Integer &denominator = rhsChildRat->denominator(); - - if (numerator == 1) { - if (denominator == 2) { - return functionToString(Sqrt{}, {lhsChild}); - } - - return functionToString(Root{}, {lhsChild, denominator.clone()}); - } - } - - if (const auto rhsChildExpr = cast(rhsChild); - rhsChildExpr && is
(rhsChildExpr->getFunction())) { - - if (*rhsChildExpr->getChildren().front() == Integer(1)) { - return functionToString(Root{}, {lhsChild, rhsChildExpr->getChildren().back()}); - } - } - - return IBinaryExpression::toString(); -} - const std::shared_ptr &PowExpr::getOutputFunction() const { + static const std::shared_ptr pow = std::make_shared(); static const std::shared_ptr sqrt = std::make_shared(); static const std::shared_ptr root = std::make_shared(); @@ -93,7 +70,21 @@ const std::shared_ptr &PowExpr::getOutputFunction() const { return root; } - return IBinaryExpression::getFunction(); + return pow; +} + +std::string PowExpr::toString() const { + const auto outFunc = getOutputFunction(); + + if (is(outFunc)) { + return functionToString(Sqrt{}, {lhsChild}); + } + + if (is(outFunc)) { + return functionToString(Root{}, {lhsChild, invert(rhsChild)}); + } + + return IBinaryExpression::toString(); } ArgumentPtr PowExpr::approximate() const { diff --git a/src/fintamath/expressions/binary/PowExpr.hpp b/src/fintamath/expressions/binary/PowExpr.hpp index d271c4dad..7345201fa 100644 --- a/src/fintamath/expressions/binary/PowExpr.hpp +++ b/src/fintamath/expressions/binary/PowExpr.hpp @@ -18,10 +18,10 @@ class PowExpr final : public IBinaryExpressionCRTP { public: explicit PowExpr(ArgumentPtr inLhsChild, ArgumentPtr inRhsChild); - std::string toString() const override; - const std::shared_ptr &getOutputFunction() const override; + std::string toString() const override; + protected: ArgumentPtr approximate() const override; diff --git a/src/fintamath/expressions/interfaces/IBinaryExpression.cpp b/src/fintamath/expressions/interfaces/IBinaryExpression.cpp index 650cfabd7..a03e319d8 100644 --- a/src/fintamath/expressions/interfaces/IBinaryExpression.cpp +++ b/src/fintamath/expressions/interfaces/IBinaryExpression.cpp @@ -23,11 +23,14 @@ IBinaryExpression::IBinaryExpression(const IFunction &inFunc, ArgumentPtr lhs, A } std::string IBinaryExpression::toString() const { - if (const auto oper = cast(func)) { - return binaryOperatorToString(*oper, lhsChild, rhsChild); + const auto &outFunc = getOutputFunction(); + const auto outOper = cast(outFunc); + + if (!outOper) { + return functionToString(*outFunc, {lhsChild, rhsChild}); } - return functionToString(*func, {lhsChild, rhsChild}); + return binaryOperatorToString(*outOper, lhsChild, rhsChild); } const std::shared_ptr &IBinaryExpression::getFunction() const { diff --git a/src/fintamath/expressions/interfaces/IPolynomExpression.cpp b/src/fintamath/expressions/interfaces/IPolynomExpression.cpp index 8773d2c32..abcc9c757 100644 --- a/src/fintamath/expressions/interfaces/IPolynomExpression.cpp +++ b/src/fintamath/expressions/interfaces/IPolynomExpression.cpp @@ -18,6 +18,7 @@ #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/IOperator.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" namespace fintamath { @@ -38,21 +39,29 @@ const ArgumentPtrVector &IPolynomExpression::getChildren() const { return children; } -std::string IPolynomExpression::toString() const { - const auto oper = cast(func); - if (!oper) { - return functionToString(*func, children); +void IPolynomExpression::setChildren(const ArgumentPtrVector &childVect) { + if (childVect.empty()) { + throw InvalidInputFunctionException(toString(), {}); } - std::string result; + children = childVect; +} - result += childToString(*oper, children.front(), {}); +std::string IPolynomExpression::toString() const { + const auto &outFunc = getOutputFunction(); + const auto outOper = cast(outFunc); + + if (!outOper) { + return functionToString(*outFunc, children); + } + + std::string result = childToString(*outOper, children.front(), {}); for (const auto i : stdv::iota(1U, children.size())) { - const std::string childStr = childToString(*oper, children[i], children[i - 1]); + const std::string childStr = childToString(*outOper, children[i], children[i - 1]); if (childStr.size() > 2 && childStr[0] == ' ' && std::isdigit(childStr[1]) && std::isdigit(result.back())) { - result += Mul{}.toString() + childStr.substr(1); + result += MulOper{}.toString() + childStr.substr(1); } else { result += childStr; @@ -197,15 +206,8 @@ IPolynomExpression::SimplifyFunctionVector IPolynomExpression::getFunctionsForPo std::string IPolynomExpression::childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const { const std::string childStr = operatorChildToString(oper, inChild); - return prevChild ? (putInSpaces(func->toString()) + childStr) : childStr; -} - -std::strong_ordering IPolynomExpression::compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const { - const ComparatorOptions options = { - .termOrderInversed = isTermOrderInversed(), - .comparableOrderInversed = isComparableOrderInversed(), - }; - return fintamath::compare(lhs, rhs, options); + const std::string operStr = prevChild ? putInSpaces(oper.toString()) : ""; + return operStr + childStr; } bool IPolynomExpression::isTermOrderInversed() const { @@ -216,12 +218,12 @@ bool IPolynomExpression::isComparableOrderInversed() const { return false; } -void IPolynomExpression::setChildren(const ArgumentPtrVector &childVect) { - if (childVect.empty()) { - throw InvalidInputFunctionException(toString(), {}); - } - - children = childVect; +std::strong_ordering IPolynomExpression::compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const { + const ComparatorOptions options = { + .termOrderInversed = isTermOrderInversed(), + .comparableOrderInversed = isComparableOrderInversed(), + }; + return fintamath::compare(lhs, rhs, options); } void IPolynomExpression::sort() { diff --git a/src/fintamath/expressions/interfaces/IUnaryExpression.cpp b/src/fintamath/expressions/interfaces/IUnaryExpression.cpp index eea6dd31f..e0b547f06 100644 --- a/src/fintamath/expressions/interfaces/IUnaryExpression.cpp +++ b/src/fintamath/expressions/interfaces/IUnaryExpression.cpp @@ -22,15 +22,18 @@ IUnaryExpression::IUnaryExpression(const IFunction &inFunc, ArgumentPtr rhs) } std::string IUnaryExpression::toString() const { - if (const auto oper = cast(func)) { - if (oper->getPriority() == IOperator::Priority::PostfixUnary) { - return detail::postfixUnaryOperatorToString(*oper, child); - } + const auto &outFunc = getOutputFunction(); + const auto outOper = cast(outFunc); + + if (!outOper) { + return functionToString(*outFunc, {child}); + } - return detail::prefixUnaryOperatorToString(*oper, child); + if (outOper->getPriority() == IOperator::Priority::PostfixUnary) { + return postfixUnaryOperatorToString(*outOper, child); } - return detail::functionToString(*func, {child}); + return prefixUnaryOperatorToString(*outOper, child); } const std::shared_ptr &IUnaryExpression::getFunction() const { diff --git a/src/fintamath/expressions/polynomial/AddExpr.cpp b/src/fintamath/expressions/polynomial/AddExpr.cpp index af2354d9c..0110192e2 100644 --- a/src/fintamath/expressions/polynomial/AddExpr.cpp +++ b/src/fintamath/expressions/polynomial/AddExpr.cpp @@ -16,6 +16,7 @@ #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/IOperator.hpp" #include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" @@ -39,6 +40,11 @@ AddExpr::AddExpr(ArgumentPtrVector inChildren) : IPolynomExpressionCRTP(Add{}, std::move(inChildren)) { } +const std::shared_ptr &AddExpr::getOutputFunction() const { + static const std::shared_ptr oper = std::make_shared(); + return oper; +} + std::string AddExpr::childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const { std::string result = operatorChildToString(oper, inChild); bool isChildNegated = false; @@ -53,7 +59,7 @@ std::string AddExpr::childToString(const IOperator &oper, const ArgumentPtr &inC std::string funcStr; if (isChildNegated) { - funcStr = Sub{}.toString(); + funcStr = Neg{}.toString(); } else if (prevChild) { funcStr = oper.toString(); diff --git a/src/fintamath/expressions/polynomial/AddExpr.hpp b/src/fintamath/expressions/polynomial/AddExpr.hpp index c9413a78f..5328b32f0 100644 --- a/src/fintamath/expressions/polynomial/AddExpr.hpp +++ b/src/fintamath/expressions/polynomial/AddExpr.hpp @@ -20,6 +20,8 @@ class AddExpr final : public IPolynomExpressionCRTP { public: explicit AddExpr(ArgumentPtrVector inChildren); + const std::shared_ptr &getOutputFunction() const override; + protected: SimplifyFunctionVector getFunctionsForPreSimplify() const override; @@ -27,15 +29,6 @@ class AddExpr final : public IPolynomExpressionCRTP { std::string childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const override; - /** - * @brief - * - * @param lhs - * @param rhs - * @return -1 if we should swap the arguments - * @return 1 if we should not swap the arguments - * @return 0 if this comparator fails - */ std::strong_ordering compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const override; private: diff --git a/src/fintamath/expressions/polynomial/AndExpr.cpp b/src/fintamath/expressions/polynomial/AndExpr.cpp index d3e70d7c7..3f7dc5bab 100644 --- a/src/fintamath/expressions/polynomial/AndExpr.cpp +++ b/src/fintamath/expressions/polynomial/AndExpr.cpp @@ -8,6 +8,7 @@ #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/logic/And.hpp" +#include "fintamath/functions/logic/AndOper.hpp" #include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/logic/Or.hpp" #include "fintamath/literals/Boolean.hpp" @@ -18,6 +19,11 @@ AndExpr::AndExpr(ArgumentPtrVector inChildren) : IPolynomExpressionCRTP(And{}, std::move(inChildren)) { } +const std::shared_ptr &AndExpr::getOutputFunction() const { + static const std::shared_ptr oper = std::make_shared(); + return oper; +} + AndExpr::SimplifyFunctionVector AndExpr::getFunctionsForPreSimplify() const { static const SimplifyFunctionVector simplifyFunctions = { &AndExpr::boolSimplify, @@ -62,10 +68,10 @@ ArgumentPtr AndExpr::equalSimplify(const IFunction & /*func*/, const ArgumentPtr } ArgumentPtr AndExpr::notSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { - if (const auto rhsExpr = cast(rhs); - rhsExpr && - is(rhsExpr->getFunction()) && - *rhsExpr->getChildren().front() == *lhs) { + if (const auto lhsExpr = cast(lhs); + lhsExpr && + is(lhsExpr->getFunction()) && + *lhsExpr->getChildren().front() == *rhs) { return Boolean(false).clone(); } diff --git a/src/fintamath/expressions/polynomial/AndExpr.hpp b/src/fintamath/expressions/polynomial/AndExpr.hpp index fe19e63a2..27fcab081 100644 --- a/src/fintamath/expressions/polynomial/AndExpr.hpp +++ b/src/fintamath/expressions/polynomial/AndExpr.hpp @@ -13,6 +13,8 @@ class AndExpr final : public IPolynomExpressionCRTP { public: explicit AndExpr(ArgumentPtrVector inChildren); + const std::shared_ptr &getOutputFunction() const override; + protected: SimplifyFunctionVector getFunctionsForPreSimplify() const override; diff --git a/src/fintamath/expressions/polynomial/MulExpr.cpp b/src/fintamath/expressions/polynomial/MulExpr.cpp index 3dedd03bc..69e7bd2cf 100644 --- a/src/fintamath/expressions/polynomial/MulExpr.cpp +++ b/src/fintamath/expressions/polynomial/MulExpr.cpp @@ -14,6 +14,7 @@ #include "fintamath/functions/arithmetic/Add.hpp" #include "fintamath/functions/arithmetic/Div.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sign.hpp" #include "fintamath/functions/logarithms/Log.hpp" @@ -35,6 +36,15 @@ MulExpr::MulExpr(ArgumentPtrVector inChildren) : IPolynomExpressionCRTP(Mul{}, std::move(inChildren)) { } +const std::shared_ptr &MulExpr::getOutputFunction() const { + static const std::shared_ptr oper = std::make_shared(); + return oper; +} + +bool MulExpr::isTermOrderInversed() const { + return true; +} + std::string MulExpr::toString() const { auto [childNumerator, childDenominator] = splitRational(children.front()); @@ -51,7 +61,7 @@ std::string MulExpr::toString() const { numeratorChildren.front() = childNumerator; } - ArgumentPtr numerator = makePolynom(Mul{}, std::move(numeratorChildren)); + ArgumentPtr numerator = mulExpr(std::move(numeratorChildren)); ArgumentPtr denominator = childDenominator; const ArgumentPtr res = divExpr(std::move(numerator), std::move(denominator)); @@ -105,10 +115,6 @@ MulExpr::SimplifyFunctionVector MulExpr::getFunctionsForPostSimplify() const { return simplifyFunctions; } -bool MulExpr::isTermOrderInversed() const { - return true; -} - ArgumentPtr MulExpr::constSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { if (*lhs == Integer(0)) { if (isMulInfinity(rhs)) { diff --git a/src/fintamath/expressions/polynomial/MulExpr.hpp b/src/fintamath/expressions/polynomial/MulExpr.hpp index f31aede8b..01628d9f3 100644 --- a/src/fintamath/expressions/polynomial/MulExpr.hpp +++ b/src/fintamath/expressions/polynomial/MulExpr.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "fintamath/core/MathObjectClass.hpp" @@ -16,6 +17,8 @@ class MulExpr final : public IPolynomExpressionCRTP { std::string toString() const override; + const std::shared_ptr &getOutputFunction() const override; + protected: std::string childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const override; diff --git a/src/fintamath/expressions/polynomial/OrExpr.cpp b/src/fintamath/expressions/polynomial/OrExpr.cpp index 3fd2bbe34..db9332a77 100644 --- a/src/fintamath/expressions/polynomial/OrExpr.cpp +++ b/src/fintamath/expressions/polynomial/OrExpr.cpp @@ -14,6 +14,7 @@ #include "fintamath/functions/logic/And.hpp" #include "fintamath/functions/logic/Not.hpp" #include "fintamath/functions/logic/Or.hpp" +#include "fintamath/functions/logic/OrOper.hpp" #include "fintamath/literals/Boolean.hpp" namespace fintamath { @@ -21,54 +22,24 @@ namespace fintamath { using namespace detail; OrExpr::OrExpr(ArgumentPtrVector inChildren) - : IPolynomExpressionCRTP(Or{}, std::move(inChildren)) { + : IPolynomExpressionCRTP(Or{}, std::move(inChildren)) { +} + +const std::shared_ptr &OrExpr::getOutputFunction() const { + static const std::shared_ptr oper = std::make_shared(); + return oper; } std::string OrExpr::childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const { std::string result = operatorChildToString(oper, inChild); if (const auto &childExpr = cast(inChild); - childExpr && is(childExpr->getFunction())) { + childExpr && is(childExpr->getFunction())) { result = putInBrackets(result); } - return prevChild ? (putInSpaces(func->toString()) + result) : result; -} - -ArgumentPtr OrExpr::postSimplify() const { - ArgumentPtr simplObj = IPolynomExpression::postSimplify(); - auto simpl = cast(simplObj); - - if (!simpl) { - return simplObj; - } - - ArgumentPtrVector simplChildren = simpl->children; - const size_t simplChildrenSizeInitial = simplChildren.size(); - - // TODO: use more efficient algorithm - for (size_t i = 0; i + 1 < simplChildren.size(); i++) { - for (size_t j = i + 1; j < simplChildren.size(); j++) { - if (auto res = absorptionSimplify(simplChildren[i], simplChildren[j])) { - simplChildren[i] = std::move(res); - simplChildren.erase(simplChildren.begin() + static_cast(j)); - j--; - } - } - } - - if (simplChildren.size() != simplChildrenSizeInitial) { - if (simplChildren.size() > 1) { - ArgumentPtr res = orExpr(std::move(simplChildren)); - postSimplifyChild(res); - return res; - } - - return simplChildren.front(); - } - - return simpl; + return (prevChild ? putInSpaces(getOutputFunction()->toString()) : "") + result; } OrExpr::SimplifyFunctionVector OrExpr::getFunctionsForPreSimplify() const { @@ -86,6 +57,7 @@ OrExpr::SimplifyFunctionVector OrExpr::getFunctionsForPostSimplify() const { &OrExpr::notSimplify, &OrExpr::boolSimplify, &OrExpr::equalSimplify, + &OrExpr::absorptionSimplify, }; return simplifyFunctions; } @@ -116,10 +88,10 @@ ArgumentPtr OrExpr::equalSimplify(const IFunction & /*func*/, const ArgumentPtr } ArgumentPtr OrExpr::notSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { - if (const auto rhsExpr = cast(rhs); - rhsExpr && - is(rhsExpr->getFunction()) && - *rhsExpr->getChildren().front() == *lhs) { + if (const auto lhsExpr = cast(lhs); + lhsExpr && + is(lhsExpr->getFunction()) && + *lhsExpr->getChildren().front() == *rhs) { return Boolean(true).clone(); } @@ -152,8 +124,8 @@ ArgumentPtr OrExpr::andSimplify(const IFunction & /*func*/, const ArgumentPtr &l bool isLhsSubChildNot = false; if (const auto lhsSubChildNotExpr = cast(lhsSubChild); - lhsSubChildNotExpr && - is(lhsSubChildNotExpr->getFunction())) { + lhsSubChildNotExpr && + is(lhsSubChildNotExpr->getFunction())) { isLhsSubChildNot = true; lhsSubChild = lhsSubChildNotExpr->getChildren().front(); @@ -162,8 +134,8 @@ ArgumentPtr OrExpr::andSimplify(const IFunction & /*func*/, const ArgumentPtr &l bool isRhsSubChildNot = false; if (const auto rhsSubChildNotExpr = cast(rhsSubChild); - rhsSubChildNotExpr && - is(rhsSubChildNotExpr->getFunction())) { + rhsSubChildNotExpr && + is(rhsSubChildNotExpr->getFunction())) { isRhsSubChildNot = true; rhsSubChild = rhsSubChildNotExpr->getChildren().front(); @@ -197,7 +169,7 @@ ArgumentPtr OrExpr::andSimplify(const IFunction & /*func*/, const ArgumentPtr &l return resultChildren.front(); } -ArgumentPtr OrExpr::absorptionSimplify(const ArgumentPtr &lhs, const ArgumentPtr &rhs) { +ArgumentPtr OrExpr::absorptionSimplify(const IFunction & /*func*/, const ArgumentPtr &lhs, const ArgumentPtr &rhs) { const auto lhsExpr = cast(lhs); const auto rhsExpr = cast(rhs); @@ -252,4 +224,4 @@ ArgumentPtr OrExpr::absorptionSimplify(const ArgumentPtr &lhs, const ArgumentPtr return {}; } -} +} \ No newline at end of file diff --git a/src/fintamath/expressions/polynomial/OrExpr.hpp b/src/fintamath/expressions/polynomial/OrExpr.hpp index 0c12762cb..e1563636e 100644 --- a/src/fintamath/expressions/polynomial/OrExpr.hpp +++ b/src/fintamath/expressions/polynomial/OrExpr.hpp @@ -15,11 +15,11 @@ class OrExpr final : public IPolynomExpressionCRTP { public: explicit OrExpr(ArgumentPtrVector inChildren); + const std::shared_ptr &getOutputFunction() const override; + protected: std::string childToString(const IOperator &oper, const ArgumentPtr &inChild, const ArgumentPtr &prevChild) const override; - ArgumentPtr postSimplify() const override; - SimplifyFunctionVector getFunctionsForPreSimplify() const override; SimplifyFunctionVector getFunctionsForPostSimplify() const override; @@ -35,7 +35,7 @@ class OrExpr final : public IPolynomExpressionCRTP { static ArgumentPtr andSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); - static ArgumentPtr absorptionSimplify(const ArgumentPtr &lhs, const ArgumentPtr &rhs); + static ArgumentPtr absorptionSimplify(const IFunction &func, const ArgumentPtr &lhs, const ArgumentPtr &rhs); }; } \ No newline at end of file diff --git a/src/fintamath/expressions/unary/InvTrigExpr.cpp b/src/fintamath/expressions/unary/InvTrigExpr.cpp index 611e9307a..eb2ef30f0 100644 --- a/src/fintamath/expressions/unary/InvTrigExpr.cpp +++ b/src/fintamath/expressions/unary/InvTrigExpr.cpp @@ -12,6 +12,7 @@ #include "fintamath/functions/FunctionArguments.hpp" #include "fintamath/functions/IFunction.hpp" #include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/powers/Pow.hpp" #include "fintamath/functions/powers/Sqrt.hpp" #include "fintamath/functions/trigonometry/Acos.hpp" #include "fintamath/functions/trigonometry/Acot.hpp" @@ -46,18 +47,18 @@ InvTrigExpr::SimplifyFunctionVector InvTrigExpr::getFunctionsForPostSimplify() c ArgumentPtr InvTrigExpr::constSimplify(const IFunction &func, const ArgumentPtr &rhs) { if (const auto rat = convert(*rhs)) { const Rational sqr = pow(*rat, 2) * rat->sign(); - return TrigTableSimplify(func, sqr); + return trigTableSimplify(func, sqr); } if (const auto expr = cast(rhs)) { - if (is(expr->getOutputFunction())) { + if (is(expr->getFunction()) && *expr->getChildren().back() == Rational(1, 2)) { if (const auto sqrtChildInt = cast(expr->getChildren().front())) { const Rational sqr = (*sqrtChildInt); - return TrigTableSimplify(func, sqr); + return trigTableSimplify(func, sqr); } } - if (is(expr->getOutputFunction())) { + if (is(expr->getFunction())) { const auto childRat = convert(*expr->getChildren().front()); const auto childExpr = cast(expr->getChildren().back()); @@ -66,7 +67,7 @@ ArgumentPtr InvTrigExpr::constSimplify(const IFunction &func, const ArgumentPtr if (const auto sqrtChildInt = cast(childExpr->getChildren().front())) { const Rational sqr = pow(*childRat, 2) * (*sqrtChildInt) * childRat->sign(); - return TrigTableSimplify(func, sqr); + return trigTableSimplify(func, sqr); } } } @@ -75,7 +76,7 @@ ArgumentPtr InvTrigExpr::constSimplify(const IFunction &func, const ArgumentPtr return {}; } -ArgumentPtr InvTrigExpr::TrigTableSimplify(const IFunction &func, const Rational &rhs) { +ArgumentPtr InvTrigExpr::trigTableSimplify(const IFunction &func, const Rational &rhs) { static const NameToSimplifyFunctionMap nameToSimplifyFunctionMap = { {Asin{}.toString(), &TrigTableAsinSimplify}, {Acos{}.toString(), &TrigTableAcosSimplify}, diff --git a/src/fintamath/expressions/unary/InvTrigExpr.hpp b/src/fintamath/expressions/unary/InvTrigExpr.hpp index df8f0f5ae..53a187686 100644 --- a/src/fintamath/expressions/unary/InvTrigExpr.hpp +++ b/src/fintamath/expressions/unary/InvTrigExpr.hpp @@ -21,7 +21,7 @@ class InvTrigExpr final : public IUnaryExpressionCRTP { private: static ArgumentPtr constSimplify(const IFunction &func, const ArgumentPtr &rhs); - static ArgumentPtr TrigTableSimplify(const IFunction &func, const Rational &rhs); + static ArgumentPtr trigTableSimplify(const IFunction &func, const Rational &rhs); static ArgumentPtr TrigTableAsinSimplify(const Rational &rhs); diff --git a/src/fintamath/expressions/unary/TrigExpr.cpp b/src/fintamath/expressions/unary/TrigExpr.cpp index b0cf0fdd1..ff984dfc1 100644 --- a/src/fintamath/expressions/unary/TrigExpr.cpp +++ b/src/fintamath/expressions/unary/TrigExpr.cpp @@ -127,11 +127,11 @@ ArgumentPtr TrigExpr::negSimplify(const IFunction &func, const ArgumentPtr &rhs) ArgumentPtr TrigExpr::constSimplify(const IFunction &func, const ArgumentPtr &rhs) { if (*rhs == Pi{}) { - return TrigTableSimplify(func, 1); + return trigTableSimplify(func, 1); } if (*rhs == *negExpr(Pi{})) { - return TrigTableSimplify(func, -1); + return trigTableSimplify(func, -1); } const auto rhsExpr = cast(rhs); @@ -149,13 +149,13 @@ ArgumentPtr TrigExpr::constSimplify(const IFunction &func, const ArgumentPtr &rh return {}; } - return TrigTableSimplify(func, *rhsChildRat); + return trigTableSimplify(func, *rhsChildRat); } -ArgumentPtr TrigExpr::TrigTableSimplify(const IFunction &func, const Rational &rhs) { +ArgumentPtr TrigExpr::trigTableSimplify(const IFunction &func, const Rational &rhs) { static const NameToTrigFunctionMap nameToTrigFunctionMap = { - {Sin{}.toString(), &TrigTableSinSimplify}, - {Cos{}.toString(), &TrigTableCosSimplify}, + {Sin{}.toString(), &trigTableSinSimplify}, + {Cos{}.toString(), &trigTableCosSimplify}, }; if (const auto iter = nameToTrigFunctionMap.find(func.toString()); iter != nameToTrigFunctionMap.end()) { @@ -166,7 +166,7 @@ ArgumentPtr TrigExpr::TrigTableSimplify(const IFunction &func, const Rational &r return {}; } -ArgumentPtr TrigExpr::TrigTableSinSimplify(const Rational &rhs) { +ArgumentPtr TrigExpr::trigTableSinSimplify(const Rational &rhs) { static const TrigTable trigTable = { {Rational(0), Integer(0).clone()}, // 0 | 0 {Rational(1, 6), Rational(1, 2).clone()}, // π/6 | 1/2 @@ -182,7 +182,7 @@ ArgumentPtr TrigExpr::TrigTableSinSimplify(const Rational &rhs) { return findValue(trigTable, rhsShifted, isNegated); } -ArgumentPtr TrigExpr::TrigTableCosSimplify(const Rational &rhs) { +ArgumentPtr TrigExpr::trigTableCosSimplify(const Rational &rhs) { static const TrigTable trigTable = { {Rational(0), Integer(1).clone()}, // 0 | 1 {Rational(1, 6), mulExpr(Rational(1, 2).clone(), sqrtExpr(Integer(3)))}, // π/6 | √3/2 diff --git a/src/fintamath/expressions/unary/TrigExpr.hpp b/src/fintamath/expressions/unary/TrigExpr.hpp index 6affab39e..aee3ea448 100644 --- a/src/fintamath/expressions/unary/TrigExpr.hpp +++ b/src/fintamath/expressions/unary/TrigExpr.hpp @@ -32,11 +32,11 @@ class TrigExpr final : public IUnaryExpressionCRTP { static ArgumentPtr constSimplify(const IFunction &func, const ArgumentPtr &rhs); - static ArgumentPtr TrigTableSimplify(const IFunction &func, const Rational &rhs); + static ArgumentPtr trigTableSimplify(const IFunction &func, const Rational &rhs); - static ArgumentPtr TrigTableSinSimplify(const Rational &rhs); + static ArgumentPtr trigTableSinSimplify(const Rational &rhs); - static ArgumentPtr TrigTableCosSimplify(const Rational &rhs); + static ArgumentPtr trigTableCosSimplify(const Rational &rhs); static std::tuple phaseShiftSin(const Rational &rhs); diff --git a/src/fintamath/functions/IFunction.cpp b/src/fintamath/functions/IFunction.cpp index a85518b1b..4ada3680b 100644 --- a/src/fintamath/functions/IFunction.cpp +++ b/src/fintamath/functions/IFunction.cpp @@ -10,18 +10,4 @@ namespace fintamath { FINTAMATH_PARENT_CLASS_IMPLEMENTATION(IFunction) -void IFunction::validateArgsSize(const ArgumentRefVector &argVect) const { - if (!argVect.empty() && (getArgumentClasses().size() == argVect.size() || isVariadic())) { - return; - } - - std::vector argNameVect(argVect.size()); - - for (const auto i : stdv::iota(0U, argNameVect.size())) { - argNameVect[i] = argVect[i].get().toString(); - } - - throw InvalidInputFunctionException(toString(), argNameVect); -} - } diff --git a/src/fintamath/functions/arithmetic/Add.cpp b/src/fintamath/functions/arithmetic/Add.cpp index 3b67b7c9f..418b8bd57 100644 --- a/src/fintamath/functions/arithmetic/Add.cpp +++ b/src/fintamath/functions/arithmetic/Add.cpp @@ -10,10 +10,13 @@ namespace fintamath { std::unique_ptr Add::call(const ArgumentRefVector &argVect) const { - const auto &lhs = cast(argVect.front().get()); - const auto &rhs = cast(argVect.back().get()); + auto res = cast(argVect.front().get().clone()); - return lhs + rhs; + for (const auto &arg : argVect | stdv::drop(1)) { + res = *res + cast(arg.get()); + } + + return res; } } diff --git a/src/fintamath/functions/arithmetic/AddOper.cpp b/src/fintamath/functions/arithmetic/AddOper.cpp new file mode 100644 index 000000000..92e639c88 --- /dev/null +++ b/src/fintamath/functions/arithmetic/AddOper.cpp @@ -0,0 +1,15 @@ +#include "fintamath/functions/arithmetic/AddOper.hpp" + +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/arithmetic/Add.hpp" + +namespace fintamath { + +std::unique_ptr AddOper::call(const ArgumentRefVector &argVect) const { + return Add{}(argVect); +} + +} diff --git a/src/fintamath/functions/arithmetic/Mul.cpp b/src/fintamath/functions/arithmetic/Mul.cpp index 5661abf75..d9c70fa05 100644 --- a/src/fintamath/functions/arithmetic/Mul.cpp +++ b/src/fintamath/functions/arithmetic/Mul.cpp @@ -10,10 +10,13 @@ namespace fintamath { std::unique_ptr Mul::call(const ArgumentRefVector &argVect) const { - const auto &lhs = cast(argVect.front().get()); - const auto &rhs = cast(argVect.back().get()); + auto res = cast(argVect.front().get().clone()); - return lhs * rhs; + for (const auto &arg : argVect | stdv::drop(1)) { + res = *res * cast(arg.get()); + } + + return res; } } diff --git a/src/fintamath/functions/arithmetic/MulOper.cpp b/src/fintamath/functions/arithmetic/MulOper.cpp new file mode 100644 index 000000000..251e9e449 --- /dev/null +++ b/src/fintamath/functions/arithmetic/MulOper.cpp @@ -0,0 +1,15 @@ +#include "fintamath/functions/arithmetic/MulOper.hpp" + +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/arithmetic/Mul.hpp" + +namespace fintamath { + +std::unique_ptr MulOper::call(const ArgumentRefVector &argVect) const { + return Mul{}(argVect); +} + +} diff --git a/src/fintamath/functions/logic/And.cpp b/src/fintamath/functions/logic/And.cpp index ea06c8073..a1b95f966 100644 --- a/src/fintamath/functions/logic/And.cpp +++ b/src/fintamath/functions/logic/And.cpp @@ -10,10 +10,13 @@ namespace fintamath { std::unique_ptr And::call(const ArgumentRefVector &argVect) const { - const auto &lhs = cast(argVect.front().get()); - const auto &rhs = cast(argVect.back().get()); + auto res = cast(argVect.front().get()); - return Boolean(lhs && rhs).clone(); + for (const auto &arg : argVect | stdv::drop(1)) { + res = res && cast(arg.get()); + } + + return res.clone(); } } diff --git a/src/fintamath/functions/logic/AndOper.cpp b/src/fintamath/functions/logic/AndOper.cpp new file mode 100644 index 000000000..a3672043d --- /dev/null +++ b/src/fintamath/functions/logic/AndOper.cpp @@ -0,0 +1,15 @@ +#include "fintamath/functions/logic/AndOper.hpp" + +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/logic/And.hpp" + +namespace fintamath { + +std::unique_ptr AndOper::call(const ArgumentRefVector &argVect) const { + return And{}(argVect); +} + +} diff --git a/src/fintamath/functions/logic/Or.cpp b/src/fintamath/functions/logic/Or.cpp index d460896a1..aec3ef402 100644 --- a/src/fintamath/functions/logic/Or.cpp +++ b/src/fintamath/functions/logic/Or.cpp @@ -10,10 +10,13 @@ namespace fintamath { std::unique_ptr Or::call(const ArgumentRefVector &argVect) const { - const auto &lhs = cast(argVect.front().get()); - const auto &rhs = cast(argVect.back().get()); + auto res = cast(argVect.front().get()); - return Boolean(lhs || rhs).clone(); + for (const auto &arg : argVect | stdv::drop(1)) { + res = res || cast(arg.get()); + } + + return res.clone(); } } diff --git a/src/fintamath/functions/logic/OrOper.cpp b/src/fintamath/functions/logic/OrOper.cpp new file mode 100644 index 000000000..df3f81766 --- /dev/null +++ b/src/fintamath/functions/logic/OrOper.cpp @@ -0,0 +1,15 @@ +#include "fintamath/functions/logic/OrOper.hpp" + +#include + +#include "fintamath/core/IMathObject.hpp" +#include "fintamath/functions/FunctionArguments.hpp" +#include "fintamath/functions/logic/Or.hpp" + +namespace fintamath { + +std::unique_ptr OrOper::call(const ArgumentRefVector &argVect) const { + return Or{}(argVect); +} + +} diff --git a/src/fintamath/functions/powers/PowFunction.cpp b/src/fintamath/functions/powers/PowOper.cpp similarity index 60% rename from src/fintamath/functions/powers/PowFunction.cpp rename to src/fintamath/functions/powers/PowOper.cpp index 2cb0dd7dc..89cab9859 100644 --- a/src/fintamath/functions/powers/PowFunction.cpp +++ b/src/fintamath/functions/powers/PowOper.cpp @@ -1,4 +1,4 @@ -#include "fintamath/functions/powers/PowFunction.hpp" +#include "fintamath/functions/powers/PowOper.hpp" #include @@ -8,7 +8,7 @@ namespace fintamath { -std::unique_ptr PowFunction::call(const ArgumentRefVector &argVect) const { +std::unique_ptr PowOper::call(const ArgumentRefVector &argVect) const { return Pow{}(argVect); } diff --git a/tests/src/FintamathTests.cpp b/tests/src/FintamathTests.cpp index 1ced8cacf..68d47c46a 100644 --- a/tests/src/FintamathTests.cpp +++ b/tests/src/FintamathTests.cpp @@ -67,7 +67,7 @@ TEST(FintamathTests, fintamathTest) { EXPECT_EQ(expr.toString(), "-0.039790759931157709524"); expr = Expression("~a & b | ~c -> a <-> b !<-> c"); - EXPECT_EQ(expr.toString(), "(a & b & ~c) | (~a & ~b & ~c) | (~a & c) | (~b & c)"); + EXPECT_EQ(expr.toString(), "(~a & ~b & ~c) | (~a & c) | (a & b & ~c) | (~b & c)"); //-------------------------------------------------------------------------------------// diff --git a/tests/src/core/ParserTests.cpp b/tests/src/core/ParserTests.cpp index 50d5ee4e2..7369e8a20 100644 --- a/tests/src/core/ParserTests.cpp +++ b/tests/src/core/ParserTests.cpp @@ -4,7 +4,7 @@ #include "fintamath/expressions/Expression.hpp" #include "fintamath/functions/IFunction.hpp" -#include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/literals/constants/E.hpp" #include "fintamath/numbers/INumber.hpp" #include "fintamath/numbers/Integer.hpp" @@ -51,7 +51,7 @@ TEST(ParserTests, parseRvalueTest) { TEST(ParserTests, parseFirstTest) { EXPECT_EQ(IMathObject::parseFirst("123").value()->getClass(), Integer::getClassStatic()); - EXPECT_EQ(IMathObject::parseFirst("+").value()->getClass(), Add::getClassStatic()); + EXPECT_EQ(IMathObject::parseFirst("+").value()->getClass(), AddOper::getClassStatic()); EXPECT_EQ(IMathObject::parseFirst("E").value()->getClass(), E::getClassStatic()); EXPECT_EQ(IMathObject::parseFirst("1+1").value()->getClass(), Expression::getClassStatic()); EXPECT_FALSE(IMathObject::parseFirst("1*)")); diff --git a/tests/src/expressions/ExpressionComparatorTests.cpp b/tests/src/expressions/ExpressionComparatorTests.cpp index a018920c1..78209c2fa 100644 --- a/tests/src/expressions/ExpressionComparatorTests.cpp +++ b/tests/src/expressions/ExpressionComparatorTests.cpp @@ -1,20 +1,35 @@ #include -#include "fintamath/expressions/Expression.hpp" #include "fintamath/expressions/ExpressionComparator.hpp" +#include "fintamath/expressions/Expression.hpp" +#include "fintamath/expressions/ExpressionParser.hpp" + using namespace fintamath; using namespace detail; TEST(ExpressionComparatorTests, comparatorTest) { - EXPECT_EQ(compare(Variable("a").clone(), Expression("a").clone()), std::strong_ordering::equal); - EXPECT_EQ(compare(Expression("a").clone(), Expression("a").clone()), std::strong_ordering::equal); - EXPECT_EQ(compare(Integer(2).clone(), Expression("2 a").clone()), std::strong_ordering::less); + EXPECT_EQ(compare({}, {}), std::strong_ordering::equal); + EXPECT_EQ(compare({}, Integer(2).clone()), std::strong_ordering::less); + EXPECT_EQ(compare(Integer(2).clone(), {}), std::strong_ordering::greater); + + EXPECT_EQ(compare(Integer(2).clone(), Integer(2).clone()), std::strong_ordering::equal); + EXPECT_EQ(compare(Integer(2).clone(), Expression(2).clone()), std::strong_ordering::equal); EXPECT_EQ(compare(Integer(2).clone(), Expression("2 a").clone()), std::strong_ordering::less); + + EXPECT_EQ(compare(Variable("a").clone(), Variable("a").clone()), std::strong_ordering::equal); + EXPECT_EQ(compare(Variable("a").clone(), Expression("a").clone()), std::strong_ordering::equal); EXPECT_EQ(compare(Variable("a").clone(), Expression("a b").clone()), std::strong_ordering::less); EXPECT_EQ(compare(Variable("a").clone(), Expression("a + b").clone()), std::strong_ordering::less); + + EXPECT_EQ(compare(Expression("a").clone(), Expression("a").clone()), std::strong_ordering::equal); EXPECT_EQ(compare(Expression("a^b").clone(), Expression("a b c").clone()), std::strong_ordering::greater); - EXPECT_EQ(compare(Expression("x^x ln(x)").clone(), Expression("x^x").clone()), std::strong_ordering::greater); + EXPECT_EQ(compare(Expression("x^x").clone(), Expression("x^y").clone()), std::strong_ordering::greater); + + EXPECT_EQ(compare(parseExpr("sqrt(11)"), parseExpr("root(2022369065670411386760301914510907000742418, 4)")), std::strong_ordering::greater); + EXPECT_EQ(compare(parseExpr("x^x ln(x)"), parseExpr("x^x")), std::strong_ordering::greater); + EXPECT_EQ(compare(parseExpr("~a & c"), parseExpr("a & b & ~c")), std::strong_ordering::greater); - // TODO: add more tests -} + EXPECT_EQ(compare(parseExpr("x"), parseExpr("ln(x)"), {.termOrderInversed = false}), std::strong_ordering::less); + EXPECT_EQ(compare(parseExpr("x"), parseExpr("ln(x)"), {.termOrderInversed = true}), std::strong_ordering::greater); +} \ No newline at end of file diff --git a/tests/src/expressions/ExpressionFunctionsTests.cpp b/tests/src/expressions/ExpressionFunctionsTests.cpp index bfd154f17..fee472f95 100644 --- a/tests/src/expressions/ExpressionFunctionsTests.cpp +++ b/tests/src/expressions/ExpressionFunctionsTests.cpp @@ -288,7 +288,7 @@ TEST(ExpressionFunctionsTests, derivativeTest) { EXPECT_EQ(derivative(Expression("a"), Expression("a")).toString(), "1"); EXPECT_EQ(derivative(Expression("(a+5)"), Expression("a")).toString(), "1"); EXPECT_EQ(derivative(Expression("sin(a^2)"), Expression("a")).toString(), "2 a cos(a^2)"); - EXPECT_EQ(derivative(Expression("(ln(a)/tan(a))^(1/2)"), Expression("a")).toString(), "-(sqrt(cot(a) ln(a)) csc(a)^2 tan(a))/2 + sqrt(cot(a) ln(a))/(2 a ln(a))"); + EXPECT_EQ(derivative(Expression("(ln(a)/tan(a))^(1/2)"), Expression("a")).toString(), "-(csc(a)^2 sqrt(ln(a) cot(a)) tan(a))/2 + sqrt(ln(a) cot(a))/(2 a ln(a))"); } TEST(ExpressionFunctionsTests, notTest) { diff --git a/tests/src/expressions/ExpressionUtilsTests.cpp b/tests/src/expressions/ExpressionUtilsTests.cpp index ed30240ee..59c62c37f 100644 --- a/tests/src/expressions/ExpressionUtilsTests.cpp +++ b/tests/src/expressions/ExpressionUtilsTests.cpp @@ -121,10 +121,6 @@ TEST(ExpressionUtilsTests, isNegativeNumberTest) { // TODO: implement } -TEST(ExpressionUtilsTests, makePolynomTest) { - // TODO: implement -} - TEST(ExpressionUtilsTests, negateTest) { // TODO: implement } diff --git a/tests/src/expressions/interfaces/IBinaryExpressionTests.cpp b/tests/src/expressions/interfaces/IBinaryExpressionTests.cpp index 581d1dc8d..074676a28 100644 --- a/tests/src/expressions/interfaces/IBinaryExpressionTests.cpp +++ b/tests/src/expressions/interfaces/IBinaryExpressionTests.cpp @@ -2,11 +2,11 @@ #include "fintamath/expressions/interfaces/IBinaryExpression.hpp" -#include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" using namespace fintamath; -const Add f; +const AddOper f; namespace { diff --git a/tests/src/expressions/interfaces/IPolynomExpressionTests.cpp b/tests/src/expressions/interfaces/IPolynomExpressionTests.cpp index 8478c8000..a34463ea5 100644 --- a/tests/src/expressions/interfaces/IPolynomExpressionTests.cpp +++ b/tests/src/expressions/interfaces/IPolynomExpressionTests.cpp @@ -33,10 +33,10 @@ TEST(IPolynomExpressionTests, parseTest) { TEST(IPolynomExpressionTests, toStringTest) { TestPolynomExpression expr({Integer(1).clone(), Integer(2).clone(), Integer(3).clone()}); - EXPECT_EQ(expr.toString(), "1 * 2 * 3"); + EXPECT_EQ(expr.toString(), "mul(1, 2, 3)"); expr = TestPolynomExpression({addExpr(Variable("x"), Variable("y")), Variable("a").clone()}); - EXPECT_EQ(expr.toString(), "(x + y) * a"); + EXPECT_EQ(expr.toString(), "mul(x + y, a)"); } TEST(IPolynomExpressionTests, getFunctionTest) { @@ -75,7 +75,7 @@ TEST(IPolynomExpressionTests, setChildren) { TEST(IPolynomExpressionTests, toMinimalObjectTest) { const TestPolynomExpression expr({Integer(1).clone(), Integer(2).clone(), Variable("a").clone()}); - EXPECT_EQ(expr.toMinimalObject()->toString(), "a * 2"); + EXPECT_EQ(expr.toMinimalObject()->toString(), "mul(a, 2)"); } TEST(IPolynomExpressionTests, getClassTest) { diff --git a/tests/src/functions/FunctionUtilsTests.cpp b/tests/src/functions/FunctionUtilsTests.cpp index 092b761cb..9628f4914 100644 --- a/tests/src/functions/FunctionUtilsTests.cpp +++ b/tests/src/functions/FunctionUtilsTests.cpp @@ -5,7 +5,7 @@ #include "fintamath/expressions/IExpression.hpp" #include "fintamath/functions/arithmetic/Add.hpp" -#include "fintamath/functions/arithmetic/Mul.hpp" +#include "fintamath/functions/arithmetic/MulOper.hpp" #include "fintamath/functions/powers/Pow.hpp" #include "fintamath/functions/trigonometry/Cos.hpp" #include "fintamath/literals/Variable.hpp" @@ -27,10 +27,10 @@ TEST(FunctionUtilsTests, makeExpressionPtrsTest) { EXPECT_EQ(expr2->toString(), "cos(a)"); EXPECT_TRUE(is(expr2)); - EXPECT_THROW(makeExpr(Mul(), ArgumentPtrVector{var})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Mul(), ArgumentPtrVector{})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Pow(), ArgumentPtrVector{var})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Pow(), ArgumentPtrVector{})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentPtrVector{var})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentPtrVector{})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentPtrVector{var})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentPtrVector{})->toString(), InvalidInputException); } TEST(FunctionUtilsTests, makeExpressionRefsTest) { @@ -45,10 +45,10 @@ TEST(FunctionUtilsTests, makeExpressionRefsTest) { EXPECT_EQ(expr2->toString(), "cos(a)"); EXPECT_TRUE(is(expr2)); - EXPECT_THROW(makeExpr(Mul(), ArgumentRefVector{var})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Mul(), ArgumentRefVector{})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Pow(), ArgumentRefVector{var})->toString(), InvalidInputException); - EXPECT_THROW(makeExpr(Pow(), ArgumentRefVector{})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentRefVector{var})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentRefVector{})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentRefVector{var})->toString(), InvalidInputException); + EXPECT_THROW(makeExpr(MulOper(), ArgumentRefVector{})->toString(), InvalidInputException); } TEST(FunctionUtilsTests, makeExpressionAnyArgsRefTest) { diff --git a/tests/src/functions/IFunctionTests.cpp b/tests/src/functions/IFunctionTests.cpp index b8bf41ba7..4639b02a7 100644 --- a/tests/src/functions/IFunctionTests.cpp +++ b/tests/src/functions/IFunctionTests.cpp @@ -3,10 +3,11 @@ #include "fintamath/functions/IFunction.hpp" -#include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/Mul.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" #include "fintamath/functions/arithmetic/Sub.hpp" #include "fintamath/functions/arithmetic/UnaryPlus.hpp" +#include "fintamath/functions/logarithms/Log.hpp" #include "fintamath/functions/trigonometry/Sin.hpp" #include "fintamath/literals/Variable.hpp" #include "fintamath/numbers/Integer.hpp" @@ -37,17 +38,17 @@ TEST(IFunctionTests, parseTest) { } TEST(IFunctionTests, callTest) { - std::unique_ptr f = std::make_unique(); + std::unique_ptr f = std::make_unique(); Integer a = 3; Rational b(1, 2); Variable c("c"); - EXPECT_EQ((*f)(a, a)->toString(), "6"); + EXPECT_EQ((*f)(a, a)->toString(), "1"); EXPECT_EQ((*f)(b, b)->toString(), "1"); - EXPECT_EQ((*f)(a, b)->toString(), "7/2"); - EXPECT_EQ((*f)(b, a)->toString(), "7/2"); + EXPECT_EQ((*f)(a, b)->toString(), "-0.6309297535714574371"); + EXPECT_EQ((*f)(b, a)->toString(), "-1.5849625007211561815"); - EXPECT_EQ((*f)(a, c)->toString(), "c + 3"); + EXPECT_EQ((*f)(a, c)->toString(), "log(3, c)"); EXPECT_THROW((*f)(), InvalidInputFunctionException); EXPECT_THROW((*f)(a), InvalidInputFunctionException); @@ -56,17 +57,17 @@ TEST(IFunctionTests, callTest) { } TEST(IFunctionTests, callVectTest) { - std::unique_ptr f = std::make_unique(); + std::unique_ptr f = std::make_unique(); Integer a = 3; Rational b(1, 2); Variable c("c"); - EXPECT_EQ((*f)({a, a})->toString(), "6"); + EXPECT_EQ((*f)({a, a})->toString(), "1"); EXPECT_EQ((*f)({b, b})->toString(), "1"); - EXPECT_EQ((*f)({a, b})->toString(), "7/2"); - EXPECT_EQ((*f)({b, a})->toString(), "7/2"); + EXPECT_EQ((*f)({a, b})->toString(), "-0.6309297535714574371"); + EXPECT_EQ((*f)({b, a})->toString(), "-1.5849625007211561815"); - EXPECT_EQ((*f)({a, c})->toString(), "c + 3"); + EXPECT_EQ((*f)({a, c})->toString(), "log(3, c)"); EXPECT_THROW((*f)({}), InvalidInputFunctionException); EXPECT_THROW((*f)({a}), InvalidInputFunctionException); @@ -75,23 +76,23 @@ TEST(IFunctionTests, callVectTest) { } TEST(IFunctionTests, equalsTest) { - EXPECT_EQ(Add(), Add()); - EXPECT_NE(Add(), Sub()); - EXPECT_NE(Sub(), Add()); - EXPECT_NE(Add(), UnaryPlus()); - EXPECT_NE(UnaryPlus(), Add()); - EXPECT_NE(Add(), Sin()); - EXPECT_NE(Sin(), Add()); + EXPECT_EQ(Log(), Log()); + EXPECT_NE(Log(), Sub()); + EXPECT_NE(Sub(), Log()); + EXPECT_NE(Log(), UnaryPlus()); + EXPECT_NE(UnaryPlus(), Log()); + EXPECT_NE(Log(), Sin()); + EXPECT_NE(Sin(), Log()); } TEST(IFunctionTests, getArgumentClassesTest) { - EXPECT_THAT(Add().getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); + EXPECT_THAT(Log().getArgumentClasses(), testing::ElementsAre(INumber::getClassStatic(), INumber::getClassStatic())); EXPECT_THAT(Neg().getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic())); EXPECT_THAT(Sin().getArgumentClasses(), testing::ElementsAre(INumber::getClassStatic())); } TEST(IFunctionTests, getReturnClassTest) { - EXPECT_EQ(Add().getReturnClass(), IArithmetic::getClassStatic()); + EXPECT_EQ(Log().getReturnClass(), INumber::getClassStatic()); EXPECT_EQ(Neg().getReturnClass(), IArithmetic::getClassStatic()); EXPECT_EQ(Sin().getReturnClass(), INumber::getClassStatic()); } @@ -101,14 +102,29 @@ TEST(IFunctionTests, doArgsMatchTest) { Rational b(1, 2); Variable c("c"); - EXPECT_TRUE(Add().doArgsMatch({a, b})); - EXPECT_FALSE(Add().doArgsMatch({c, c})); - EXPECT_FALSE(Add().doArgsMatch({a, c})); - EXPECT_FALSE(Add().doArgsMatch({c, a})); - EXPECT_FALSE(Add().doArgsMatch({})); - EXPECT_FALSE(Add().doArgsMatch({a})); - EXPECT_FALSE(Add().doArgsMatch({a, a, a})); - EXPECT_FALSE(Add().doArgsMatch({a, b, a, b})); + { + EXPECT_TRUE(Log().doArgsMatch({a, b})); + EXPECT_FALSE(Log().doArgsMatch({c, c})); + EXPECT_FALSE(Log().doArgsMatch({a, c})); + EXPECT_FALSE(Log().doArgsMatch({c, a})); + + EXPECT_FALSE(Log().doArgsMatch({})); + EXPECT_FALSE(Log().doArgsMatch({a})); + EXPECT_FALSE(Log().doArgsMatch({a, a, a})); + EXPECT_FALSE(Log().doArgsMatch({a, b, a, b})); + } + { + EXPECT_TRUE(Mul().doArgsMatch({a, b, a})); + EXPECT_FALSE(Mul().doArgsMatch({a, c, c})); + EXPECT_FALSE(Mul().doArgsMatch({c, b, b})); + EXPECT_FALSE(Mul().doArgsMatch({b, b, c, a})); + + EXPECT_FALSE(Mul().doArgsMatch({})); + EXPECT_TRUE(Mul().doArgsMatch({a})); + EXPECT_TRUE(Mul().doArgsMatch({a, a})); + EXPECT_TRUE(Mul().doArgsMatch({a, a, a})); + EXPECT_TRUE(Mul().doArgsMatch({a, b, a, b})); + } } TEST(IFunctionTests, getClassTest) { diff --git a/tests/src/functions/IOperatorTests.cpp b/tests/src/functions/IOperatorTests.cpp index 3fcba96da..776c617da 100644 --- a/tests/src/functions/IOperatorTests.cpp +++ b/tests/src/functions/IOperatorTests.cpp @@ -3,10 +3,11 @@ #include "fintamath/functions/IOperator.hpp" #include "fintamath/functions/arithmetic/Add.hpp" +#include "fintamath/functions/arithmetic/AddOper.hpp" #include "fintamath/functions/arithmetic/Neg.hpp" -#include "fintamath/functions/logic/Or.hpp" +#include "fintamath/functions/logic/OrOper.hpp" #include "fintamath/functions/other/Factorial.hpp" -#include "fintamath/functions/powers/Pow.hpp" +#include "fintamath/functions/powers/PowOper.hpp" using namespace fintamath; @@ -38,17 +39,17 @@ TEST(IOperatorTests, parseTest) { } TEST(IOperatorTests, getPriorityTest) { - EXPECT_EQ(Add().getPriority(), IOperator::Priority::Addition); + EXPECT_EQ(AddOper().getPriority(), IOperator::Priority::Addition); EXPECT_EQ(Neg().getPriority(), IOperator::Priority::PrefixUnary); EXPECT_EQ(Factorial().getPriority(), IOperator::Priority::PostfixUnary); - EXPECT_EQ(Or().getPriority(), IOperator::Priority::Disjunction); + EXPECT_EQ(OrOper().getPriority(), IOperator::Priority::Disjunction); } TEST(IOperatorTests, isAssociativeTest) { - EXPECT_TRUE(Add().isAssociative()); + EXPECT_TRUE(AddOper().isAssociative()); EXPECT_FALSE(Neg().isAssociative()); - EXPECT_TRUE(Or().isAssociative()); - EXPECT_FALSE(Pow().isAssociative()); + EXPECT_TRUE(OrOper().isAssociative()); + EXPECT_FALSE(PowOper().isAssociative()); } TEST(IOperatorTests, getClassTest) { diff --git a/tests/src/functions/arithmetic/AddOperTests.cpp b/tests/src/functions/arithmetic/AddOperTests.cpp new file mode 100644 index 000000000..525837d86 --- /dev/null +++ b/tests/src/functions/arithmetic/AddOperTests.cpp @@ -0,0 +1,60 @@ +#include +#include + +#include "fintamath/functions/arithmetic/AddOper.hpp" + +#include "fintamath/exceptions/InvalidInputException.hpp" +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Rational.hpp" + +using namespace fintamath; + +const AddOper f; + +TEST(AddOperTests, toStringTest) { + EXPECT_EQ(f.toString(), "+"); +} + +TEST(AddOperTests, getArgumentClassesTest) { + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); +} + +TEST(AddOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), IArithmetic::getClassStatic()); +} + +TEST(AddOperTests, isVariadicTest) { + EXPECT_FALSE(f.isVariadic()); +} + +TEST(AddOperTests, isEvaluatableTest) { + EXPECT_TRUE(f.isEvaluatable()); +} + +TEST(AddOperTests, getPriorityTest) { + EXPECT_EQ(f.getPriority(), IOperator::Priority::Addition); +} + +TEST(AddOperTests, isAssociativeTest) { + EXPECT_TRUE(f.isAssociative()); +} + +TEST(AddOperTests, callTest) { + EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "8"); + EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "11/2"); + EXPECT_EQ(f(Rational(5, 2), Integer(3))->toString(), "11/2"); + EXPECT_EQ(f(Rational(5, 2), Rational(5, 2))->toString(), "5"); + EXPECT_EQ(f(Rational(5, 2), Rational(5, 3))->toString(), "25/6"); + + EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "a + 3"); + + EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); + EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} + +TEST(AddOperTests, getClassTest) { + EXPECT_EQ(f.getClass(), MathObjectClass("AddOper")); + EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); +} diff --git a/tests/src/functions/arithmetic/AddTests.cpp b/tests/src/functions/arithmetic/AddTests.cpp index c2e92eb43..9de5218f1 100644 --- a/tests/src/functions/arithmetic/AddTests.cpp +++ b/tests/src/functions/arithmetic/AddTests.cpp @@ -12,11 +12,11 @@ using namespace fintamath; const Add f; TEST(AddTests, toStringTest) { - EXPECT_EQ(f.toString(), "+"); + EXPECT_EQ(f.toString(), "add"); } TEST(AddTests, getArgumentClassesTest) { - EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic())); } TEST(AddTests, getReturnClassTest) { @@ -24,34 +24,28 @@ TEST(AddTests, getReturnClassTest) { } TEST(AddTests, isVariadicTest) { - EXPECT_FALSE(f.isVariadic()); + EXPECT_TRUE(f.isVariadic()); } TEST(AddTests, isEvaluatableTest) { EXPECT_TRUE(f.isEvaluatable()); } -TEST(AddTests, getPriorityTest) { - EXPECT_EQ(f.getPriority(), IOperator::Priority::Addition); -} - -TEST(AddTests, isAssociativeTest) { - EXPECT_TRUE(f.isAssociative()); -} - TEST(AddTests, callTest) { + // TODO! add more tests + EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "8"); EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "11/2"); EXPECT_EQ(f(Rational(5, 2), Integer(3))->toString(), "11/2"); EXPECT_EQ(f(Rational(5, 2), Rational(5, 2))->toString(), "5"); EXPECT_EQ(f(Rational(5, 2), Rational(5, 3))->toString(), "25/6"); + EXPECT_EQ(f(Integer(1))->toString(), "1"); + EXPECT_EQ(f(Rational(2, 3))->toString(), "2/3"); + EXPECT_EQ(f(Integer(1), Integer(1), Integer(1))->toString(), "3"); EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "a + 3"); - EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); - EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); EXPECT_THROW(f(), InvalidInputFunctionException); - EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); } TEST(AddTests, exprTest) { @@ -60,5 +54,5 @@ TEST(AddTests, exprTest) { TEST(AddTests, getClassTest) { EXPECT_EQ(f.getClass(), MathObjectClass("Add")); - EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); + EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); } diff --git a/tests/src/functions/arithmetic/MulOperTests.cpp b/tests/src/functions/arithmetic/MulOperTests.cpp new file mode 100644 index 000000000..ec175ff2b --- /dev/null +++ b/tests/src/functions/arithmetic/MulOperTests.cpp @@ -0,0 +1,58 @@ +#include +#include + +#include "fintamath/functions/arithmetic/MulOper.hpp" + +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Rational.hpp" + +using namespace fintamath; + +const MulOper f; + +TEST(MulOperTests, toStringTest) { + EXPECT_EQ(f.toString(), "*"); +} + +TEST(MulOperTests, getArgumentClassesTest) { + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); +} + +TEST(MulOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), IArithmetic::getClassStatic()); +} + +TEST(MulOperTests, isVariadicTest) { + EXPECT_FALSE(f.isVariadic()); +} + +TEST(MulOperTests, isEvaluatableTest) { + EXPECT_TRUE(f.isEvaluatable()); +} + +TEST(MulOperTests, getPriorityTest) { + EXPECT_EQ(f.getPriority(), IOperator::Priority::Multiplication); +} + +TEST(MulOperTests, isAssociativeTest) { + EXPECT_TRUE(f.isAssociative()); +} + +TEST(MulOperTests, callTest) { + EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "15"); + EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "15/2"); + EXPECT_EQ(f(Rational(5, 2), Integer(3))->toString(), "15/2"); + EXPECT_EQ(f(Rational(5, 2), Rational(5, 3))->toString(), "25/6"); + + EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3 a"); + + EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); + EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); +} + +TEST(MulOperTests, getClassTest) { + EXPECT_EQ(f.getClass(), MathObjectClass("MulOper")); + EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); +} diff --git a/tests/src/functions/arithmetic/MulTests.cpp b/tests/src/functions/arithmetic/MulTests.cpp index 330e18c33..f81a63b0c 100644 --- a/tests/src/functions/arithmetic/MulTests.cpp +++ b/tests/src/functions/arithmetic/MulTests.cpp @@ -11,11 +11,11 @@ using namespace fintamath; const Mul f; TEST(MulTests, toStringTest) { - EXPECT_EQ(f.toString(), "*"); + EXPECT_EQ(f.toString(), "mul"); } TEST(MulTests, getArgumentClassesTest) { - EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic())); } TEST(MulTests, getReturnClassTest) { @@ -23,33 +23,27 @@ TEST(MulTests, getReturnClassTest) { } TEST(MulTests, isVariadicTest) { - EXPECT_FALSE(f.isVariadic()); + EXPECT_TRUE(f.isVariadic()); } TEST(MulTests, isEvaluatableTest) { EXPECT_TRUE(f.isEvaluatable()); } -TEST(MulTests, getPriorityTest) { - EXPECT_EQ(f.getPriority(), IOperator::Priority::Multiplication); -} - -TEST(MulTests, isAssociativeTest) { - EXPECT_TRUE(f.isAssociative()); -} - TEST(MulTests, callTest) { + // TODO! add more tests + EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "15"); EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "15/2"); EXPECT_EQ(f(Rational(5, 2), Integer(3))->toString(), "15/2"); EXPECT_EQ(f(Rational(5, 2), Rational(5, 3))->toString(), "25/6"); + EXPECT_EQ(f(Integer(1))->toString(), "1"); + EXPECT_EQ(f(Rational(2, 3))->toString(), "2/3"); + EXPECT_EQ(f(Integer(1), Integer(1), Integer(1))->toString(), "1"); EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3 a"); - EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); - EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); EXPECT_THROW(f(), InvalidInputFunctionException); - EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); } TEST(MulTests, exprTest) { @@ -58,5 +52,5 @@ TEST(MulTests, exprTest) { TEST(MulTests, getClassTest) { EXPECT_EQ(f.getClass(), MathObjectClass("Mul")); - EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); + EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); } diff --git a/tests/src/functions/logic/AndOperTests.cpp b/tests/src/functions/logic/AndOperTests.cpp new file mode 100644 index 000000000..70dd3b569 --- /dev/null +++ b/tests/src/functions/logic/AndOperTests.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include "fintamath/functions/logic/AndOper.hpp" + +#include "fintamath/literals/Boolean.hpp" +#include "fintamath/literals/Variable.hpp" + +using namespace fintamath; + +const AndOper f; + +TEST(AndOperTests, toStringTest) { + EXPECT_EQ(f.toString(), "&"); +} + +TEST(AndOperTests, getArgumentClassesTest) { + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic(), Boolean::getClassStatic())); +} + +TEST(AndOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), Boolean::getClassStatic()); +} + +TEST(AndOperTests, isVariadicTest) { + EXPECT_FALSE(f.isVariadic()); +} + +TEST(AndOperTests, isEvaluatableTest) { + EXPECT_TRUE(f.isEvaluatable()); +} + +TEST(AndOperTests, getPriorityTest) { + EXPECT_EQ(f.getPriority(), IOperator::Priority::Conjunction); +} + +TEST(AndOperTests, isAssociativeTest) { + EXPECT_TRUE(f.isAssociative()); +} + +TEST(AndOperTests, callTest) { + EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); + EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "False"); + EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "False"); + EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "True"); + + EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "a & b"); + + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); + EXPECT_THROW(f(Boolean(true), Boolean(true), Boolean(true)), InvalidInputFunctionException); +} + +TEST(AndOperTests, getClassTest) { + EXPECT_EQ(f.getClass(), MathObjectClass("AndOper")); + EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); +} diff --git a/tests/src/functions/logic/AndTests.cpp b/tests/src/functions/logic/AndTests.cpp index b8655b9cc..60ff0d16a 100644 --- a/tests/src/functions/logic/AndTests.cpp +++ b/tests/src/functions/logic/AndTests.cpp @@ -11,11 +11,11 @@ using namespace fintamath; const And f; TEST(AndTests, toStringTest) { - EXPECT_EQ(f.toString(), "&"); + EXPECT_EQ(f.toString(), "and"); } TEST(AndTests, getArgumentClassesTest) { - EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic(), Boolean::getClassStatic())); + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic())); } TEST(AndTests, getReturnClassTest) { @@ -23,32 +23,26 @@ TEST(AndTests, getReturnClassTest) { } TEST(AndTests, isVariadicTest) { - EXPECT_FALSE(f.isVariadic()); + EXPECT_TRUE(f.isVariadic()); } TEST(AndTests, isEvaluatableTest) { EXPECT_TRUE(f.isEvaluatable()); } -TEST(AndTests, getPriorityTest) { - EXPECT_EQ(f.getPriority(), IOperator::Priority::Conjunction); -} - -TEST(AndTests, isAssociativeTest) { - EXPECT_TRUE(f.isAssociative()); -} - TEST(AndTests, callTest) { + // TODO! add more tests + EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "False"); EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "True"); + EXPECT_EQ(f(Boolean(true))->toString(), "True"); + EXPECT_EQ(f(Boolean(true), Boolean(true), Boolean(true))->toString(), "True"); EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "a & b"); EXPECT_THROW(f(), InvalidInputFunctionException); - EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); - EXPECT_THROW(f(Boolean(true), Boolean(true), Boolean(true)), InvalidInputFunctionException); } TEST(AndTests, exprTest) { @@ -57,5 +51,5 @@ TEST(AndTests, exprTest) { TEST(AndTests, getClassTest) { EXPECT_EQ(f.getClass(), MathObjectClass("And")); - EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); + EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); } diff --git a/tests/src/functions/logic/EquivTests.cpp b/tests/src/functions/logic/EquivTests.cpp index 547663e0f..77e3184a3 100644 --- a/tests/src/functions/logic/EquivTests.cpp +++ b/tests/src/functions/logic/EquivTests.cpp @@ -44,7 +44,7 @@ TEST(EquivTests, callTest) { EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "True"); - EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "(a & b) | (~a & ~b)"); + EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "(~a & ~b) | (a & b)"); EXPECT_THROW(f(), InvalidInputFunctionException); EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); diff --git a/tests/src/functions/logic/NequivTests.cpp b/tests/src/functions/logic/NequivTests.cpp index 3c04227c1..3f925c34b 100644 --- a/tests/src/functions/logic/NequivTests.cpp +++ b/tests/src/functions/logic/NequivTests.cpp @@ -44,7 +44,7 @@ TEST(NequivTests, callTest) { EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "True"); EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "False"); - EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "(a & ~b) | (~a & b)"); + EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "(~a & b) | (a & ~b)"); EXPECT_THROW(f(), InvalidInputFunctionException); EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); diff --git a/tests/src/functions/logic/OrOperTests.cpp b/tests/src/functions/logic/OrOperTests.cpp new file mode 100644 index 000000000..915f03b78 --- /dev/null +++ b/tests/src/functions/logic/OrOperTests.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include "fintamath/functions/logic/OrOper.hpp" + +#include "fintamath/literals/Boolean.hpp" +#include "fintamath/literals/Variable.hpp" + +using namespace fintamath; + +const OrOper f; + +TEST(OrOperTests, toStringTest) { + EXPECT_EQ(f.toString(), "|"); +} + +TEST(OrOperTests, getArgumentClassesTest) { + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic(), Boolean::getClassStatic())); +} + +TEST(OrOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), Boolean::getClassStatic()); +} + +TEST(OrOperTests, isVariadicTest) { + EXPECT_FALSE(f.isVariadic()); +} + +TEST(OrOperTests, isEvaluatableTest) { + EXPECT_TRUE(f.isEvaluatable()); +} + +TEST(OrOperTests, getPriorityTest) { + EXPECT_EQ(f.getPriority(), IOperator::Priority::Disjunction); +} + +TEST(OrOperTests, isAssociativeTest) { + EXPECT_TRUE(f.isAssociative()); +} + +TEST(OrOperTests, callTest) { + EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); + EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "True"); + EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "True"); + EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "True"); + + EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "a | b"); + + EXPECT_THROW(f(), InvalidInputFunctionException); + EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); + EXPECT_THROW(f(Boolean(true), Boolean(true), Boolean(true)), InvalidInputFunctionException); +} + +TEST(OrOperTests, getClassTest) { + EXPECT_EQ(f.getClass(), MathObjectClass("OrOper")); + EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); +} diff --git a/tests/src/functions/logic/OrTests.cpp b/tests/src/functions/logic/OrTests.cpp index b469d5d70..a2254e4c3 100644 --- a/tests/src/functions/logic/OrTests.cpp +++ b/tests/src/functions/logic/OrTests.cpp @@ -11,11 +11,11 @@ using namespace fintamath; const Or f; TEST(OrTests, toStringTest) { - EXPECT_EQ(f.toString(), "|"); + EXPECT_EQ(f.toString(), "or"); } TEST(OrTests, getArgumentClassesTest) { - EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic(), Boolean::getClassStatic())); + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(Boolean::getClassStatic())); } TEST(OrTests, getReturnClassTest) { @@ -23,32 +23,26 @@ TEST(OrTests, getReturnClassTest) { } TEST(OrTests, isVariadicTest) { - EXPECT_FALSE(f.isVariadic()); + EXPECT_TRUE(f.isVariadic()); } TEST(OrTests, isEvaluatableTest) { EXPECT_TRUE(f.isEvaluatable()); } -TEST(OrTests, getPriorityTest) { - EXPECT_EQ(f.getPriority(), IOperator::Priority::Disjunction); -} - -TEST(OrTests, isAssociativeTest) { - EXPECT_TRUE(f.isAssociative()); -} - TEST(OrTests, callTest) { + // TODO! add more tests + EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "True"); EXPECT_EQ(f(Boolean(true), Boolean(false))->toString(), "True"); EXPECT_EQ(f(Boolean(true), Boolean(true))->toString(), "True"); + EXPECT_EQ(f(Boolean(true))->toString(), "True"); + EXPECT_EQ(f(Boolean(true), Boolean(true), Boolean(true))->toString(), "True"); EXPECT_EQ(f(Variable("a"), Variable("b"))->toString(), "a | b"); EXPECT_THROW(f(), InvalidInputFunctionException); - EXPECT_THROW(f(Boolean(true)), InvalidInputFunctionException); - EXPECT_THROW(f(Boolean(true), Boolean(true), Boolean(true)), InvalidInputFunctionException); } TEST(OrTests, exprTest) { @@ -57,5 +51,5 @@ TEST(OrTests, exprTest) { TEST(OrTests, getClassTest) { EXPECT_EQ(f.getClass(), MathObjectClass("Or")); - EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); + EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); } diff --git a/tests/src/functions/powers/PowFunctionTests.cpp b/tests/src/functions/powers/PowFunctionTests.cpp deleted file mode 100644 index e6f552b12..000000000 --- a/tests/src/functions/powers/PowFunctionTests.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include "fintamath/functions/powers/PowFunction.hpp" - -#include "fintamath/literals/Variable.hpp" -#include "fintamath/numbers/Rational.hpp" -#include "fintamath/numbers/Real.hpp" - -using namespace fintamath; - -const PowFunction f; - -TEST(PowFunctionTests, toStringTest) { - EXPECT_EQ(f.toString(), "pow"); -} - -TEST(PowFunctionTests, getArgumentClassesTest) { - EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); -} - -TEST(PowFunctionTests, getReturnClassTest) { - EXPECT_EQ(f.getReturnClass(), IArithmetic::getClassStatic()); -} - -TEST(PowFunctionTests, isVariadicTest) { - EXPECT_FALSE(f.isVariadic()); -} - -TEST(PowFunctionTests, isEvaluatableTest) { - EXPECT_TRUE(f.isEvaluatable()); -} - -TEST(PowFunctionTests, callTest) { - EXPECT_EQ(f(Integer(3), Integer(2))->toString(), "9"); - EXPECT_EQ(f(Rational(-10), Rational(-3))->toString(), "-1/1000"); - - EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3^a"); - EXPECT_EQ(f(Variable("a"), Rational(1, 2))->toString(), "sqrt(a)"); - EXPECT_EQ(f(Variable("a"), Rational(3, 2))->toString(), "a^(3/2)"); - - EXPECT_THROW(f(), InvalidInputFunctionException); - EXPECT_THROW(f(Integer(1)), InvalidInputFunctionException); - EXPECT_THROW(f(Rational(2, 3)), InvalidInputFunctionException); - EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputFunctionException); -} - -TEST(PowFunctionTests, getClassTest) { - EXPECT_EQ(f.getClass(), MathObjectClass("PowFunction")); - EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); -} diff --git a/tests/src/functions/powers/PowOperTests.cpp b/tests/src/functions/powers/PowOperTests.cpp new file mode 100644 index 000000000..3231fcd23 --- /dev/null +++ b/tests/src/functions/powers/PowOperTests.cpp @@ -0,0 +1,60 @@ +#include +#include + +#include "fintamath/functions/powers/PowOper.hpp" + +#include "fintamath/literals/Variable.hpp" +#include "fintamath/numbers/Complex.hpp" +#include "fintamath/numbers/Rational.hpp" +#include "fintamath/numbers/Real.hpp" + +using namespace fintamath; + +const PowOper f; + +TEST(PowOperTests, toStringTest) { + EXPECT_EQ(f.toString(), "^"); +} + +TEST(PowOperTests, getArgumentClassesTest) { + EXPECT_THAT(f.getArgumentClasses(), testing::ElementsAre(INumber::getClassStatic(), INumber::getClassStatic())); +} + +TEST(PowOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), INumber::getClassStatic()); +} + +TEST(PowOperTests, isVariadicTest) { + EXPECT_FALSE(f.isVariadic()); +} + +TEST(PowOperTests, isEvaluatableTest) { + EXPECT_TRUE(f.isEvaluatable()); +} + +TEST(PowOperTests, getPriorityTest) { + EXPECT_EQ(f.getPriority(), IOperator::Priority::Exponentiation); +} + +TEST(PowOperTests, isAssociativeTest) { + EXPECT_FALSE(f.isAssociative()); +} + +TEST(PowOperTests, callTest) { + EXPECT_EQ(f(Integer(3), Integer(2))->toString(), "9"); + EXPECT_EQ(f(Rational(-10), Rational(-3))->toString(), "-1/1000"); + + EXPECT_EQ(f(Integer(3), Variable("a"))->toString(), "3^a"); + EXPECT_EQ(f(Variable("a"), Rational(1, 2))->toString(), "sqrt(a)"); + EXPECT_EQ(f(Variable("a"), Rational(3, 2))->toString(), "a^(3/2)"); + + EXPECT_THROW(f(), InvalidInputException); + EXPECT_THROW(f(Integer(1)), InvalidInputException); + EXPECT_THROW(f(Rational(2, 3)), InvalidInputException); + EXPECT_THROW(f(Integer(1), Integer(1), Integer(1)), InvalidInputException); +} + +TEST(PowOperTests, getClassTest) { + EXPECT_EQ(f.getClass(), MathObjectClass("PowOper")); + EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); +} diff --git a/tests/src/functions/powers/PowTests.cpp b/tests/src/functions/powers/PowTests.cpp index fb4d409e5..db65f1c68 100644 --- a/tests/src/functions/powers/PowTests.cpp +++ b/tests/src/functions/powers/PowTests.cpp @@ -13,7 +13,7 @@ using namespace fintamath; const Pow f; TEST(PowTests, toStringTest) { - EXPECT_EQ(f.toString(), "^"); + EXPECT_EQ(f.toString(), "pow"); } TEST(PowTests, getArgumentClassesTest) { @@ -32,14 +32,6 @@ TEST(PowTests, isEvaluatableTest) { EXPECT_TRUE(f.isEvaluatable()); } -TEST(PowTests, getPriorityTest) { - EXPECT_EQ(f.getPriority(), IOperator::Priority::Exponentiation); -} - -TEST(PowTests, isAssociativeTest) { - EXPECT_FALSE(f.isAssociative()); -} - TEST(PowTests, callTest) { EXPECT_EQ(f(Integer(3), Integer(0))->toString(), "1"); @@ -170,5 +162,5 @@ TEST(PowTests, exprTest) { TEST(PowTests, getClassTest) { EXPECT_EQ(f.getClass(), MathObjectClass("Pow")); - EXPECT_EQ(f.getClass().getParent(), IOperator::getClassStatic()); + EXPECT_EQ(f.getClass().getParent(), IFunction::getClassStatic()); } diff --git a/tests/src/overall/simplify/SimplifyDerivativeTests.cpp b/tests/src/overall/simplify/SimplifyDerivativeTests.cpp index 4e5617fe7..0dcff53a7 100644 --- a/tests/src/overall/simplify/SimplifyDerivativeTests.cpp +++ b/tests/src/overall/simplify/SimplifyDerivativeTests.cpp @@ -102,23 +102,23 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(lg(x), x)").toString(), "1/(ln(10) x)"); EXPECT_EQ(Expression("derivative(log(x, y), x)").toString(), - "-ln(y)/(ln(x)^2 x)"); + "-ln(y)/(x ln(x)^2)"); EXPECT_EQ(Expression("derivative(log(y, x), x)").toString(), "1/(x ln(y))"); EXPECT_EQ(Expression("derivative(log(x, 2), x)").toString(), - "-ln(2)/(ln(x)^2 x)"); + "-ln(2)/(x ln(x)^2)"); EXPECT_EQ(Expression("derivative(log(2, x), x)").toString(), "1/(ln(2) x)"); EXPECT_EQ(Expression("derivative(log(x, (3/5)), x)").toString(), - "-ln(3/5)/(ln(x)^2 x)"); + "-ln(3/5)/(x ln(x)^2)"); EXPECT_EQ(Expression("derivative(log((3/5), x), x)").toString(), "1/(ln(3/5) x)"); EXPECT_EQ(Expression("derivative(log(x, (-3/5)), x)").toString(), - "-ln(-3/5)/(ln(x)^2 x)"); + "-ln(-3/5)/(x ln(x)^2)"); EXPECT_EQ(Expression("derivative(log((-3/5), x), x)").toString(), "1/(ln(-3/5) x)"); EXPECT_EQ(Expression("derivative(log(x, (2+I)), x)").toString(), - "-ln(2 + I)/(ln(x)^2 x)"); + "-ln(2 + I)/(x ln(x)^2)"); EXPECT_EQ(Expression("derivative(log((2+I), x), x)").toString(), "1/(ln(2 + I) x)"); EXPECT_EQ(Expression("derivative(sin(x), x)").toString(), @@ -252,7 +252,7 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(E^sin(x), x)").toString(), "E^sin(x) cos(x)"); EXPECT_EQ(Expression("derivative(5E^(-x^3), x)").toString(), - "-15 E x^2 E^(-x^3 - 1)"); // TODO: -15 E^(-x^3) x^2 + "-15 E^(-x^3) x^2"); EXPECT_EQ(Expression("derivative(8^(x^2 - 5x), x)").toString(), "(16*8^(x^2 - 5 x - 1) x - 40*8^(x^2 - 5 x - 1)) ln(8)"); // TODO: simplify this EXPECT_EQ(Expression("derivative((1 + 5x)^3, x)").toString(), @@ -260,7 +260,7 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(x^5 (2 - x/3 + 3x^2), x)").toString(), "21 x^6 - 2 x^5 + 10 x^4"); EXPECT_EQ(Expression("derivative(x^3 3^x, x)").toString(), - "x^3*3^x ln(3) + 3 x^2*3^x"); + "3^(x + 1) x^2 + 3^x x^3 ln(3)"); EXPECT_EQ(Expression("derivative(ln(3x + 5), x)").toString(), "3/(3 x + 5)"); EXPECT_EQ(Expression("derivative(ln(x^5 - 2x^2 + 5), x)").toString(), @@ -282,7 +282,7 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(ln(cos(3x)), x)").toString(), "-3 tan(3 x)"); EXPECT_EQ(Expression("derivative(log(sin(x^5), tan(x^3)), x)").toString(), - "(3 sec(x^3)^2 x^2 cos(x^3) csc(x^3))/ln(sin(x^5)) - (5 x^4 cos(x^5) csc(x^5) ln(tan(x^3)))/(ln(sin(x^5))^2)"); + "(3 sec(x^3)^2 x^2 cos(x^3) csc(x^3))/ln(sin(x^5)) - (5 x^4 ln(tan(x^3)) cos(x^5) csc(x^5))/(ln(sin(x^5))^2)"); EXPECT_EQ(Expression("derivative(acos(4x + 5)^5, x)").toString(), "-(20 acos(4 x + 5)^4)/sqrt(-16 x^2 - 40 x - 24)"); EXPECT_EQ(Expression("derivative(sin(sin(sin(x))), x)").toString(), @@ -292,11 +292,11 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(a b cos(x), x)").toString(), "-a b sin(x)"); EXPECT_EQ(Expression("derivative(a x cos(x) ln(x) sign(x), x)").toString(), - "(a x derivative(sign(x), x) cos(x) - a x sin(x) sign(x) + a cos(x) sign(x)) ln(x) + a cos(x) sign(x)"); + "a ln(x) cos(x) sign(x) + a cos(x) sign(x) + a x ln(x) (-sin(x) sign(x) + cos(x) derivative(sign(x), x))"); EXPECT_EQ(Expression("derivative(a * c * cos(x)/(x^2 + 1), x)").toString(), - "-(a c x^2 sin(x) + 2 a c x cos(x) + a c sin(x))/(x^4 + 2 x^2 + 1)"); + "-(a c x^2 sin(x) + a c sin(x) + 2 a c x cos(x))/(x^4 + 2 x^2 + 1)"); EXPECT_EQ(Expression("derivative((2x^3)/tan(x), x)").toString(), - "-2 x^3 csc(x)^2 + 6 x^2 cot(x)"); + "-2 csc(x)^2 x^3 + 6 x^2 cot(x)"); // TODO: -2 x^3 csc(x)^2 + 6 x^2 cot(x) EXPECT_EQ(Expression("derivative(acos(x)/(x^2 + 1), x)").toString(), "-(x^2 + 2 x sqrt(-x^2 + 1) acos(x) + 1)/(sqrt(-x^2 + 1) x^4 + 2 sqrt(-x^2 + 1) x^2 + sqrt(-x^2 + 1))"); EXPECT_EQ(Expression("derivative(sin(x)/sinh(x), x)").toString(), diff --git a/tests/src/overall/simplify/SimplifyLogicTests.cpp b/tests/src/overall/simplify/SimplifyLogicTests.cpp index 506dd5881..6a7104fa5 100644 --- a/tests/src/overall/simplify/SimplifyLogicTests.cpp +++ b/tests/src/overall/simplify/SimplifyLogicTests.cpp @@ -72,7 +72,7 @@ TEST(SimplifyLogicTests, simplifyTest) { EXPECT_EQ(Expression("~(x <= 1)").toString(), "x - 1 > 0"); EXPECT_EQ(Expression("~(x <= 1 | y >= 1)").toString(), - "x - 1 > 0 & y - 1 < 0"); + "y - 1 < 0 & x - 1 > 0"); EXPECT_EQ(Expression("~a").toString(), "~a"); @@ -92,9 +92,9 @@ TEST(SimplifyLogicTests, simplifyTest) { EXPECT_EQ(Expression("a -> b").toString(), "~a | b"); EXPECT_EQ(Expression("a <-> b").toString(), - "(a & b) | (~a & ~b)"); + "(~a & ~b) | (a & b)"); EXPECT_EQ(Expression("a !<-> b").toString(), - "(a & ~b) | (~a & b)"); + "(~a & b) | (a & ~b)"); EXPECT_EQ(Expression("a & a").toString(), "a"); @@ -177,7 +177,7 @@ TEST(SimplifyLogicTests, simplifyTest) { EXPECT_EQ(Expression("a<->a<->a<->a<->a<->a<->a").toString(), "a"); EXPECT_EQ(Expression("a&b->b&c").toString(), - "~a | (b & c) | ~b"); + "~a | ~b | (b & c)"); EXPECT_EQ(Expression("a&b&c").toString(), "a & b & c"); EXPECT_EQ(Expression("a&(b&c)").toString(), @@ -223,11 +223,11 @@ TEST(SimplifyLogicTests, simplifyTest) { EXPECT_EQ(Expression("(x | ~y | (x | ~y | z) & (y | z)) & (y | (x & ~y & z) | (y & z))").toString(), "(x & ~y & z) | (x & y) | (y & z)"); EXPECT_EQ(Expression("~a & b | ~c -> a <-> b !<-> c").toString(), - "(a & b & ~c) | (~a & ~b & ~c) | (~a & c) | (~b & c)"); + "(~a & ~b & ~c) | (~a & c) | (a & b & ~c) | (~b & c)"); EXPECT_EQ(Expression("~~~a & ~~b | ~~~c -> ~~a <-> ~~b !<-> ~~c").toString(), - "(a & b & ~c) | (~a & ~b & ~c) | (~a & c) | (~b & c)"); + "(~a & ~b & ~c) | (~a & c) | (a & b & ~c) | (~b & c)"); EXPECT_EQ(Expression("((a | b) & (a -> c)) <-> (~a -> b)").toString(), - "(a & c) | ~a | (b & c)"); + "~a | (a & c) | (b & c)"); EXPECT_EQ(Expression("x=1&a").toString(), "a & x - 1 = 0"); @@ -246,22 +246,22 @@ TEST(SimplifyLogicTests, simplifyLargeTest) { // EXPECT_EQ(Expression("a<->b<->c<->d<->e<->f").toString(), EXPECT_EQ(Expression("a<->b<->c<->d<->e").toString(), - "(a & b & c & d & e) | " - "(a & b & c & ~d & ~e) | " - "(a & b & ~c & d & ~e) | " - "(a & b & ~c & ~d & e) | " - "(a & ~b & c & d & ~e) | " - "(a & ~b & c & ~d & e) | " - "(a & ~b & ~c & d & e) | " - "(a & ~b & ~c & ~d & ~e) | " - "(~a & b & c & d & ~e) | " - "(~a & b & c & ~d & e) | " - "(~a & b & ~c & d & e) | " - "(~a & b & ~c & ~d & ~e) | " - "(~a & ~b & c & d & e) | " - "(~a & ~b & c & ~d & ~e) | " + "(~a & ~b & ~c & ~d & e) | " "(~a & ~b & ~c & d & ~e) | " - "(~a & ~b & ~c & ~d & e)"); + "(~a & ~b & c & ~d & ~e) | " + "(~a & ~b & c & d & e) | " + "(~a & b & ~c & ~d & ~e) | " + "(~a & b & ~c & d & e) | " + "(~a & b & c & ~d & e) | " + "(~a & b & c & d & ~e) | " + "(a & ~b & ~c & ~d & ~e) | " + "(a & ~b & ~c & d & e) | " + "(a & ~b & c & ~d & e) | " + "(a & ~b & c & d & ~e) | " + "(a & b & ~c & ~d & e) | " + "(a & b & ~c & d & ~e) | " + "(a & b & c & ~d & ~e) | " + "(a & b & c & d & e)"); EXPECT_EQ(Expression("a & b & c & d & e & f & g & h & i & j & k & l & m & n & o & p & q & r & s & t & u & v & w & x & y & z & x_1 & x_2 & x_3 | x_4").toString(), "(a & b & c & d & e & f & g & h & i & j & k & l & m & n & o & p & q & r & s & t & u & v & w & x & x_1 & x_2 & x_3 & y & z) | x_4"); diff --git a/tests/src/overall/simplify/SimplifyTests.cpp b/tests/src/overall/simplify/SimplifyTests.cpp index d25724fa6..8ade07916 100644 --- a/tests/src/overall/simplify/SimplifyTests.cpp +++ b/tests/src/overall/simplify/SimplifyTests.cpp @@ -390,9 +390,9 @@ TEST(SimplifyTests, simplifyTest) { EXPECT_EQ(Expression("a 5^x").toString(), "a 5^x"); EXPECT_EQ(Expression("a 5^x a").toString(), - "a^2*5^x"); + "5^x a^2"); EXPECT_EQ(Expression("2 5^x 6^y 7^z x^2 y^3").toString(), - "2 x^2 y^3*5^x 6^y 7^z"); + "2*5^x 6^y 7^z x^2 y^3"); EXPECT_EQ(Expression("1*(a+b)*1").toString(), "a + b"); EXPECT_EQ(Expression("-1*(a+b)*1").toString(), @@ -531,7 +531,7 @@ TEST(SimplifyTests, simplifyTest) { EXPECT_EQ(Expression("a - sqrt(2) x - sqrt(3) x - Pi^4 x + 1").toString(), "a + (-Pi^4 - sqrt(3) - sqrt(2)) x + 1"); EXPECT_EQ(Expression("x Pi^4 ln(5) + x E^2 sin(1) sinh(2)").toString(), - "(E^2 sinh(2) sin(1) + Pi^4 ln(5)) x"); + "(E^2 sin(1) sinh(2) + Pi^4 ln(5)) x"); EXPECT_EQ(Expression("(a+b) (-sqrt2 + sqrt3 - sqrt5)").toString(), "(sqrt(3) - sqrt(5) - sqrt(2)) a + (sqrt(3) - sqrt(5) - sqrt(2)) b"); EXPECT_EQ(Expression("(sqrt(2) x + sqrt(3) x + Pi^4 x + 1) / (sqrt(2) + sqrt(3) + Pi^4)").toString(), @@ -583,11 +583,11 @@ TEST(SimplifyTests, simplifyTest) { EXPECT_EQ(Expression("(x)sin(a)").toString(), "sin(a) x"); EXPECT_EQ(Expression("tan(4 a^3 b) + cot(4 a b^3) + b^4 + sin(a^4) + cos(6 a^2 b^2)").toString(), - "sin(a^4) + tan(4 a^3 b) + cos(6 a^2 b^2) + cot(4 a b^3) + b^4"); + "b^4 + sin(a^4) + cos(6 a^2 b^2) + tan(4 a^3 b) + cot(4 a b^3)"); EXPECT_EQ(Expression("tan(4 a^3 b) + cot(sin(4 a b^3)) + b^4 + asin(sin(a^4)) + cos(6 a^2 b^2)").toString(), - "asin(sin(a^4)) + tan(4 a^3 b) + cos(6 a^2 b^2) + cot(sin(4 a b^3)) + b^4"); + "b^4 + cos(6 a^2 b^2) + tan(4 a^3 b) + cot(sin(4 a b^3)) + asin(sin(a^4))"); 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(), - "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)) + b^4"); + "b^4 + cos(6 a_1^2 b^2) + tan(4 a_1^3 b) + cot(sin(4 a_1 b^3)) + asin(sin(a_1^4))"); EXPECT_EQ(Expression("a!!!!!!!!!!").toString(), "a!!!!!!!!!!"); EXPECT_EQ(Expression("a% * a!!! * a! * a!!").toString(), @@ -605,7 +605,7 @@ TEST(SimplifyTests, simplifyTest) { EXPECT_EQ(Expression("cos(b) log(b, a)").toString(), "log(b, a) cos(b)"); EXPECT_EQ(Expression("cos(a) log(b, c)").toString(), - "cos(a) log(b, c)"); + "log(b, c) cos(a)"); EXPECT_EQ(Expression("cos(b^2) log(b, c)").toString(), "log(b, c) cos(b^2)"); EXPECT_EQ(Expression("(x + y^3)^2 * sin(x)/ln(2)/x^2 - (2 sin(x) y^3)/(x ln(2))").toString(), diff --git a/tests/src/overall/simplify/SimplifyTrigonometryTests.cpp b/tests/src/overall/simplify/SimplifyTrigonometryTests.cpp index c358b1e1f..ac0a3e1d7 100644 --- a/tests/src/overall/simplify/SimplifyTrigonometryTests.cpp +++ b/tests/src/overall/simplify/SimplifyTrigonometryTests.cpp @@ -89,7 +89,7 @@ TEST(SimplifyTrigonometryTests, simplifyTest) { EXPECT_EQ(Expression("sin(x)cos(x)").toString(), "sin(2 x)/2"); EXPECT_EQ(Expression("sin(x)cos(x)sign(x)").toString(), - "(sign(x) sin(2 x))/2"); + "(sin(2 x) sign(x))/2"); EXPECT_EQ(Expression("sin(x)^2").toString(), "sin(x)^2"); diff --git a/tests/src/overall/solve/SolveTests.cpp b/tests/src/overall/solve/SolveTests.cpp index e7a04abd2..009eb1a24 100644 --- a/tests/src/overall/solve/SolveTests.cpp +++ b/tests/src/overall/solve/SolveTests.cpp @@ -105,7 +105,7 @@ TEST(SolveTests, solveTest) { EXPECT_EQ(solve(Expression("x = x sqrt(x)")).toString(), "x^(3/2) - x = 0"); EXPECT_EQ(solve(Expression("x = 3^x")).toString(), - "x - 3^x = 0"); + "3^x - x = 0"); EXPECT_EQ(solve(Expression("E = Ey")).toString(), "y = 1");