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..58e86f1fa 100644 --- a/include/fintamath/expressions/ExpressionUtils.hpp +++ b/include/fintamath/expressions/ExpressionUtils.hpp @@ -76,6 +76,8 @@ std::pair splitRational(const ArgumentPtr &arg); ArgumentPtr negate(const ArgumentPtr &arg); +ArgumentPtr invert(const ArgumentPtr &arg); + ArgumentPtr makePolynom(const IFunction &func, ArgumentPtrVector &&args); ArgumentPtr makePolynom(const IFunction &func, const ArgumentPtrVector &args); diff --git a/include/fintamath/expressions/IExpression.hpp b/include/fintamath/expressions/IExpression.hpp index 5ab17d38e..aba17bd88 100644 --- a/include/fintamath/expressions/IExpression.hpp +++ b/include/fintamath/expressions/IExpression.hpp @@ -36,6 +36,12 @@ class IExpression : public IMathObject { virtual const std::shared_ptr &getOutputFunction() const; protected: + virtual bool isTermOrderInversed() const; + + virtual bool isComparableOrderInversed() const; + + virtual std::strong_ordering compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const; + virtual ArgumentPtr simplify() const; virtual ArgumentPtr preSimplify() const; diff --git a/include/fintamath/expressions/interfaces/IPolynomExpression.hpp b/include/fintamath/expressions/interfaces/IPolynomExpression.hpp index daaf0739f..0d0d3f4f3 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,16 +40,10 @@ 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; - virtual bool isTermOrderInversed() const; - - virtual bool isComparableOrderInversed() const; - private: void simplifyRec(bool isPostSimplify); diff --git a/include/fintamath/functions/IFunctionCRTP.hpp b/include/fintamath/functions/IFunctionCRTP.hpp index c523e6405..cb27430f0 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()) { @@ -85,8 +85,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 +94,23 @@ 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) { + 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) && !detail::isExpression(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..7f5fab93a 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 34f99ace3..84f12e7d1 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]) && @@ -504,6 +505,11 @@ namespace detail { std::unique_ptr makeExpr(const IFunction &func, ArgumentPtrVector args) { stdr::transform(args, args.begin(), &Expression::compress); + + if (func.isVariadic() && args.size() == 1) { + return std::move(args.front())->clone(); + } + Expression::validateFunctionArgs(func, args); if (const auto strToConstr = Expression::getExpressionMaker().find(func.getClass()); diff --git a/src/fintamath/expressions/ExpressionComparator.cpp b/src/fintamath/expressions/ExpressionComparator.cpp index d391c60a3..b45614c84 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); + + if (lhsComp && rhsComp) { + ordering = *lhsComp < *rhsComp ? Ordering::less : Ordering::greater; - return *lhsComp > *rhsComp ? Ordering::greater : Ordering::less; + 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,22 +245,16 @@ 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()); - - if ((lhsOper != nullptr) != (rhsOper != nullptr)) { - return compareFunctions(lhs->getFunction(), rhs->getFunction(), options); +Ordering compareExpressions(const ExpressionPtr &lhs, const ExpressionPtr &rhs, const ComparatorOptions options) { + if (*lhs->getFunction() != *rhs->getFunction()) { + return compareFunctions(lhs->getFunction(), rhs->getFunction()); } ComparatorOptions childCompOptions = options; @@ -260,32 +270,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 +296,20 @@ 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; - } - - return Ordering::less; - } - + // TODO!!! remove Mul from here 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 +321,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 +334,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; - } - - if (result.postfix == Ordering::equal) { - result.postfix = compare(compLhs, compRhs, options); + result.literals = compareTerms(lhsChildren[i], rhsChildren[j], options); } - if (result.postfix != Ordering::equal) { + if (result.postfix != Ordering::equal && result.literals != Ordering::equal) { break; } } @@ -411,18 +373,6 @@ 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 && diff --git a/src/fintamath/expressions/ExpressionUtils.cpp b/src/fintamath/expressions/ExpressionUtils.cpp index 99ad079c3..34ea59073 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" @@ -254,6 +256,22 @@ ArgumentPtr negate(const ArgumentPtr &arg) { return mulExpr(Integer(-1).clone(), arg); } +ArgumentPtr invert(const ArgumentPtr &arg) { + if (const auto num = cast(arg)) { + return Integer(1) / (*num); + } + + if (const auto expr = cast(arg); expr && is
(expr->getFunction())) { + if (*expr->getChildren().front() == Integer(1)) { + return expr->getChildren().back(); + } + + return divExpr(expr->getChildren().back(), expr->getChildren().front()); + } + + return divExpr(Integer(1).clone(), arg); +} + ArgumentPtr makePolynom(const IFunction &func, ArgumentPtrVector &&args) { if (args.empty()) { return {}; @@ -329,14 +347,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 +365,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 182018937..b9e4f654d 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" @@ -88,6 +89,22 @@ const std::shared_ptr &IExpression::getOutputFunction() const { return getFunction(); } +bool IExpression::isTermOrderInversed() const { + return false; +} + +bool IExpression::isComparableOrderInversed() const { + return false; +} + +std::strong_ordering IExpression::compare(const ArgumentPtr &lhs, const ArgumentPtr &rhs) const { + const ComparatorOptions options = { + .termOrderInversed = isTermOrderInversed(), + .comparableOrderInversed = isComparableOrderInversed(), + }; + return fintamath::compare(lhs, rhs, options); +} + ArgumentPtr IExpression::simplify() const { ArgumentPtr simpl = cast(clone()); preSimplifyChild(simpl); @@ -167,8 +184,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 +357,7 @@ ArgumentPtr IExpression::approximateSimplify() 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/DivExpr.cpp b/src/fintamath/expressions/binary/DivExpr.cpp index 0c92896ff..abb01ad0c 100644 --- a/src/fintamath/expressions/binary/DivExpr.cpp +++ b/src/fintamath/expressions/binary/DivExpr.cpp @@ -402,7 +402,7 @@ std::pair DivExpr::mulSumSimplify(const ArgumentPtr &l 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 {}; } diff --git a/src/fintamath/expressions/binary/PowExpr.cpp b/src/fintamath/expressions/binary/PowExpr.cpp index fd7e1c866..7cac3e5d6 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::approximateSimplify() const { diff --git a/src/fintamath/expressions/binary/PowExpr.hpp b/src/fintamath/expressions/binary/PowExpr.hpp index 41b69e567..f80b2bc22 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 approximateSimplify() 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..6e4b0b4f9 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 { @@ -39,20 +40,20 @@ const ArgumentPtrVector &IPolynomExpression::getChildren() const { } std::string IPolynomExpression::toString() const { - const auto oper = cast(func); - if (!oper) { - return functionToString(*func, children); - } + const auto &outFunc = getOutputFunction(); + const auto outOper = cast(outFunc); - std::string result; + if (!outOper) { + return functionToString(*outFunc, children); + } - result += childToString(*oper, children.front(), {}); + 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,23 +198,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); -} - -bool IPolynomExpression::isTermOrderInversed() const { - return false; -} - -bool IPolynomExpression::isComparableOrderInversed() const { - return false; + const std::string operStr = prevChild ? putInSpaces(oper.toString()) : ""; + return operStr + childStr; } void IPolynomExpression::setChildren(const ArgumentPtrVector &childVect) { 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..95107f0d6 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,7 @@ 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 - */ + // TODO!!! remove from here 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..bfb8694d7 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()); @@ -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/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/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/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/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..1837436c4 100644 --- a/tests/src/expressions/ExpressionComparatorTests.cpp +++ b/tests/src/expressions/ExpressionComparatorTests.cpp @@ -1,20 +1,32 @@ #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); - // TODO: add more tests -} + 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); +} \ No newline at end of file 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..e9c74c8ff 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,7 +38,7 @@ 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"); @@ -56,7 +57,7 @@ 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"); @@ -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(IArithmetic::getClassStatic(), IArithmetic::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(), IArithmetic::getClassStatic()); EXPECT_EQ(Neg().getReturnClass(), IArithmetic::getClassStatic()); EXPECT_EQ(Sin().getReturnClass(), INumber::getClassStatic()); } @@ -101,14 +102,25 @@ 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})); + EXPECT_FALSE(Mul().doArgsMatch({b, b, c, a})); + + EXPECT_FALSE(Mul().doArgsMatch({})); + EXPECT_TRUE(Mul().doArgsMatch({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..8537f4216 100644 --- a/tests/src/functions/arithmetic/AddTests.cpp +++ b/tests/src/functions/arithmetic/AddTests.cpp @@ -12,7 +12,7 @@ using namespace fintamath; const Add f; TEST(AddTests, toStringTest) { - EXPECT_EQ(f.toString(), "+"); + EXPECT_EQ(f.toString(), "add"); } TEST(AddTests, getArgumentClassesTest) { @@ -31,14 +31,6 @@ 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) { EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "8"); EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "11/2"); @@ -60,5 +52,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..28db73965 100644 --- a/tests/src/functions/arithmetic/MulTests.cpp +++ b/tests/src/functions/arithmetic/MulTests.cpp @@ -11,7 +11,7 @@ using namespace fintamath; const Mul f; TEST(MulTests, toStringTest) { - EXPECT_EQ(f.toString(), "*"); + EXPECT_EQ(f.toString(), "mul"); } TEST(MulTests, getArgumentClassesTest) { @@ -30,14 +30,6 @@ 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) { EXPECT_EQ(f(Integer(3), Integer(5))->toString(), "15"); EXPECT_EQ(f(Integer(3), Rational(5, 2))->toString(), "15/2"); @@ -58,5 +50,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..4cb50cb7e 100644 --- a/tests/src/functions/logic/AndTests.cpp +++ b/tests/src/functions/logic/AndTests.cpp @@ -11,7 +11,7 @@ using namespace fintamath; const And f; TEST(AndTests, toStringTest) { - EXPECT_EQ(f.toString(), "&"); + EXPECT_EQ(f.toString(), "and"); } TEST(AndTests, getArgumentClassesTest) { @@ -30,14 +30,6 @@ 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) { EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "False"); @@ -57,5 +49,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/OrOperTests.cpp b/tests/src/functions/logic/OrOperTests.cpp new file mode 100644 index 000000000..44d63c487 --- /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("Or")); + 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..71728f2ca 100644 --- a/tests/src/functions/logic/OrTests.cpp +++ b/tests/src/functions/logic/OrTests.cpp @@ -11,7 +11,7 @@ using namespace fintamath; const Or f; TEST(OrTests, toStringTest) { - EXPECT_EQ(f.toString(), "|"); + EXPECT_EQ(f.toString(), "or"); } TEST(OrTests, getArgumentClassesTest) { @@ -30,14 +30,6 @@ 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) { EXPECT_EQ(f(Boolean(false), Boolean(false))->toString(), "False"); EXPECT_EQ(f(Boolean(false), Boolean(true))->toString(), "True"); @@ -57,5 +49,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..b38e9255b --- /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(IArithmetic::getClassStatic(), IArithmetic::getClassStatic())); +} + +TEST(PowOperTests, getReturnClassTest) { + EXPECT_EQ(f.getReturnClass(), IArithmetic::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..a4ccb9caa 100644 --- a/tests/src/overall/simplify/SimplifyDerivativeTests.cpp +++ b/tests/src/overall/simplify/SimplifyDerivativeTests.cpp @@ -60,15 +60,15 @@ TEST(SimplifyDerivativeTests, simplifyTest) { EXPECT_EQ(Expression("derivative(2 mod x, x)").toString(), "derivative(2 mod x, x)"); EXPECT_EQ(Expression("derivative(x ^ x, x)").toString(), - "x^x ln(x) + x^x"); + "ln(x) x^x + x^x"); EXPECT_EQ(Expression("derivative(x ^ y, x)").toString(), "x^(y - 1) y"); EXPECT_EQ(Expression("derivative(y ^ x, x)").toString(), - "y^x ln(y)"); + "ln(y) y^x"); EXPECT_EQ(Expression("derivative(x ^ 2, x)").toString(), "2 x"); EXPECT_EQ(Expression("derivative(2 ^ x, x)").toString(), - "2^x ln(2)"); + "2 ln(2) 2^(x - 1)"); EXPECT_EQ(Expression("derivative(x ^ (3/5), x)").toString(), "3/(5 x^(2/5))"); EXPECT_EQ(Expression("derivative((3/5) ^ x, x)").toString(), diff --git a/tests/src/overall/simplify/SimplifyInfinityTests.cpp b/tests/src/overall/simplify/SimplifyInfinityTests.cpp index 139f7b26c..a8b4caeb7 100644 --- a/tests/src/overall/simplify/SimplifyInfinityTests.cpp +++ b/tests/src/overall/simplify/SimplifyInfinityTests.cpp @@ -128,7 +128,7 @@ TEST(SimplifyInfinityTests, simplifyTest) { EXPECT_EQ(Expression("(-Inf)^3").toString(), "-Inf"); EXPECT_EQ(Expression("(-Inf)^(2/3)").toString(), - "Inf sign((-1)^(2/3))"); + "sign((-1)^(2/3)) Inf"); EXPECT_EQ(Expression("ComplexInf^2").toString(), "ComplexInf"); EXPECT_EQ(Expression("ComplexInf^(2/3)").toString(), @@ -202,7 +202,7 @@ TEST(SimplifyInfinityTests, simplifyTest) { EXPECT_EQ(Expression("Inf ^ -sqrt(5)").toString(), "0"); EXPECT_EQ(Expression("(-Inf) ^ sqrt(5)").toString(), - "Inf sign((-1)^sqrt(5))"); + "sign((-1)^sqrt(5)) Inf"); EXPECT_EQ(Expression("(-Inf) ^ -sqrt(5)").toString(), "0"); EXPECT_EQ(Expression("ComplexInf ^ sqrt(5)").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..ae94aa281 100644 --- a/tests/src/overall/simplify/SimplifyTests.cpp +++ b/tests/src/overall/simplify/SimplifyTests.cpp @@ -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"); + "(sin(1) sinh(2) E^2 + ln(5) Pi^4) 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(), @@ -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(),